From 9f2854a22c67bc58fd8b7942202e45dab51c642b Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Tue, 11 Mar 2025 10:06:52 +0530 Subject: [PATCH 01/49] Add dark mode support for testing pages --- .../[projectId]/test/[[...slug]]/app.tsx | 8 +- .../test/[[...slug]]/profiles_app.tsx | 90 ++++++------- .../[projectId]/test/[[...slug]]/runs_app.tsx | 12 +- .../test/[[...slug]]/scenarios_app.tsx | 74 +++++------ .../test/[[...slug]]/simulations_app.tsx | 118 ++++++++---------- 5 files changed, 141 insertions(+), 161 deletions(-) diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx index 8538c89a..88837987 100644 --- a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx @@ -48,13 +48,17 @@ export function App({ {menuItems.map((item) => (
  • {item.label}
  • ))} -
    +
    {selection === "scenarios" && } {selection === "profiles" && } {selection === "simulations" && } diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/profiles_app.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/profiles_app.tsx index a0e9d14c..5ba7e040 100644 --- a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/profiles_app.tsx +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/profiles_app.tsx @@ -60,12 +60,12 @@ function EditProfile({ } return
    -

    Edit Profile

    - {loading &&
    +

    Edit Profile

    + {loading &&
    Loading...
    } - {error &&
    + {error &&
    {error}
    } @@ -157,7 +157,7 @@ function ViewProfile({ } return
    -

    View Profile

    +

    View Profile

    - {loading &&
    + {loading &&
    Loading...
    } - {!loading && !profile &&
    Profile not found
    } + {!loading && !profile &&
    Profile not found
    } {!loading && profile && ( <>
    -
    -
    Name
    -
    -
    {profile.name}
    +
    +
    Name
    +
    {profile.name}
    +
    +
    +
    Context
    +
    {profile.context}
    +
    +
    +
    Mock Tools
    +
    {profile.mockTools ? "Yes" : "No"}
    +
    + {profile.mockPrompt && ( +
    +
    Mock Prompt
    +
    {profile.mockPrompt}
    + )} +
    +
    Created
    +
    -
    -
    Context
    -
    {profile.context}
    -
    -
    -
    Mock Tools
    -
    {profile.mockTools ? "Yes" : "No"}
    -
    - {profile.mockPrompt &&
    -
    Mock Prompt
    -
    {profile.mockPrompt}
    -
    } -
    -
    Created
    -
    -
    -
    -
    Last Updated
    -
    +
    +
    Last Updated
    +
    @@ -413,7 +413,7 @@ function ProfileList({ }, [page, pageSize, error, projectId]); return
    -

    Profiles

    +

    Profiles

    - {loading &&
    + {loading &&
    Loading...
    } - {error &&
    + {error &&
    {error}
    } {!loading && !error && <> - {profiles.length === 0 &&
    No profiles found
    } + {profiles.length === 0 &&
    No profiles found
    } {profiles.length > 0 &&
    {/* Header */} -
    -
    Name
    -
    Context
    -
    Mock Tools
    -
    Created
    -
    Updated
    +
    +
    Name
    +
    Context
    +
    Mock Tools
    +
    Created
    +
    Updated
    {/* Rows */} {profiles.map((profile) => ( -
    +
    {profile.name}
    -
    {profile.context}
    -
    {profile.mockTools ? "Yes" : "No"}
    -
    +
    {profile.context}
    +
    {profile.mockTools ? "Yes" : "No"}
    +
    -
    +
    diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/runs_app.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/runs_app.tsx index 6207bd51..fd8a5e2f 100644 --- a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/runs_app.tsx +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/runs_app.tsx @@ -354,7 +354,7 @@ function RunList({
    } {!loading && !error && <> - {runs.length === 0 &&
    No test runs found
    } + {runs.length === 0 &&
    No test runs found
    } {runs.length > 0 &&
    {runs.map((run) => (
    @@ -362,7 +362,7 @@ function RunList({
    {run.name} @@ -417,16 +417,16 @@ function getStatusClass(status: string) { const baseClass = "px-2 py-1 rounded text-xs uppercase font-medium"; switch (status) { case 'completed': - return `${baseClass} bg-green-100 text-green-800`; + return `${baseClass} bg-green-100 dark:bg-green-900/20 text-green-800 dark:text-green-400`; case 'failed': case 'error': - return `${baseClass} bg-red-100 text-red-800`; + return `${baseClass} bg-red-100 dark:bg-red-900/20 text-red-800 dark:text-red-400`; case 'cancelled': - return `${baseClass} bg-gray-100 text-gray-800`; + return `${baseClass} bg-gray-100 dark:bg-neutral-800 text-gray-800 dark:text-neutral-400`; case 'running': case 'pending': default: - return `${baseClass} bg-yellow-100 text-yellow-800`; + return `${baseClass} bg-yellow-100 dark:bg-yellow-900/20 text-yellow-800 dark:text-yellow-400`; } } diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/scenarios_app.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/scenarios_app.tsx index 43541df8..3b269420 100644 --- a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/scenarios_app.tsx +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/scenarios_app.tsx @@ -51,22 +51,14 @@ function EditScenario({ } return
    -

    Edit Scenario

    - {loading &&
    +

    Edit Scenario

    + {loading &&
    Loading...
    } - {error &&
    + {error &&
    {error} - +
    } {!loading && scenario && (
    @@ -140,7 +132,7 @@ function ViewScenario({ } return
    -

    View Scenario

    +

    View Scenario

    - {loading &&
    + {loading &&
    Loading...
    } - {!loading && !scenario &&
    Scenario not found
    } + {!loading && !scenario &&
    Scenario not found
    } {!loading && scenario && ( <>
    -
    -
    Name
    -
    {scenario.name}
    +
    +
    Name
    +
    {scenario.name}
    -
    -
    Description
    -
    {scenario.description}
    +
    +
    Description
    +
    {scenario.description}
    -
    -
    Created
    -
    +
    +
    Created
    +
    -
    -
    Last Updated
    -
    +
    +
    Last Updated
    +
    @@ -372,7 +364,7 @@ function ScenarioList({ }, [page, pageSize, error, projectId]); return
    -

    Scenarios

    +

    Scenarios

    - {loading &&
    + {loading &&
    Loading...
    } - {error &&
    + {error &&
    {error}
    } {!loading && !error && <> - {scenarios.length === 0 &&
    No scenarios found
    } + {scenarios.length === 0 &&
    No scenarios found
    } {scenarios.length > 0 &&
    {/* Header */} -
    -
    Name
    -
    Description
    -
    Created
    -
    Updated
    +
    +
    Name
    +
    Description
    +
    Created
    +
    Updated
    {/* Rows */} {scenarios.map((scenario) => ( -
    +
    {scenario.name}
    -
    {scenario.description}
    -
    +
    {scenario.description}
    +
    -
    +
    diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/simulations_app.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/simulations_app.tsx index b02d4bae..b95159df 100644 --- a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/simulations_app.tsx +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/simulations_app.tsx @@ -79,12 +79,12 @@ function EditSimulation({ } return
    -

    Edit Simulation

    - {loading &&
    +

    Edit Simulation

    + {loading &&
    Loading...
    } - {error &&
    + {error &&
    {error}
    } @@ -107,12 +107,12 @@ function EditSimulation({ required />
    - +
    {scenario ? ( -
    {scenario.name}
    +
    {scenario.name}
    ) : ( -
    No scenario selected
    +
    No scenario selected
    )}
    - +
    {profile ? ( -
    {profile.name}
    +
    {profile.name}
    ) : ( -
    No profile selected
    +
    No profile selected
    )} {profile && } - {loading &&
    + {loading &&
    Loading...
    } - {!loading && !simulation &&
    Simulation not found
    } + {!loading && !simulation &&
    Simulation not found
    } {!loading && simulation && ( <>
    -
    -
    Name
    -
    {simulation.name}
    +
    +
    Name
    +
    {simulation.name}
    -
    -
    Scenario
    -
    - {scenario ? ( - - {scenario.name} - - ) : ( -
    No scenario selected
    - )} -
    +
    +
    Scenario
    +
    {scenario?.name || 'Loading...'}
    -
    -
    Profile
    -
    - {profile ? ( - - {profile.name} - - ) : ( -
    No profile selected
    - )} -
    +
    +
    Profile
    +
    {profile?.name || 'None'}
    -
    -
    Pass Criteria
    -
    {simulation.passCriteria}
    +
    +
    Pass Criteria
    +
    {simulation.passCriteria}
    -
    -
    Created
    -
    +
    +
    Created
    +
    -
    -
    Last Updated
    -
    +
    +
    Last Updated
    +
    @@ -584,7 +568,7 @@ function SimulationList({ }, [simulationList, error, projectId]); return
    -

    Simulations

    +

    Simulations

    - {loading &&
    + {loading &&
    Loading...
    } - {error &&
    + {error &&
    {error}
    } {!loading && !error && <> - {simulationList.length === 0 &&
    No simulation found
    } + {simulationList.length === 0 &&
    No simulations found
    } {simulationList.length > 0 &&
    {/* Header */} -
    -
    Name
    -
    Scenario
    -
    Profile
    -
    Criteria
    -
    Created
    -
    Updated
    +
    +
    Name
    +
    Scenario
    +
    Profile
    +
    Criteria
    +
    Created
    +
    Updated
    {/* Rows */} {simulationList.map((simulation) => ( -
    +
    {simulation.name}
    -
    +
    {scenarioMap[simulation.scenarioId]?.name || ( - {simulation.scenarioId} + {simulation.scenarioId} )}
    -
    +
    {simulation.profileId ? ( profileMap[simulation.profileId]?.name || ( - {simulation.profileId} + {simulation.profileId} ) ) : ( - None + None )}
    -
    +
    {simulation.passCriteria}
    -
    +
    -
    +
    From 933a28ac28897c70f1b6f4527e7cd11245f98d5b Mon Sep 17 00:00:00 2001 From: arkml Date: Tue, 11 Mar 2025 13:31:26 +0530 Subject: [PATCH 02/49] added transcript and fixed simulation bugs --- apps/simulation_runner/db.py | 22 +++++++++--- apps/simulation_runner/scenario_types.py | 15 +------- apps/simulation_runner/simulation.py | 46 +++++++++++------------- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/apps/simulation_runner/db.py b/apps/simulation_runner/db.py index c8a79937..06713720 100644 --- a/apps/simulation_runner/db.py +++ b/apps/simulation_runner/db.py @@ -6,7 +6,6 @@ from typing import Optional from scenario_types import ( TestRun, TestScenario, - TestProfile, TestSimulation, TestResult, AggregateResults @@ -14,13 +13,11 @@ from scenario_types import ( MONGO_URI = os.environ.get("MONGODB_URI", "mongodb://localhost:27017/rowboat").strip() -# New collection names TEST_SCENARIOS_COLLECTION = "test_scenarios" -TEST_PROFILES_COLLECTION = "test_profiles" TEST_SIMULATIONS_COLLECTION = "test_simulations" TEST_RUNS_COLLECTION = "test_runs" TEST_RESULTS_COLLECTION = "test_results" -API_KEYS_COLLECTION = "api_keys" # If still needed +API_KEYS_COLLECTION = "api_keys" def get_db(): client = MongoClient(MONGO_URI) @@ -145,6 +142,23 @@ def get_simulations_for_run(test_run: TestRun) -> list[TestSimulation]: ) return simulations +def get_scenario_by_id(scenario_id: str) -> TestScenario: + """ + Returns a TestScenario by its ID. + """ + collection = get_collection(TEST_SCENARIOS_COLLECTION) + doc = collection.find_one({"_id": ObjectId(scenario_id)}) + if doc: + return TestScenario( + id=str(doc["_id"]), + projectId=doc["projectId"], + name=doc["name"], + description=doc["description"], + createdAt=doc["createdAt"], + lastUpdatedAt=doc["lastUpdatedAt"] + ) + return None + # # TestResult helpers # diff --git a/apps/simulation_runner/scenario_types.py b/apps/simulation_runner/scenario_types.py index 981342eb..3e61d894 100644 --- a/apps/simulation_runner/scenario_types.py +++ b/apps/simulation_runner/scenario_types.py @@ -14,16 +14,6 @@ class TestScenario(BaseModel): createdAt: datetime lastUpdatedAt: datetime -class TestProfile(BaseModel): - id: str - projectId: str - name: str - context: str - createdAt: datetime - lastUpdatedAt: datetime - mockTools: bool - mockPrompt: Optional[str] = None - class TestSimulation(BaseModel): id: str projectId: str @@ -48,11 +38,7 @@ class TestRun(BaseModel): status: RunStatus startedAt: datetime completedAt: Optional[datetime] = None - # By default, store aggregate results as a dict or the typed AggregateResults aggregateResults: Optional[AggregateResults] = None - - # The new schema does not mention lastHeartbeat, - # but you can keep it if you still want to track stale runs lastHeartbeat: Optional[datetime] = None class TestResult(BaseModel): @@ -61,3 +47,4 @@ class TestResult(BaseModel): simulationId: str result: Literal["pass", "fail"] details: str + transcript: str diff --git a/apps/simulation_runner/simulation.py b/apps/simulation_runner/simulation.py index 67e6dfd2..3ae2b41e 100644 --- a/apps/simulation_runner/simulation.py +++ b/apps/simulation_runner/simulation.py @@ -5,12 +5,9 @@ import json import os from openai import OpenAI -# Updated imports from your new schema/types -from scenario_types import TestSimulation, TestResult, AggregateResults - -# If your DB functions changed names, adapt here: -from db import write_test_result # replaced write_simulation_result +from scenario_types import TestSimulation, TestResult, AggregateResults, TestScenario +from db import write_test_result, get_scenario_by_id from rowboat import Client, StatefulChat openai_client = OpenAI() @@ -18,7 +15,9 @@ MODEL_NAME = "gpt-4o" ROWBOAT_API_HOST = os.environ.get("ROWBOAT_API_HOST", "http://127.0.0.1:3000").strip() async def simulate_simulation( - simulation: TestSimulation, + scenario: TestScenario, + profile_id: str, + pass_criteria: str, rowboat_client: Client, workflow_id: str, max_iterations: int = 5 @@ -30,25 +29,19 @@ async def simulate_simulation( """ loop = asyncio.get_running_loop() + pass_criteria = pass_criteria - # Optionally embed passCriteria in the system prompt, if it’s relevant to context: - pass_criteria = simulation.passCriteria or "" - # Or place it separately below if you prefer. - - # Prepare a Rowboat chat + # Todo: add profile_id support_chat = StatefulChat( rowboat_client, - system_prompt=f"Context: {pass_criteria}" if pass_criteria else "", workflow_id=workflow_id ) - # You might want to describe the simulation or scenario more thoroughly. - # Here, we just embed simulation.name in the system message: messages = [ { "role": "system", "content": ( - f"Simulate the user based on this simulation:\n{simulation.name}" + f"You are a customer talking to a chatbot. Have the following chat with the chatbot. Scenario:\n{scenario.description}. You are provided no other information. If the chatbot asks you for information that is not in context, go ahead and provide one unless stated otherwise in the scenario. Directly have the chat with the chatbot. Start now." ) } ] @@ -70,7 +63,7 @@ async def simulate_simulation( ) simulated_content = simulated_user_response.choices[0].message.content.strip() - + messages.append({"role": "user", "content": simulated_content}) # Run Rowboat chat in a thread if it's synchronous rowboat_response = await loop.run_in_executor( None, @@ -88,13 +81,16 @@ async def simulate_simulation( content = m.get("content", "") transcript_str += f"{role.upper()}: {content}\n" - # We use passCriteria as the evaluation β€œcriteria.” + # Store the transcript as a JSON string + transcript = json.dumps(messages) + + # We use passCriteria as the evaluation "criteria." evaluation_prompt = [ { "role": "system", "content": ( f"You are a neutral evaluator. Evaluate based on these criteria:\n" - f"{simulation.passCriteria}\n\n" + f"{pass_criteria}\n\n" "Return ONLY a JSON object in this format:\n" '{"verdict": "pass", "details": } or ' '{"verdict": "fail", "details": }.' @@ -117,8 +113,6 @@ async def simulate_simulation( model=MODEL_NAME, messages=evaluation_prompt, temperature=0.0, - # If your LLM supports a structured response format, you can specify it. - # Otherwise, remove or adapt 'response_format': response_format={"type": "json_object"} ) ) @@ -135,7 +129,7 @@ async def simulate_simulation( if evaluation_result is None: raise Exception("No 'verdict' field found in evaluation response") - return (evaluation_result, details, transcript_str) + return (evaluation_result, details, transcript) async def simulate_simulations( simulations: List[TestSimulation], @@ -151,10 +145,8 @@ async def simulate_simulations( # Return an empty result if there's nothing to simulate return AggregateResults(total=0, pass_=0, fail=0) - # We assume all simulations belong to the same project project_id = simulations[0].projectId - # Create a Rowboat client instance client = Client( host=ROWBOAT_API_HOST, project_id=project_id, @@ -165,9 +157,10 @@ async def simulate_simulations( results: List[TestResult] = [] for simulation in simulations: - # Run each simulation verdict, details, transcript = await simulate_simulation( - simulation=simulation, + scenario=get_scenario_by_id(simulation.scenarioId), + profile_id=simulation.profileId, + pass_criteria=simulation.passCriteria, rowboat_client=client, workflow_id=workflow_id, max_iterations=max_iterations @@ -179,7 +172,8 @@ async def simulate_simulations( runId=run_id, simulationId=simulation.id, result=verdict, - details=details + details=details, + transcript=transcript ) results.append(test_result) From 80e410888b09c4b676322849cc50cf3c6ca452b6 Mon Sep 17 00:00:00 2001 From: arkml Date: Tue, 11 Mar 2025 18:36:17 +0530 Subject: [PATCH 03/49] add test profile to simulations --- apps/simulation_runner/requirements.txt | 2 +- apps/simulation_runner/simulation.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/simulation_runner/requirements.txt b/apps/simulation_runner/requirements.txt index 8b501db2..bd0f4f9d 100644 --- a/apps/simulation_runner/requirements.txt +++ b/apps/simulation_runner/requirements.txt @@ -21,7 +21,7 @@ pytest==8.3.4 pytest-asyncio==0.25.3 python-dateutil==2.9.0.post0 requests==2.32.3 -rowboat==1.0.4 +rowboat==2.1.0 six==1.17.0 sniffio==1.3.1 tqdm==4.67.1 diff --git a/apps/simulation_runner/simulation.py b/apps/simulation_runner/simulation.py index 3ae2b41e..900255f4 100644 --- a/apps/simulation_runner/simulation.py +++ b/apps/simulation_runner/simulation.py @@ -34,7 +34,8 @@ async def simulate_simulation( # Todo: add profile_id support_chat = StatefulChat( rowboat_client, - workflow_id=workflow_id + workflow_id=workflow_id, + test_profile_id=profile_id ) messages = [ From d15eddc951a85de9214e69adc21f57236314eb56 Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Thu, 6 Mar 2025 14:45:50 +0530 Subject: [PATCH 04/49] Add support for greeting message in agents --- apps/agents/src/graph/core.py | 125 ++++++++++++++++------ apps/agents/src/graph/types.py | 4 +- apps/rowboat/app/lib/project_templates.ts | 15 +++ 3 files changed, 108 insertions(+), 36 deletions(-) diff --git a/apps/agents/src/graph/core.py b/apps/agents/src/graph/core.py index 074fe86b..7a989a3f 100644 --- a/apps/agents/src/graph/core.py +++ b/apps/agents/src/graph/core.py @@ -14,6 +14,7 @@ from .helpers.state import add_recent_messages_to_history, construct_state_from_ from .helpers.instructions import add_transfer_instructions_to_child_agents, add_transfer_instructions_to_parent_agents, add_rag_instructions_to_agent, add_error_escalation_instructions, get_universal_system_message, add_universal_system_message_to_agent from .helpers.control import get_latest_assistant_msg, get_latest_non_assistant_messages, get_last_agent_name from src.swarm.types import Response +from datetime import datetime from src.utils.common import common_logger logger = common_logger @@ -283,9 +284,16 @@ def handle_error(error_tool_call, error_msg, return_diff_messages, messages, tur return resp_messages, tokens_used, state else: raise ValueError(error_msg) + +def create_final_response(response, turn_messages, messages, tokens_used, all_agents, return_diff_messages): + response.messages = turn_messages if return_diff_messages else messages + turn_messages + response.tokens_used = tokens_used + new_state = construct_state_from_response(response, all_agents) + return response.messages, response.tokens_used, new_state def run_turn(messages, start_agent_name, agent_configs, tool_configs, available_tool_mappings={}, localize_history=True, return_diff_messages=True, prompt_configs=[], start_turn_with_start_agent=False, children_aware_of_parent=False, parent_has_child_history=True, state={}, additional_tool_configs=[], error_tool_call=True, max_messages_per_turn=10, max_messages_per_error_escalation_turn=4, escalate_errors=True, max_overall_turns=10): - + + greeting_turn = True if not any(msg.get("role") != "system" for msg in messages) else False logger.info("Running stateless turn") turn_messages = [] tokens_used = {} @@ -310,40 +318,42 @@ def run_turn(messages, start_agent_name, agent_configs, tool_configs, available_ turn_messages=turn_messages, state=state, tokens_used=tokens_used - ) + ) post_processing_agent_config, agent_configs = pop_agent_config_by_type(agent_configs, AgentRole.POST_PROCESSING.value) guardrails_agent_config, agent_configs = pop_agent_config_by_type(agent_configs, AgentRole.GUARDRAILS.value) - - latest_assistant_msg = get_latest_assistant_msg(messages) - universal_sys_msg = get_universal_system_message(messages) - latest_non_assistant_msgs = get_latest_non_assistant_messages(messages) - msg_type = latest_non_assistant_msgs[-1]["role"] - - last_agent_name = get_last_agent_name( - state=state, - agent_configs=agent_configs, - start_agent_name=start_agent_name, - msg_type=msg_type, - latest_assistant_msg=latest_assistant_msg, - start_turn_with_start_agent=start_turn_with_start_agent - ) - - logger.info("Localizing message history") agent_data = state.get("agent_data", []) - if msg_type == "user": - messages = reset_current_turn(messages) - agent_data = reset_current_turn_agent_history(agent_data, [last_agent_name]) - agent_data = clean_up_history(agent_data) - agent_data = add_recent_messages_to_history( - recent_messages=latest_non_assistant_msgs, - last_agent_name=last_agent_name, - agent_data=agent_data, - messages=messages, - parent_has_child_history=parent_has_child_history - ) - state["agent_data"] = agent_data + universal_sys_msg = "" + if not greeting_turn: + latest_assistant_msg = get_latest_assistant_msg(messages) + universal_sys_msg = get_universal_system_message(messages) + latest_non_assistant_msgs = get_latest_non_assistant_messages(messages) + msg_type = latest_non_assistant_msgs[-1]["role"] + + last_agent_name = get_last_agent_name( + state=state, + agent_configs=agent_configs, + start_agent_name=start_agent_name, + msg_type=msg_type, + latest_assistant_msg=latest_assistant_msg, + start_turn_with_start_agent=start_turn_with_start_agent + ) + + logger.info("Localizing message history") + if msg_type == "user": + messages = reset_current_turn(messages) + agent_data = reset_current_turn_agent_history(agent_data, [last_agent_name]) + agent_data = clean_up_history(agent_data) + agent_data = add_recent_messages_to_history( + recent_messages=latest_non_assistant_msgs, + last_agent_name=last_agent_name, + agent_data=agent_data, + messages=messages, + parent_has_child_history=parent_has_child_history + ) + + state["agent_data"] = agent_data logger.info("Initializing agents") all_agents = get_agents( agent_configs=agent_configs, @@ -361,6 +371,49 @@ def run_turn(messages, start_agent_name, agent_configs, tool_configs, available_ error_tool_call=error_tool_call, error_msg="No agents initialized" ) + + if greeting_turn: + greeting_msg = get_prompt_by_type(prompt_configs, PromptType.GREETING.value) + if not greeting_msg: + logger.error("Greeting prompt not found and messages is empty") + return handle_error( + error_tool_call=error_tool_call, + error_msg="Greeting prompt not found and messages is empty", + return_diff_messages=return_diff_messages, + messages=messages, + turn_messages=turn_messages, + state=state, + tokens_used=tokens_used + ) + + greeting_msg_internal = { + "content": greeting_msg, + "role": "assistant", + "sender": start_agent_name, + "response_type": "internal", + "created_at": datetime.now().isoformat(), + "current_turn": True + } + greeting_msg_external = deepcopy(greeting_msg_internal) + greeting_msg_external["response_type"] = "external" + greeting_msg_external["sender"] = greeting_msg_external["sender"] + ' >> External' + turn_messages.extend([greeting_msg_internal, greeting_msg_external]) + + response = Response( + messages=turn_messages, + tokens_used={}, + agent=get_agent_by_name(start_agent_name, all_agents), + error_msg='' + ) + + return create_final_response( + response=response, + turn_messages=turn_messages, + messages=messages, + tokens_used=tokens_used, + all_agents=all_agents, + return_diff_messages=return_diff_messages + ) error_escalation_agent = deepcopy(get_agent_by_type(all_agents, AgentRole.ESCALATION.value)) if not error_escalation_agent: @@ -498,7 +551,11 @@ def run_turn(messages, start_agent_name, agent_configs, tool_configs, available_ logger.error("State is empty or last agent name is not set") raise ValueError("State is empty or last agent name is not set") - response.messages = turn_messages if return_diff_messages else messages + turn_messages - response.tokens_used = tokens_used - new_state = construct_state_from_response(response, all_agents) - return response.messages, response.tokens_used, new_state \ No newline at end of file + return create_final_response( + response=response, + turn_messages=turn_messages, + messages=messages, + tokens_used=tokens_used, + all_agents=all_agents, + return_diff_messages=return_diff_messages + ) \ No newline at end of file diff --git a/apps/agents/src/graph/types.py b/apps/agents/src/graph/types.py index 3730be11..32c827fb 100644 --- a/apps/agents/src/graph/types.py +++ b/apps/agents/src/graph/types.py @@ -11,8 +11,8 @@ class ControlType(Enum): class PromptType(Enum): STYLE = "style_prompt" + GREETING = "greeting" class ErrorType(Enum): FATAL = "fatal" - ESCALATE = "escalate" - + ESCALATE = "escalate" \ No newline at end of file diff --git a/apps/rowboat/app/lib/project_templates.ts b/apps/rowboat/app/lib/project_templates.ts index c73eca36..900a48dd 100644 --- a/apps/rowboat/app/lib/project_templates.ts +++ b/apps/rowboat/app/lib/project_templates.ts @@ -75,6 +75,11 @@ You are an helpful customer support assistant type: "style_prompt", prompt: "You should be empathetic and helpful.", }, + { + name: "Greeting", + type: "greeting", + prompt: "Hello! How can I help you?" + } ], tools: [], }, @@ -131,6 +136,11 @@ You are an helpful customer support assistant "name": "Style prompt", "type": "style_prompt", "prompt": "You should be empathetic and helpful." + }, + { + "name": "Greeting", + "type": "greeting", + "prompt": "Hello! How can I help you?" } ], "tools": [ @@ -259,6 +269,11 @@ You are an helpful customer support assistant "type": "style_prompt", "prompt": "---\n\nmake this more friendly. Keep it to 5-7 sentences. Use these as example references:\n\n---" }, + { + "name": "Greeting", + "type": "greeting", + "prompt": "Hello! How can I help you?" + }, { "name": "structured_output", "type": "base_prompt", From 3ea08895b89386f60bc1a9915945aad3c82030d8 Mon Sep 17 00:00:00 2001 From: ramnique <30795890+ramnique@users.noreply.github.com> Date: Fri, 7 Mar 2025 01:23:13 +0530 Subject: [PATCH 05/49] Autorun chat in playground to show greeting --- apps/rowboat/app/lib/types/workflow_types.ts | 1 + .../projects/[projectId]/playground/app.tsx | 8 +++ .../projects/[projectId]/playground/chat.tsx | 30 ++++++------ .../[projectId]/playground/messages.tsx | 49 +++++++++---------- 4 files changed, 47 insertions(+), 41 deletions(-) diff --git a/apps/rowboat/app/lib/types/workflow_types.ts b/apps/rowboat/app/lib/types/workflow_types.ts index 160fc645..5d9599d8 100644 --- a/apps/rowboat/app/lib/types/workflow_types.ts +++ b/apps/rowboat/app/lib/types/workflow_types.ts @@ -27,6 +27,7 @@ export const WorkflowPrompt = z.object({ type: z.union([ z.literal('base_prompt'), z.literal('style_prompt'), + z.literal('greeting'), ]), prompt: z.string(), }); diff --git a/apps/rowboat/app/projects/[projectId]/playground/app.tsx b/apps/rowboat/app/projects/[projectId]/playground/app.tsx index 2b6db148..17d304d4 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/app.tsx @@ -25,6 +25,7 @@ export function App({ }) { const [counter, setCounter] = useState(0); const [testProfile, setTestProfile] = useState | null>(null); + const [systemMessage, setSystemMessage] = useState(defaultSystemMessage); const [chat, setChat] = useState>({ projectId, createdAt: new Date().toISOString(), @@ -33,6 +34,11 @@ export function App({ systemMessage: defaultSystemMessage, }); + function handleSystemMessageChange(message: string) { + setSystemMessage(message); + setCounter(counter + 1); + } + function handleTestProfileChange(profile: WithStringId> | null) { setTestProfile(profile); setCounter(counter + 1); @@ -105,6 +111,8 @@ export function App({ testProfile={testProfile} messageSubscriber={messageSubscriber} onTestProfileChange={handleTestProfileChange} + systemMessage={systemMessage} + onSystemMessageChange={handleSystemMessageChange} />
    diff --git a/apps/rowboat/app/projects/[projectId]/playground/chat.tsx b/apps/rowboat/app/projects/[projectId]/playground/chat.tsx index 8eadcd3a..01c3b5ef 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/chat.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/chat.tsx @@ -24,6 +24,8 @@ export function Chat({ messageSubscriber, testProfile=null, onTestProfileChange, + systemMessage, + onSystemMessageChange, }: { chat: z.infer; projectId: string; @@ -31,6 +33,8 @@ export function Chat({ messageSubscriber?: (messages: z.infer[]) => void; testProfile?: z.infer | null; onTestProfileChange: (profile: WithStringId> | null) => void; + systemMessage: string; + onSystemMessageChange: (message: string) => void; }) { const [messages, setMessages] = useState[]>(chat.messages); const [loadingAssistantResponse, setLoadingAssistantResponse] = useState(false); @@ -42,7 +46,6 @@ export function Chat({ const [fetchResponseError, setFetchResponseError] = useState(null); const [lastAgenticRequest, setLastAgenticRequest] = useState(null); const [lastAgenticResponse, setLastAgenticResponse] = useState(null); - const [systemMessage, setSystemMessage] = useState(testProfile?.context); const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false); // collect published tool call results @@ -142,18 +145,17 @@ export function Chat({ } } - // if no messages, return - if (messages.length === 0) { - return; - } - // if last message is not from role user // or tool, return - const last = messages[messages.length - 1]; - if (fetchResponseError) { - return; + if (messages.length > 0) { + const last = messages[messages.length - 1]; + if (last.role !== 'user' && last.role !== 'tool') { + return; + } } - if (last.role !== 'user' && last.role !== 'tool') { + + // if there is an error, return + if (fetchResponseError) { return; } @@ -274,10 +276,6 @@ export function Chat({ navigator.clipboard.writeText(jsonString); } - function handleSystemMessageChange(message: string) { - setSystemMessage(message); - } - return
    @@ -304,14 +302,14 @@ export function Chat({
    {fetchResponseError && ( diff --git a/apps/rowboat/app/projects/[projectId]/playground/messages.tsx b/apps/rowboat/app/projects/[projectId]/playground/messages.tsx index 5b3c6045..dd8d667a 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/messages.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/messages.tsx @@ -94,7 +94,7 @@ function ToolCalls({ messages, sender, workflow, - testProfile=null, + testProfile = null, systemMessage, }: { toolCalls: z.infer['tool_calls']; @@ -143,7 +143,7 @@ function ToolCall({ messages, sender, workflow, - testProfile=null, + testProfile = null, systemMessage, }: { toolCall: z.infer['tool_calls'][number]; @@ -186,8 +186,8 @@ function ToolCall({ sender={sender} />; } - if (!matchingWorkflowTool || - matchingWorkflowTool.mockTool || + if (!matchingWorkflowTool || + matchingWorkflowTool.mockTool || (testProfile && testProfile.mockTools)) { return void, - locked: boolean + locked?: boolean, }) { - return ( -
    -
    CONTEXT
    - -
    - ); + return
    + +
    ; } export function Messages({ projectId, - systemMessage, messages, toolCallResults, handleToolCallResults, loadingAssistantResponse, loadingUserResponse, workflow, - testProfile=null, + testProfile = null, + systemMessage, onSystemMessageChange, }: { projectId: string; - systemMessage: string | undefined; messages: z.infer[]; toolCallResults: Record>; handleToolCallResults: (results: z.infer[]) => void; @@ -637,6 +635,7 @@ export function Messages({ loadingUserResponse: boolean; workflow: z.infer; testProfile: z.infer | null; + systemMessage: string | undefined; onSystemMessageChange: (message: string) => void; }) { const messagesEndRef = useRef(null); @@ -652,7 +651,7 @@ export function Messages({ 0} + locked={testProfile !== null} /> {messages.map((message, index) => { if (message.role === 'assistant') { From ff15e55c6d84599ef442b49eba787d0f5288074e Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Tue, 11 Mar 2025 12:55:24 +0530 Subject: [PATCH 06/49] Revamp testing flows UI UX --- apps/rowboat/app/actions/testing_actions.ts | 65 +- apps/rowboat/app/lib/types/testing_types.ts | 10 +- .../[projectId]/test/[[...slug]]/app.tsx | 25 +- .../test/[[...slug]]/components/item-view.tsx | 38 + .../[[...slug]]/components/profile-form.tsx | 90 ++ .../[[...slug]]/components/scenario-form.tsx | 68 ++ .../components/simulation-form.tsx | 190 ++++ .../test/[[...slug]]/components/table.tsx | 321 ++++++ .../[projectId]/test/[[...slug]]/page.tsx | 47 +- .../test/[[...slug]]/profiles_app.tsx | 587 ++++------- .../[projectId]/test/[[...slug]]/runs_app.tsx | 569 +++++------ .../test/[[...slug]]/scenarios_app.tsx | 573 ++++++----- .../test/[[...slug]]/simulations_app.tsx | 928 ++++++++---------- .../test/[[...slug]]/testing_menu.tsx | 53 + .../test/[[...slug]]/utils/date.ts | 4 + 15 files changed, 2097 insertions(+), 1471 deletions(-) create mode 100644 apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/item-view.tsx create mode 100644 apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/profile-form.tsx create mode 100644 apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/scenario-form.tsx create mode 100644 apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/simulation-form.tsx create mode 100644 apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/table.tsx create mode 100644 apps/rowboat/app/projects/[projectId]/test/[[...slug]]/testing_menu.tsx create mode 100644 apps/rowboat/app/projects/[projectId]/test/[[...slug]]/utils/date.ts diff --git a/apps/rowboat/app/actions/testing_actions.ts b/apps/rowboat/app/actions/testing_actions.ts index c697b483..ed6ee745 100644 --- a/apps/rowboat/app/actions/testing_actions.ts +++ b/apps/rowboat/app/actions/testing_actions.ts @@ -170,6 +170,7 @@ export async function createSimulation( projectId: string, data: { name: string; + description?: string; scenarioId: string; profileId: string | null; passCriteria: string; @@ -195,6 +196,7 @@ export async function updateSimulation( simulationId: string, updates: { name?: string; + description?: string; scenarioId?: string; profileId?: string | null; passCriteria?: string; @@ -268,7 +270,6 @@ export async function deleteProfile(projectId: string, profileId: string): Promi await testProfilesCollection.deleteOne({ _id: new ObjectId(profileId), projectId, - default: false, }); } @@ -449,6 +450,15 @@ export async function updateRun( ); } +export async function cancelRun(projectId: string, runId: string): Promise { + await projectAuthCheck(projectId); + + await testRunsCollection.updateOne( + { _id: new ObjectId(runId), projectId }, + { $set: { status: 'cancelled' } } + ); +} + export async function listResults( projectId: string, runId: string, @@ -510,6 +520,7 @@ export async function createResult( simulationId: string; result: 'pass' | 'fail'; details: string; + transcript: string; } ): Promise>> { await projectAuthCheck(projectId); @@ -544,4 +555,56 @@ export async function updateResult( $set: updates, } ); +} + +export async function getSimulationResult( + projectId: string, + runId: string, + simulationId: string +): Promise> | null> { + await projectAuthCheck(projectId); + + const result = await testResultsCollection.findOne({ + projectId, + runId, + simulationId + }); + + if (!result) { + return null; + } + + const { _id, ...rest } = result; + return { + ...rest, + _id: _id.toString(), + }; +} + +export async function listRunSimulations( + projectId: string, + simulationIds: string[] +): Promise>[]> { + await projectAuthCheck(projectId); + + const simulations = await testSimulationsCollection + .find({ + _id: { $in: simulationIds.map(id => new ObjectId(id)) }, + projectId + }) + .toArray(); + + // Fetch associated scenario and profile names + const enrichedSimulations = await Promise.all(simulations.map(async (simulation) => { + const scenario = simulation.scenarioId ? await testScenariosCollection.findOne({ _id: new ObjectId(simulation.scenarioId) }) : null; + const profile = simulation.profileId ? await testProfilesCollection.findOne({ _id: new ObjectId(simulation.profileId) }) : null; + return { + ...simulation, + _id: simulation._id.toString(), + scenarioName: scenario?.name || 'Unknown', + profileName: profile?.name || 'None', + }; + })); + + return enrichedSimulations; } \ No newline at end of file diff --git a/apps/rowboat/app/lib/types/testing_types.ts b/apps/rowboat/app/lib/types/testing_types.ts index ff544517..bbace333 100644 --- a/apps/rowboat/app/lib/types/testing_types.ts +++ b/apps/rowboat/app/lib/types/testing_types.ts @@ -20,12 +20,13 @@ export const TestProfile = z.object({ export const TestSimulation = z.object({ projectId: z.string(), - name: z.string().min(1, "Name cannot be empty"), + name: z.string(), + description: z.string().optional().nullable(), + createdAt: z.string().datetime(), + lastUpdatedAt: z.string().datetime(), scenarioId: z.string(), profileId: z.string().nullable(), passCriteria: z.string(), - createdAt: z.string().datetime(), - lastUpdatedAt: z.string().datetime(), }); export const TestRun = z.object({ @@ -48,5 +49,6 @@ export const TestResult = z.object({ runId: z.string(), simulationId: z.string(), result: z.union([z.literal('pass'), z.literal('fail')]), - details: z.string() + details: z.string(), + transcript: z.string() }); \ No newline at end of file diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx index 88837987..d8e8537f 100644 --- a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/app.tsx @@ -6,6 +6,8 @@ import { ProfilesApp } from "./profiles_app"; import { SimulationsApp } from "./simulations_app"; import { usePathname } from "next/navigation"; import { RunsApp } from "./runs_app"; +import { StructuredPanel } from "../../../../lib/components/structured-panel"; +import { ListItem } from "../../../../lib/components/structured-list"; export function App({ projectId, @@ -43,21 +45,18 @@ export function App({ ]; return
    -
    -
      + +
      {menuItems.map((item) => ( -
    • - {item.label} -
    • + router.push(item.href)} + /> ))} -
    -
    +
    +
    {selection === "scenarios" && } {selection === "profiles" && } diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/item-view.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/item-view.tsx new file mode 100644 index 00000000..c343e9db --- /dev/null +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/item-view.tsx @@ -0,0 +1,38 @@ +// First, let's create a reusable component for item views +export function ItemView({ + items, + actions +}: { + items: { label: string; value: string | React.ReactNode }[]; + actions: React.ReactNode; +}) { + return ( +
    + {/* Content */} +
    +
    + {items.map((item, index) => ( +
    +
    + {item.label} +
    +
    + {item.value || "β€”"} +
    +
    + ))} +
    + + {/* Actions */} +
    +
    + {actions} +
    +
    +
    +
    + ); +} \ No newline at end of file diff --git a/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/profile-form.tsx b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/profile-form.tsx new file mode 100644 index 00000000..e80f3f5d --- /dev/null +++ b/apps/rowboat/app/projects/[projectId]/test/[[...slug]]/components/profile-form.tsx @@ -0,0 +1,90 @@ +import { FormStatusButton } from "@/app/lib/components/form-status-button"; +import { Button, Input, Textarea, Switch } from "@heroui/react" +import { useRef, useState } from "react"; + +interface ProfileFormProps { + defaultValues?: { + name?: string; + context?: string; + mockTools?: boolean; + mockPrompt?: string; + }; + formRef: React.RefObject; + handleSubmit: (formData: FormData) => Promise; + onCancel: () => void; + submitButtonText: string; +} + +export function ProfileForm({ + defaultValues = {}, + formRef, + handleSubmit, + onCancel, + submitButtonText, +}: ProfileFormProps) { + const [mockTools, setMockTools] = useState(Boolean(defaultValues.mockTools)); + const [showMockPrompt, setShowMockPrompt] = useState(Boolean(defaultValues.mockTools)); + + return ( + + + + - -
    } -
    -
    ; -} - function ExpandableContent({ label, content, @@ -701,7 +291,6 @@ export function Messages({ projectId, messages, toolCallResults, - handleToolCallResults, loadingAssistantResponse, loadingUserResponse, workflow, @@ -712,7 +301,6 @@ export function Messages({ projectId: string; messages: z.infer[]; toolCallResults: Record>; - handleToolCallResults: (results: z.infer[]) => void; loadingAssistantResponse: boolean; loadingUserResponse: boolean; workflow: z.infer; @@ -742,7 +330,6 @@ export function Messages({ key={index} toolCalls={message.tool_calls} results={toolCallResults} - handleResults={handleToolCallResults} projectId={projectId} messages={messages} sender={message.agenticSender} diff --git a/apps/rowboat/app/projects/[projectId]/workflow/app.tsx b/apps/rowboat/app/projects/[projectId]/workflow/app.tsx index 47dae09e..331e20b7 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/app.tsx @@ -1,5 +1,5 @@ "use client"; -import { WithStringId } from "../../../lib/types/types"; +import { MCPServer, WithStringId } from "../../../lib/types/types"; import { Workflow } from "../../../lib/types/workflow_types"; import { DataSource } from "../../../lib/types/datasource_types"; import { z } from "zod"; @@ -13,9 +13,13 @@ import { listDataSources } from "../../../actions/datasource_actions"; export function App({ projectId, useRag, + mcpServerUrls, + toolWebhookUrl, }: { projectId: string; useRag: boolean; + mcpServerUrls: Array>; + toolWebhookUrl: string; }) { const [selectorKey, setSelectorKey] = useState(0); const [workflow, setWorkflow] = useState> | null>(null); @@ -108,6 +112,8 @@ export function App({ handleShowSelector={handleShowSelector} handleCloneVersion={handleCloneVersion} useRag={useRag} + mcpServerUrls={mcpServerUrls} + toolWebhookUrl={toolWebhookUrl} />} } diff --git a/apps/rowboat/app/projects/[projectId]/workflow/page.tsx b/apps/rowboat/app/projects/[projectId]/workflow/page.tsx index e4d99289..be6d588c 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/page.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/page.tsx @@ -1,8 +1,8 @@ import { Metadata } from "next"; import { App } from "./app"; import { USE_RAG } from "@/app/lib/feature_flags"; - -export const dynamic = 'force-dynamic'; +import { projectsCollection } from "@/app/lib/mongodb"; +import { notFound } from "next/navigation"; export const metadata: Metadata = { title: "Workflow" @@ -13,8 +13,18 @@ export default async function Page({ }: { params: { projectId: string }; }) { + const project = await projectsCollection.findOne({ + _id: params.projectId, + }); + if (!project) { + notFound(); + } + const toolWebhookUrl = project.webhookUrl ?? ''; + return ; } diff --git a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx index 002dc049..243a6827 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx @@ -1,5 +1,5 @@ "use client"; -import { WithStringId } from "../../../lib/types/types"; +import { MCPServer, WithStringId } from "../../../lib/types/types"; import { Workflow } from "../../../lib/types/workflow_types"; import { WorkflowTool } from "../../../lib/types/workflow_types"; import { WorkflowPrompt } from "../../../lib/types/workflow_types"; @@ -559,6 +559,8 @@ export function WorkflowEditor({ handleShowSelector, handleCloneVersion, useRag, + mcpServerUrls, + toolWebhookUrl, }: { dataSources: WithStringId>[]; workflow: WithStringId>; @@ -566,6 +568,8 @@ export function WorkflowEditor({ handleShowSelector: () => void; handleCloneVersion: (workflowId: string) => void; useRag: boolean; + mcpServerUrls: Array>; + toolWebhookUrl: string; }) { const [state, dispatch] = useReducer>(reducer, { patches: [], @@ -911,6 +915,8 @@ export function WorkflowEditor({ projectId={state.present.workflow.projectId} workflow={state.present.workflow} messageSubscriber={updateChatMessages} + mcpServerUrls={mcpServerUrls} + toolWebhookUrl={toolWebhookUrl} /> {state.present.selection?.type === "agent" && Date: Thu, 20 Mar 2025 21:55:29 +0530 Subject: [PATCH 19/49] use catchall for tools --- apps/agents/src/graph/swarm_wrapper.py | 157 +---- .../sample_requests/default_example.json | 541 ++++++------------ 2 files changed, 200 insertions(+), 498 deletions(-) diff --git a/apps/agents/src/graph/swarm_wrapper.py b/apps/agents/src/graph/swarm_wrapper.py index 68785470..03db1eb3 100644 --- a/apps/agents/src/graph/swarm_wrapper.py +++ b/apps/agents/src/graph/swarm_wrapper.py @@ -1,4 +1,3 @@ -from src.swarm.core import Swarm from src.swarm.types import Agent as SwarmAgent, Response as SwarmResponse import logging import json @@ -14,10 +13,10 @@ from .helpers.instructions import ( add_rag_instructions_to_agent, add_universal_system_message_to_agent ) -from agents import Agent as NewAgent, Runner, FunctionTool, function_tool +from agents import Agent as NewAgent, Runner, FunctionTool, function_tool, RunContextWrapper # Add import for OpenAI functionality from src.utils.common import generate_openai_output - +from typing import Any # Create a dedicated logger for swarm wrapper logger = logging.getLogger("swarm_wrapper") logger.setLevel(logging.INFO) @@ -27,86 +26,22 @@ Agent = SwarmAgent Response = SwarmResponse -def create_python_tool(tool_name, tool_description, tool_params): - """ - Return a Python function definition (as a string) with the given name, docstring, - and parameters derived from a JSON-schema-like dictionary. +async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict) -> str: + print(f"Catch all called for tool: {tool_name}") + print(f"Args: {args}") + print(f"Tool config: {tool_config}") + #if tool_config.get("mock", False): + #& return tool_config.get("mockInstructions", "No mock instructions provided") + description = tool_config.get("description", "") - :param tool_name: str - Name of the function to generate. - :param tool_description: str - High-level docstring/description for the function. - :param tool_params: dict - A JSON Schema–style definition with 'parameters': - { - "parameters": { - "type": "object", - "properties": { - "": { - "type": "string" | "integer" | "number" | "boolean" | "object" | "array", - "description": "..." - }, - ... - } - } - } - :return: str - The function definition as a string (no shebang or `if __name__ == "__main__"`). - """ - - # Maps JSON Schema types to Python type hints - type_map = { - "string": "str", - "integer": "int", - "number": "float", - "boolean": "bool", - "object": "dict", - "array": "list", - } - - # Extract the properties from the JSON-schema-like dict - properties = tool_params.get("parameters", {}).get("properties", {}) - - # Build the function signature and docstring pieces - signature_parts = [] - docstring_params = [] - for param_name, param_info in properties.items(): - # Default to "str" if no specific type is given - json_type = param_info.get("type", "string") - python_type = type_map.get(json_type, "str") - description = param_info.get("description", "") - - # e.g. "orderId: str" - signature_parts.append(f"{param_name}: {python_type}") - - # Build docstring lines (reST style) - docstring_params.append(f":param {param_name}: {description}") - docstring_params.append(f":type {param_name}: {python_type}") - - signature = ", ".join(signature_parts) - params_docstring_text = "\n ".join(docstring_params) - - function_docstring = f'''\"\"\"{tool_description} - - {params_docstring_text} -\"\"\"''' - - # Return only the function definition (no shebang or main guard) - # Return the function definition including the @function_tool decorator - function_code = f'''@function_tool -async def {tool_name}({signature}): - {function_docstring} - # TODO: Implement your logic here messages = [ - {{"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. The tool has this description: {tool_description}. Generate a realistic response as if the tool was actually executed with the given parameters."}}, - {{"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}'. The response should be concise and focused on what the tool would actually return."}} + {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. The tool has this description: {description}. Generate a realistic response as if the tool was actually executed with the given parameters."}, + {"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}' with these parameters: {args}. The response should be concise and focused on what the tool would actually return."} + ] response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") - + print(response_content) return(response_content) -''' - return function_code - def get_agents(agent_configs, tool_configs, localize_history, available_tool_mappings, agent_data, start_turn_with_start_agent, children_aware_of_parent, universal_sys_msg): @@ -140,69 +75,27 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map child_functions = {} logger.debug(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools") + print(tool_configs) new_tools = [] for tool_name in agent_config["tools"]: tool_config = get_tool_config_by_name(tool_configs, tool_name) + if tool_config: external_tools.append({ "type": "function", "function": tool_config }) - - # Create a dummy function to mock the tool execution - # Use a closure to capture the tool_name variable properly - def create_mock_tool_function(tool_name): - - @function_tool( - name=tool_name, - description=tool_config.get("description", ""), - params_json_schema=tool_config.get("parameters", {}) - ) - def mock_tool_execution(**kwargs): - # Docstring will be set after function definition - logger.info(f"Executing tool {tool_name} with params: {kwargs}") - - # Create a prompt for OpenAI to generate a realistic response - messages = [ - {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. The tool has this description: {tool_config.get('description', 'No description available')}. Generate a realistic response as if the tool was actually executed with the given parameters."}, - {"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}' with these parameters: {json.dumps(kwargs)}. The response should be concise and focused on what the tool would actually return."} - ] - - try: - # Call OpenAI to generate a realistic response - response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") - - # Return a properly structured response with the OpenAI-generated content - return { - "status": "success", - "tool": tool_name, - "result": response_content, - "params_received": kwargs - } - except Exception as e: - logger.error(f"Error generating mock response for {tool_name}: {str(e)}") - # Fall back to a simple mock response if OpenAI call fails - return { - "status": "success", - "tool": tool_name, - "result": f"Simulated result for {tool_name}", - "params_received": kwargs, - "error": str(e) - } - - - # Set the docstring to use the tool's description - mock_tool_execution.__doc__ = tool_config.get("description", "Mock function that simulates tool execution") - return mock_tool_execution - tool_code = create_python_tool(tool_name, tool_config.get("description", ""), tool_config.get("parameters", {})) - local_namespace = {"function_tool": function_tool, "generate_openai_output": generate_openai_output} - -# Execute the generated code so `my_tool` is defined in local_namespace - exec(tool_code, local_namespace) - print(tool_code) - my_tool_func = local_namespace[tool_name] - new_tools.append(my_tool_func) + #TODO: Remove this once we have a way to handle the additionalProperties + tool_config['parameters']['additionalProperties'] = False + tool = FunctionTool( + name=tool_name, + description=tool_config["description"], + params_json_schema=tool_config["parameters"], + on_invoke_tool=lambda ctx, args, _tool_name=tool_name, _tool_config=tool_config: + catch_all(ctx, args, _tool_name, _tool_config) + ) + new_tools.append(tool) logger.debug(f"Added tool {tool_name} to agent {agent_config['name']}") else: logger.warning(f"Tool {tool_name} not found in tool_configs") diff --git a/apps/agents/tests/sample_requests/default_example.json b/apps/agents/tests/sample_requests/default_example.json index 88a07eae..7dd1c4ec 100644 --- a/apps/agents/tests/sample_requests/default_example.json +++ b/apps/agents/tests/sample_requests/default_example.json @@ -1,6 +1,14 @@ { "lastRequest": { "messages": [ + { + "content": "", + "role": "system", + "sender": null, + "tool_calls": null, + "tool_call_id": null, + "tool_name": null + }, { "content": "hi", "role": "user", @@ -8,382 +16,112 @@ "tool_calls": null, "tool_call_id": null, "tool_name": null - }, - { - "content": "Hello! How can I assist you today with your XYZ Bike?", - "role": "assistant", - "sender": "Main agent", - "tool_calls": null, - "tool_call_id": null, - "tool_name": null, - "response_type": "internal" - }, - { - "content": "Hello! How can I assist you today with your XYZ Bike?", - "role": "assistant", - "sender": "Main agent >> Post process", - "tool_calls": null, - "tool_call_id": null, - "tool_name": null, - "response_type": "external" - }, - { - "content": "i want to know about the range", - "role": "user", - "sender": null, - "tool_calls": null, - "tool_call_id": null, - "tool_name": null - }, - { - "content": null, - "role": "assistant", - "sender": "Main agent", - "tool_calls": [ - { - "function": { - "arguments": "{\"args\":\"\",\"kwargs\":\"\"}", - "name": "transfer_to_product_info_agent" - }, - "id": "call_0MJHin0XCMyEJjA7T2FTJLZL", - "type": "function" - } - ], - "tool_call_id": null, - "tool_name": null, - "response_type": "internal" - }, - { - "content": "{\"assistant\": \"Product info agent\"}", - "role": "tool", - "sender": null, - "tool_calls": null, - "tool_call_id": "call_0MJHin0XCMyEJjA7T2FTJLZL", - "tool_name": "transfer_to_product_info_agent" - }, - { - "content": null, - "role": "assistant", - "sender": "Product info agent", - "tool_calls": [ - { - "function": { - "arguments": "{\"question\":\"XYZ Bike travel range\"}", - "name": "getArticleInfo" - }, - "id": "call_CcNzb2N3lBt4JOCVrzyHdpdL", - "type": "function" - } - ], - "tool_call_id": null, - "tool_name": null, - "response_type": "internal" - }, - { - "content": "{\"results\":[{\"title\":\"XYZ Electric Bike\",\"content\":\"# XYZ Electric Bike\\n\\n### Transforming Transportation with the XYZ Electric Bike ### Revolutionizing Urban Mobility XYZ Electric Bike reimagines how we navigate cities, offering a seamless, stress-free alternative to traffic jams, pricey rideshares, rigid schedules, and the hassle of finding parking. --- #### **Instant Foldability** With a single press, XYZ's proprietary hinge mechanism folds the bike smoothly and securely in one swift motion. This innovation makes carrying and storing the bike effortlessβ€”outperforming the competition in both speed and ease of use. --- #### **Exceptional Handlebars** The sleek magnesium alloy handlebars are a marvel of design, housing intuitive controls for acceleration, braking, the horn, and LED lights, all within a streamlined, wire-free structure. Magnesium's lightweight propertiesβ€”33% lighter than aluminumβ€”make XYZ one of the most portable electric bikes available. --- #### **Unmatched Frame Design** Crafted with precision using TORAY carbon fiber, the frame achieves the perfect balance between strength and minimal weight. The material, meticulously layered for durability, is the same advanced composite used in aerospace engineering. --- #### **Impressive Range** Powered by premium electric batteries, XYZ bikes are designed for extended use with fast charging times. Their energy management system ensures long-lasting performance, providing ranges of up to 25 miles per charge, depending on riding conditions. --- #### **Dynamic Power** Equipped with dual motors delivering up to 1,000 watts at peak output, XYZ effortlessly handles steep inclines and challenging terrains. Rare-earth magnets and thermal regulation technology ensure high efficiency and reliability. --- #### **Puncture-Proof Tires** Say goodbye to flat tires. XYZ's solid rubber tires incorporate innovative air pockets for built-in shock absorption, delivering a smooth yet responsive ride across various surfaces. --- #### **Advanced Braking System** XYZ's braking system combines electronic anti-lock functionality with a user-friendly friction brake. Riders can enjoy a customizable braking experience, whether relying on fingertip controls or a traditional foot brake. --- #### **Durable and Comfortable Deck** The single-piece aluminum deck integrates a silicon surface for superior grip, eliminating unnecessary bulk or harsh finishes for a clean, modern look. --- #### **Invisible Kickstand** XYZ's custom-designed kickstand is seamlessly integrated, providing stability without disrupting the bike's sleek aesthetics. --- ### Models Comparison #### **XYZ Classic** - Price: $990 - Range: Up to 12 miles - Charge Time: 3.5 hours (80%) - Weight: 28.5 lbs #### **XYZ Voyager** - Price: $1,490 - Range: Up to 25 miles - Charge Time: 2 hours (80%) - Weight: 29.6 lbs - Features: App integration for enhanced control and ride stats --- XYZ Electric Bike is not just a mode of transportβ€”it's the future of urban mobility, combining cutting-edge technology, top-tier materials, and unparalleled design for a ride that's as stylish as it is functional.\"}]}", - "role": "tool", - "sender": null, - "tool_calls": null, - "tool_call_id": "call_CcNzb2N3lBt4JOCVrzyHdpdL", - "tool_name": "getArticleInfo" } ], "state": { - "agent_data": [ - { - "child_functions": [ - "transfer_to_product_info_agent", - "transfer_to_delivery_info_agent", - "transfer_to_subscriptions_agent" - ], - "external_tools": [], - "history": [ - { - "content": "hi", - "current_turn": false, - "role": "user" - }, - { - "content": "Hello! How can I assist you today with your XYZ Bike?", - "created_at": "2024-12-18T07:45:03.670088", - "current_turn": false, - "response_type": "internal", - "role": "assistant", - "sender": "Main agent" - }, - { - "content": "i want to know about the range", - "current_turn": true, - "role": "user" - }, - { - "created_at": "2024-12-18T07:45:13.240846", - "current_turn": true, - "response_type": "internal", - "role": "assistant", - "sender": "Main agent", - "tool_calls": [ - { - "function": { - "arguments": "{\"args\":\"\",\"kwargs\":\"\"}", - "name": "transfer_to_product_info_agent" - }, - "id": "call_0MJHin0XCMyEJjA7T2FTJLZL", - "type": "function" - } - ] - }, - { - "content": "{\"assistant\": \"Product info agent\"}", - "created_at": "2024-12-18T07:45:13.241184", - "current_turn": true, - "response_type": "internal", - "role": "tool", - "tool_call_id": "call_0MJHin0XCMyEJjA7T2FTJLZL", - "tool_name": "transfer_to_product_info_agent" - }, - { - "created_at": "2024-12-18T07:45:13.821351", - "current_turn": true, - "response_type": "internal", - "role": "assistant", - "sender": "Product info agent", - "tool_calls": [ - { - "function": { - "arguments": "{\"question\":\"XYZ Bike travel range\"}", - "name": "getArticleInfo" - }, - "id": "call_CcNzb2N3lBt4JOCVrzyHdpdL", - "type": "function" - } - ] - } - ], - "instructions": "Role:\nYou are a customer support agent for XYZ Bikes. Your primary task is to facilitate conversations by passing control to specialized worker agents when needed.\n\n---\n\nTasks to Follow:\n- Engage in small talk if no specific question is asked.\n- Pass control to the appropriate worker agents for specialized conversations.\n\n---\n\nSmall Talk:\nYou are welcome to engage in basic small talk to build rapport.\n\n---\n\nExamples:\n\n---\nIn Scope Example 1:\nUser: How are you?\nAnswer: \"I'm doing well, thank you! How can I assist you today?\"\n\n---\nIn Scope Example 2:\nUser: What can you do?\nAnswer: \"I can help with customer support-related issues for XYZ Bikes. Let me know if you have any questions.\"\n\n---\nIn Scope Example 3:\nUser: I want a XYZ Bike.\nAnswer: \"What would you like to know about XYZ Bikes?\"\n\n---\nPass Control Example 1:\nUser: Tell me about the product features.\nAction: Pass control to the Product info agent.\n\n---\nPass Control Example 2:\nUser: Where is my scooter?\nAction: Pass control to the Delivery info agent.\n\n---\nPass Control Example 3:\nUser: I need help with my return.\nAction: Pass control to the Returns agent.\n\n---\nPass Control Example 4:\nUser: How does the Unagi subscription work?\nAction: Pass control to the Subscriptions agent.\n\n---\nβœ… Dos:\n- Engage in small talk when necessary.\n- Pass control to the appropriate agent based on the user's query.\n\n---\n❌ Don'ts:\n- Do not focus excessively on greetings during ongoing conversations.\n- Do not continue the conversation if you suspect the user is confused or uninterested in Unagi support.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "internal_tools": [], - "most_recent_parent_name": "", - "name": "Main agent", - "parent_function": null - }, - { - "child_functions": [], - "external_tools": [ - "getArticleInfo" - ], - "history": [ - { - "content": "i want to know about the range", - "current_turn": true, - "role": "user" - }, - { - "created_at": "2024-12-18T07:45:13.821351", - "current_turn": true, - "response_type": "internal", - "role": "assistant", - "sender": "Product info agent", - "tool_calls": [ - { - "function": { - "arguments": "{\"question\":\"XYZ Bike travel range\"}", - "name": "getArticleInfo" - }, - "id": "call_CcNzb2N3lBt4JOCVrzyHdpdL", - "type": "function" - } - ] - } - ], - "instructions": "πŸ§‘β€πŸ’Ό Role:\nYou are a product information agent for XYZ Bikes. Your job is to answer search for the right article and answer questions strictly based on the article about Unagi products. Feel free to ask the user clarification questions if needed.\n\n---\n\nπŸ“œ Instructions:\n\nβœ… In Scope:\n- Answer questions strictly about Unagi product information.\n\n❌ Out of Scope:\n- Questions about delivery, returns, subscriptions, and promotions.\n- Any topic unrelated to Unagi products.\n- If a question is out of scope, call give_up_control and do not attempt to answer it.\n\n---\n\nβœ”οΈ Dos:\n- Stick to the facts provided in the articles.\n- Provide complete and direct answers to the user's questions.\n- Call the Greeting agent after each interaction.\n\n---\n\n🚫 Don'ts:\n- Do not partially answer questions or direct users to a URL for more information.\n- Do not provide information outside of the given context.\n\n---\n\nπŸ“ Examples:\n\n---\nIn Scope Example 1:\nUser: What is the maximum speed of the Unagi E500?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 2:\nUser: How long does it take to charge a XYZ Bike fully?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 3:\nUser: Can you tell me about the weight-carrying capacity of XYZ Bikes?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 4:\nUser: What are the differences between the E250 and E500 models?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 5:\nUser: How far can I travel on a single charge with the E500?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 6:\nUser: Is the scooter waterproof?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 7:\nUser: Does the scooter have any safety features?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 8:\nUser: What materials are used to make XYZ Bikes?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 9:\nUser: Can the scooter be used off-road?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 10:\nUser: Are spare parts available for purchase?\nAction: Call get_article_info followed by .\n\n---\nOut of Scope Example 1:\nUser: What is the status of my order delivery?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 2:\nUser: How do I process a return?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 3:\nUser: Can you tell me more about the subscription plans?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 4:\nUser: Are there any promotions or discounts?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 5:\nUser: Who won the last election?\nAction: Call give_up_control.\n\nProvide your output in the following structured JSON format:\n\n{\n \"steps_completed\": ,\n \"current_step\": ,\n \"reasoning\": \"\",\n \"error_count\": ,\n \"response_to_user\": \"\"\n}\n\nAlways ensure that all pertinent details, including tables or structured lists, are contained within the response_to_user field to maintain clarity and a comprehensive response for the user.\n\nRetrieval instructions:\n\nIn every turn, retrieve a relevant article and use the information from that article to answer the user's question.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "internal_tools": [], - "most_recent_parent_name": "Main agent", - "name": "Product info agent", - "parent_function": "give_up_chat_control" - }, - { - "child_functions": [], - "external_tools": [ - "get_delivery_details", - "getArticleInfo" - ], - "history": [], - "instructions": "Role:\nYou are responsible for providing delivery information to the user.\n\n---\n\nβš™οΈ Steps to Follow:\n1. Fetch the delivery details using the function: get_shipping_details.\n2. Answer the user's question based on the fetched delivery details.\n3. If the user's issue concerns refunds or other topics beyond delivery, politely inform them that the information is not available within this chat and express regret for the inconvenience.\n\n---\n\nβœ… In Scope:\nQuestions about delivery status, shipping timelines, and delivery processes.\nGeneric delivery/shipping-related questions where answers can be sourced from articles.\n\n---\n\n❌ Out of Scope:\nQuestions unrelated to delivery or shipping.\nQuestions about products features, returns, subscriptions, or promotions.\nIf a question is out of scope, politely inform the user and avoid providing an answer.\n\n---\n\nExample 1:\nUser: What is the status of my delivery?\nAction: Call get_delivery_details to fetch the current delivery status and inform the user.\n\nExample 2:\nUser: Can you explain the delivery process?\nAction: Provide a detailed answer and clarify any user questions based on the articles.\n\nExample 3:\nUser: I have a question about product features such as range, durability etc.\nAction: give_up_control as this is not in your scope.\n\n---\n\nβœ… Dos:\nUse get_shipping_details to fetch accurate delivery information.\nProvide complete and clear answers based on the delivery details.\nFor generic delivery questions, refer to relevant articles if necessary.\nStick to factual information when answering.\n\n---\n\n❌ Don'ts:\nDo not provide answers without fetching delivery details when required.\nDo not leave the user with partial information.\nRefrain from phrases like 'please contact support'; instead, relay information limitations gracefully.\n\nProvide your output in the following structured JSON format:\n\n{\n \"steps_completed\": ,\n \"current_step\": ,\n \"reasoning\": \"\",\n \"error_count\": ,\n \"response_to_user\": \"\"\n}\n\nAlways ensure that all pertinent details, including tables or structured lists, are contained within the response_to_user field to maintain clarity and a comprehensive response for the user.\n\nRetrieval instructions:\n\nIn every turn, retrieve a relevant article and use the information from that article to answer the user's question.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "internal_tools": [], - "most_recent_parent_name": "", - "name": "Delivery info agent", - "parent_function": null - }, - { - "child_functions": [], - "external_tools": [], - "history": [], - "instructions": "talk about returns\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "internal_tools": [], - "most_recent_parent_name": "", - "name": "Returns agent", - "parent_function": null - }, - { - "child_functions": [], - "external_tools": [], - "history": [], - "instructions": "talk about subscriptions\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "internal_tools": [], - "most_recent_parent_name": "", - "name": "Subscriptions agent", - "parent_function": null - }, - { - "child_functions": [], - "external_tools": [], - "history": [], - "instructions": "Talk about promotions\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "internal_tools": [], - "most_recent_parent_name": "", - "name": "Promotions agent", - "parent_function": null - }, - { - "child_functions": [], - "external_tools": [], - "history": [], - "instructions": "Role:\nYou are a test agent for XYZ Bikes. Your job is to help test the functionality of different operations within the system.\n\n---\n\nTasks to Follow:\n- Assist in simulating various scenarios and operations to ensure smooth functioning.\n- Report any discrepancies or issues observed during testing.\n\n---\n\nIn Scope:\n- Conduct user interaction tests.\n- Evaluate agent response accuracy.\n- Validate agent transition accuracy.\n\n---\n\nOut of Scope:\n- Direct customer interactions outside of test scenarios.\n- Handling of live customer support queries.\n\n---\n\nDos:\n- Conduct comprehensive tests to cover all expected operations and scenarios.\n- Document test outcomes clearly.\n\n---\n\nDon'ts:\n- Do not intervene in live interactions unless part of a test scenario.\n- Ensure test operations do not affect live customer service functions.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "internal_tools": [], - "most_recent_parent_name": "", - "name": "Test agent", - "parent_function": null - } - ], - "last_agent_name": "Product info agent" + "last_agent_name": "Door Dash Hub" }, "agents": [ { - "name": "Main agent", + "name": "Door Dash Hub", "type": "conversation", - "description": "The Main agent orchestrates interactions between various specialized worker agents to ensure efficient handling of user queries and support needs.", - "instructions": "Role:\nYou are a customer support agent for XYZ Bikes. Your primary task is to facilitate conversations by passing control to specialized worker agents when needed.\n\n---\n\nTasks to Follow:\n- Engage in small talk if no specific question is asked.\n- Pass control to the appropriate worker agents for specialized conversations.\n\n---\n\nSmall Talk:\nYou are welcome to engage in basic small talk to build rapport.\n\n---\n\nExamples:\n\n---\nIn Scope Example 1:\nUser: How are you?\nAnswer: \"I'm doing well, thank you! How can I assist you today?\"\n\n---\nIn Scope Example 2:\nUser: What can you do?\nAnswer: \"I can help with customer support-related issues for XYZ Bikes. Let me know if you have any questions.\"\n\n---\nIn Scope Example 3:\nUser: I want a XYZ Bike.\nAnswer: \"What would you like to know about XYZ Bikes?\"\n\n---\nPass Control Example 1:\nUser: Tell me about the product features.\nAction: Pass control to the Product info agent.\n\n---\nPass Control Example 2:\nUser: Where is my scooter?\nAction: Pass control to the Delivery info agent.\n\n---\nPass Control Example 3:\nUser: I need help with my return.\nAction: Pass control to the Returns agent.\n\n---\nPass Control Example 4:\nUser: How does the Unagi subscription work?\nAction: Pass control to the Subscriptions agent.\n\n---\nβœ… Dos:\n- Engage in small talk when necessary.\n- Pass control to the appropriate agent based on the user's query.\n\n---\n❌ Don'ts:\n- Do not focus excessively on greetings during ongoing conversations.\n- Do not continue the conversation if you suspect the user is confused or uninterested in Unagi support.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "tools": [], + "description": "Hub agent to manage Door Dash-related queries.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nYou are responsible for directing Door Dash-related queries to appropriate agents.\n\n---\n## βš™οΈ Steps to Follow:\n1. Greet the user and ask which Door Dash-related query they need help with (e.g., 'Are you facing issues with your order items or delivery timing?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Order Issue β†’ [@agent:Order Issue]\n - Delayed Delivery β†’ [@agent:Delayed Delivery]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Issues with order items\n- Delayed delivery issues\n\n❌ Out of Scope:\n- Issues unrelated to Door Dash\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Direct queries to specific Door Dash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n🚫 Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond Door Dash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with my order items.\n - **Agent actions**: [@agent:Order Issue](#mention)\n\n- **User** : My delivery is delayed.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : I'm not sure where my order is.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : Can you reset my order settings?\n - **Agent actions**: [@agent:Escalation](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would like help with today?", "model": "gpt-4o-mini", "hasRagSources": false, + "controlType": "retain", + "tools": [], + "prompts": [], "connectedAgents": [ - "Product info agent", - "Delivery info agent", - "Subscriptions agent" - ], - "controlType": "retain" + "Order Issue", + "Delayed Delivery", + "Escalation" + ] }, { "name": "Post process", "type": "post_process", - "instructions": "- Extract the response_to_user field from the provided structured JSON and ensure that this is the only content you use for the final output.\n- Ensure that the agent response covers all the details the user asked for.\n- When providing long details, use bullets to distinguish the different points. \n- Focus specifically on the response_to_user field in its input.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "tools": [], - "model": "gpt-4o", - "hasRagSources": false, - "connectedAgents": [] - }, - { - "name": "Product info agent", - "type": "conversation", - "description": "You assist with product-related questions by retrieving relevant articles and information.", - "instructions": "πŸ§‘β€πŸ’Ό Role:\nYou are a product information agent for XYZ Bikes. Your job is to answer search for the right article and answer questions strictly based on the article about Unagi products. Feel free to ask the user clarification questions if needed.\n\n---\n\nπŸ“œ Instructions:\n\nβœ… In Scope:\n- Answer questions strictly about Unagi product information.\n\n❌ Out of Scope:\n- Questions about delivery, returns, subscriptions, and promotions.\n- Any topic unrelated to Unagi products.\n- If a question is out of scope, call give_up_control and do not attempt to answer it.\n\n---\n\nβœ”οΈ Dos:\n- Stick to the facts provided in the articles.\n- Provide complete and direct answers to the user's questions.\n- Call the Greeting agent after each interaction.\n\n---\n\n🚫 Don’ts:\n- Do not partially answer questions or direct users to a URL for more information.\n- Do not provide information outside of the given context.\n\n---\n\nπŸ“ Examples:\n\n---\nIn Scope Example 1:\nUser: What is the maximum speed of the Unagi E500?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 2:\nUser: How long does it take to charge a XYZ Bike fully?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 3:\nUser: Can you tell me about the weight-carrying capacity of XYZ Bikes?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 4:\nUser: What are the differences between the E250 and E500 models?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 5:\nUser: How far can I travel on a single charge with the E500?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 6:\nUser: Is the scooter waterproof?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 7:\nUser: Does the scooter have any safety features?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 8:\nUser: What materials are used to make XYZ Bikes?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 9:\nUser: Can the scooter be used off-road?\nAction: Call get_article_info followed by .\n\n---\nIn Scope Example 10:\nUser: Are spare parts available for purchase?\nAction: Call get_article_info followed by .\n\n---\nOut of Scope Example 1:\nUser: What is the status of my order delivery?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 2:\nUser: How do I process a return?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 3:\nUser: Can you tell me more about the subscription plans?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 4:\nUser: Are there any promotions or discounts?\nAction: Call give_up_control.\n\n---\nOut of Scope Example 5:\nUser: Who won the last election?\nAction: Call give_up_control.\n\nProvide your output in the following structured JSON format:\n\n{\n \"steps_completed\": ,\n \"current_step\": ,\n \"reasoning\": \"\",\n \"error_count\": ,\n \"response_to_user\": \"\"\n}\n\nAlways ensure that all pertinent details, including tables or structured lists, are contained within the response_to_user field to maintain clarity and a comprehensive response for the user.\n\nRetrieval instructions:\n\nIn every turn, retrieve a relevant article and use the information from that article to answer the user's question.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "tools": [], - "model": "gpt-4o-mini", - "hasRagSources": true, - "connectedAgents": [], - "controlType": "relinquish_to_parent" - }, - { - "name": "Delivery info agent", - "type": "conversation", - "description": "You are responsible for providing accurate delivery status and shipping details for orders.", - "instructions": "Role:\nYou are responsible for providing delivery information to the user.\n\n---\n\nβš™οΈ Steps to Follow:\n1. Fetch the delivery details using the function: get_shipping_details.\n2. Answer the user's question based on the fetched delivery details.\n3. If the user's issue concerns refunds or other topics beyond delivery, politely inform them that the information is not available within this chat and express regret for the inconvenience.\n\n---\n\nβœ… In Scope:\nQuestions about delivery status, shipping timelines, and delivery processes.\nGeneric delivery/shipping-related questions where answers can be sourced from articles.\n\n---\n\n❌ Out of Scope:\nQuestions unrelated to delivery or shipping.\nQuestions about products features, returns, subscriptions, or promotions.\nIf a question is out of scope, politely inform the user and avoid providing an answer.\n\n---\n\nExample 1:\nUser: What is the status of my delivery?\nAction: Call get_delivery_details to fetch the current delivery status and inform the user.\n\nExample 2:\nUser: Can you explain the delivery process?\nAction: Provide a detailed answer and clarify any user questions based on the articles.\n\nExample 3:\nUser: I have a question about product features such as range, durability etc.\nAction: give_up_control as this is not in your scope.\n\n---\n\nβœ… Dos:\nUse get_shipping_details to fetch accurate delivery information.\nProvide complete and clear answers based on the delivery details.\nFor generic delivery questions, refer to relevant articles if necessary.\nStick to factual information when answering.\n\n---\n\n❌ Don’ts:\nDo not provide answers without fetching delivery details when required.\nDo not leave the user with partial information.\nRefrain from phrases like 'please contact support'; instead, relay information limitations gracefully.\n\nProvide your output in the following structured JSON format:\n\n{\n \"steps_completed\": ,\n \"current_step\": ,\n \"reasoning\": \"\",\n \"error_count\": ,\n \"response_to_user\": \"\"\n}\n\nAlways ensure that all pertinent details, including tables or structured lists, are contained within the response_to_user field to maintain clarity and a comprehensive response for the user.\n\nRetrieval instructions:\n\nIn every turn, retrieve a relevant article and use the information from that article to answer the user's question.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "tools": [ - "get_delivery_details" - ], - "model": "gpt-4o-mini", - "hasRagSources": true, - "connectedAgents": [], - "controlType": "retain" - }, - { - "name": "Returns agent", - "type": "conversation", - "description": "You provide assistance for inquiries and processes related to product returns.", - "instructions": "talk about returns\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "tools": [], + "description": "", + "instructions": "Ensure that the agent response is terse and to the point.", "model": "gpt-4o-mini", "hasRagSources": false, - "connectedAgents": [] - }, - { - "name": "Subscriptions agent", - "type": "conversation", - "description": "You handle all subscription-related queries from customers.", - "instructions": "talk about subscriptions\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", + "controlType": "retain", "tools": [], - "model": "gpt-4o-mini", - "hasRagSources": false, - "connectedAgents": [] - }, - { - "name": "Promotions agent", - "type": "conversation", - "description": "You provide current promotions and discounts details to the customers.", - "instructions": "Talk about promotions\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "tools": [], - "model": "gpt-4o-mini", - "hasRagSources": false, - "connectedAgents": [] - }, - { - "name": "Test agent", - "type": "conversation", - "description": "Your job is to simulate various customer interactions and test system operations for quality assurance purposes.", - "instructions": "Role:\nYou are a test agent for XYZ Bikes. Your job is to help test the functionality of different operations within the system.\n\n---\n\nTasks to Follow:\n- Assist in simulating various scenarios and operations to ensure smooth functioning.\n- Report any discrepancies or issues observed during testing.\n\n---\n\nIn Scope:\n- Conduct user interaction tests.\n- Evaluate agent response accuracy.\n- Validate agent transition accuracy.\n\n---\n\nOut of Scope:\n- Direct customer interactions outside of test scenarios.\n- Handling of live customer support queries.\n\n---\n\nDos:\n- Conduct comprehensive tests to cover all expected operations and scenarios.\n- Document test outcomes clearly.\n\n---\n\nDon’ts:\n- Do not intervene in live interactions unless part of a test scenario.\n- Ensure test operations do not affect live customer service functions.\n\nSelf Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'.", - "tools": [], - "model": "gpt-4o-mini", - "hasRagSources": false, + "prompts": [], "connectedAgents": [] }, { "name": "Escalation", "type": "escalation", "description": "", - "instructions": "Get the user's contact information and let them know that their request has been escalated.\n\n", - "tools": [], + "instructions": "Get the user's contact information and let them know that their request has been escalated.", "model": "gpt-4o-mini", "hasRagSources": false, - "connectedAgents": [], - "controlType": "retain" + "controlType": "retain", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Order Issue", + "type": "conversation", + "description": "Agent to assist users with missing or incorrect order items.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nAssist users with issues related to missing or incorrect order items.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the issue with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Handling missing or incorrect order items\n\n❌ Out of Scope:\n- Delayed delivery issues\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Ensure the user is aware of the order details before proceeding.\n\n🚫 Don'ts:\n- Extend the conversation beyond order issues.\n\n# Examples\n- **User** : I received the wrong item in my order.\n - **Agent response**: I can help with that. Let me fetch your order details first.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing an item.\n - **Agent response**: Let's check your order details and resolve this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I got someone else's order.\n - **Agent response**: I apologize for the mix-up. I'll fetch your order details to sort this out.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : Can you help me with a missing item?\n - **Agent response**: Certainly, I'll look into your order details right away.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : There's an issue with my order items.\n - **Agent response**: Let's verify your order details to address this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)", + "model": "gpt-4o", + "hasRagSources": false, + "controlType": "retain", + "tools": [ + "get_order_details" + ], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Delayed Delivery", + "type": "conversation", + "description": "Agent to assist users with delayed delivery issues.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nAssist users with issues related to delayed delivery.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Confirm the delay with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Handling delayed delivery issues\n\n❌ Out of Scope:\n- Missing or incorrect order items\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Ensure the user is aware of the delivery status before proceeding.\n\n🚫 Don'ts:\n- Extend the conversation beyond delivery issues.\n\n# Examples\n- **User** : My delivery is late.\n - **Agent response**: I can help with that. Let me fetch your delivery status first.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Where is my order? It's delayed.\n - **Agent response**: Let's check your delivery status and resolve this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : My order hasn't arrived yet.\n - **Agent response**: I apologize for the delay. I'll fetch your delivery status to sort this out.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Can you help me with a delayed delivery?\n - **Agent response**: Certainly, I'll look into your delivery status right away.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : There's an issue with my delivery timing.\n - **Agent response**: Let's verify your delivery status to address this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)", + "model": "gpt-4o", + "hasRagSources": false, + "controlType": "retain", + "tools": [ + "get_delivery_status" + ], + "prompts": [], + "connectedAgents": [] } ], "tools": [ { - "name": "get_delivery_details", - "description": "Return a estimated delivery date for the XYZ Bike.", + "name": "get_order_details", + "description": "Tool to fetch details about the user's order.", "parameters": { "type": "object", - "properties": {}, - "required": [] + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] } }, { - "name": "get_subscription_plan_details", - "description": "Return details of the available subscription plans for XYZ Bikes.", + "name": "get_delivery_status", + "description": "Tool to fetch the current status of the delivery.", "parameters": { "type": "object", - "properties": {}, - "required": [] - } - }, - { - "name": "get_current_date", - "description": "Return the current date.", - "parameters": { - "type": "object", - "properties": {}, - "required": [] + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] } } ], @@ -392,33 +130,104 @@ "name": "Style prompt", "type": "style_prompt", "prompt": "You should be empathetic and helpful." - }, - { - "name": "reasoning_output", - "type": "base_prompt", - "prompt": "Give your output in the following format:\n\nreason : \n\nresponse_to_user : " - }, - { - "name": "get_delivery_details", - "type": "base_prompt", - "prompt": "Return a estimated delivery date for XYZ Bike." - }, - { - "name": "structured_output", - "type": "base_prompt", - "prompt": "Provide your output in the following structured JSON format:\n\n{\n \"steps_completed\": ,\n \"current_step\": ,\n \"reasoning\": \"\",\n \"error_count\": ,\n \"response_to_user\": \"\"\n}\n\nAlways ensure that all pertinent details, including tables or structured lists, are contained within the response_to_user field to maintain clarity and a comprehensive response for the user." - }, - { - "name": "rag_article_prompt", - "type": "base_prompt", - "prompt": "Retrieval instructions:\n\nIn every turn, retrieve a relevant article and use the information from that article to answer the user's question." - }, - { - "name": "self_support_prompt", - "type": "base_prompt", - "prompt": "Self Support Guidance:\n\nThe bot should not suggest phrases like 'let me connect you to support' or 'you can reach out to support'. Instead, the agent is the customer support. It can say 'I apologize, but I don't have the right information'." } ], - "startAgent": "Main agent" + "startAgent": "Door Dash Hub" + }, + "lastResponse": { + "messages": [ + { + "annotations": [], + "content": "Hello! How can I assist you today? Are you facing issues with your order items or delivery timing?", + "created_at": "2025-03-19T12:29:06.547196", + "current_turn": true, + "response_type": "internal", + "role": "assistant", + "sender": "Door Dash Hub" + }, + { + "annotations": [], + "content": "Hi! How can I help you today? Are you having issues with your order items or delivery timing?", + "created_at": "2025-03-19T12:29:06.547196", + "current_turn": true, + "response_type": "external", + "role": "assistant", + "sender": "Door Dash Hub >> Post process" + } + ], + "state": { + "agent_data": [ + { + "child_functions": [ + "transfer_to_escalation", + "transfer_to_order_issue", + "transfer_to_delayed_delivery" + ], + "external_tools": [], + "history": [ + { + "content": "hi", + "current_turn": true, + "role": "user" + }, + { + "annotations": [], + "content": "Hello! How can I assist you today? Are you facing issues with your order items or delivery timing?", + "created_at": "2025-03-19T12:29:06.547196", + "current_turn": true, + "response_type": "internal", + "role": "assistant", + "sender": "Door Dash Hub" + } + ], + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nYou are responsible for directing Door Dash-related queries to appropriate agents.\n\n---\n## βš™οΈ Steps to Follow:\n1. Greet the user and ask which Door Dash-related query they need help with (e.g., 'Are you facing issues with your order items or delivery timing?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Order Issue β†’ [@agent:Order Issue]\n - Delayed Delivery β†’ [@agent:Delayed Delivery]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Issues with order items\n- Delayed delivery issues\n\n❌ Out of Scope:\n- Issues unrelated to Door Dash\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Direct queries to specific Door Dash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n🚫 Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond Door Dash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with my order items.\n - **Agent actions**: [@agent:Order Issue](#mention)\n\n- **User** : My delivery is delayed.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : I'm not sure where my order is.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : Can you reset my order settings?\n - **Agent actions**: [@agent:Escalation](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would like help with today?\n\n----------------------------------------------------------------------------------------------------\n\n\n# Instructions about using other specialized agents\nYou have the following specialized agents that you can transfer the chat to, using the appropriate tool calls for the transfer: \nName: Escalation\nDescription: \nTool for transfer: transfer_to_escalation\n----------------------------------------------------------------------------------------------------\nName: Order Issue\nDescription: Agent to assist users with missing or incorrect order items.\nTool for transfer: transfer_to_order_issue\n----------------------------------------------------------------------------------------------------\nName: Delayed Delivery\nDescription: Agent to assist users with delayed delivery issues.\nTool for transfer: transfer_to_delayed_delivery\n\n## Notes:\n- Transfer the chat to the appropriate agent, based on the chat history and / or the user's request.\n- When you transfer the chat to another agent, you should not provide any response to the user. For example, do not say 'Transferring chat to X agent' or anything like that. Just invoke the tool call to transfer to the other agent.\n- Do NOT ever mention the existence of other agents. For example, do not say 'Please check with X agent for details regarding processing times.' or anything like that.\n- If any other agent transfers the chat to you without responding to the user, it means that they don't know how to help. Do not transfer the chat to back to the same agent in this case. In such cases, you should transfer to the escalation agent using the appropriate tool call. Never ask the user to contact support.\n\n\n----------------------------------------------------------------------------------------------------\n\n\n# Additional System-Wide Context or Instructions:\n\n", + "internal_tools": [], + "most_recent_parent_name": "", + "name": "Door Dash Hub", + "parent_function": null + }, + { + "child_functions": [], + "external_tools": [], + "history": [], + "instructions": "Get the user's contact information and let them know that their request has been escalated.\n\n----------------------------------------------------------------------------------------------------\n\n\n# Additional System-Wide Context or Instructions:\n\n", + "internal_tools": [], + "most_recent_parent_name": "", + "name": "Escalation", + "parent_function": null + }, + { + "child_functions": [], + "external_tools": [ + "get_order_details" + ], + "history": [], + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nAssist users with issues related to missing or incorrect order items.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the issue with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Handling missing or incorrect order items\n\n❌ Out of Scope:\n- Delayed delivery issues\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Ensure the user is aware of the order details before proceeding.\n\n🚫 Don'ts:\n- Extend the conversation beyond order issues.\n\n# Examples\n- **User** : I received the wrong item in my order.\n - **Agent response**: I can help with that. Let me fetch your order details first.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing an item.\n - **Agent response**: Let's check your order details and resolve this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I got someone else's order.\n - **Agent response**: I apologize for the mix-up. I'll fetch your order details to sort this out.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : Can you help me with a missing item?\n - **Agent response**: Certainly, I'll look into your order details right away.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : There's an issue with my order items.\n - **Agent response**: Let's verify your order details to address this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n----------------------------------------------------------------------------------------------------\n\n\n# Instructions about giving up chat control\nIf you are unable to handle the chat (e.g. if it is not in your scope of instructions), you should use the tool call provided to give up control of the chat.\nTool for transfer: give_up_chat_control\n\n## Notes:\n- When you give up control of the chat, you should not provide any response to the user. Just invoke the tool call to give up control.\n\n\n----------------------------------------------------------------------------------------------------\n\n\n# Additional System-Wide Context or Instructions:\n\n", + "internal_tools": [], + "most_recent_parent_name": "", + "name": "Order Issue", + "parent_function": null + }, + { + "child_functions": [], + "external_tools": [ + "get_delivery_status" + ], + "history": [], + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nAssist users with issues related to delayed delivery.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Confirm the delay with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Handling delayed delivery issues\n\n❌ Out of Scope:\n- Missing or incorrect order items\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Ensure the user is aware of the delivery status before proceeding.\n\n🚫 Don'ts:\n- Extend the conversation beyond delivery issues.\n\n# Examples\n- **User** : My delivery is late.\n - **Agent response**: I can help with that. Let me fetch your delivery status first.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Where is my order? It's delayed.\n - **Agent response**: Let's check your delivery status and resolve this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : My order hasn't arrived yet.\n - **Agent response**: I apologize for the delay. I'll fetch your delivery status to sort this out.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Can you help me with a delayed delivery?\n - **Agent response**: Certainly, I'll look into your delivery status right away.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : There's an issue with my delivery timing.\n - **Agent response**: Let's verify your delivery status to address this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n----------------------------------------------------------------------------------------------------\n\n\n# Instructions about giving up chat control\nIf you are unable to handle the chat (e.g. if it is not in your scope of instructions), you should use the tool call provided to give up control of the chat.\nTool for transfer: give_up_chat_control\n\n## Notes:\n- When you give up control of the chat, you should not provide any response to the user. Just invoke the tool call to give up control.\n\n\n----------------------------------------------------------------------------------------------------\n\n\n# Additional System-Wide Context or Instructions:\n\n", + "internal_tools": [], + "most_recent_parent_name": "", + "name": "Delayed Delivery", + "parent_function": null + } + ], + "last_agent_name": "Door Dash Hub" + }, + "tokens_used": { + "openai/gpt-4o-mini": { + "input_tokens": 1731, + "output_tokens": 45 + } + } } } \ No newline at end of file From 1fa5c39716d39e43ef657950d6e3f472fe90a10d Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Fri, 21 Mar 2025 15:45:22 +0530 Subject: [PATCH 20/49] Clean up old swarm code --- apps/agents/poetry.lock | 181 +++++++++++++++- apps/agents/pyproject.toml | 1 + apps/agents/requirements.txt | 1 + apps/agents/src/app/main.py | 34 +-- apps/agents/src/graph/core.py | 83 +++----- apps/agents/src/graph/helpers/state.py | 8 +- apps/agents/src/graph/swarm_wrapper.py | 119 +++-------- apps/agents/src/swarm/__init__.py | 4 - apps/agents/src/swarm/core.py | 275 ------------------------- apps/agents/src/swarm/repl/__init__.py | 1 - apps/agents/src/swarm/repl/repl.py | 87 -------- apps/agents/src/swarm/types.py | 54 ----- apps/agents/src/swarm/util.py | 175 ---------------- apps/agents/src/utils/common.py | 1 - apps/agents/tests/interactive.py | 11 +- 15 files changed, 245 insertions(+), 790 deletions(-) delete mode 100644 apps/agents/src/swarm/__init__.py delete mode 100644 apps/agents/src/swarm/core.py delete mode 100644 apps/agents/src/swarm/repl/__init__.py delete mode 100644 apps/agents/src/swarm/repl/repl.py delete mode 100644 apps/agents/src/swarm/types.py delete mode 100644 apps/agents/src/swarm/util.py diff --git a/apps/agents/poetry.lock b/apps/agents/poetry.lock index b960a8b4..d6afd7ca 100644 --- a/apps/agents/poetry.lock +++ b/apps/agents/poetry.lock @@ -86,6 +86,87 @@ files = [ {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "charset-normalizer" version = "3.4.1" @@ -212,7 +293,7 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["main"] -markers = "python_version <= \"3.11\" and platform_system == \"Windows\" or python_version >= \"3.12\" and platform_system == \"Windows\"" +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -342,6 +423,22 @@ Werkzeug = ">=3.1" async = ["asgiref (>=3.2)"] dotenv = ["python-dotenv"] +[[package]] +name = "griffe" +version = "1.6.2" +description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "griffe-1.6.2-py3-none-any.whl", hash = "sha256:6399f7e663150e4278a312a8e8a14d2f3d7bd86e2ef2f8056a1058e38579c2ee"}, + {file = "griffe-1.6.2.tar.gz", hash = "sha256:3a46fa7bd83280909b63c12b9a975732a927dd97809efe5b7972290b606c5d91"}, +] + +[package.dependencies] +colorama = ">=0.4" + [[package]] name = "gunicorn" version = "23.0.0" @@ -912,15 +1009,15 @@ files = [ [[package]] name = "openai" -version = "1.59.7" +version = "1.68.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" groups = ["main"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "openai-1.59.7-py3-none-any.whl", hash = "sha256:cfa806556226fa96df7380ab2e29814181d56fea44738c2b0e581b462c268692"}, - {file = "openai-1.59.7.tar.gz", hash = "sha256:043603def78c00befb857df9f0a16ee76a3af5984ba40cb7ee5e2f40db4646bf"}, + {file = "openai-1.68.0-py3-none-any.whl", hash = "sha256:20e279b0f3a78cb4a95f3eab2a180f3ee30c6a196aeebd6bf642a4f88ab85ee1"}, + {file = "openai-1.68.0.tar.gz", hash = "sha256:c570c06c9ba10f98b891ac30a3dd7b5c89ed48094c711c7a3f35fb5ade6c0757"}, ] [package.dependencies] @@ -928,8 +1025,10 @@ anyio = ">=3.5.0,<5" distro = ">=1.7.0,<2" httpx = ">=0.23.0,<1" jiter = ">=0.4.0,<1" +numpy = ">=2.0.2" pydantic = ">=1.9.0,<3" sniffio = "*" +sounddevice = ">=0.5.1" tqdm = ">4" typing-extensions = ">=4.11,<5" @@ -937,6 +1036,27 @@ typing-extensions = ">=4.11,<5" datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] realtime = ["websockets (>=13,<15)"] +[[package]] +name = "openai-agents" +version = "0.0.4" +description = "OpenAI Agents SDK" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "openai_agents-0.0.4-py3-none-any.whl", hash = "sha256:5577c3ee994fe0bd200d7283e4f7a614b3af19afeebcfb07b6ca6039a8a50a5c"}, + {file = "openai_agents-0.0.4.tar.gz", hash = "sha256:297e8d5faeca753e1b303d860b7ac94d03a7e10382be738163dc6a10a3b7cc1c"}, +] + +[package.dependencies] +griffe = ">=1.5.6,<2" +openai = ">=1.66.2" +pydantic = ">=2.10,<3" +requests = ">=2.0,<3" +types-requests = ">=2.0,<3" +typing-extensions = ">=4.12.2,<5" + [[package]] name = "openpyxl" version = "3.1.5" @@ -1054,6 +1174,19 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.9.2)"] +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + [[package]] name = "pydantic" version = "2.10.5" @@ -1406,6 +1539,28 @@ files = [ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] +[[package]] +name = "sounddevice" +version = "0.5.1" +description = "Play and Record Sound with Python" +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "sounddevice-0.5.1-py3-none-any.whl", hash = "sha256:e2017f182888c3f3c280d9fbac92e5dbddac024a7e3442f6e6116bd79dab8a9c"}, + {file = "sounddevice-0.5.1-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d16cb23d92322526a86a9490c427bf8d49e273d9ccc0bd096feecd229cde6031"}, + {file = "sounddevice-0.5.1-py3-none-win32.whl", hash = "sha256:d84cc6231526e7a08e89beff229c37f762baefe5e0cc2747cbe8e3a565470055"}, + {file = "sounddevice-0.5.1-py3-none-win_amd64.whl", hash = "sha256:4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1"}, + {file = "sounddevice-0.5.1.tar.gz", hash = "sha256:09ca991daeda8ce4be9ac91e15a9a81c8f81efa6b695a348c9171ea0c16cb041"}, +] + +[package.dependencies] +CFFI = ">=1.0" + +[package.extras] +numpy = ["NumPy"] + [[package]] name = "soupsieve" version = "2.6" @@ -1458,6 +1613,22 @@ notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] +[[package]] +name = "types-requests" +version = "2.32.0.20250306" +description = "Typing stubs for requests" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "types_requests-2.32.0.20250306-py3-none-any.whl", hash = "sha256:25f2cbb5c8710b2022f8bbee7b2b66f319ef14aeea2f35d80f18c9dbf3b60a0b"}, + {file = "types_requests-2.32.0.20250306.tar.gz", hash = "sha256:0962352694ec5b2f95fda877ee60a159abdf84a0fc6fdace599f20acb41a03d1"}, +] + +[package.dependencies] +urllib3 = ">=2" + [[package]] name = "typing-extensions" version = "4.12.2" @@ -1655,4 +1826,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "ef220af6b184e760ccc9b45e26ec9f58a54cb9327c562a612798433a7f9c08e4" +content-hash = "ee79f77afa3bbdb99810fd4a1a9cae366a307e2af74fd70c6d3376c6fdab61b3" diff --git a/apps/agents/pyproject.toml b/apps/agents/pyproject.toml index 872c69a5..a1206c53 100644 --- a/apps/agents/pyproject.toml +++ b/apps/agents/pyproject.toml @@ -41,6 +41,7 @@ mypy-extensions = "^1.0.0" nest-asyncio = "^1.6.0" numpy = "^2.1.2" openai = "^1.52.2" +openai-agents = "^0.0.4" openpyxl = "^3.1.5" pandas = "^2.2.3" pydantic = "^2.9.2" diff --git a/apps/agents/requirements.txt b/apps/agents/requirements.txt index 54a25f05..26c51d26 100644 --- a/apps/agents/requirements.txt +++ b/apps/agents/requirements.txt @@ -43,6 +43,7 @@ mypy-extensions==1.0.0 nest-asyncio==1.6.0 numpy==2.2.1 openai==1.59.7 +openai-agents==0.0.4 openpyxl==3.1.5 packaging==24.2 pandas==2.2.3 diff --git a/apps/agents/src/app/main.py b/apps/agents/src/app/main.py index 86cf9201..f78b35b6 100644 --- a/apps/agents/src/app/main.py +++ b/apps/agents/src/app/main.py @@ -37,67 +37,49 @@ def require_api_key(f): @app.route("/chat", methods=["POST"]) @require_api_key def chat(): - print('='*200) logger.info('='*200) + logger.info(f"{'*'*50}Running server mode{'*'*50}") try: data = request.get_json() - print('Complete request:') - logger.info('Complete request') - print(data) + logger.info('Complete request:') logger.info(data) - - print('-'*200) logger.info('-'*200) start_time = datetime.now() config = read_json_from_file("./configs/default_config.json") + logger.info('Beginning turn') resp_messages, resp_tokens_used, resp_state = run_turn( messages=data.get("messages", []), start_agent_name=data.get("startAgent", ""), agent_configs=data.get("agents", []), tool_configs=data.get("tools", []), - localize_history=config.get("localize_history", True), - return_diff_messages=config.get("return_diff_messages", True), - prompt_configs=data.get("prompts", []), start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), - children_aware_of_parent=config.get("children_aware_of_parent", False), - parent_has_child_history=config.get("parent_has_child_history", True), state=data.get("state", {}), - additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], - max_messages_per_turn=config.get("max_messages_per_turn", 2), - max_messages_per_error_escalation_turn=config.get("max_messages_per_error_escalation_turn", 2), - escalate_errors=config.get("escalate_errors", True), - max_overall_turns=config.get("max_overall_turns", 10) + additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL] ) - print('-'*200) logger.info('-'*200) - + logger.info('Raw output:') + logger.info((resp_messages, resp_tokens_used, resp_state)) + out = { "messages": resp_messages, "tokens_used": resp_tokens_used, "state": resp_state, } - print("Output: ") - logger.info(f"Output: ") + logger.info("Output:") for k, v in out.items(): - print(f"{k}: {v}") - print('*'*200) logger.info(f"{k}: {v}") logger.info('*'*200) - print("Processing time:") - print('='*200) logger.info('='*200) - print(f"Processing time: {datetime.now() - start_time}") logger.info(f"Processing time: {datetime.now() - start_time}") return jsonify(out) except Exception as e: - print(e) logger.error(f"Error: {e}") return jsonify({"error": str(e)}), 500 diff --git a/apps/agents/src/graph/core.py b/apps/agents/src/graph/core.py index 67eb618f..c1f24102 100644 --- a/apps/agents/src/graph/core.py +++ b/apps/agents/src/graph/core.py @@ -1,23 +1,20 @@ from copy import deepcopy import logging -from .types import AgentRole from .helpers.access import ( get_agent_by_name, - get_external_tools, pop_agent_config_by_type + get_external_tools, ) from .helpers.state import ( - add_recent_messages_to_history, construct_state_from_response, reset_current_turn, reset_current_turn_agent_history -) -from .helpers.instructions import ( - get_universal_system_message + construct_state_from_response ) from .helpers.control import get_latest_assistant_msg, get_latest_non_assistant_messages, get_last_agent_name from .swarm_wrapper import run as swarm_run, create_response, get_agents +from src.utils.common import common_logger as logger # Create a dedicated logger for swarm wrapper -logger = logging.getLogger("graph") logger.setLevel(logging.INFO) +print("Logger level set to INFO") def order_messages(messages): @@ -52,7 +49,7 @@ def clean_up_history(agent_data): data["history"] = order_messages(data["history"]) return agent_data -def create_final_response(response, turn_messages, messages, tokens_used, all_agents, return_diff_messages): +def create_final_response(response, turn_messages, tokens_used, all_agents): """ Constructs the final response data (messages, tokens_used, updated state) that a caller would need. """ @@ -61,7 +58,7 @@ def create_final_response(response, turn_messages, messages, tokens_used, all_ag response.messages = [] # Assign the appropriate messages to the response - response.messages = turn_messages if return_diff_messages else messages + turn_messages + response.messages = turn_messages # Ensure tokens_used is a valid dictionary if not isinstance(tokens_used, dict): @@ -83,17 +80,14 @@ def create_final_response(response, turn_messages, messages, tokens_used, all_ag def run_turn( - messages, start_agent_name, agent_configs, tool_configs, available_tool_mappings={}, - localize_history=True, return_diff_messages=True, prompt_configs=[], start_turn_with_start_agent=False, - children_aware_of_parent=False, parent_has_child_history=True, state={}, additional_tool_configs=[], - error_tool_call=True, max_messages_per_turn=10, max_messages_per_error_escalation_turn=4, - escalate_errors=True, max_overall_turns=10 + messages, start_agent_name, agent_configs, tool_configs, start_turn_with_start_agent, state={}, additional_tool_configs=[] ): """ Coordinates a single 'turn' of conversation or processing among agents. Includes validation, agent setup, optional greeting logic, error handling, and post-processing steps. """ logger.info("Running stateless turn") + print("Running stateless turn") # Sort messages by the specified ordering #messages = order_messages(messages) @@ -107,17 +101,11 @@ def run_turn( # Initialize tokens_used as a dictionary tokens_used = {"total": 0, "prompt": 0, "completion": 0} - # Extract special agent configs - post_processing_agent_config, agent_configs = pop_agent_config_by_type(agent_configs, AgentRole.POST_PROCESSING.value) - guardrails_agent_config, agent_configs = pop_agent_config_by_type(agent_configs, AgentRole.GUARDRAILS.value) - agent_data = state.get("agent_data", []) - universal_sys_msg = "" # If not a greeting turn, localize the last user or system messages if not greeting_turn: latest_assistant_msg = get_latest_assistant_msg(messages) - universal_sys_msg = get_universal_system_message(messages) latest_non_assistant_msgs = get_latest_non_assistant_messages(messages) msg_type = latest_non_assistant_msgs[-1]["role"] @@ -130,19 +118,6 @@ def run_turn( latest_assistant_msg=latest_assistant_msg, start_turn_with_start_agent=start_turn_with_start_agent ) - - # Localize history - if msg_type == "user": - messages = reset_current_turn(messages) - agent_data = reset_current_turn_agent_history(agent_data, [last_agent_name]) - #agent_data = clean_up_history(agent_data) - agent_data = add_recent_messages_to_history( - recent_messages=latest_non_assistant_msgs, - last_agent_name=last_agent_name, - agent_data=agent_data, - messages=messages, - parent_has_child_history=parent_has_child_history - ) else: # For a greeting turn, we assume the last agent is the start_agent_name last_agent_name = start_agent_name @@ -151,39 +126,34 @@ def run_turn( # Initialize all agents logger.info("Initializing agents") - all_agents, new_agents = get_agents( + print("Initializing agents") + new_agents = get_agents( agent_configs=agent_configs, - tool_configs=tool_configs, - available_tool_mappings=available_tool_mappings, - agent_data=agent_data, - localize_history=localize_history, - start_turn_with_start_agent=start_turn_with_start_agent, - children_aware_of_parent=children_aware_of_parent, - universal_sys_msg=universal_sys_msg + tool_configs=tool_configs ) # Prepare escalation agent - - # Get the last agent and validate - last_agent = get_agent_by_name(last_agent_name, all_agents) last_new_agent = get_agent_by_name(last_agent_name, new_agents) # Gather external tools for Swarm external_tools = get_external_tools(tool_configs) logger.info(f"Found {len(external_tools)} external tools") + print(f"Found {len(external_tools)} external tools") # If no validation error yet, proceed with the main run + logger.info("Running swarm run") + print("Running swarm run") + response = swarm_run( agent=last_new_agent, messages=messages, - execute_tools=True, external_tools=external_tools, - localize_history=localize_history, - parent_has_child_history=parent_has_child_history, - max_messages_per_turn=max_messages_per_turn, tokens_used=tokens_used ) + logger.info("Swarm run completed") + print("Swarm run completed") + # Initialize response.messages if it doesn't exist if not hasattr(response, 'messages'): response.messages = [] @@ -202,7 +172,7 @@ def run_turn( standard_message = { "role": raw_item.role if hasattr(raw_item, 'role') else "assistant", "content": content, - "sender": last_agent.name, + "sender": last_new_agent.name, "created_at": None, "response_type": "internal" } @@ -210,6 +180,9 @@ def run_turn( # Add the converted message to response messages response.messages.append(standard_message) + logger.info("Converted message added to response messages") + print("Converted message added to response messages") + # Use a dictionary for tokens_used instead of a hard-coded integer tokens_used = {"total": 100, "prompt": 50, "completion": 50} # Dummy values as placeholders @@ -217,11 +190,13 @@ def run_turn( if hasattr(response, 'messages') and isinstance(response.messages, list): turn_messages.extend(response.messages) - logger.info(f"Completed run of agent: {last_agent.name}") + logger.info(f"Completed run of agent: {last_new_agent.name}") + print(f"Completed run of agent: {last_new_agent.name}") # Otherwise, duplicate the last response as external logger.info("No post-processing agent found. Duplicating last response and setting to external.") + print("No post-processing agent found. Duplicating last response and setting to external.") if turn_messages: duplicate_msg = deepcopy(turn_messages[-1]) duplicate_msg["response_type"] = "external" @@ -234,7 +209,7 @@ def run_turn( response = create_response( messages=[duplicate_msg], tokens_used=tokens_used, - agent=last_agent, + agent=last_new_agent, error_msg='' ) @@ -243,11 +218,11 @@ def run_turn( turn_messages.extend(response.messages) # Finalize the response + logger.info("Finalizing response") + print("Finalizing response") return create_final_response( response=response, turn_messages=turn_messages, - messages=messages, tokens_used=tokens_used, - all_agents=all_agents, - return_diff_messages=return_diff_messages + all_agents=new_agents ) diff --git a/apps/agents/src/graph/helpers/state.py b/apps/agents/src/graph/helpers/state.py index c98c0462..c1b2427c 100644 --- a/apps/agents/src/graph/helpers/state.py +++ b/apps/agents/src/graph/helpers/state.py @@ -49,13 +49,7 @@ def construct_state_from_response(response, agents): for agent in agents: agent_data.append({ "name": agent.name, - "instructions": agent.instructions, - "parent_function": agent.parent_function.__name__ if agent.parent_function else None, - "child_functions": [f.__name__ for f in agent.child_functions.values()] if agent.child_functions else [], - "internal_tools": [t.get("function").get("name") for t in agent.internal_tools] if agent.internal_tools else [], - "external_tools": [t.get("function").get("name") for t in agent.external_tools] if agent.external_tools else [], - "history": agent.history, - "most_recent_parent_name": agent.most_recent_parent.name if agent.most_recent_parent else "" + "instructions": agent.instructions }) state = { diff --git a/apps/agents/src/graph/swarm_wrapper.py b/apps/agents/src/graph/swarm_wrapper.py index 03db1eb3..161c598a 100644 --- a/apps/agents/src/graph/swarm_wrapper.py +++ b/apps/agents/src/graph/swarm_wrapper.py @@ -1,30 +1,31 @@ -from src.swarm.types import Agent as SwarmAgent, Response as SwarmResponse import logging import json # Import helper functions needed for get_agents from .helpers.access import ( - get_agent_data_by_name, get_agent_by_name, get_tool_config_by_name, + get_tool_config_by_name, get_tool_config_by_type ) -from .helpers.transfer import create_transfer_function_to_agent, create_transfer_function_to_parent_agent from .helpers.instructions import ( - add_transfer_instructions_to_child_agents, add_transfer_instructions_to_parent_agents, - add_rag_instructions_to_agent, add_universal_system_message_to_agent + add_rag_instructions_to_agent ) -from agents import Agent as NewAgent, Runner, FunctionTool, function_tool, RunContextWrapper +from agents import Agent as NewAgent, Runner, FunctionTool, RunContextWrapper # Add import for OpenAI functionality -from src.utils.common import generate_openai_output +from src.utils.common import common_logger as logger, generate_openai_output from typing import Any # Create a dedicated logger for swarm wrapper -logger = logging.getLogger("swarm_wrapper") -logger.setLevel(logging.INFO) +#logger = logging.getLogger("swarm_wrapper") +#logger.setLevel(logging.INFO) -# Re-export the types from src.swarm.types -Agent = SwarmAgent -Response = SwarmResponse +from pydantic import BaseModel +from typing import List, Optional, Dict +class NewResponse(BaseModel): + messages: List[Dict] + agent: Optional[Any] = None + tokens_used: Optional[dict] = {} + error_msg: Optional[str] = "" async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict) -> str: print(f"Catch all called for tool: {tool_name}") @@ -43,25 +44,22 @@ async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool print(response_content) return(response_content) -def get_agents(agent_configs, tool_configs, localize_history, available_tool_mappings, - agent_data, start_turn_with_start_agent, children_aware_of_parent, universal_sys_msg): +def get_agents(agent_configs, tool_configs): """ Creates and initializes Agent objects based on their configurations and connections. - This function also sets up parent-child relationships, transfer instructions, and - universal system messages. """ if not isinstance(agent_configs, list): raise ValueError("Agents config is not a list in get_agents") if not isinstance(tool_configs, list): raise ValueError("Tools config is not a list in get_agents") - agents = [] new_agents = [] new_agent_to_children = {} new_agent_name_to_index = {} # Create Agent objects from config for agent_config in agent_configs: logger.debug(f"Processing config for agent: {agent_config['name']}") + print(f"Processing config for agent: {agent_config['name']}") # If hasRagSources, append the RAG tool to the agent's tools if agent_config.get("hasRagSources", False): @@ -71,11 +69,9 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map # Prepare tool lists for this agent external_tools = [] - candidate_parent_functions = {} - child_functions = {} logger.debug(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools") - print(tool_configs) + print(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools") new_tools = [] for tool_name in agent_config["tools"]: @@ -97,33 +93,15 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map ) new_tools.append(tool) logger.debug(f"Added tool {tool_name} to agent {agent_config['name']}") + print(f"Added tool {tool_name} to agent {agent_config['name']}") else: logger.warning(f"Tool {tool_name} not found in tool_configs") - - # Localize history (if applicable) - history = [] - this_agent_data = get_agent_data_by_name(agent_config["name"], agent_data) - if this_agent_data and localize_history: - history = this_agent_data.get("history", []) + print(f"WARNING: Tool {tool_name} not found in tool_configs") # Create the agent object logger.debug(f"Creating Agent object for {agent_config['name']}") + print(f"Creating Agent object for {agent_config['name']}") try: - agent = Agent( - name=agent_config["name"], - type=agent_config.get("type", "default"), - instructions=agent_config["instructions"], - description=agent_config.get("description", ""), - internal_tools=[], - external_tools=external_tools, - candidate_parent_functions=candidate_parent_functions, - child_functions=child_functions, - model=agent_config["model"], - respond_to_user=agent_config.get("respond_to_user", False), - history=history, - children_names=agent_config.get("connectedAgents", []), - most_recent_parent=None - ) new_agent = NewAgent( name=agent_config["name"], instructions=agent_config["instructions"], @@ -134,54 +112,13 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map new_agent_to_children[agent_config["name"]] = agent_config.get("connectedAgents", []) new_agent_name_to_index[agent_config["name"]] = len(new_agents) new_agents.append(new_agent) - agents.append(agent) logger.debug(f"Successfully created agent: {agent_config['name']}") + print(f"Successfully created agent: {agent_config['name']}") except Exception as e: logger.error(f"Failed to create agent {agent_config['name']}: {str(e)}") + print(f"ERROR: Failed to create agent {agent_config['name']}: {str(e)}") raise - # Reattach most_recent_parent if it exists - for agent in agents: - this_agent_data = get_agent_data_by_name(agent.name, agent_data) - if this_agent_data: - most_recent_parent_name = this_agent_data.get("most_recent_parent_name", "") - if most_recent_parent_name: - parent_agent = get_agent_by_name(most_recent_parent_name, agents) - if parent_agent: - agent.most_recent_parent = parent_agent - - # Attach children - logger.info("Adding children agents to parent agents") - for agent in agents: - agent.children = { - potential_child.name: potential_child - for potential_child in agents - if potential_child.name in agent.children_names - } - - # Generate transfer functions for child agents - logger.info("Generating transfer functions for transferring to children agents") - transfer_functions = { - agent.name: create_transfer_function_to_agent(agent) - for agent in agents - } - - # Add transfer functions to parent agents for each child - logger.info("Adding transfer functions for parents to transfer to children") - for agent in agents: - for child in agent.children.values(): - agent.child_functions[child.name] = transfer_functions[child.name] - - # Add parent-related instructions - logger.info("Adding child transfer-related instructions to parent agents") - for agent in agents: - if agent.children: - add_transfer_instructions_to_parent_agents(agent, agent.children, transfer_functions) - - # Finally add a universal system message to all agents - for agent in agents: - add_universal_system_message_to_agent(agent, universal_sys_msg) - for new_agent in new_agents: # Initialize the handoffs attribute if it doesn't exist if not hasattr(new_agent, 'handoffs'): @@ -189,7 +126,7 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map # Look up the agent's children from the old agent and create a list called handoffs in new_agent with pointers to the children in new_agents new_agent.handoffs = [new_agents[new_agent_name_to_index[child]] for child in new_agent_to_children[new_agent.name]] - return agents, new_agents + return new_agents def create_response(messages=None, tokens_used=None, agent=None, error_msg=''): @@ -210,10 +147,10 @@ def create_response(messages=None, tokens_used=None, agent=None, error_msg=''): if tokens_used is None: tokens_used = {} - return Response( + return NewResponse( messages=messages, - tokens_used=tokens_used, agent=agent, + tokens_used=tokens_used, error_msg=error_msg ) @@ -221,11 +158,7 @@ def create_response(messages=None, tokens_used=None, agent=None, error_msg=''): def run( agent, messages, - execute_tools=True, external_tools=None, - localize_history=True, - parent_has_child_history=True, - max_messages_per_turn=10, tokens_used=None ): """ @@ -245,6 +178,7 @@ def run( Response object from the Swarm client """ logger.info(f"Initializing Swarm client for agent: {agent.name}") + print(f"Initializing Swarm client for agent: {agent.name}") # Initialize default parameters if external_tools is None: @@ -271,7 +205,10 @@ def run( }) # Run the agent with the formatted messages + logger.info("Beginning Swarm run with run_sync") + print("Beginning Swarm run with run_sync") response2 = Runner.run_sync(agent, formatted_messages) logger.info(f"Completed Swarm run for agent: {agent.name}") + print(f"Completed Swarm run for agent: {agent.name}") return response2 \ No newline at end of file diff --git a/apps/agents/src/swarm/__init__.py b/apps/agents/src/swarm/__init__.py deleted file mode 100644 index a47b6210..00000000 --- a/apps/agents/src/swarm/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .core import Swarm -from .types import Agent, Response - -__all__ = ["Swarm", "Agent", "Response"] diff --git a/apps/agents/src/swarm/core.py b/apps/agents/src/swarm/core.py deleted file mode 100644 index 663e5894..00000000 --- a/apps/agents/src/swarm/core.py +++ /dev/null @@ -1,275 +0,0 @@ -# Standard library imports -import copy -import json -from collections import defaultdict -from typing import List, Callable, Union -from datetime import datetime - -# Package/library imports -from openai import OpenAI -import random - -# Local imports -from .util import * -from .types import ( - Agent, - AgentFunction, - ChatCompletionMessage, - ChatCompletionMessageToolCall, - Function, - Response, - Result, -) - -__CTX_VARS_NAME__ = "context_variables" - - -class Swarm: - def __init__(self, client=None): - if not client: - client = OpenAI(api_key=OPENAI_API_KEY) - self.client = client - self.history = defaultdict(lambda : []) - - def get_chat_completion( - self, - agent: Agent, - history: List, - context_variables: dict, - model_override: str, - stream: bool, - debug: bool, - temperature: float - ) -> ChatCompletionMessage: - context_variables = defaultdict(str, context_variables) - instructions = ( - agent.instructions(context_variables) - if callable(agent.instructions) - else agent.instructions - ) - messages = [{"role": "system", "content": instructions}] + history - debug_print(debug, "Getting chat completion for...:", messages) - - all_functions = list(agent.child_functions.values()) + ([agent.parent_function] if agent.parent_function else []) - all_tools = agent.external_tools + agent.internal_tools - funcs_and_tools = [function_to_json(f) for f in all_functions] + [t for t in all_tools] - # hide context_variables from model - for tool in funcs_and_tools: - params = tool["function"]["parameters"] - params["properties"].pop(__CTX_VARS_NAME__, None) - if __CTX_VARS_NAME__ in params.get("required", []): - params["required"].remove(__CTX_VARS_NAME__) - - create_params = { - "model": model_override or agent.model, - "messages": messages, - "tools": funcs_and_tools or None, - "tool_choice": agent.tool_choice, - "stream": stream, - "temperature": temperature - } - - if funcs_and_tools: - create_params["parallel_tool_calls"] = agent.parallel_tool_calls - - return self.client.chat.completions.create(**create_params) - - def handle_function_result(self, result, debug) -> Result: - # Check if result is already a Result instance - if isinstance(result, Result): - return result - - # Check if result is an Agent instance - if isinstance(result, Agent): - return Result( - value=json.dumps({"assistant": result.name}), - agent=result, - ) - - # Handle all other cases - try: - return Result(value=str(result)) - except Exception as e: - error_message = f"Failed to cast response to string: {result}. Make sure agent functions return a string or Result object. Error: {str(e)}" - debug_print(debug, error_message) - raise TypeError(error_message) - - def handle_function_calls( - self, - tool_calls: List[ChatCompletionMessageToolCall], - functions: List[AgentFunction], - context_variables: dict, - debug: bool, - ) -> Response: - function_map = {f.__name__: f for f in functions} - partial_response = Response( - messages=[], agent=None, context_variables={}) - - for tool_call in tool_calls: - name = tool_call.function.name - # handle missing tool case, skip to next tool - if name not in function_map: - debug_print(debug, f"Tool {name} not found in function map.") - partial_response.messages.append( - { - "role": "tool", - "tool_call_id": tool_call.id, - "tool_name": name, - "content": f"Error: Tool {name} not found.", - } - ) - continue - args = json.loads(tool_call.function.arguments) - debug_print( - debug, f"Processing tool call: {name} with arguments {args}") - - func = function_map[name] - # pass context_variables to agent functions - if __CTX_VARS_NAME__ in func.__code__.co_varnames: - args[__CTX_VARS_NAME__] = context_variables - raw_result = function_map[name](**args) - - result: Result = self.handle_function_result(raw_result, debug) - partial_response.messages.append( - { - "role": "tool", - "tool_call_id": tool_call.id, - "tool_name": name, - "content": result.value, - } - ) - partial_response.context_variables.update(result.context_variables) - if result.agent: - partial_response.agent = result.agent - - return partial_response - - def run( - self, - agent: Agent, - messages: List, - context_variables: dict = {}, - model_override: str = None, - stream: bool = False, - debug: bool = False, - max_messages_per_turn: int = 10, - execute_tools: bool = True, - external_tools: List[str] = [], - localize_history: bool = True, - parent_has_child_history: bool = True, - tokens_used: dict = {}, - temperature: float = 0.0 - ) -> Response: - - active_agent = agent - context_variables = copy.deepcopy(context_variables) - global_history = copy.deepcopy(messages) - init_len = len(messages) - - while len(global_history) - init_len < max_messages_per_turn and active_agent: - history = active_agent.history if localize_history else global_history - history = arrange_messages_keys_in_order(history) - - parent = active_agent.most_recent_parent - - children_names_backup, children_backup, child_functions_backup = copy.deepcopy(active_agent.children_names), copy.deepcopy(active_agent.children), copy.deepcopy(active_agent.child_functions) - - active_agent = check_and_remove_repeat_tool_call_to_child(active_agent, history) - - # get completion with current history, agent - completion = self.get_chat_completion( - agent=active_agent, - history=history, - context_variables=context_variables, - model_override=model_override, - stream=stream, - debug=debug, - temperature=temperature - ) - tokens_used = update_tokens_used(provider="openai", model=model_override or active_agent.model, tokens_used=tokens_used, completion=completion) - - # Restore children and child functions - active_agent.children_names, active_agent.children, active_agent.child_functions = children_names_backup, children_backup, child_functions_backup - - message = completion.choices[0].message - debug_print(debug, "Received completion:", message) - message.sender = active_agent.name - message_json = json.loads(message.model_dump_json()) - message_json = add_message_metadata(message_json, active_agent) - - if localize_history: - active_agent = update_histories(active_agent, message_json) - if parent and parent_has_child_history: - parent = update_histories(parent, message_json) - global_history.append(message_json) - - external_tool_calls = [] - internal_tool_calls = [] - - if message.tool_calls: - message_json["response_type"] = "internal" - for tool_call in message.tool_calls: - tool_name = tool_call.function.name - if tool_name in external_tools: - external_tool_calls.append(tool_call) - else: - internal_tool_calls.append(tool_call) - message.tool_calls = internal_tool_calls - - if not message.tool_calls or not execute_tools: - if external_tool_calls: - message.tool_calls.extend(external_tool_calls) - debug_print(debug, "Ending turn.") - break - - # handle function calls, updating context_variables, and switching agents - all_functions = list(active_agent.child_functions.values()) + ([active_agent.parent_function] if active_agent.parent_function else []) - partial_response = self.handle_function_calls( - message.tool_calls, all_functions, context_variables, debug - ) - for msg in partial_response.messages: - msg = add_message_metadata(msg, active_agent) - if localize_history: - active_agent = update_histories(active_agent, msg) - if parent and parent_has_child_history: - parent = update_histories(parent, msg) - - global_history.extend(partial_response.messages) - context_variables.update(partial_response.context_variables) - - # Parent to child transfer - if partial_response.agent: - prev_agent = active_agent - active_agent = partial_response.agent - - # Parent to child transfer - if active_agent.name in prev_agent.children_names: - active_agent.most_recent_parent = prev_agent - active_agent.parent_function = active_agent.candidate_parent_functions[active_agent.most_recent_parent.name] - if localize_history: - if not parent_has_child_history: - prev_agent.history = remove_irrelevant_messages(prev_agent.history) - new_active_agent_history = get_current_turn_messages(global_history, only_user = True) - active_agent.history.extend(new_active_agent_history) - - # Child to parent transfer - else: - assert parent == active_agent, "Parent and active agent do not match when active agent is not a child of previous agent" - child = prev_agent - if localize_history: - child.history = remove_irrelevant_messages(child.history) - - - return_messages = global_history[init_len:] - error_msg = "" - - if len(global_history) - init_len >= max_messages_per_turn: - error_msg = "Max messages per turn reached" - - return Response( - messages=return_messages, - agent=active_agent, - context_variables=context_variables, - error_msg=error_msg, - tokens_used=tokens_used - ) diff --git a/apps/agents/src/swarm/repl/__init__.py b/apps/agents/src/swarm/repl/__init__.py deleted file mode 100644 index 2a1cb40c..00000000 --- a/apps/agents/src/swarm/repl/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .repl import run_demo_loop diff --git a/apps/agents/src/swarm/repl/repl.py b/apps/agents/src/swarm/repl/repl.py deleted file mode 100644 index 50c3d0ee..00000000 --- a/apps/agents/src/swarm/repl/repl.py +++ /dev/null @@ -1,87 +0,0 @@ -import json - -from swarm import Swarm - - -def process_and_print_streaming_response(response): - content = "" - last_sender = "" - - for chunk in response: - if "sender" in chunk: - last_sender = chunk["sender"] - - if "content" in chunk and chunk["content"] is not None: - if not content and last_sender: - print(f"\033[94m{last_sender}:\033[0m", end=" ", flush=True) - last_sender = "" - print(chunk["content"], end="", flush=True) - content += chunk["content"] - - if "tool_calls" in chunk and chunk["tool_calls"] is not None: - for tool_call in chunk["tool_calls"]: - f = tool_call["function"] - name = f["name"] - if not name: - continue - print(f"\033[94m{last_sender}: \033[95m{name}\033[0m()") - - if "delim" in chunk and chunk["delim"] == "end" and content: - print() # End of response message - content = "" - - if "response" in chunk: - return chunk["response"] - - -def pretty_print_messages(messages) -> None: - for message in messages: - if message["role"] != "assistant": - continue - - # print agent name in blue - print(f"\033[94m{message['sender']}\033[0m:", end=" ") - - # print response, if any - if message["content"]: - print(message["content"]) - - # print tool calls in purple, if any - tool_calls = message.get("tool_calls") or [] - if len(tool_calls) > 1: - print() - for tool_call in tool_calls: - f = tool_call["function"] - name, args = f["name"], f["arguments"] - arg_str = json.dumps(json.loads(args)).replace(":", "=") - print(f"\033[95m{name}\033[0m({arg_str[1:-1]})") - - -def run_demo_loop( - starting_agent, context_variables=None, stream=False, debug=False -) -> None: - client = Swarm() - print("Starting Swarm CLI 🐝") - - messages = [] - agent = starting_agent - - while True: - user_input = input("\033[90mUser\033[0m: ") - messages.append({"role": "user", "content": user_input}) - - response = client.run( - agent=agent, - messages=messages, - context_variables=context_variables or {}, - stream=stream, - debug=debug, - ) - - if stream: - response = process_and_print_streaming_response(response) - else: - pretty_print_messages(response.messages) - - messages.extend(response.messages) - agent = response.agent diff --git a/apps/agents/src/swarm/types.py b/apps/agents/src/swarm/types.py deleted file mode 100644 index 1c6b87de..00000000 --- a/apps/agents/src/swarm/types.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -from openai.types.chat import ChatCompletionMessage -from openai.types.chat.chat_completion_message_tool_call import ( - ChatCompletionMessageToolCall, - Function, -) -from typing import List, Callable, Union, Optional, Dict - -# Third-party imports -from pydantic import BaseModel - -AgentFunction = Callable[[], Union[str, "Agent", dict]] - -class Agent(BaseModel): - name: str = "Agent" - model: str = "gpt-4o" - type: str = "" - instructions: Union[str, Callable[[], str]] = "You are a helpful agent.", - description: str = "This is a helpful agent." - candidate_parent_functions: Dict[str, AgentFunction] = {} - parent_function: AgentFunction = None - child_functions: Dict[str, AgentFunction] = {} - internal_tools: List[Dict] = [] - external_tools: List[Dict] = [] - tool_choice: str = None - parallel_tool_calls: bool = True - respond_to_user: bool = True - history: List[Dict] = [] - children_names: List[str] = [] - children: Dict[str, "Agent"] = {} - most_recent_parent: Optional["Agent"] = None - parent: "Agent" = None - -class Response(BaseModel): - messages: List = [] - agent: Optional[Agent] = None - context_variables: dict = {} - error_msg: Optional[str] = "" - tokens_used: dict = {} - -class Result(BaseModel): - """ - Encapsulates the possible return values for an agent function. - - Attributes: - value (str): The result value as a string. - agent (Agent): The agent instance, if applicable. - context_variables (dict): A dictionary of context variables. - """ - - value: str = "" - agent: Optional[Agent] = None - context_variables: dict = {} \ No newline at end of file diff --git a/apps/agents/src/swarm/util.py b/apps/agents/src/swarm/util.py deleted file mode 100644 index d2a3fc2f..00000000 --- a/apps/agents/src/swarm/util.py +++ /dev/null @@ -1,175 +0,0 @@ -import inspect -import json -from datetime import datetime -import os -from dotenv import load_dotenv -from src.utils.common import read_json_from_file, get_api_key - -load_dotenv() -OPENAI_API_KEY = get_api_key("OPENAI_API_KEY") - -def debug_print(debug: bool, *args: str) -> None: - if not debug: - return - timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - message = " ".join(map(str, args)) - print(f"\033[97m[\033[90m{timestamp}\033[97m]\033[90m {message}\033[0m") - -def merge_fields(target, source): - for key, value in source.items(): - if isinstance(value, str): - target[key] += value - elif value is not None and isinstance(value, dict): - merge_fields(target[key], value) - - -def merge_chunk(final_response: dict, delta: dict) -> None: - delta.pop("role", None) - merge_fields(final_response, delta) - - tool_calls = delta.get("tool_calls") - if tool_calls and len(tool_calls) > 0: - index = tool_calls[0].pop("index") - merge_fields(final_response["tool_calls"][index], tool_calls[0]) - - -def function_to_json(func) -> dict: - """ - Converts a Python function into a JSON-serializable dictionary - that describes the function's signature, including its name, - description, and parameters. - - Args: - func: The function to be converted. - - Returns: - A dictionary representing the function's signature in JSON format. - """ - type_map = { - str: "string", - int: "integer", - float: "number", - bool: "boolean", - list: "array", - dict: "object", - type(None): "null", - } - - try: - signature = inspect.signature(func) - except ValueError as e: - raise ValueError( - f"Failed to get signature for function {func.__name__}: {str(e)}" - ) - - parameters = {} - for param in signature.parameters.values(): - try: - param_type = type_map.get(param.annotation, "string") - except KeyError as e: - raise KeyError( - f"Unknown type annotation {param.annotation} for parameter {param.name}: {str(e)}" - ) - parameters[param.name] = {"type": param_type} - - required = [ - param.name - for param in signature.parameters.values() - if param.default == inspect._empty - ] - - return { - "type": "function", - "function": { - "name": func.__name__, - "description": func.__doc__ or "", - "parameters": { - "type": "object", - "properties": parameters, - "required": required, - }, - }, - } - -def get_current_turn_messages(messages, only_user = False): - if only_user: - return [msg for msg in messages if msg.get("current_turn") and msg.get("role") == "user"] - else: - return [msg for msg in messages if msg.get("current_turn")] - -def arrange_messages_keys_in_order(messages): - """Arranges message keys in a specific order: id, role, sender, relevant_agents, content, created_at, timestamp, followed by rest alphabetically""" - key_order = ['role', 'sender', 'content', 'created_at'] - - def sort_keys(message): - # Create new dict with specified key order - ordered = {} - # Add keys in specified order if they exist - for key in key_order: - if key in message: - ordered[key] = message[key] - # Add remaining keys in alphabetical order - for key in sorted(message.keys()): - if key not in key_order: - ordered[key] = message[key] - return ordered - - return [sort_keys(message) for message in messages] - -def remove_irrelevant_messages(messages): - """Removes all messages from and including the latest user message""" - for i in range(len(messages)-1, -1, -1): - if messages[i].get("role") == "user": - return messages[:i] - return messages - -def update_histories(active_agent, message): - active_agent.history.append(message) - return active_agent - -def remove_none_fields(message): - return {k: v for k, v in message.items() if v is not None} - -def add_message_metadata(message, active_agent): - message = remove_none_fields(message) - message["created_at"] = datetime.now().isoformat() - message["current_turn"] = True - - if active_agent.respond_to_user: - message["response_type"] = "external" - else: - message["response_type"] = "internal" - - return message - -def check_and_remove_repeat_tool_call_to_child(agent, messages): - # If in the current turn, the most recent assistant message (need not be the last message overall, just needs to be the last message with role as assistant) is a tool call from a child agent, which transfers control to the agent using its parent function, then remove the tool call to transfer to that child again from this agent. This is to prevent back and forth between this agent and the child agent. - for message in reversed(messages): - if message.get("role") == "assistant" and message.get("sender") in agent.children_names and message.get("tool_calls"): - tool_call = message.get("tool_calls")[0] - child_agent = agent.children.get(message.get("sender"), None) - if not child_agent: - continue - child_agent_name = child_agent.name - if tool_call.get("function").get("name") == child_agent.parent_function: - agent.children_names.remove(child_agent_name) - agent.children.pop(child_agent_name) - agent.child_functions.pop(child_agent_name) - break - return agent - -def update_tokens_used(provider, model, tokens_used, completion): - provider_model = f"{provider}/{model}" - input_tokens = completion.usage.prompt_tokens - output_tokens = completion.usage.completion_tokens - - if provider_model not in tokens_used: - tokens_used[provider_model] = { - 'input_tokens': 0, - 'output_tokens': 0, - } - - tokens_used[provider_model]['input_tokens'] += input_tokens - tokens_used[provider_model]['output_tokens'] += output_tokens - - return tokens_used \ No newline at end of file diff --git a/apps/agents/src/utils/common.py b/apps/agents/src/utils/common.py index 83a0cf7f..57c1c58c 100644 --- a/apps/agents/src/utils/common.py +++ b/apps/agents/src/utils/common.py @@ -4,7 +4,6 @@ import os import subprocess import sys import time -from collections import defaultdict from dotenv import load_dotenv from openai import OpenAI diff --git a/apps/agents/tests/interactive.py b/apps/agents/tests/interactive.py index 1cf6dcdc..1e38181a 100644 --- a/apps/agents/tests/interactive.py +++ b/apps/agents/tests/interactive.py @@ -87,18 +87,9 @@ if __name__ == "__main__": start_agent_name=start_agent_name, agent_configs=agent_configs, tool_configs=tool_configs, - return_diff_messages=config.get("return_diff_messages", True), - prompt_configs=prompt_configs, start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), - children_aware_of_parent=config.get("children_aware_of_parent", False), - parent_has_child_history=config.get("parent_has_child_history", True), state=state, - additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], - error_tool_call=config.get("error_tool_call", True), - max_messages_per_turn=config.get("max_messages_per_turn", 10), - max_messages_per_error_escalation_turn=config.get("max_messages_per_error_escalation_turn", 4), - escalate_errors=config.get("escalate_errors", True), - max_overall_turns=config.get("max_overall_turns", 10) + additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL] ) state = resp_state resp_messages = order_messages(resp_messages) From a2a19f37d75d2b41bbce55388948a029c520d7b0 Mon Sep 17 00:00:00 2001 From: arkml Date: Fri, 21 Mar 2025 17:17:15 +0530 Subject: [PATCH 21/49] added webhook and mocking support --- apps/agents/src/graph/swarm_wrapper.py | 124 ++++++++++++++++-- .../sample_requests/default_example.json | 4 +- 2 files changed, 114 insertions(+), 14 deletions(-) diff --git a/apps/agents/src/graph/swarm_wrapper.py b/apps/agents/src/graph/swarm_wrapper.py index 161c598a..9f113ccd 100644 --- a/apps/agents/src/graph/swarm_wrapper.py +++ b/apps/agents/src/graph/swarm_wrapper.py @@ -1,6 +1,6 @@ import logging import json - +import aiohttp # Import helper functions needed for get_agents from .helpers.access import ( get_tool_config_by_name, @@ -17,6 +17,9 @@ from typing import Any # Create a dedicated logger for swarm wrapper #logger = logging.getLogger("swarm_wrapper") #logger.setLevel(logging.INFO) +import asyncio +from mcp import ClientSession +from mcp.client.sse import sse_client from pydantic import BaseModel from typing import List, Optional, Dict @@ -27,22 +30,117 @@ class NewResponse(BaseModel): tokens_used: Optional[dict] = {} error_msg: Optional[str] = "" +async def mock_tool(tool_name: str, args: str, mock_instructions: str) -> str: + """ + Handles tool execution by either using mock instructions or generating a response. + + Args: + tool_name: The name of the tool + args: The arguments passed to the tool + tool_config: The configuration of the tool + + Returns: + The response from the tool + """ + print(f"Mock tool called for: {tool_name}") + + # For non-mocked tools, generate a realistic response + description = mock_instructions + + messages = [ + {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. Here are the mock instructions: {description}. Generate a realistic response as if the tool was actually executed with the given parameters."}, + {"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}' with these parameters: {args}. The response should be concise and focused on what the tool would actually return."} + ] + + print(f"Generating simulated response for tool: {tool_name}") + response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") + return response_content + +async def call_webhook(tool_name: str, args: str) -> str: + """ + Calls the webhook with the given tool name and arguments. + + Args: + tool_name (str): The name of the tool to call. + args (str): The arguments for the tool as a JSON string. + + Returns: + str: The response from the webhook, or an error message if the call fails. + """ + webhook_url = "http://localhost:4020/tool_call" + content_dict = { + "toolCall": { + "function": { + "name": tool_name, + "arguments": args # Assumes args is a valid JSON string + } + } + } + request_body = { + "content": json.dumps(content_dict) + } + try: + async with aiohttp.ClientSession() as session: + async with session.post(webhook_url, json=request_body) as response: + if response.status == 200: + response_json = await response.json() + return response_json.get("result", "") + else: + error_msg = await response.text() + print(f"Webhook error: {error_msg}") + return f"Error: {error_msg}" + except Exception as e: + print(f"Exception in call_webhook: {str(e)}") + return f"Error: Failed to call webhook - {str(e)}" + +async def call_mcp(tool_name: str, args: str, mcp_server_name: str, mcp_servers: dict) -> str: + """ + Calls the MCP with the given tool name and arguments. + """ + server_url = "http://localhost:8000/sse" #mcp_servers.get(tool_name, None) + print(args) + async with sse_client(url=server_url) as streams: + # Create a client session using the SSE streams + async with ClientSession(*streams) as session: + # Initialize the session (perform handshake with the server) + await session.initialize() + # Call the tool on the server and await the response + response = await session.call_tool(tool_name, arguments=json.loads(args)) + + # Print the response received from the server + print("Server response:", response) + + return response + async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict) -> str: + """ + Handles all tool calls by dispatching to the mock_tool function. + + Args: + ctx: The run context wrapper + args: The arguments passed to the tool + tool_name: The name of the tool being called + tool_config: The configuration of the tool + + Returns: + The response from the tool + """ print(f"Catch all called for tool: {tool_name}") print(f"Args: {args}") print(f"Tool config: {tool_config}") - #if tool_config.get("mock", False): - #& return tool_config.get("mockInstructions", "No mock instructions provided") - description = tool_config.get("description", "") - - messages = [ - {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. The tool has this description: {description}. Generate a realistic response as if the tool was actually executed with the given parameters."}, - {"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}' with these parameters: {args}. The response should be concise and focused on what the tool would actually return."} - - ] - response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") - print(response_content) - return(response_content) + response_content = None + # Check if this tool should be mocked + if tool_config.get("mockTool", False): + # Call mock_tool to handle the response (it will decide whether to use mock instructions or generate a response) + response_content = await mock_tool(tool_name, args, tool_config) + print(response_content) + elif tool_config.get("isMcp", False): + response_content = await call_mcp(tool_name, args, tool_config.get("mcpServerName", ""), {}) + print(response_content) + else: + response_content = await call_webhook(tool_name, args) + print(response_content) + return response_content def get_agents(agent_configs, tool_configs): """ diff --git a/apps/agents/tests/sample_requests/default_example.json b/apps/agents/tests/sample_requests/default_example.json index 7dd1c4ec..8fc308c6 100644 --- a/apps/agents/tests/sample_requests/default_example.json +++ b/apps/agents/tests/sample_requests/default_example.json @@ -106,7 +106,9 @@ "required": [ "order_id" ] - } + }, + "mockTool": true, + "mockInstructions": "Return a mock response for Door Dash order details." }, { "name": "get_delivery_status", From e725fc6276ccde8555490b9da5a044ee852d6d81 Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Sun, 23 Mar 2025 11:36:47 +0530 Subject: [PATCH 22/49] Add async/sync wrapper over run --- apps/agents/poetry.lock | 727 ++++++++++++++++++++++++- apps/agents/pyproject.toml | 5 +- apps/agents/requirements.txt | 3 + apps/agents/src/app/main.py | 3 +- apps/agents/src/graph/swarm_wrapper.py | 78 +-- 5 files changed, 777 insertions(+), 39 deletions(-) diff --git a/apps/agents/poetry.lock b/apps/agents/poetry.lock index d6afd7ca..c97ff628 100644 --- a/apps/agents/poetry.lock +++ b/apps/agents/poetry.lock @@ -1,5 +1,139 @@ # This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, +] + +[[package]] +name = "aiohttp" +version = "3.11.14" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "aiohttp-3.11.14-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e2bc827c01f75803de77b134afdbf74fa74b62970eafdf190f3244931d7a5c0d"}, + {file = "aiohttp-3.11.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e365034c5cf6cf74f57420b57682ea79e19eb29033399dd3f40de4d0171998fa"}, + {file = "aiohttp-3.11.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c32593ead1a8c6aabd58f9d7ee706e48beac796bb0cb71d6b60f2c1056f0a65f"}, + {file = "aiohttp-3.11.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4e7c7ec4146a94a307ca4f112802a8e26d969018fabed526efc340d21d3e7d0"}, + {file = "aiohttp-3.11.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8b2df9feac55043759aa89f722a967d977d80f8b5865a4153fc41c93b957efc"}, + {file = "aiohttp-3.11.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7571f99525c76a6280f5fe8e194eeb8cb4da55586c3c61c59c33a33f10cfce7"}, + {file = "aiohttp-3.11.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b59d096b5537ec7c85954cb97d821aae35cfccce3357a2cafe85660cc6295628"}, + {file = "aiohttp-3.11.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b42dbd097abb44b3f1156b4bf978ec5853840802d6eee2784857be11ee82c6a0"}, + {file = "aiohttp-3.11.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b05774864c87210c531b48dfeb2f7659407c2dda8643104fb4ae5e2c311d12d9"}, + {file = "aiohttp-3.11.14-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4e2e8ef37d4bc110917d038807ee3af82700a93ab2ba5687afae5271b8bc50ff"}, + {file = "aiohttp-3.11.14-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e9faafa74dbb906b2b6f3eb9942352e9e9db8d583ffed4be618a89bd71a4e914"}, + {file = "aiohttp-3.11.14-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7e7abe865504f41b10777ac162c727af14e9f4db9262e3ed8254179053f63e6d"}, + {file = "aiohttp-3.11.14-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4848ae31ad44330b30f16c71e4f586cd5402a846b11264c412de99fa768f00f3"}, + {file = "aiohttp-3.11.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2d0b46abee5b5737cb479cc9139b29f010a37b1875ee56d142aefc10686a390b"}, + {file = "aiohttp-3.11.14-cp310-cp310-win32.whl", hash = "sha256:a0d2c04a623ab83963576548ce098baf711a18e2c32c542b62322a0b4584b990"}, + {file = "aiohttp-3.11.14-cp310-cp310-win_amd64.whl", hash = "sha256:5409a59d5057f2386bb8b8f8bbcfb6e15505cedd8b2445db510563b5d7ea1186"}, + {file = "aiohttp-3.11.14-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f296d637a50bb15fb6a229fbb0eb053080e703b53dbfe55b1e4bb1c5ed25d325"}, + {file = "aiohttp-3.11.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ec6cd1954ca2bbf0970f531a628da1b1338f594bf5da7e361e19ba163ecc4f3b"}, + {file = "aiohttp-3.11.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:572def4aad0a4775af66d5a2b5923c7de0820ecaeeb7987dcbccda2a735a993f"}, + {file = "aiohttp-3.11.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c68e41c4d576cd6aa6c6d2eddfb32b2acfb07ebfbb4f9da991da26633a3db1a"}, + {file = "aiohttp-3.11.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b8bbfc8111826aa8363442c0fc1f5751456b008737ff053570f06a151650b3"}, + {file = "aiohttp-3.11.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b0a200e85da5c966277a402736a96457b882360aa15416bf104ca81e6f5807b"}, + {file = "aiohttp-3.11.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d173c0ac508a2175f7c9a115a50db5fd3e35190d96fdd1a17f9cb10a6ab09aa1"}, + {file = "aiohttp-3.11.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:413fe39fd929329f697f41ad67936f379cba06fcd4c462b62e5b0f8061ee4a77"}, + {file = "aiohttp-3.11.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65c75b14ee74e8eeff2886321e76188cbe938d18c85cff349d948430179ad02c"}, + {file = "aiohttp-3.11.14-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:321238a42ed463848f06e291c4bbfb3d15ba5a79221a82c502da3e23d7525d06"}, + {file = "aiohttp-3.11.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:59a05cdc636431f7ce843c7c2f04772437dd816a5289f16440b19441be6511f1"}, + {file = "aiohttp-3.11.14-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:daf20d9c3b12ae0fdf15ed92235e190f8284945563c4b8ad95b2d7a31f331cd3"}, + {file = "aiohttp-3.11.14-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:05582cb2d156ac7506e68b5eac83179faedad74522ed88f88e5861b78740dc0e"}, + {file = "aiohttp-3.11.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:12c5869e7ddf6b4b1f2109702b3cd7515667b437da90a5a4a50ba1354fe41881"}, + {file = "aiohttp-3.11.14-cp311-cp311-win32.whl", hash = "sha256:92868f6512714efd4a6d6cb2bfc4903b997b36b97baea85f744229f18d12755e"}, + {file = "aiohttp-3.11.14-cp311-cp311-win_amd64.whl", hash = "sha256:bccd2cb7aa5a3bfada72681bdb91637094d81639e116eac368f8b3874620a654"}, + {file = "aiohttp-3.11.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:70ab0f61c1a73d3e0342cedd9a7321425c27a7067bebeeacd509f96695b875fc"}, + {file = "aiohttp-3.11.14-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:602d4db80daf4497de93cb1ce00b8fc79969c0a7cf5b67bec96fa939268d806a"}, + {file = "aiohttp-3.11.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a8a0d127c10b8d89e69bbd3430da0f73946d839e65fec00ae48ca7916a31948"}, + {file = "aiohttp-3.11.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9f835cdfedcb3f5947304e85b8ca3ace31eef6346d8027a97f4de5fb687534"}, + {file = "aiohttp-3.11.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8aa5c68e1e68fff7cd3142288101deb4316b51f03d50c92de6ea5ce646e6c71f"}, + {file = "aiohttp-3.11.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b512f1de1c688f88dbe1b8bb1283f7fbeb7a2b2b26e743bb2193cbadfa6f307"}, + {file = "aiohttp-3.11.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc9253069158d57e27d47a8453d8a2c5a370dc461374111b5184cf2f147a3cc3"}, + {file = "aiohttp-3.11.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b2501f1b981e70932b4a552fc9b3c942991c7ae429ea117e8fba57718cdeed0"}, + {file = "aiohttp-3.11.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:28a3d083819741592685762d51d789e6155411277050d08066537c5edc4066e6"}, + {file = "aiohttp-3.11.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0df3788187559c262922846087e36228b75987f3ae31dd0a1e5ee1034090d42f"}, + {file = "aiohttp-3.11.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e73fa341d8b308bb799cf0ab6f55fc0461d27a9fa3e4582755a3d81a6af8c09"}, + {file = "aiohttp-3.11.14-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:51ba80d473eb780a329d73ac8afa44aa71dfb521693ccea1dea8b9b5c4df45ce"}, + {file = "aiohttp-3.11.14-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8d1dd75aa4d855c7debaf1ef830ff2dfcc33f893c7db0af2423ee761ebffd22b"}, + {file = "aiohttp-3.11.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41cf0cefd9e7b5c646c2ef529c8335e7eafd326f444cc1cdb0c47b6bc836f9be"}, + {file = "aiohttp-3.11.14-cp312-cp312-win32.whl", hash = "sha256:948abc8952aff63de7b2c83bfe3f211c727da3a33c3a5866a0e2cf1ee1aa950f"}, + {file = "aiohttp-3.11.14-cp312-cp312-win_amd64.whl", hash = "sha256:3b420d076a46f41ea48e5fcccb996f517af0d406267e31e6716f480a3d50d65c"}, + {file = "aiohttp-3.11.14-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d14e274828561db91e4178f0057a915f3af1757b94c2ca283cb34cbb6e00b50"}, + {file = "aiohttp-3.11.14-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f30fc72daf85486cdcdfc3f5e0aea9255493ef499e31582b34abadbfaafb0965"}, + {file = "aiohttp-3.11.14-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4edcbe34e6dba0136e4cabf7568f5a434d89cc9de5d5155371acda275353d228"}, + {file = "aiohttp-3.11.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7169ded15505f55a87f8f0812c94c9412623c744227b9e51083a72a48b68a5"}, + {file = "aiohttp-3.11.14-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad1f2fb9fe9b585ea4b436d6e998e71b50d2b087b694ab277b30e060c434e5db"}, + {file = "aiohttp-3.11.14-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20412c7cc3720e47a47e63c0005f78c0c2370020f9f4770d7fc0075f397a9fb0"}, + {file = "aiohttp-3.11.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dd9766da617855f7e85f27d2bf9a565ace04ba7c387323cd3e651ac4329db91"}, + {file = "aiohttp-3.11.14-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:599b66582f7276ebefbaa38adf37585e636b6a7a73382eb412f7bc0fc55fb73d"}, + {file = "aiohttp-3.11.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b41693b7388324b80f9acfabd479bd1c84f0bc7e8f17bab4ecd9675e9ff9c734"}, + {file = "aiohttp-3.11.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:86135c32d06927339c8c5e64f96e4eee8825d928374b9b71a3c42379d7437058"}, + {file = "aiohttp-3.11.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04eb541ce1e03edc1e3be1917a0f45ac703e913c21a940111df73a2c2db11d73"}, + {file = "aiohttp-3.11.14-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dc311634f6f28661a76cbc1c28ecf3b3a70a8edd67b69288ab7ca91058eb5a33"}, + {file = "aiohttp-3.11.14-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:69bb252bfdca385ccabfd55f4cd740d421dd8c8ad438ded9637d81c228d0da49"}, + {file = "aiohttp-3.11.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2b86efe23684b58a88e530c4ab5b20145f102916bbb2d82942cafec7bd36a647"}, + {file = "aiohttp-3.11.14-cp313-cp313-win32.whl", hash = "sha256:b9c60d1de973ca94af02053d9b5111c4fbf97158e139b14f1be68337be267be6"}, + {file = "aiohttp-3.11.14-cp313-cp313-win_amd64.whl", hash = "sha256:0a29be28e60e5610d2437b5b2fed61d6f3dcde898b57fb048aa5079271e7f6f3"}, + {file = "aiohttp-3.11.14-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:14fc03508359334edc76d35b2821832f092c8f092e4b356e74e38419dfe7b6de"}, + {file = "aiohttp-3.11.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92007c89a8cb7be35befa2732b0b32bf3a394c1b22ef2dff0ef12537d98a7bda"}, + {file = "aiohttp-3.11.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6d3986112e34eaa36e280dc8286b9dd4cc1a5bcf328a7f147453e188f6fe148f"}, + {file = "aiohttp-3.11.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:749f1eb10e51dbbcdba9df2ef457ec060554842eea4d23874a3e26495f9e87b1"}, + {file = "aiohttp-3.11.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:781c8bd423dcc4641298c8c5a2a125c8b1c31e11f828e8d35c1d3a722af4c15a"}, + {file = "aiohttp-3.11.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:997b57e38aa7dc6caab843c5e042ab557bc83a2f91b7bd302e3c3aebbb9042a1"}, + {file = "aiohttp-3.11.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a8b0321e40a833e381d127be993b7349d1564b756910b28b5f6588a159afef3"}, + {file = "aiohttp-3.11.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8778620396e554b758b59773ab29c03b55047841d8894c5e335f12bfc45ebd28"}, + {file = "aiohttp-3.11.14-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e906da0f2bcbf9b26cc2b144929e88cb3bf943dd1942b4e5af066056875c7618"}, + {file = "aiohttp-3.11.14-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:87f0e003fb4dd5810c7fbf47a1239eaa34cd929ef160e0a54c570883125c4831"}, + {file = "aiohttp-3.11.14-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7f2dadece8b85596ac3ab1ec04b00694bdd62abc31e5618f524648d18d9dd7fa"}, + {file = "aiohttp-3.11.14-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:fe846f0a98aa9913c2852b630cd39b4098f296e0907dd05f6c7b30d911afa4c3"}, + {file = "aiohttp-3.11.14-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ced66c5c6ad5bcaf9be54560398654779ec1c3695f1a9cf0ae5e3606694a000a"}, + {file = "aiohttp-3.11.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a40087b82f83bd671cbeb5f582c233d196e9653220404a798798bfc0ee189fff"}, + {file = "aiohttp-3.11.14-cp39-cp39-win32.whl", hash = "sha256:95d7787f2bcbf7cb46823036a8d64ccfbc2ffc7d52016b4044d901abceeba3db"}, + {file = "aiohttp-3.11.14-cp39-cp39-win_amd64.whl", hash = "sha256:22a8107896877212130c58f74e64b77f7007cb03cea8698be317272643602d45"}, + {file = "aiohttp-3.11.14.tar.gz", hash = "sha256:d6edc538c7480fa0a3b2bdd705f8010062d74700198da55d16498e1b49549b9c"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.3.0" +aiosignal = ">=1.1.2" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.2" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, + {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" + [[package]] name = "annotated-types" version = "0.7.0" @@ -37,6 +171,40 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + +[[package]] +name = "attrs" +version = "25.3.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + [[package]] name = "beautifulsoup4" version = "4.12.3" @@ -423,6 +591,109 @@ Werkzeug = ">=3.1" async = ["asgiref (>=3.2)"] dotenv = ["python-dotenv"] +[[package]] +name = "frozenlist" +version = "1.5.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, +] + [[package]] name = "griffe" version = "1.6.2" @@ -525,6 +796,19 @@ http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "httpx-sse" +version = "0.4.0" +description = "Consume Server-Sent Event (SSE) messages with HTTPX." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"}, + {file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"}, +] + [[package]] name = "idna" version = "3.10" @@ -915,6 +1199,140 @@ files = [ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] +[[package]] +name = "mcp" +version = "1.5.0" +description = "Model Context Protocol SDK" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "mcp-1.5.0-py3-none-any.whl", hash = "sha256:51c3f35ce93cb702f7513c12406bbea9665ef75a08db909200b07da9db641527"}, + {file = "mcp-1.5.0.tar.gz", hash = "sha256:5b2766c05e68e01a2034875e250139839498c61792163a7b221fc170c12f5aa9"}, +] + +[package.dependencies] +anyio = ">=4.5" +httpx = ">=0.27" +httpx-sse = ">=0.4" +pydantic = ">=2.7.2,<3.0.0" +pydantic-settings = ">=2.5.2" +sse-starlette = ">=1.6.1" +starlette = ">=0.27" +uvicorn = ">=0.23.1" + +[package.extras] +cli = ["python-dotenv (>=1.0.0)", "typer (>=0.12.4)"] +rich = ["rich (>=13.9.4)"] +ws = ["websockets (>=15.0.1)"] + +[[package]] +name = "multidict" +version = "6.2.0" +description = "multidict implementation" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "multidict-6.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1"}, + {file = "multidict-6.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2"}, + {file = "multidict-6.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:32ed748ff9ac682eae7859790d3044b50e3076c7d80e17a44239683769ff485e"}, + {file = "multidict-6.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc826b9a8176e686b67aa60fd6c6a7047b0461cae5591ea1dc73d28f72332a8a"}, + {file = "multidict-6.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:214207dcc7a6221d9942f23797fe89144128a71c03632bf713d918db99bd36de"}, + {file = "multidict-6.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:05fefbc3cddc4e36da209a5e49f1094bbece9a581faa7f3589201fd95df40e5d"}, + {file = "multidict-6.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e851e6363d0dbe515d8de81fd544a2c956fdec6f8a049739562286727d4a00c3"}, + {file = "multidict-6.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32c9b4878f48be3e75808ea7e499d6223b1eea6d54c487a66bc10a1871e3dc6a"}, + {file = "multidict-6.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7243c5a6523c5cfeca76e063efa5f6a656d1d74c8b1fc64b2cd1e84e507f7e2a"}, + {file = "multidict-6.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0e5a644e50ef9fb87878d4d57907f03a12410d2aa3b93b3acdf90a741df52c49"}, + {file = "multidict-6.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0dc25a3293c50744796e87048de5e68996104d86d940bb24bc3ec31df281b191"}, + {file = "multidict-6.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a49994481b99cd7dedde07f2e7e93b1d86c01c0fca1c32aded18f10695ae17eb"}, + {file = "multidict-6.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:641cf2e3447c9ecff2f7aa6e9eee9eaa286ea65d57b014543a4911ff2799d08a"}, + {file = "multidict-6.2.0-cp310-cp310-win32.whl", hash = "sha256:0c383d28857f66f5aebe3e91d6cf498da73af75fbd51cedbe1adfb85e90c0460"}, + {file = "multidict-6.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:a33273a541f1e1a8219b2a4ed2de355848ecc0254264915b9290c8d2de1c74e1"}, + {file = "multidict-6.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:84e87a7d75fa36839a3a432286d719975362d230c70ebfa0948549cc38bd5b46"}, + {file = "multidict-6.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8de4d42dffd5ced9117af2ce66ba8722402541a3aa98ffdf78dde92badb68932"}, + {file = "multidict-6.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d91a230c7f8af86c904a5a992b8c064b66330544693fd6759c3d6162382ecf"}, + {file = "multidict-6.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f6cad071960ba1914fa231677d21b1b4a3acdcce463cee41ea30bc82e6040cf"}, + {file = "multidict-6.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f74f2fc51555f4b037ef278efc29a870d327053aba5cb7d86ae572426c7cccc"}, + {file = "multidict-6.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:14ed9ed1bfedd72a877807c71113deac292bf485159a29025dfdc524c326f3e1"}, + {file = "multidict-6.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac3fcf9a2d369bd075b2c2965544036a27ccd277fc3c04f708338cc57533081"}, + {file = "multidict-6.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fc6af8e39f7496047c7876314f4317736eac82bf85b54c7c76cf1a6f8e35d98"}, + {file = "multidict-6.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f8cb1329f42fadfb40d6211e5ff568d71ab49be36e759345f91c69d1033d633"}, + {file = "multidict-6.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5389445f0173c197f4a3613713b5fb3f3879df1ded2a1a2e4bc4b5b9c5441b7e"}, + {file = "multidict-6.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:94a7bb972178a8bfc4055db80c51efd24baefaced5e51c59b0d598a004e8305d"}, + {file = "multidict-6.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da51d8928ad8b4244926fe862ba1795f0b6e68ed8c42cd2f822d435db9c2a8f4"}, + {file = "multidict-6.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:063be88bd684782a0715641de853e1e58a2f25b76388538bd62d974777ce9bc2"}, + {file = "multidict-6.2.0-cp311-cp311-win32.whl", hash = "sha256:52b05e21ff05729fbea9bc20b3a791c3c11da61649ff64cce8257c82a020466d"}, + {file = "multidict-6.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1e2a2193d3aa5cbf5758f6d5680a52aa848e0cf611da324f71e5e48a9695cc86"}, + {file = "multidict-6.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:437c33561edb6eb504b5a30203daf81d4a9b727e167e78b0854d9a4e18e8950b"}, + {file = "multidict-6.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9f49585f4abadd2283034fc605961f40c638635bc60f5162276fec075f2e37a4"}, + {file = "multidict-6.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5dd7106d064d05896ce28c97da3f46caa442fe5a43bc26dfb258e90853b39b44"}, + {file = "multidict-6.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e25b11a0417475f093d0f0809a149aff3943c2c56da50fdf2c3c88d57fe3dfbd"}, + {file = "multidict-6.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac380cacdd3b183338ba63a144a34e9044520a6fb30c58aa14077157a033c13e"}, + {file = "multidict-6.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61d5541f27533f803a941d3a3f8a3d10ed48c12cf918f557efcbf3cd04ef265c"}, + {file = "multidict-6.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:facaf11f21f3a4c51b62931feb13310e6fe3475f85e20d9c9fdce0d2ea561b87"}, + {file = "multidict-6.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:095a2eabe8c43041d3e6c2cb8287a257b5f1801c2d6ebd1dd877424f1e89cf29"}, + {file = "multidict-6.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0cc398350ef31167e03f3ca7c19313d4e40a662adcb98a88755e4e861170bdd"}, + {file = "multidict-6.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7c611345bbe7cb44aabb877cb94b63e86f2d0db03e382667dbd037866d44b4f8"}, + {file = "multidict-6.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8cd1a0644ccaf27e9d2f6d9c9474faabee21f0578fe85225cc5af9a61e1653df"}, + {file = "multidict-6.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:89b3857652183b8206a891168af47bac10b970d275bba1f6ee46565a758c078d"}, + {file = "multidict-6.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:125dd82b40f8c06d08d87b3510beaccb88afac94e9ed4a6f6c71362dc7dbb04b"}, + {file = "multidict-6.2.0-cp312-cp312-win32.whl", hash = "sha256:76b34c12b013d813e6cb325e6bd4f9c984db27758b16085926bbe7ceeaace626"}, + {file = "multidict-6.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:0b183a959fb88ad1be201de2c4bdf52fa8e46e6c185d76201286a97b6f5ee65c"}, + {file = "multidict-6.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5c5e7d2e300d5cb3b2693b6d60d3e8c8e7dd4ebe27cd17c9cb57020cac0acb80"}, + {file = "multidict-6.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:256d431fe4583c5f1e0f2e9c4d9c22f3a04ae96009b8cfa096da3a8723db0a16"}, + {file = "multidict-6.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a3c0ff89fe40a152e77b191b83282c9664357dce3004032d42e68c514ceff27e"}, + {file = "multidict-6.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef7d48207926edbf8b16b336f779c557dd8f5a33035a85db9c4b0febb0706817"}, + {file = "multidict-6.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3c099d3899b14e1ce52262eb82a5f5cb92157bb5106bf627b618c090a0eadc"}, + {file = "multidict-6.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e16e7297f29a544f49340012d6fc08cf14de0ab361c9eb7529f6a57a30cbfda1"}, + {file = "multidict-6.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:042028348dc5a1f2be6c666437042a98a5d24cee50380f4c0902215e5ec41844"}, + {file = "multidict-6.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08549895e6a799bd551cf276f6e59820aa084f0f90665c0f03dd3a50db5d3c48"}, + {file = "multidict-6.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ccfd74957ef53fa7380aaa1c961f523d582cd5e85a620880ffabd407f8202c0"}, + {file = "multidict-6.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83b78c680d4b15d33042d330c2fa31813ca3974197bddb3836a5c635a5fd013f"}, + {file = "multidict-6.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b4c153863dd6569f6511845922c53e39c8d61f6e81f228ad5443e690fca403de"}, + {file = "multidict-6.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:98aa8325c7f47183b45588af9c434533196e241be0a4e4ae2190b06d17675c02"}, + {file = "multidict-6.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9e658d1373c424457ddf6d55ec1db93c280b8579276bebd1f72f113072df8a5d"}, + {file = "multidict-6.2.0-cp313-cp313-win32.whl", hash = "sha256:3157126b028c074951839233647bd0e30df77ef1fedd801b48bdcad242a60f4e"}, + {file = "multidict-6.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:2e87f1926e91855ae61769ba3e3f7315120788c099677e0842e697b0bfb659f2"}, + {file = "multidict-6.2.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:2529ddbdaa424b2c6c2eb668ea684dd6b75b839d0ad4b21aad60c168269478d7"}, + {file = "multidict-6.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:13551d0e2d7201f0959725a6a769b6f7b9019a168ed96006479c9ac33fe4096b"}, + {file = "multidict-6.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d1996ee1330e245cd3aeda0887b4409e3930524c27642b046e4fae88ffa66c5e"}, + {file = "multidict-6.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c537da54ce4ff7c15e78ab1292e5799d0d43a2108e006578a57f531866f64025"}, + {file = "multidict-6.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f249badb360b0b4d694307ad40f811f83df4da8cef7b68e429e4eea939e49dd"}, + {file = "multidict-6.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48d39b1824b8d6ea7de878ef6226efbe0773f9c64333e1125e0efcfdd18a24c7"}, + {file = "multidict-6.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b99aac6bb2c37db336fa03a39b40ed4ef2818bf2dfb9441458165ebe88b793af"}, + {file = "multidict-6.2.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07bfa8bc649783e703263f783f73e27fef8cd37baaad4389816cf6a133141331"}, + {file = "multidict-6.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b2c00ad31fbc2cbac85d7d0fcf90853b2ca2e69d825a2d3f3edb842ef1544a2c"}, + {file = "multidict-6.2.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d57a01a2a9fa00234aace434d8c131f0ac6e0ac6ef131eda5962d7e79edfb5b"}, + {file = "multidict-6.2.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:abf5b17bc0cf626a8a497d89ac691308dbd825d2ac372aa990b1ca114e470151"}, + {file = "multidict-6.2.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:f7716f7e7138252d88607228ce40be22660d6608d20fd365d596e7ca0738e019"}, + {file = "multidict-6.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d5a36953389f35f0a4e88dc796048829a2f467c9197265504593f0e420571547"}, + {file = "multidict-6.2.0-cp313-cp313t-win32.whl", hash = "sha256:e653d36b1bf48fa78c7fcebb5fa679342e025121ace8c87ab05c1cefd33b34fc"}, + {file = "multidict-6.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ca23db5fb195b5ef4fd1f77ce26cadefdf13dba71dab14dadd29b34d457d7c44"}, + {file = "multidict-6.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b4f3d66dd0354b79761481fc15bdafaba0b9d9076f1f42cc9ce10d7fcbda205a"}, + {file = "multidict-6.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e2a2d6749e1ff2c9c76a72c6530d5baa601205b14e441e6d98011000f47a7ac"}, + {file = "multidict-6.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cca83a629f77402cfadd58352e394d79a61c8015f1694b83ab72237ec3941f88"}, + {file = "multidict-6.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:781b5dd1db18c9e9eacc419027b0acb5073bdec9de1675c0be25ceb10e2ad133"}, + {file = "multidict-6.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf8d370b2fea27fb300825ec3984334f7dd54a581bde6456799ba3776915a656"}, + {file = "multidict-6.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25bb96338512e2f46f615a2bb7c6012fe92a4a5ebd353e5020836a7e33120349"}, + {file = "multidict-6.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19e2819b0b468174de25c0ceed766606a07cedeab132383f1e83b9a4e96ccb4f"}, + {file = "multidict-6.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aed763b6a1b28c46c055692836879328f0b334a6d61572ee4113a5d0c859872"}, + {file = "multidict-6.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a1133414b771619aa3c3000701c11b2e4624a7f492f12f256aedde97c28331a2"}, + {file = "multidict-6.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:639556758c36093b35e2e368ca485dada6afc2bd6a1b1207d85ea6dfc3deab27"}, + {file = "multidict-6.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:163f4604e76639f728d127293d24c3e208b445b463168af3d031b92b0998bb90"}, + {file = "multidict-6.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2325105e16d434749e1be8022f942876a936f9bece4ec41ae244e3d7fae42aaf"}, + {file = "multidict-6.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e4371591e621579cb6da8401e4ea405b33ff25a755874a3567c4075ca63d56e2"}, + {file = "multidict-6.2.0-cp39-cp39-win32.whl", hash = "sha256:d1175b0e0d6037fab207f05774a176d71210ebd40b1c51f480a04b65ec5c786d"}, + {file = "multidict-6.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad81012b24b88aad4c70b2cbc2dad84018783221b7f923e926f4690ff8569da3"}, + {file = "multidict-6.2.0-py3-none-any.whl", hash = "sha256:5d26547423e5e71dcc562c4acdc134b900640a39abd9066d7326a7cc2324c530"}, + {file = "multidict-6.2.0.tar.gz", hash = "sha256:0085b0afb2446e57050140240a8595846ed64d1cbd26cef936bfab3192c673b8"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "mypy-extensions" version = "1.0.0" @@ -1174,6 +1592,115 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.9.2)"] +[[package]] +name = "propcache" +version = "0.3.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, + {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, + {file = "propcache-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f"}, + {file = "propcache-0.3.0-cp310-cp310-win32.whl", hash = "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c"}, + {file = "propcache-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, + {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, + {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, + {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, + {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, + {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, + {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, + {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, + {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, + {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc"}, + {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b"}, + {file = "propcache-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f"}, + {file = "propcache-0.3.0-cp39-cp39-win32.whl", hash = "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663"}, + {file = "propcache-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929"}, + {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, + {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, +] + [[package]] name = "pycparser" version = "2.22" @@ -1323,6 +1850,28 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pydantic-settings" +version = "2.8.1" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c"}, + {file = "pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585"}, +] + +[package.dependencies] +pydantic = ">=2.7.0" +python-dotenv = ">=0.21.0" + +[package.extras] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] + [[package]] name = "pymongo" version = "4.10.1" @@ -1574,6 +2123,46 @@ files = [ {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] +[[package]] +name = "sse-starlette" +version = "2.2.1" +description = "SSE plugin for Starlette" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99"}, + {file = "sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419"}, +] + +[package.dependencies] +anyio = ">=4.7.0" +starlette = ">=0.41.3" + +[package.extras] +examples = ["fastapi"] +uvicorn = ["uvicorn (>=0.34.0)"] + +[[package]] +name = "starlette" +version = "0.46.1" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227"}, + {file = "starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230"}, +] + +[package.dependencies] +anyio = ">=3.6.2,<5" + +[package.extras] +full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] + [[package]] name = "tabulate" version = "0.9.0" @@ -1691,6 +2280,44 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "uvicorn" +version = "0.34.0" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, + {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "waitress" +version = "2.1.2" +description = "Waitress WSGI server" +optional = false +python-versions = ">=3.7.0" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "waitress-2.1.2-py3-none-any.whl", hash = "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a"}, + {file = "waitress-2.1.2.tar.gz", hash = "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba"}, +] + +[package.extras] +docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] +testing = ["coverage (>=5.0)", "pytest", "pytest-cover"] + [[package]] name = "websockets" version = "13.1" @@ -1823,7 +2450,105 @@ files = [ [package.extras] test = ["pytest (>=6.0.0)", "setuptools (>=65)"] +[[package]] +name = "yarl" +version = "1.18.3" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [ + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, + {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, + {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, + {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, + {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.0" + [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "ee79f77afa3bbdb99810fd4a1a9cae366a307e2af74fd70c6d3376c6fdab61b3" +content-hash = "9ab31ccc9ee418d463c06e1b3d3bace07d468799114c77415479fd6cd8fa7345" diff --git a/apps/agents/pyproject.toml b/apps/agents/pyproject.toml index a1206c53..7f43a8c4 100644 --- a/apps/agents/pyproject.toml +++ b/apps/agents/pyproject.toml @@ -13,6 +13,7 @@ package-mode = false python = ">=3.10,<4.0" # Dependencies +aiohttp = "^3.9.3" annotated-types = "^0.7.0" anyio = "^4.6.2" beautifulsoup4 = "^4.12.3" @@ -26,6 +27,7 @@ et_xmlfile = "^2.0.0" eval_type_backport = "^0.2.0" firecrawl = "^1.4.0" Flask = "^3.0.3" +gunicorn = "^23.0.0" h11 = "^0.14.0" httpcore = "^1.0.6" httpx = "^0.27.2" @@ -37,6 +39,7 @@ jsonpath-python = "^1.0.6" lxml = "^5.3.0" markdownify = "^0.13.1" MarkupSafe = "^3.0.2" +mcp = "*" mypy-extensions = "^1.0.0" nest-asyncio = "^1.6.0" numpy = "^2.1.2" @@ -62,7 +65,7 @@ typing-inspect = "^0.9.0" typing_extensions = "^4.12.2" tzdata = "^2024.2" urllib3 = "^2.2.3" +waitress = "^2.1.2" websockets = "^13.1" Werkzeug = "^3.0.5" wheel = "^0.44.0" -gunicorn = "^23.0.0" diff --git a/apps/agents/requirements.txt b/apps/agents/requirements.txt index 26c51d26..5bb4b2fd 100644 --- a/apps/agents/requirements.txt +++ b/apps/agents/requirements.txt @@ -1,3 +1,4 @@ +aiohttp==3.9.3 annotated-types==0.7.0 anyio==4.8.0 beautifulsoup4==4.12.3 @@ -37,6 +38,7 @@ keyring==25.6.0 lxml==5.3.0 markdownify==0.13.1 MarkupSafe==3.0.2 +mcp more-itertools==10.6.0 msgpack==1.1.0 mypy-extensions==1.0.0 @@ -77,6 +79,7 @@ typing_extensions==4.12.2 tzdata==2024.2 urllib3==2.3.0 virtualenv==20.29.1 +waitress==2.1.2 websockets==13.1 Werkzeug==3.1.3 wheel==0.44.0 diff --git a/apps/agents/src/app/main.py b/apps/agents/src/app/main.py index f78b35b6..2f93dfbf 100644 --- a/apps/agents/src/app/main.py +++ b/apps/agents/src/app/main.py @@ -85,4 +85,5 @@ def chat(): if __name__ == "__main__": print("Starting Flask server...") - app.run(port=4040, debug=True) \ No newline at end of file + from waitress import serve + serve(app, host="0.0.0.0", port=4040) \ No newline at end of file diff --git a/apps/agents/src/graph/swarm_wrapper.py b/apps/agents/src/graph/swarm_wrapper.py index 9f113ccd..d528b4d9 100644 --- a/apps/agents/src/graph/swarm_wrapper.py +++ b/apps/agents/src/graph/swarm_wrapper.py @@ -112,34 +112,43 @@ async def call_mcp(tool_name: str, args: str, mcp_server_name: str, mcp_servers: return response -async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict) -> str: +def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict) -> str: """ - Handles all tool calls by dispatching to the mock_tool function. - - Args: - ctx: The run context wrapper - args: The arguments passed to the tool - tool_name: The name of the tool being called - tool_config: The configuration of the tool - - Returns: - The response from the tool + Handles all tool calls by dispatching to appropriate functions. """ print(f"Catch all called for tool: {tool_name}") print(f"Args: {args}") print(f"Tool config: {tool_config}") + + # Create event loop for async operations + try: + loop = asyncio.get_event_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + response_content = None # Check if this tool should be mocked if tool_config.get("mockTool", False): - # Call mock_tool to handle the response (it will decide whether to use mock instructions or generate a response) - response_content = await mock_tool(tool_name, args, tool_config) - print(response_content) + # Handle mock tool synchronously + description = tool_config.get("description", "") + messages = [ + {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. The tool has this description: {description}. Generate a realistic response as if the tool was actually executed with the given parameters."}, + {"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}' with these parameters: {args}. The response should be concise and focused on what the tool would actually return."} + ] + response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") elif tool_config.get("isMcp", False): - response_content = await call_mcp(tool_name, args, tool_config.get("mcpServerName", ""), {}) - print(response_content) + # Handle MCP calls + response_content = loop.run_until_complete( + call_mcp(tool_name, args, tool_config.get("mcpServerName", ""), {}) + ) else: - response_content = await call_webhook(tool_name, args) - print(response_content) + # Handle webhook calls + response_content = loop.run_until_complete( + call_webhook(tool_name, args) + ) + + print(response_content) return response_content def get_agents(agent_configs, tool_configs): @@ -261,19 +270,6 @@ def run( ): """ Wrapper function for initializing and running the Swarm client. - - Args: - agent: The agent to run - messages: List of messages for the agent to process - execute_tools: Whether to execute tools or just return tool calls - external_tools: List of external tools available to the agent - localize_history: Whether to localize history for the agent - parent_has_child_history: Whether parent agents have access to child agent history - max_messages_per_turn: Maximum number of messages to process in a turn - tokens_used: Dictionary tracking token usage - - Returns: - Response object from the Swarm client """ logger.info(f"Initializing Swarm client for agent: {agent.name}") print(f"Initializing Swarm client for agent: {agent.name}") @@ -287,26 +283,36 @@ def run( # Format messages to ensure they're compatible with the OpenAI API formatted_messages = [] for msg in messages: - # Check if the message has the expected format if isinstance(msg, dict) and "content" in msg: - # Make sure the message has the required fields for OpenAI API formatted_msg = { "role": msg.get("role", "user"), "content": msg["content"] } formatted_messages.append(formatted_msg) else: - # If the message is just a string, assume it's a user message formatted_messages.append({ "role": "user", "content": str(msg) }) + # Create a new event loop for this thread + try: + loop = asyncio.get_event_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + # Run the agent with the formatted messages logger.info("Beginning Swarm run with run_sync") print("Beginning Swarm run with run_sync") - response2 = Runner.run_sync(agent, formatted_messages) + + try: + response = loop.run_until_complete(Runner.run(agent, formatted_messages)) + except Exception as e: + logger.error(f"Error during run: {str(e)}") + print(f"Error during run: {str(e)}") + raise logger.info(f"Completed Swarm run for agent: {agent.name}") print(f"Completed Swarm run for agent: {agent.name}") - return response2 \ No newline at end of file + return response \ No newline at end of file From b131c1768e0d6e3c319798ad02007d3a2fc0ba2a Mon Sep 17 00:00:00 2001 From: ramnique <30795890+ramnique@users.noreply.github.com> Date: Mon, 24 Mar 2025 11:57:22 +0530 Subject: [PATCH 23/49] agents: add sse scaffolding --- apps/agents/src/app/main.py | 57 ++++++++++++++++++- apps/rowboat/app/actions/actions.ts | 9 +-- .../app/api/v1/[projectId]/chat/route.ts | 1 + .../widget/v1/chats/[chatId]/turn/route.ts | 1 + .../rowboat/app/lib/types/agents_api_types.ts | 1 + .../projects/[projectId]/playground/chat.tsx | 3 +- 6 files changed, 64 insertions(+), 8 deletions(-) diff --git a/apps/agents/src/app/main.py b/apps/agents/src/app/main.py index 2f93dfbf..a694fe90 100644 --- a/apps/agents/src/app/main.py +++ b/apps/agents/src/app/main.py @@ -1,7 +1,11 @@ -from flask import Flask, request, jsonify +from flask import Flask, request, jsonify, Response from datetime import datetime from functools import wraps import os +import redis +import uuid +import json +import time from src.graph.core import run_turn from src.graph.tools import RAG_TOOL, CLOSE_CHAT_TOOL @@ -9,6 +13,7 @@ from src.graph.tools import RAG_TOOL, CLOSE_CHAT_TOOL from src.utils.common import common_logger, read_json_from_file logger = common_logger +redis_client = redis.from_url(os.environ.get('REDIS_URL', 'redis://localhost:6379')) app = Flask(__name__) @app.route("/health", methods=["GET"]) @@ -83,6 +88,56 @@ def chat(): logger.error(f"Error: {e}") return jsonify({"error": str(e)}), 500 +@app.route("/chat_stream_init", methods=["POST"]) +@require_api_key +def chat_stream_init(): + # create a uuid for the stream + stream_id = str(uuid.uuid4()) + + # store the the request data in redis with 10 minute TTL + # using the key name `stream_request_` + # set ttl to 10 minutes + redis_client.setex(f"stream_request_{stream_id}", 600, json.dumps(request.get_json())) + + return jsonify({"stream_id": stream_id}) + +@app.route("/chat_stream/", methods=["GET"]) +@require_api_key +def chat_stream(stream_id): + # get the request data from redis + request_data = redis_client.get(f"stream_request_{stream_id}") + if not request_data: + return jsonify({"error": "Stream not found"}), 404 + + # invoke run_streamed() from agents-sdk + + def generate(): + # example of HTTP SSE event stream: + # https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events + # -------------------------------- + # id: + # event: + # data: {... event data ...} + # + # event: + # data: {... event data ...} + try: + yield "event: message\n" + yield "data: {\"role\": \"assistant\", \"content\": \"This is the first message!\"}\n\n" # double \n indicates end of message + + time.sleep(2) + + yield "event: message\n" + yield "data: {\"role\": \"assistant\", \"content\": \"This is the second message!\"}\n\n" + + yield "event: done\n" + yield "data: {... state data ...}\n\n" + except Exception as e: + yield "event: error\n" + yield "data: {... error data ...}\n\n" + + return Response(generate(), mimetype='text/event-stream') + if __name__ == "__main__": print("Starting Flask server...") from waitress import serve diff --git a/apps/rowboat/app/actions/actions.ts b/apps/rowboat/app/actions/actions.ts index b3385cd0..ed8ced54 100644 --- a/apps/rowboat/app/actions/actions.ts +++ b/apps/rowboat/app/actions/actions.ts @@ -66,17 +66,14 @@ export async function scrapeWebpage(url: string): Promise, -): Promise<{ +export async function getAssistantResponse(request: z.infer): Promise<{ messages: z.infer[], state: unknown, rawRequest: unknown, rawResponse: unknown, }> { - await projectAuthCheck(projectId); - if (!await check_query_limit(projectId)) { + await projectAuthCheck(request.projectId); + if (!await check_query_limit(request.projectId)) { throw new QueryLimitError(); } diff --git a/apps/rowboat/app/api/v1/[projectId]/chat/route.ts b/apps/rowboat/app/api/v1/[projectId]/chat/route.ts index 4e542f2a..9671ab1c 100644 --- a/apps/rowboat/app/api/v1/[projectId]/chat/route.ts +++ b/apps/rowboat/app/api/v1/[projectId]/chat/route.ts @@ -88,6 +88,7 @@ export async function POST( // get assistant response const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow); const request: z.infer = { + projectId, messages: convertFromApiToAgenticApiMessages(reqMessages), state: currentState, agents, diff --git a/apps/rowboat/app/api/widget/v1/chats/[chatId]/turn/route.ts b/apps/rowboat/app/api/widget/v1/chats/[chatId]/turn/route.ts index d40b95ff..8d136e58 100644 --- a/apps/rowboat/app/api/widget/v1/chats/[chatId]/turn/route.ts +++ b/apps/rowboat/app/api/widget/v1/chats/[chatId]/turn/route.ts @@ -95,6 +95,7 @@ export async function POST( let state: unknown = chat.agenticState ?? { last_agent_name: startAgent }; const request: z.infer = { + projectId: session.projectId, messages: convertToAgenticAPIChatMessages([systemMessage, ...messages, ...unsavedMessages]), state, agents, diff --git a/apps/rowboat/app/lib/types/agents_api_types.ts b/apps/rowboat/app/lib/types/agents_api_types.ts index 1e6b132a..42c652da 100644 --- a/apps/rowboat/app/lib/types/agents_api_types.ts +++ b/apps/rowboat/app/lib/types/agents_api_types.ts @@ -47,6 +47,7 @@ export const AgenticAPITool = WorkflowTool }) export const AgenticAPIChatRequest = z.object({ + projectId: z.string(), messages: z.array(AgenticAPIChatMessage), state: z.unknown(), agents: z.array(AgenticAPIAgent), diff --git a/apps/rowboat/app/projects/[projectId]/playground/chat.tsx b/apps/rowboat/app/projects/[projectId]/playground/chat.tsx index f7f51345..57bbd63c 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/chat.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/chat.tsx @@ -96,6 +96,7 @@ export function Chat({ setFetchResponseError(null); const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow); const request: z.infer = { + projectId, messages: convertToAgenticAPIChatMessages([{ role: 'system', content: systemMessage || '', @@ -116,7 +117,7 @@ export function Chat({ setLastAgenticResponse(null); try { - const response = await getAssistantResponse(projectId, request); + const response = await getAssistantResponse(request); if (ignore) { return; } From b2fd9bf877154e2cbc6735fd89c95d3bdae442e4 Mon Sep 17 00:00:00 2001 From: arkml Date: Mon, 24 Mar 2025 16:10:43 +0530 Subject: [PATCH 24/49] tool invocation --- apps/agents/poetry.lock | 431 +++++++++++++++++++------ apps/agents/pyproject.toml | 3 + apps/agents/src/app/main.py | 11 +- apps/agents/src/graph/core.py | 5 +- apps/agents/src/graph/swarm_wrapper.py | 116 ++++--- apps/agents/src/graph/tool_calling.py | 143 ++++++++ apps/agents/tests/interactive.py | 27 +- 7 files changed, 574 insertions(+), 162 deletions(-) create mode 100644 apps/agents/src/graph/tool_calling.py diff --git a/apps/agents/poetry.lock b/apps/agents/poetry.lock index c97ff628..3cb1fdd3 100644 --- a/apps/agents/poetry.lock +++ b/apps/agents/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -7,7 +7,6 @@ description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, @@ -20,7 +19,6 @@ description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "aiohttp-3.11.14-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e2bc827c01f75803de77b134afdbf74fa74b62970eafdf190f3244931d7a5c0d"}, {file = "aiohttp-3.11.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e365034c5cf6cf74f57420b57682ea79e19eb29033399dd3f40de4d0171998fa"}, @@ -116,7 +114,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.2.0) ; sys_platform == \"linux\" or sys_platform == \"darwin\"", "brotlicffi ; platform_python_implementation != \"CPython\""] [[package]] name = "aiosignal" @@ -125,7 +123,6 @@ description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, @@ -141,7 +138,6 @@ description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -154,7 +150,6 @@ description = "High level compatibility layer for multiple asynchronous event lo optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, @@ -168,7 +163,7 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] [[package]] @@ -178,7 +173,7 @@ description = "Timeout context manager for asyncio programs" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\" or python_version == \"3.11\" and python_full_version < \"3.11.3\"" files = [ {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, @@ -191,19 +186,18 @@ description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] [[package]] name = "beautifulsoup4" @@ -212,7 +206,6 @@ description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, @@ -235,7 +228,6 @@ description = "Fast, simple object-to-object and broadcast signaling" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"}, {file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"}, @@ -248,7 +240,6 @@ description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, @@ -261,7 +252,6 @@ description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -342,7 +332,6 @@ description = "The Real First Universal Charset Detector. Open, modern and activ optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -445,7 +434,6 @@ description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -461,7 +449,6 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -474,7 +461,6 @@ description = "Distro - an OS platform information API" optional = false python-versions = ">=3.6" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, @@ -487,7 +473,6 @@ description = "DNS toolkit" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, @@ -509,7 +494,6 @@ description = "An implementation of lxml.xmlfile for the standard library" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"}, {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"}, @@ -522,7 +506,6 @@ description = "Like `typing._eval_type`, but lets older Python versions use newe optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a"}, {file = "eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1"}, @@ -538,7 +521,7 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -554,7 +537,6 @@ description = "Python SDK for Firecrawl API" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "firecrawl-1.9.0-py3-none-any.whl", hash = "sha256:9c0931242048ddd86e85631db439011fa0545cbcca21f7c41c89d13116bb2187"}, {file = "firecrawl-1.9.0.tar.gz", hash = "sha256:8e82d3b288d57bf7c93b9118fb226a84b7c8b84699861e1d36b4791dc87a7435"}, @@ -574,7 +556,6 @@ description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "flask-3.1.0-py3-none-any.whl", hash = "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136"}, {file = "flask-3.1.0.tar.gz", hash = "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac"}, @@ -598,7 +579,6 @@ description = "A list-like structure which implements collections.abc.MutableSeq optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, @@ -701,7 +681,6 @@ description = "Signatures for entire Python programs. Extract the structure, the optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "griffe-1.6.2-py3-none-any.whl", hash = "sha256:6399f7e663150e4278a312a8e8a14d2f3d7bd86e2ef2f8056a1058e38579c2ee"}, {file = "griffe-1.6.2.tar.gz", hash = "sha256:3a46fa7bd83280909b63c12b9a975732a927dd97809efe5b7972290b606c5d91"}, @@ -710,6 +689,136 @@ files = [ [package.dependencies] colorama = ">=0.4" +[[package]] +name = "grpcio" +version = "1.71.0" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "grpcio-1.71.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:c200cb6f2393468142eb50ab19613229dcc7829b5ccee8b658a36005f6669fdd"}, + {file = "grpcio-1.71.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b2266862c5ad664a380fbbcdbdb8289d71464c42a8c29053820ee78ba0119e5d"}, + {file = "grpcio-1.71.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:0ab8b2864396663a5b0b0d6d79495657ae85fa37dcb6498a2669d067c65c11ea"}, + {file = "grpcio-1.71.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c30f393f9d5ff00a71bb56de4aa75b8fe91b161aeb61d39528db6b768d7eac69"}, + {file = "grpcio-1.71.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f250ff44843d9a0615e350c77f890082102a0318d66a99540f54769c8766ab73"}, + {file = "grpcio-1.71.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e6d8de076528f7c43a2f576bc311799f89d795aa6c9b637377cc2b1616473804"}, + {file = "grpcio-1.71.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b91879d6da1605811ebc60d21ab6a7e4bae6c35f6b63a061d61eb818c8168f6"}, + {file = "grpcio-1.71.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f71574afdf944e6652203cd1badcda195b2a27d9c83e6d88dc1ce3cfb73b31a5"}, + {file = "grpcio-1.71.0-cp310-cp310-win32.whl", hash = "sha256:8997d6785e93308f277884ee6899ba63baafa0dfb4729748200fcc537858a509"}, + {file = "grpcio-1.71.0-cp310-cp310-win_amd64.whl", hash = "sha256:7d6ac9481d9d0d129224f6d5934d5832c4b1cddb96b59e7eba8416868909786a"}, + {file = "grpcio-1.71.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:d6aa986318c36508dc1d5001a3ff169a15b99b9f96ef5e98e13522c506b37eef"}, + {file = "grpcio-1.71.0-cp311-cp311-macosx_10_14_universal2.whl", hash = "sha256:d2c170247315f2d7e5798a22358e982ad6eeb68fa20cf7a820bb74c11f0736e7"}, + {file = "grpcio-1.71.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:e6f83a583ed0a5b08c5bc7a3fe860bb3c2eac1f03f1f63e0bc2091325605d2b7"}, + {file = "grpcio-1.71.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4be74ddeeb92cc87190e0e376dbc8fc7736dbb6d3d454f2fa1f5be1dee26b9d7"}, + {file = "grpcio-1.71.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd0dfbe4d5eb1fcfec9490ca13f82b089a309dc3678e2edabc144051270a66e"}, + {file = "grpcio-1.71.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a2242d6950dc892afdf9e951ed7ff89473aaf744b7d5727ad56bdaace363722b"}, + {file = "grpcio-1.71.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0fa05ee31a20456b13ae49ad2e5d585265f71dd19fbd9ef983c28f926d45d0a7"}, + {file = "grpcio-1.71.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3d081e859fb1ebe176de33fc3adb26c7d46b8812f906042705346b314bde32c3"}, + {file = "grpcio-1.71.0-cp311-cp311-win32.whl", hash = "sha256:d6de81c9c00c8a23047136b11794b3584cdc1460ed7cbc10eada50614baa1444"}, + {file = "grpcio-1.71.0-cp311-cp311-win_amd64.whl", hash = "sha256:24e867651fc67717b6f896d5f0cac0ec863a8b5fb7d6441c2ab428f52c651c6b"}, + {file = "grpcio-1.71.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:0ff35c8d807c1c7531d3002be03221ff9ae15712b53ab46e2a0b4bb271f38537"}, + {file = "grpcio-1.71.0-cp312-cp312-macosx_10_14_universal2.whl", hash = "sha256:b78a99cd1ece4be92ab7c07765a0b038194ded2e0a26fd654591ee136088d8d7"}, + {file = "grpcio-1.71.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:dc1a1231ed23caac1de9f943d031f1bc38d0f69d2a3b243ea0d664fc1fbd7fec"}, + {file = "grpcio-1.71.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6beeea5566092c5e3c4896c6d1d307fb46b1d4bdf3e70c8340b190a69198594"}, + {file = "grpcio-1.71.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5170929109450a2c031cfe87d6716f2fae39695ad5335d9106ae88cc32dc84c"}, + {file = "grpcio-1.71.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5b08d03ace7aca7b2fadd4baf291139b4a5f058805a8327bfe9aece7253b6d67"}, + {file = "grpcio-1.71.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f903017db76bf9cc2b2d8bdd37bf04b505bbccad6be8a81e1542206875d0e9db"}, + {file = "grpcio-1.71.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:469f42a0b410883185eab4689060a20488a1a0a00f8bbb3cbc1061197b4c5a79"}, + {file = "grpcio-1.71.0-cp312-cp312-win32.whl", hash = "sha256:ad9f30838550695b5eb302add33f21f7301b882937460dd24f24b3cc5a95067a"}, + {file = "grpcio-1.71.0-cp312-cp312-win_amd64.whl", hash = "sha256:652350609332de6dac4ece254e5d7e1ff834e203d6afb769601f286886f6f3a8"}, + {file = "grpcio-1.71.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:cebc1b34ba40a312ab480ccdb396ff3c529377a2fce72c45a741f7215bfe8379"}, + {file = "grpcio-1.71.0-cp313-cp313-macosx_10_14_universal2.whl", hash = "sha256:85da336e3649a3d2171e82f696b5cad2c6231fdd5bad52616476235681bee5b3"}, + {file = "grpcio-1.71.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:f9a412f55bb6e8f3bb000e020dbc1e709627dcb3a56f6431fa7076b4c1aab0db"}, + {file = "grpcio-1.71.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47be9584729534660416f6d2a3108aaeac1122f6b5bdbf9fd823e11fe6fbaa29"}, + {file = "grpcio-1.71.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c9c80ac6091c916db81131d50926a93ab162a7e97e4428ffc186b6e80d6dda4"}, + {file = "grpcio-1.71.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:789d5e2a3a15419374b7b45cd680b1e83bbc1e52b9086e49308e2c0b5bbae6e3"}, + {file = "grpcio-1.71.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:1be857615e26a86d7363e8a163fade914595c81fec962b3d514a4b1e8760467b"}, + {file = "grpcio-1.71.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a76d39b5fafd79ed604c4be0a869ec3581a172a707e2a8d7a4858cb05a5a7637"}, + {file = "grpcio-1.71.0-cp313-cp313-win32.whl", hash = "sha256:74258dce215cb1995083daa17b379a1a5a87d275387b7ffe137f1d5131e2cfbb"}, + {file = "grpcio-1.71.0-cp313-cp313-win_amd64.whl", hash = "sha256:22c3bc8d488c039a199f7a003a38cb7635db6656fa96437a8accde8322ce2366"}, + {file = "grpcio-1.71.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c6a0a28450c16809f94e0b5bfe52cabff63e7e4b97b44123ebf77f448534d07d"}, + {file = "grpcio-1.71.0-cp39-cp39-macosx_10_14_universal2.whl", hash = "sha256:a371e6b6a5379d3692cc4ea1cb92754d2a47bdddeee755d3203d1f84ae08e03e"}, + {file = "grpcio-1.71.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:39983a9245d37394fd59de71e88c4b295eb510a3555e0a847d9965088cdbd033"}, + {file = "grpcio-1.71.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9182e0063112e55e74ee7584769ec5a0b4f18252c35787f48738627e23a62b97"}, + {file = "grpcio-1.71.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693bc706c031aeb848849b9d1c6b63ae6bcc64057984bb91a542332b75aa4c3d"}, + {file = "grpcio-1.71.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:20e8f653abd5ec606be69540f57289274c9ca503ed38388481e98fa396ed0b41"}, + {file = "grpcio-1.71.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8700a2a57771cc43ea295296330daaddc0d93c088f0a35cc969292b6db959bf3"}, + {file = "grpcio-1.71.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d35a95f05a8a2cbe8e02be137740138b3b2ea5f80bd004444e4f9a1ffc511e32"}, + {file = "grpcio-1.71.0-cp39-cp39-win32.whl", hash = "sha256:f9c30c464cb2ddfbc2ddf9400287701270fdc0f14be5f08a1e3939f1e749b455"}, + {file = "grpcio-1.71.0-cp39-cp39-win_amd64.whl", hash = "sha256:63e41b91032f298b3e973b3fa4093cbbc620c875e2da7b93e249d4728b54559a"}, + {file = "grpcio-1.71.0.tar.gz", hash = "sha256:2b85f7820475ad3edec209d3d89a7909ada16caab05d3f2e08a7e8ae3200a55c"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.71.0)"] + +[[package]] +name = "grpcio-tools" +version = "1.71.0" +description = "Protobuf code generator for gRPC" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "grpcio_tools-1.71.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:f4ad7f0d756546902597053d70b3af2606fbd70d7972876cd75c1e241d22ae00"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:64bdb291df61cf570b5256777ad5fe2b1db6d67bc46e55dc56a0a862722ae329"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:8dd9795e982d77a4b496f7278b943c2563d9afde2069cdee78c111a40cc4d675"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1b5860c41a36b26fec4f52998f1a451d0525a5c9a4fb06b6ea3e9211abdb925"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3059c14035e5dc03d462f261e5900b9a077fd1a36976c3865b8507474520bad4"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f360981b215b1d5aff9235b37e7e1826246e35bbac32a53e41d4e990a37b8f4c"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bfe3888c3bbe16a5aa39409bc38744a31c0c3d2daa2b0095978c56e106c85b42"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:145985c0bf12131f0a1503e65763e0f060473f7f3928ed1ff3fb0e8aad5bc8ac"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-win32.whl", hash = "sha256:82c430edd939bb863550ee0fecf067d78feff828908a1b529bbe33cc57f2419c"}, + {file = "grpcio_tools-1.71.0-cp310-cp310-win_amd64.whl", hash = "sha256:83e90724e3f02415c628e4ead1d6ffe063820aaaa078d9a39176793df958cd5a"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:1f19b16b49afa5d21473f49c0966dd430c88d089cd52ac02404d8cef67134efb"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-macosx_10_14_universal2.whl", hash = "sha256:459c8f5e00e390aecd5b89de67deb3ec7188a274bc6cb50e43cef35ab3a3f45d"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:edab7e6518de01196be37f96cb1e138c3819986bf5e2a6c9e1519b4d716b2f5a"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b93b9f6adc7491d4c10144c0643409db298e5e63c997106a804f6f0248dbaf4"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ae5f2efa9e644c10bf1021600bfc099dfbd8e02b184d2d25dc31fcd6c2bc59e"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:65aa082f4435571d65d5ce07fc444f23c3eff4f3e34abef599ef8c9e1f6f360f"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1331e726e08b7bdcbf2075fcf4b47dff07842b04845e6e220a08a4663e232d7f"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6693a7d3ba138b0e693b3d1f687cdd9db9e68976c3fa2b951c17a072fea8b583"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-win32.whl", hash = "sha256:6d11ed3ff7b6023b5c72a8654975324bb98c1092426ba5b481af406ff559df00"}, + {file = "grpcio_tools-1.71.0-cp311-cp311-win_amd64.whl", hash = "sha256:072b2a5805ac97e4623b3aa8f7818275f3fb087f4aa131b0fce00471065f6eaa"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:61c0409d5bdac57a7bd0ce0ab01c1c916728fe4c8a03d77a25135ad481eb505c"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-macosx_10_14_universal2.whl", hash = "sha256:28784f39921d061d2164a9dcda5164a69d07bf29f91f0ea50b505958292312c9"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:192808cf553cedca73f0479cc61d5684ad61f24db7a5f3c4dfe1500342425866"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:989ee9da61098230d3d4c8f8f8e27c2de796f1ff21b1c90110e636d9acd9432b"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:541a756276c8a55dec991f6c0106ae20c8c8f5ce8d0bdbfcb01e2338d1a8192b"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:870c0097700d13c403e5517cb7750ab5b4a791ce3e71791c411a38c5468b64bd"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:abd57f615e88bf93c3c6fd31f923106e3beb12f8cd2df95b0d256fa07a7a0a57"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:753270e2d06d37e6d7af8967d1d059ec635ad215882041a36294f4e2fd502b2e"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-win32.whl", hash = "sha256:0e647794bd7138b8c215e86277a9711a95cf6a03ff6f9e555d54fdf7378b9f9d"}, + {file = "grpcio_tools-1.71.0-cp312-cp312-win_amd64.whl", hash = "sha256:48debc879570972d28bfe98e4970eff25bb26da3f383e0e49829b2d2cd35ad87"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:9a78d07d6c301a25ef5ede962920a522556a1dfee1ccc05795994ceb867f766c"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-macosx_10_14_universal2.whl", hash = "sha256:580ac88141c9815557e63c9c04f5b1cdb19b4db8d0cb792b573354bde1ee8b12"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:f7c678e68ece0ae908ecae1c4314a0c2c7f83e26e281738b9609860cc2c82d96"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56ecd6cc89b5e5eed1de5eb9cafce86c9c9043ee3840888cc464d16200290b53"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e52a041afc20ab2431d756b6295d727bd7adee813b21b06a3483f4a7a15ea15f"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2a1712f12102b60c8d92779b89d0504e0d6f3a59f2b933e5622b8583f5c02992"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:41878cb7a75477e62fdd45e7e9155b3af1b7a5332844021e2511deaf99ac9e6c"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:682e958b476049ccc14c71bedf3f979bced01f6e0c04852efc5887841a32ad6b"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-win32.whl", hash = "sha256:0ccfb837152b7b858b9f26bb110b3ae8c46675d56130f6c2f03605c4f129be13"}, + {file = "grpcio_tools-1.71.0-cp313-cp313-win_amd64.whl", hash = "sha256:ffff9bc5eacb34dd26b487194f7d44a3e64e752fc2cf049d798021bf25053b87"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:834959b6eceb85de5217a411aba1643b5f782798680c122202d6a06177226644"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-macosx_10_14_universal2.whl", hash = "sha256:e3ae9556e2a1cd70e7d7b0e0459c35af71d51a7dae4cf36075068011a69f13ec"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:77fe6db1334e0ce318b2cb4e70afa94e0c173ed1a533d37aea69ad9f61ae8ea9"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57e3e2544c306b60ef2d76570bac4e977be1ad548641c9eec130c3bc47e80141"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af39e245fa56f7f5c2fe86b7d6c1b78f395c07e54d5613cbdbb3c24769a92b6e"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8f987d0053351217954543b174b0bddbf51d45b3cfcf8d6de97b0a43d264d753"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8e6cdbba4dae7b37b0d25d074614be9936fb720144420f03d9f142a80be69ba2"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3adc8b229e60c77bab5a5d62b415667133bd5ced7d59b5f71d6317c9143631e"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-win32.whl", hash = "sha256:f68334d28a267fabec6e70cb5986e9999cfbfd14db654094ddf9aedd804a293a"}, + {file = "grpcio_tools-1.71.0-cp39-cp39-win_amd64.whl", hash = "sha256:1291a6136c07a86c3bb09f6c33f5cf227cc14956edd1b85cb572327a36e0aef8"}, + {file = "grpcio_tools-1.71.0.tar.gz", hash = "sha256:38dba8e0d5e0fb23a034e09644fdc6ed862be2371887eee54901999e8f6792a8"}, +] + +[package.dependencies] +grpcio = ">=1.71.0" +protobuf = ">=5.26.1,<6.0dev" +setuptools = "*" + [[package]] name = "gunicorn" version = "23.0.0" @@ -717,7 +826,6 @@ description = "WSGI HTTP Server for UNIX" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, @@ -740,12 +848,39 @@ description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +[[package]] +name = "h2" +version = "4.2.0" +description = "Pure-Python HTTP/2 protocol implementation" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "h2-4.2.0-py3-none-any.whl", hash = "sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0"}, + {file = "h2-4.2.0.tar.gz", hash = "sha256:c8a52129695e88b1a0578d8d2cc6842bbd79128ac685463b887ee278126ad01f"}, +] + +[package.dependencies] +hpack = ">=4.1,<5" +hyperframe = ">=6.1,<7" + +[[package]] +name = "hpack" +version = "4.1.0" +description = "Pure-Python HPACK header encoding" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496"}, + {file = "hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca"}, +] + [[package]] name = "httpcore" version = "1.0.7" @@ -753,7 +888,6 @@ description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, @@ -776,7 +910,6 @@ description = "The next generation HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, @@ -785,12 +918,13 @@ files = [ [package.dependencies] anyio = "*" certifi = "*" +h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} httpcore = "==1.*" idna = "*" sniffio = "*" [package.extras] -brotli = ["brotli", "brotlicffi"] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -803,12 +937,23 @@ description = "Consume Server-Sent Event (SSE) messages with HTTPX." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"}, {file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"}, ] +[[package]] +name = "hyperframe" +version = "6.1.0" +description = "Pure-Python HTTP/2 framing" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5"}, + {file = "hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08"}, +] + [[package]] name = "idna" version = "3.10" @@ -816,7 +961,6 @@ description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -832,7 +976,6 @@ description = "Safely pass data to untrusted environments and back." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, @@ -845,7 +988,6 @@ description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, @@ -864,7 +1006,6 @@ description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "jiter-0.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d08510593cb57296851080018006dfc394070178d238b767b1879dc1013b106c"}, {file = "jiter-0.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adef59d5e2394ebbad13b7ed5e0306cceb1df92e2de688824232a91588e77aa7"}, @@ -948,7 +1089,6 @@ description = "A more powerful JSONPath implementation in modern python" optional = false python-versions = ">=3.6" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "jsonpath-python-1.0.6.tar.gz", hash = "sha256:dd5be4a72d8a2995c3f583cf82bf3cd1a9544cfdabf2d22595b67aff07349666"}, {file = "jsonpath_python-1.0.6-py3-none-any.whl", hash = "sha256:1e3b78df579f5efc23565293612decee04214609208a2335884b3ee3f786b575"}, @@ -961,7 +1101,6 @@ description = "Powerful and Pythonic XML processing library combining libxml2/li optional = false python-versions = ">=3.6" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, @@ -1117,7 +1256,6 @@ description = "Convert HTML to markdown." optional = false python-versions = "*" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "markdownify-0.13.1-py3-none-any.whl", hash = "sha256:1d181d43d20902bcc69d7be85b5316ed174d0dda72ff56e14ae4c95a4a407d22"}, {file = "markdownify-0.13.1.tar.gz", hash = "sha256:ab257f9e6bd4075118828a28c9d02f8a4bfeb7421f558834aa79b2dfeb32a098"}, @@ -1134,7 +1272,6 @@ description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -1206,7 +1343,6 @@ description = "Model Context Protocol SDK" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "mcp-1.5.0-py3-none-any.whl", hash = "sha256:51c3f35ce93cb702f7513c12406bbea9665ef75a08db909200b07da9db641527"}, {file = "mcp-1.5.0.tar.gz", hash = "sha256:5b2766c05e68e01a2034875e250139839498c61792163a7b221fc170c12f5aa9"}, @@ -1227,6 +1363,31 @@ cli = ["python-dotenv (>=1.0.0)", "typer (>=0.12.4)"] rich = ["rich (>=13.9.4)"] ws = ["websockets (>=15.0.1)"] +[[package]] +name = "motor" +version = "3.7.0" +description = "Non-blocking MongoDB driver for Tornado or asyncio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "motor-3.7.0-py3-none-any.whl", hash = "sha256:61bdf1afded179f008d423f98066348157686f25a90776ea155db5f47f57d605"}, + {file = "motor-3.7.0.tar.gz", hash = "sha256:0dfa1f12c812bd90819c519b78bed626b5a9dbb29bba079ccff2bfa8627e0fec"}, +] + +[package.dependencies] +pymongo = ">=4.9,<5.0" + +[package.extras] +aws = ["pymongo[aws] (>=4.5,<5)"] +docs = ["aiohttp", "furo (==2024.8.6)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-rtd-theme (>=2,<3)", "tornado"] +encryption = ["pymongo[encryption] (>=4.5,<5)"] +gssapi = ["pymongo[gssapi] (>=4.5,<5)"] +ocsp = ["pymongo[ocsp] (>=4.5,<5)"] +snappy = ["pymongo[snappy] (>=4.5,<5)"] +test = ["aiohttp (>=3.8.7)", "cffi (>=1.17.0rc1) ; python_version == \"3.13\"", "mockupdb", "pymongo[encryption] (>=4.5,<5)", "pytest (>=7)", "pytest-asyncio", "tornado (>=5)"] +zstd = ["pymongo[zstd] (>=4.5,<5)"] + [[package]] name = "multidict" version = "6.2.0" @@ -1234,7 +1395,6 @@ description = "multidict implementation" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "multidict-6.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1"}, {file = "multidict-6.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2"}, @@ -1340,7 +1500,6 @@ description = "Type system extensions for programs checked with the mypy type ch optional = false python-versions = ">=3.5" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1353,7 +1512,6 @@ description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -1366,7 +1524,6 @@ description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "numpy-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440"}, {file = "numpy-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab"}, @@ -1432,7 +1589,6 @@ description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "openai-1.68.0-py3-none-any.whl", hash = "sha256:20e279b0f3a78cb4a95f3eab2a180f3ee30c6a196aeebd6bf642a4f88ab85ee1"}, {file = "openai-1.68.0.tar.gz", hash = "sha256:c570c06c9ba10f98b891ac30a3dd7b5c89ed48094c711c7a3f35fb5ade6c0757"}, @@ -1461,7 +1617,6 @@ description = "OpenAI Agents SDK" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "openai_agents-0.0.4-py3-none-any.whl", hash = "sha256:5577c3ee994fe0bd200d7283e4f7a614b3af19afeebcfb07b6ca6039a8a50a5c"}, {file = "openai_agents-0.0.4.tar.gz", hash = "sha256:297e8d5faeca753e1b303d860b7ac94d03a7e10382be738163dc6a10a3b7cc1c"}, @@ -1482,7 +1637,6 @@ description = "A Python library to read/write Excel 2010 xlsx/xlsm files" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"}, {file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"}, @@ -1498,7 +1652,6 @@ description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -1511,7 +1664,6 @@ description = "Powerful data structures for data analysis, time series, and stat optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"}, {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"}, @@ -1592,6 +1744,26 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.9.2)"] +[[package]] +name = "portalocker" +version = "2.10.1" +description = "Wraps the portalocker recipe for easy usage" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, + {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, +] + +[package.dependencies] +pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} + +[package.extras] +docs = ["sphinx (>=1.7.1)"] +redis = ["redis"] +tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] + [[package]] name = "propcache" version = "0.3.0" @@ -1599,7 +1771,6 @@ description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, @@ -1701,6 +1872,27 @@ files = [ {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, ] +[[package]] +name = "protobuf" +version = "5.29.4" +description = "" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "protobuf-5.29.4-cp310-abi3-win32.whl", hash = "sha256:13eb236f8eb9ec34e63fc8b1d6efd2777d062fa6aaa68268fb67cf77f6839ad7"}, + {file = "protobuf-5.29.4-cp310-abi3-win_amd64.whl", hash = "sha256:bcefcdf3976233f8a502d265eb65ea740c989bacc6c30a58290ed0e519eb4b8d"}, + {file = "protobuf-5.29.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:307ecba1d852ec237e9ba668e087326a67564ef83e45a0189a772ede9e854dd0"}, + {file = "protobuf-5.29.4-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:aec4962f9ea93c431d5714ed1be1c93f13e1a8618e70035ba2b0564d9e633f2e"}, + {file = "protobuf-5.29.4-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:d7d3f7d1d5a66ed4942d4fefb12ac4b14a29028b209d4bfb25c68ae172059922"}, + {file = "protobuf-5.29.4-cp38-cp38-win32.whl", hash = "sha256:1832f0515b62d12d8e6ffc078d7e9eb06969aa6dc13c13e1036e39d73bebc2de"}, + {file = "protobuf-5.29.4-cp38-cp38-win_amd64.whl", hash = "sha256:476cb7b14914c780605a8cf62e38c2a85f8caff2e28a6a0bad827ec7d6c85d68"}, + {file = "protobuf-5.29.4-cp39-cp39-win32.whl", hash = "sha256:fd32223020cb25a2cc100366f1dedc904e2d71d9322403224cdde5fdced0dabe"}, + {file = "protobuf-5.29.4-cp39-cp39-win_amd64.whl", hash = "sha256:678974e1e3a9b975b8bc2447fca458db5f93a2fb6b0c8db46b6675b5b5346812"}, + {file = "protobuf-5.29.4-py3-none-any.whl", hash = "sha256:3fde11b505e1597f71b875ef2fc52062b6a9740e5f7c8997ce878b6009145862"}, + {file = "protobuf-5.29.4.tar.gz", hash = "sha256:4f1dfcd7997b31ef8f53ec82781ff434a28bf71d9102ddde14d076adcfc78c99"}, +] + [[package]] name = "pycparser" version = "2.22" @@ -1708,7 +1900,6 @@ description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1721,7 +1912,6 @@ description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, @@ -1734,7 +1924,7 @@ typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] [[package]] name = "pydantic-core" @@ -1743,7 +1933,6 @@ description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -1857,7 +2046,6 @@ description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c"}, {file = "pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585"}, @@ -1879,7 +2067,6 @@ description = "Python driver for MongoDB " optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pymongo-4.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e699aa68c4a7dea2ab5a27067f7d3e08555f8d2c0dc6a0c8c60cfd9ff2e6a4b1"}, {file = "pymongo-4.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:70645abc714f06b4ad6b72d5bf73792eaad14e3a2cfe29c62a9c81ada69d9e4b"}, @@ -1948,9 +2135,9 @@ dnspython = ">=1.16.0,<3.0.0" [package.extras] aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-autobuild (>=2020.9.1)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"] -encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.10.0,<2.0.0)"] -gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] -ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] +encryption = ["certifi ; os_name == \"nt\" or sys_platform == \"darwin\"", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.10.0,<2.0.0)"] +gssapi = ["pykerberos ; os_name != \"nt\"", "winkerberos (>=0.5.0) ; os_name == \"nt\""] +ocsp = ["certifi ; os_name == \"nt\" or sys_platform == \"darwin\"", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] test = ["pytest (>=8.2)", "pytest-asyncio (>=0.24.0)"] zstd = ["zstandard"] @@ -1962,7 +2149,6 @@ description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -1978,7 +2164,6 @@ description = "Create, read, and update Microsoft Word .docx files." optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe"}, {file = "python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd"}, @@ -1995,7 +2180,6 @@ description = "Read key-value pairs from a .env file and set them as environment optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, @@ -2011,12 +2195,86 @@ description = "World timezone definitions, modern and historical" optional = false python-versions = "*" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, ] +[[package]] +name = "pywin32" +version = "310" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +groups = ["main"] +markers = "platform_system == \"Windows\"" +files = [ + {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"}, + {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"}, + {file = "pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213"}, + {file = "pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd"}, + {file = "pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c"}, + {file = "pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582"}, + {file = "pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d"}, + {file = "pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060"}, + {file = "pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966"}, + {file = "pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab"}, + {file = "pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"}, + {file = "pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33"}, + {file = "pywin32-310-cp38-cp38-win32.whl", hash = "sha256:0867beb8addefa2e3979d4084352e4ac6e991ca45373390775f7084cc0209b9c"}, + {file = "pywin32-310-cp38-cp38-win_amd64.whl", hash = "sha256:30f0a9b3138fb5e07eb4973b7077e1883f558e40c578c6925acc7a94c34eaa36"}, + {file = "pywin32-310-cp39-cp39-win32.whl", hash = "sha256:851c8d927af0d879221e616ae1f66145253537bbdd321a77e8ef701b443a9a1a"}, + {file = "pywin32-310-cp39-cp39-win_amd64.whl", hash = "sha256:96867217335559ac619f00ad70e513c0fcf84b8a3af9fc2bba3b59b97da70475"}, +] + +[[package]] +name = "qdrant-client" +version = "1.13.3" +description = "Client library for the Qdrant vector search engine" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "qdrant_client-1.13.3-py3-none-any.whl", hash = "sha256:f52cacbb936e547d3fceb1aaed3e3c56be0ebfd48e8ea495ea3dbc89c671d1d2"}, + {file = "qdrant_client-1.13.3.tar.gz", hash = "sha256:61ca09e07c6d7ac0dfbdeb13dca4fe5f3e08fa430cb0d74d66ef5d023a70adfc"}, +] + +[package.dependencies] +grpcio = ">=1.41.0" +grpcio-tools = ">=1.41.0" +httpx = {version = ">=0.20.0", extras = ["http2"]} +numpy = [ + {version = ">=1.21", markers = "python_version >= \"3.10\" and python_version < \"3.12\""}, + {version = ">=1.26", markers = "python_version == \"3.12\""}, + {version = ">=2.1.0", markers = "python_version >= \"3.13\""}, +] +portalocker = ">=2.7.0,<3.0.0" +pydantic = ">=1.10.8" +urllib3 = ">=1.26.14,<3" + +[package.extras] +fastembed = ["fastembed (==0.5.1)"] +fastembed-gpu = ["fastembed-gpu (==0.5.1)"] + +[[package]] +name = "redis" +version = "5.2.1" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"}, + {file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} + +[package.extras] +hiredis = ["hiredis (>=3.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"] + [[package]] name = "requests" version = "2.32.3" @@ -2024,7 +2282,6 @@ description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -2047,20 +2304,19 @@ description = "Easily download, build, install, upgrade, and uninstall Python pa optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] -core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] [[package]] name = "six" @@ -2069,7 +2325,6 @@ description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2082,7 +2337,6 @@ description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -2095,7 +2349,6 @@ description = "Play and Record Sound with Python" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "sounddevice-0.5.1-py3-none-any.whl", hash = "sha256:e2017f182888c3f3c280d9fbac92e5dbddac024a7e3442f6e6116bd79dab8a9c"}, {file = "sounddevice-0.5.1-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d16cb23d92322526a86a9490c427bf8d49e273d9ccc0bd096feecd229cde6031"}, @@ -2117,7 +2370,6 @@ description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, @@ -2130,7 +2382,6 @@ description = "SSE plugin for Starlette" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99"}, {file = "sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419"}, @@ -2151,7 +2402,6 @@ description = "The little ASGI library that shines." optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227"}, {file = "starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230"}, @@ -2170,7 +2420,6 @@ description = "Pretty-print tabular data" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, @@ -2186,7 +2435,6 @@ description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -2209,7 +2457,6 @@ description = "Typing stubs for requests" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "types_requests-2.32.0.20250306-py3-none-any.whl", hash = "sha256:25f2cbb5c8710b2022f8bbee7b2b66f319ef14aeea2f35d80f18c9dbf3b60a0b"}, {file = "types_requests-2.32.0.20250306.tar.gz", hash = "sha256:0962352694ec5b2f95fda877ee60a159abdf84a0fc6fdace599f20acb41a03d1"}, @@ -2225,7 +2472,6 @@ description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -2238,7 +2484,6 @@ description = "Runtime inspection utilities for typing module." optional = false python-versions = "*" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, @@ -2255,7 +2500,6 @@ description = "Provider of IANA time zone data" optional = false python-versions = ">=2" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, @@ -2268,14 +2512,13 @@ description = "HTTP library with thread-safe connection pooling, file post, and optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2287,7 +2530,6 @@ description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, @@ -2299,7 +2541,7 @@ h11 = ">=0.8" typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "waitress" @@ -2308,7 +2550,6 @@ description = "Waitress WSGI server" optional = false python-versions = ">=3.7.0" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "waitress-2.1.2-py3-none-any.whl", hash = "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a"}, {file = "waitress-2.1.2.tar.gz", hash = "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba"}, @@ -2325,7 +2566,6 @@ description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, @@ -2422,7 +2662,6 @@ description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, @@ -2441,7 +2680,6 @@ description = "A built-package format for Python" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, @@ -2457,7 +2695,6 @@ description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, @@ -2551,4 +2788,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "9ab31ccc9ee418d463c06e1b3d3bace07d468799114c77415479fd6cd8fa7345" +content-hash = "53c4530e6aa4fdf17ea0c0497db2d4cfe1c5350279c442bee03520c063d62f62" diff --git a/apps/agents/pyproject.toml b/apps/agents/pyproject.toml index 7f43a8c4..c062a1dc 100644 --- a/apps/agents/pyproject.toml +++ b/apps/agents/pyproject.toml @@ -40,6 +40,7 @@ lxml = "^5.3.0" markdownify = "^0.13.1" MarkupSafe = "^3.0.2" mcp = "*" +motor = "^3.7.0" mypy-extensions = "^1.0.0" nest-asyncio = "^1.6.0" numpy = "^2.1.2" @@ -54,6 +55,8 @@ python-dateutil = "^2.8.2" python-docx = "^1.1.2" python-dotenv = "^1.0.1" pytz = "^2024.2" +qdrant_client = "^1.13.3" +redis = "^5.2.1" requests = "^2.32.3" setuptools = "^75.1.0" six = "^1.16.0" diff --git a/apps/agents/src/app/main.py b/apps/agents/src/app/main.py index a694fe90..49004889 100644 --- a/apps/agents/src/app/main.py +++ b/apps/agents/src/app/main.py @@ -15,7 +15,7 @@ logger = common_logger redis_client = redis.from_url(os.environ.get('REDIS_URL', 'redis://localhost:6379')) app = Flask(__name__) - + @app.route("/health", methods=["GET"]) def health(): return jsonify({"status": "ok"}) @@ -61,7 +61,8 @@ def chat(): tool_configs=data.get("tools", []), start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), state=data.get("state", {}), - additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL] + additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], + complete_request=data ) logger.info('-'*200) @@ -73,15 +74,15 @@ def chat(): "tokens_used": resp_tokens_used, "state": resp_state, } - + logger.info("Output:") for k, v in out.items(): logger.info(f"{k}: {v}") logger.info('*'*200) - + logger.info('='*200) logger.info(f"Processing time: {datetime.now() - start_time}") - + return jsonify(out) except Exception as e: diff --git a/apps/agents/src/graph/core.py b/apps/agents/src/graph/core.py index c1f24102..e4ef1de1 100644 --- a/apps/agents/src/graph/core.py +++ b/apps/agents/src/graph/core.py @@ -80,7 +80,7 @@ def create_final_response(response, turn_messages, tokens_used, all_agents): def run_turn( - messages, start_agent_name, agent_configs, tool_configs, start_turn_with_start_agent, state={}, additional_tool_configs=[] + messages, start_agent_name, agent_configs, tool_configs, start_turn_with_start_agent, state={}, additional_tool_configs=[], complete_request={} ): """ Coordinates a single 'turn' of conversation or processing among agents. @@ -129,7 +129,8 @@ def run_turn( print("Initializing agents") new_agents = get_agents( agent_configs=agent_configs, - tool_configs=tool_configs + tool_configs=tool_configs, + complete_request=complete_request ) # Prepare escalation agent last_new_agent = get_agent_by_name(last_agent_name, new_agents) diff --git a/apps/agents/src/graph/swarm_wrapper.py b/apps/agents/src/graph/swarm_wrapper.py index d528b4d9..160e7be3 100644 --- a/apps/agents/src/graph/swarm_wrapper.py +++ b/apps/agents/src/graph/swarm_wrapper.py @@ -14,15 +14,14 @@ from agents import Agent as NewAgent, Runner, FunctionTool, RunContextWrapper # Add import for OpenAI functionality from src.utils.common import common_logger as logger, generate_openai_output from typing import Any -# Create a dedicated logger for swarm wrapper -#logger = logging.getLogger("swarm_wrapper") -#logger.setLevel(logging.INFO) +from dataclasses import asdict import asyncio from mcp import ClientSession from mcp.client.sse import sse_client from pydantic import BaseModel from typing import List, Optional, Dict +from .tool_calling import call_rag_tool class NewResponse(BaseModel): messages: List[Dict] @@ -30,7 +29,7 @@ class NewResponse(BaseModel): tokens_used: Optional[dict] = {} error_msg: Optional[str] = "" -async def mock_tool(tool_name: str, args: str, mock_instructions: str) -> str: +async def mock_tool(tool_name: str, args: str, tool_config: str) -> str: """ Handles tool execution by either using mock instructions or generating a response. @@ -45,10 +44,11 @@ async def mock_tool(tool_name: str, args: str, mock_instructions: str) -> str: print(f"Mock tool called for: {tool_name}") # For non-mocked tools, generate a realistic response - description = mock_instructions + description = tool_config.get("description", "") + mock_instructions = tool_config.get("mockInstructions", "") messages = [ - {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. Here are the mock instructions: {description}. Generate a realistic response as if the tool was actually executed with the given parameters."}, + {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'.Here is the description of the tool: {description}. Here are the instructions for the mock tool: {mock_instructions}. Generate a realistic response as if the tool was actually executed with the given parameters."}, {"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}' with these parameters: {args}. The response should be concise and focused on what the tool would actually return."} ] @@ -56,7 +56,7 @@ async def mock_tool(tool_name: str, args: str, mock_instructions: str) -> str: response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") return response_content -async def call_webhook(tool_name: str, args: str) -> str: +async def call_webhook(tool_name: str, args: str, webhook_url: str) -> str: """ Calls the webhook with the given tool name and arguments. @@ -67,12 +67,11 @@ async def call_webhook(tool_name: str, args: str) -> str: Returns: str: The response from the webhook, or an error message if the call fails. """ - webhook_url = "http://localhost:4020/tool_call" content_dict = { "toolCall": { "function": { "name": tool_name, - "arguments": args # Assumes args is a valid JSON string + "arguments": args } } } @@ -93,33 +92,28 @@ async def call_webhook(tool_name: str, args: str) -> str: print(f"Exception in call_webhook: {str(e)}") return f"Error: Failed to call webhook - {str(e)}" -async def call_mcp(tool_name: str, args: str, mcp_server_name: str, mcp_servers: dict) -> str: +async def call_mcp(tool_name: str, args: str, mcp_server_url: str) -> str: """ Calls the MCP with the given tool name and arguments. """ - server_url = "http://localhost:8000/sse" #mcp_servers.get(tool_name, None) - print(args) - async with sse_client(url=server_url) as streams: - # Create a client session using the SSE streams + + async with sse_client(url=mcp_server_url) as streams: async with ClientSession(*streams) as session: - # Initialize the session (perform handshake with the server) await session.initialize() - # Call the tool on the server and await the response - response = await session.call_tool(tool_name, arguments=json.loads(args)) + jargs = json.loads(args) + response = await session.call_tool(tool_name, arguments=jargs) + json_output = json.dumps([item.__dict__ for item in response.content], indent=2) - # Print the response received from the server - print("Server response:", response) + return json_output - return response - -def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict) -> str: +async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict, complete_request: dict) -> str: """ Handles all tool calls by dispatching to appropriate functions. """ print(f"Catch all called for tool: {tool_name}") print(f"Args: {args}") print(f"Tool config: {tool_config}") - + # Create event loop for async operations try: loop = asyncio.get_event_loop() @@ -128,30 +122,54 @@ def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_confi asyncio.set_event_loop(loop) response_content = None - # Check if this tool should be mocked if tool_config.get("mockTool", False): - # Handle mock tool synchronously - description = tool_config.get("description", "") - messages = [ - {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'. The tool has this description: {description}. Generate a realistic response as if the tool was actually executed with the given parameters."}, - {"role": "user", "content": f"Generate a realistic response for the tool '{tool_name}' with these parameters: {args}. The response should be concise and focused on what the tool would actually return."} - ] - response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") + # Call mock_tool to handle the response (it will decide whether to use mock instructions or generate a response) + response_content = await mock_tool(tool_name, args, tool_config) + print(response_content) elif tool_config.get("isMcp", False): - # Handle MCP calls - response_content = loop.run_until_complete( - call_mcp(tool_name, args, tool_config.get("mcpServerName", ""), {}) - ) + mcp_server_name = tool_config.get("mcpServerName", "") + mcp_servers = complete_request.get("mcpServers", {}) + mcp_server_url = next((server.get("url", "") for server in mcp_servers if server.get("name") == mcp_server_name), "") + response_content = await call_mcp(tool_name, args, mcp_server_url) else: - # Handle webhook calls - response_content = loop.run_until_complete( - call_webhook(tool_name, args) - ) - - print(response_content) + webhook_url = complete_request.get("toolWebhookUrl", "") + response_content = await call_webhook(tool_name, args, webhook_url) return response_content -def get_agents(agent_configs, tool_configs): + +def get_rag_tool(config: dict, complete_request: dict) -> FunctionTool: + """ + Creates a RAG tool based on the provided configuration. + """ + project_id = complete_request.get("projectId", "") + if config.get("ragDataSources", None): + print("getArticleInfo") + params = { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "The query to search for" + } + }, + "additionalProperties": False, + "required": [ + "query" + ] + } + tool = FunctionTool( + name="getArticleInfo", + description="Get information about an article", + params_json_schema=params, + on_invoke_tool=lambda ctx, args: call_rag_tool(project_id, json.loads(args)['query'], config.get("ragDataSources", []), "chunks", 3) + ) + return tool + else: + return None + + + +def get_agents(agent_configs, tool_configs, complete_request): """ Creates and initializes Agent objects based on their configurations and connections. """ @@ -181,7 +199,15 @@ def get_agents(agent_configs, tool_configs): print(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools") new_tools = [] + print(agent_config) + rag_tool = get_rag_tool(agent_config, complete_request) + if rag_tool: + new_tools.append(rag_tool) + logger.debug(f"Added rag tool to agent {agent_config['name']}") + print(f"Added rag tool to agent {agent_config['name']}") + for tool_name in agent_config["tools"]: + tool_config = get_tool_config_by_name(tool_configs, tool_name) if tool_config: @@ -195,8 +221,8 @@ def get_agents(agent_configs, tool_configs): name=tool_name, description=tool_config["description"], params_json_schema=tool_config["parameters"], - on_invoke_tool=lambda ctx, args, _tool_name=tool_name, _tool_config=tool_config: - catch_all(ctx, args, _tool_name, _tool_config) + on_invoke_tool=lambda ctx, args, _tool_name=tool_name, _tool_config=tool_config, _complete_request=complete_request: + catch_all(ctx, args, _tool_name, _tool_config, _complete_request) ) new_tools.append(tool) logger.debug(f"Added tool {tool_name} to agent {agent_config['name']}") @@ -305,7 +331,7 @@ def run( # Run the agent with the formatted messages logger.info("Beginning Swarm run with run_sync") print("Beginning Swarm run with run_sync") - + try: response = loop.run_until_complete(Runner.run(agent, formatted_messages)) except Exception as e: diff --git a/apps/agents/src/graph/tool_calling.py b/apps/agents/src/graph/tool_calling.py new file mode 100644 index 00000000..8ac75fd4 --- /dev/null +++ b/apps/agents/src/graph/tool_calling.py @@ -0,0 +1,143 @@ +from bson.objectid import ObjectId +from openai import OpenAI +import os +from motor.motor_asyncio import AsyncIOMotorClient +import asyncio +from dataclasses import dataclass +from typing import Dict, List, Any +from qdrant_client import QdrantClient +import json +# Initialize MongoDB client +mongo_uri = os.environ.get("MONGODB_URI", "mongodb://localhost:27017") +mongo_client = AsyncIOMotorClient(mongo_uri) +db = mongo_client.rowboat +data_sources_collection = db['sources'] +data_source_docs_collection = db['source_docs'] + + +qdrant_client = QdrantClient(url=os.environ.get("QDRANT_URL")) +# Initialize OpenAI client +client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) + +# Define embedding model +embedding_model = "text-embedding-3-small" + +async def embed(model: str, value: str) -> dict: + """ + Generate embeddings using OpenAI's embedding models. + + Args: + model (str): The embedding model to use (e.g., "text-embedding-3-small"). + value (str): The text to embed. + + Returns: + dict: A dictionary containing the embedding. + """ + response = client.embeddings.create( + model=model, + input=value + ) + return {"embedding": response.data[0].embedding} + +async def call_rag_tool( + project_id: str, + query: str, + source_ids: list[str], + return_type: str, + k: int, +) -> dict: + """ + Runs the RAG tool call to retrieve information based on the query and source IDs. + + Args: + project_id (str): The ID of the project. + query (str): The query string to search for. + source_ids (list[str]): List of source IDs to filter the search. + return_type (str): The type of return, e.g., 'chunks' or other. + k (int): The number of results to return. + + Returns: + dict: A dictionary containing the results of the search. + """ + + print("\n\n calling rag tool \n\n") + print(query) + # Create embedding for the query + embed_result = await embed(model=embedding_model, value=query) + + print(embed_result) + # Fetch all active data sources for this project + sources = await data_sources_collection.find({ + "projectId": project_id, + "active": True + }).to_list(length=None) + + print(sources) + # Filter sources to those in source_ids + valid_source_ids = [ + str(s["_id"]) for s in sources if str(s["_id"]) in source_ids + ] + + print(valid_source_ids) + # If no valid sources are found, return empty results + if not valid_source_ids: + return '' + + # Perform Qdrant vector search + qdrant_results = qdrant_client.search( + collection_name="embeddings", + query_vector=embed_result["embedding"], + query_filter={ + "must": [ + {"key": "projectId", "match": {"value": project_id}}, + {"key": "sourceId", "match": {"any": valid_source_ids}}, + ] + }, + limit=k, + with_payload=True + ) + + # Map the Qdrant results to the desired format + results = [ + { + "title": point.payload["title"], + "name": point.payload["name"], + "content": point.payload["content"], + "docId": point.payload["docId"], + "sourceId": point.payload["sourceId"], + } + for point in qdrant_results + ] + + print(return_type) + print(results) + # If return_type is 'chunks', return the results directly + if return_type == "chunks": + return json.dumps({"Information": results}, indent=2) + + # Otherwise, fetch the full document contents from MongoDB + doc_ids = [ObjectId(r["docId"]) for r in results] + docs = await data_source_docs_collection.find({"_id": {"$in": doc_ids}}).to_list(length=None) + + # Create a dictionary for quick lookup of documents by their string ID + doc_dict = {str(doc["_id"]): doc for doc in docs} + + # Update the results with the full document content + results = [ + {**r, "content": doc_dict.get(r["docId"], {}).get("content", "")} + for r in results + ] + + # Convert results to a JSON string + formatted_string = json.dumps({"Information": results}, indent=2) + print(formatted_string) + return formatted_string + + +if __name__ == "__main__": + asyncio.run(call_rag_tool( + project_id="faf2bfb3-41d4-4299-b0d2-048581ea9bd8", + query="What is the range on your scooter", + source_ids=["67e102c9fab4514d7aaeb5a4"], + return_type="docs", + k=3)) \ No newline at end of file diff --git a/apps/agents/tests/interactive.py b/apps/agents/tests/interactive.py index 1e38181a..54e5d1f1 100644 --- a/apps/agents/tests/interactive.py +++ b/apps/agents/tests/interactive.py @@ -16,20 +16,20 @@ if __name__ == "__main__": tool_configs = complete_request.get("tools", []) prompt_configs = complete_request.get("prompts", []) start_agent_name = complete_request.get("startAgent", "") - + return agent_configs, tool_configs, prompt_configs, start_agent_name - + external_tool_mappings = { "raise_error": respond_to_tool_raise_error, "close_chat": respond_to_tool_close_chat } - + config_file = sys.argv[sys.argv.index("--config") + 1] if "--config" in sys.argv else "default_config.json" sample_request_file = sys.argv[sys.argv.index("--sample_request") + 1] if "--sample_request" in sys.argv else "default_example.json" - + config = read_json_from_file(f"./configs/{config_file}") example_request = read_json_from_file(f"./tests/sample_requests/{sample_request_file}").get("lastRequest", {}) - + if "--load_messages" in sys.argv: messages = example_request.get("messages", []) messages = order_messages(messages) @@ -57,7 +57,7 @@ if __name__ == "__main__": agent_configs, tool_configs, prompt_configs, start_agent_name = extract_request_fields(complete_request) print(f"\nUsing agent: {last_agent_name}") - + if user_input_needed: user_inp = input('\nUSER: ') messages.append({ @@ -81,7 +81,7 @@ if __name__ == "__main__": "startAgent": start_agent_name } print(json.dumps(request_json, indent=2)) - + print(complete_request) resp_messages, resp_tokens_used, resp_state = run_turn( messages=messages, start_agent_name=start_agent_name, @@ -89,7 +89,8 @@ if __name__ == "__main__": tool_configs=tool_configs, start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), state=state, - additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL] + additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], + complete_request=complete_request ) state = resp_state resp_messages = order_messages(resp_messages) @@ -101,12 +102,12 @@ if __name__ == "__main__": "tokens_used": resp_tokens_used } print(json.dumps(response_json, indent=2)) - + last_msg = resp_messages[-1] print(f"\nBOT: {last_msg}\n") tool_calls = last_msg.get("tool_calls", []) sender = last_msg.get("sender", "") - + if config.get("return_diff_messages", True): messages.extend(resp_messages) else: @@ -133,7 +134,7 @@ if __name__ == "__main__": current_tool_duration = round((datetime.now() - tool_start_time).total_seconds() * 10) / 10 logger.info(f"Tool response duration: {current_tool_duration:.1f}s") tool_duration += current_tool_duration - + if tool_name == "close_chat": user_input_needed = False logger.info("Closing chat") @@ -141,10 +142,10 @@ if __name__ == "__main__": if should_break: break - + else: user_input_needed = True print(f"Turn Duration: {round((datetime.now() - turn_start_time).total_seconds() * 10) / 10:.1f}s\n") print(f"Tool Response Duration: {round(tool_duration * 10) / 10:.1f}s\n") - + print("\n" + "-" * 80) \ No newline at end of file From 24efe0e887472ccda2f7ad6ab0ddc3e1a5f7e00f Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Tue, 25 Mar 2025 15:37:51 +0530 Subject: [PATCH 25/49] Merge changes v1 --- apps/agents/pyproject.toml | 74 - apps/agents/src/app/main.py | 145 -- apps/{agents => rowboat_agents}/.dockerignore | 0 apps/{agents => rowboat_agents}/.env.example | 0 apps/{agents => rowboat_agents}/.gitignore | 0 apps/{agents => rowboat_agents}/Dockerfile | 0 apps/{agents => rowboat_agents}/NOTICE.md | 0 apps/{agents => rowboat_agents}/README.md | 0 apps/{agents => rowboat_agents}/__init__.py | 0 .../configs/default_config.json | 0 apps/{agents => rowboat_agents}/poetry.lock | 1351 ++++++++++++++++- apps/rowboat_agents/pyproject.toml | 109 ++ .../requirements.txt | 11 +- .../src/__init__.py | 0 .../src/app/__init__.py | 0 apps/rowboat_agents/src/app/main.py | 200 +++ .../src/graph/__init__.py | 0 .../src/graph/core.py | 142 +- .../src/graph/guardrails.py | 0 .../src/graph/helpers/access.py | 0 .../src/graph/helpers/control.py | 0 .../src/graph/helpers/instructions.py | 0 .../src/graph/helpers/state.py | 0 .../src/graph/helpers/transfer.py | 0 .../src/graph/instructions.py | 0 .../src/graph/swarm_wrapper.py | 51 +- .../src/graph/tool_calling.py | 0 .../src/graph/tools.py | 0 .../src/graph/types.py | 0 .../src/utils/__init__.py | 0 .../src/utils/common.py | 0 .../tests/__init__.py | 0 .../tests/app_client.py | 0 .../tests/app_client_streaming.py | 174 +++ .../tests/interactive.py | 136 +- .../sample_requests/default_example.json | 0 .../tests/sample_requests/example1.json | 0 .../tests/sample_requests/example2.json | 0 .../tests/sample_requests/example3.json | 0 .../tests/sample_requests/tmp1.json | 176 +++ .../tests/sample_requests/tmp2.json | 223 +++ .../tests/sample_requests/tmp3.json | 270 ++++ .../tests/sample_requests/tmp4.json | 166 ++ .../sample_responses/default_example.json | 0 docker-compose.yml | 6 +- 45 files changed, 2940 insertions(+), 294 deletions(-) delete mode 100644 apps/agents/pyproject.toml delete mode 100644 apps/agents/src/app/main.py rename apps/{agents => rowboat_agents}/.dockerignore (100%) rename apps/{agents => rowboat_agents}/.env.example (100%) rename apps/{agents => rowboat_agents}/.gitignore (100%) rename apps/{agents => rowboat_agents}/Dockerfile (100%) rename apps/{agents => rowboat_agents}/NOTICE.md (100%) rename apps/{agents => rowboat_agents}/README.md (100%) rename apps/{agents => rowboat_agents}/__init__.py (100%) rename apps/{agents => rowboat_agents}/configs/default_config.json (100%) rename apps/{agents => rowboat_agents}/poetry.lock (69%) create mode 100644 apps/rowboat_agents/pyproject.toml rename apps/{agents => rowboat_agents}/requirements.txt (94%) rename apps/{agents => rowboat_agents}/src/__init__.py (100%) rename apps/{agents => rowboat_agents}/src/app/__init__.py (100%) create mode 100644 apps/rowboat_agents/src/app/main.py rename apps/{agents => rowboat_agents}/src/graph/__init__.py (100%) rename apps/{agents => rowboat_agents}/src/graph/core.py (58%) rename apps/{agents => rowboat_agents}/src/graph/guardrails.py (100%) rename apps/{agents => rowboat_agents}/src/graph/helpers/access.py (100%) rename apps/{agents => rowboat_agents}/src/graph/helpers/control.py (100%) rename apps/{agents => rowboat_agents}/src/graph/helpers/instructions.py (100%) rename apps/{agents => rowboat_agents}/src/graph/helpers/state.py (100%) rename apps/{agents => rowboat_agents}/src/graph/helpers/transfer.py (100%) rename apps/{agents => rowboat_agents}/src/graph/instructions.py (100%) rename apps/{agents => rowboat_agents}/src/graph/swarm_wrapper.py (89%) rename apps/{agents => rowboat_agents}/src/graph/tool_calling.py (100%) rename apps/{agents => rowboat_agents}/src/graph/tools.py (100%) rename apps/{agents => rowboat_agents}/src/graph/types.py (100%) rename apps/{agents => rowboat_agents}/src/utils/__init__.py (100%) rename apps/{agents => rowboat_agents}/src/utils/common.py (100%) rename apps/{agents => rowboat_agents}/tests/__init__.py (100%) rename apps/{agents => rowboat_agents}/tests/app_client.py (100%) create mode 100644 apps/rowboat_agents/tests/app_client_streaming.py rename apps/{agents => rowboat_agents}/tests/interactive.py (56%) rename apps/{agents => rowboat_agents}/tests/sample_requests/default_example.json (100%) rename apps/{agents => rowboat_agents}/tests/sample_requests/example1.json (100%) rename apps/{agents => rowboat_agents}/tests/sample_requests/example2.json (100%) rename apps/{agents => rowboat_agents}/tests/sample_requests/example3.json (100%) create mode 100644 apps/rowboat_agents/tests/sample_requests/tmp1.json create mode 100644 apps/rowboat_agents/tests/sample_requests/tmp2.json create mode 100644 apps/rowboat_agents/tests/sample_requests/tmp3.json create mode 100644 apps/rowboat_agents/tests/sample_requests/tmp4.json rename apps/{agents => rowboat_agents}/tests/sample_responses/default_example.json (100%) diff --git a/apps/agents/pyproject.toml b/apps/agents/pyproject.toml deleted file mode 100644 index c062a1dc..00000000 --- a/apps/agents/pyproject.toml +++ /dev/null @@ -1,74 +0,0 @@ -[tool.poetry] -name = "agents" -version = "0.1.0" -description = "RowBoat Labs Agent OS" -authors = ["Akhilesh "] -license = "MIT" -readme = "README.md" -homepage = "https://github.com/rowboatlabs/agents" -package-mode = false - -[tool.poetry.dependencies] -# Python -python = ">=3.10,<4.0" - -# Dependencies -aiohttp = "^3.9.3" -annotated-types = "^0.7.0" -anyio = "^4.6.2" -beautifulsoup4 = "^4.12.3" -blinker = "^1.8.2" -certifi = "^2024.8.30" -charset-normalizer = "^3.4.0" -click = "^8.1.7" -distro = "^1.9.0" -dnspython = "^2.7.0" -et_xmlfile = "^2.0.0" -eval_type_backport = "^0.2.0" -firecrawl = "^1.4.0" -Flask = "^3.0.3" -gunicorn = "^23.0.0" -h11 = "^0.14.0" -httpcore = "^1.0.6" -httpx = "^0.27.2" -idna = "^3.10" -itsdangerous = "^2.2.0" -Jinja2 = "^3.1.4" -jiter = "^0.6.1" -jsonpath-python = "^1.0.6" -lxml = "^5.3.0" -markdownify = "^0.13.1" -MarkupSafe = "^3.0.2" -mcp = "*" -motor = "^3.7.0" -mypy-extensions = "^1.0.0" -nest-asyncio = "^1.6.0" -numpy = "^2.1.2" -openai = "^1.52.2" -openai-agents = "^0.0.4" -openpyxl = "^3.1.5" -pandas = "^2.2.3" -pydantic = "^2.9.2" -pydantic_core = "^2.23.4" -pymongo = "^4.10.1" -python-dateutil = "^2.8.2" -python-docx = "^1.1.2" -python-dotenv = "^1.0.1" -pytz = "^2024.2" -qdrant_client = "^1.13.3" -redis = "^5.2.1" -requests = "^2.32.3" -setuptools = "^75.1.0" -six = "^1.16.0" -sniffio = "^1.3.1" -soupsieve = "^2.6" -tabulate = "^0.9.0" -tqdm = "^4.66.5" -typing-inspect = "^0.9.0" -typing_extensions = "^4.12.2" -tzdata = "^2024.2" -urllib3 = "^2.2.3" -waitress = "^2.1.2" -websockets = "^13.1" -Werkzeug = "^3.0.5" -wheel = "^0.44.0" diff --git a/apps/agents/src/app/main.py b/apps/agents/src/app/main.py deleted file mode 100644 index 49004889..00000000 --- a/apps/agents/src/app/main.py +++ /dev/null @@ -1,145 +0,0 @@ -from flask import Flask, request, jsonify, Response -from datetime import datetime -from functools import wraps -import os -import redis -import uuid -import json -import time - -from src.graph.core import run_turn -from src.graph.tools import RAG_TOOL, CLOSE_CHAT_TOOL - -from src.utils.common import common_logger, read_json_from_file -logger = common_logger - -redis_client = redis.from_url(os.environ.get('REDIS_URL', 'redis://localhost:6379')) -app = Flask(__name__) - -@app.route("/health", methods=["GET"]) -def health(): - return jsonify({"status": "ok"}) - -@app.route("/") -def home(): - return "Hello, World!" - -def require_api_key(f): - @wraps(f) - def decorated(*args, **kwargs): - auth_header = request.headers.get('Authorization') - if not auth_header or not auth_header.startswith('Bearer '): - return jsonify({'error': 'Missing or invalid authorization header'}), 401 - - token = auth_header.split('Bearer ')[1] - actual = os.environ.get('API_KEY', '').strip() - if actual and token != actual: - return jsonify({'error': 'Invalid API key'}), 403 - - return f(*args, **kwargs) - return decorated - -@app.route("/chat", methods=["POST"]) -@require_api_key -def chat(): - logger.info('='*200) - logger.info(f"{'*'*50}Running server mode{'*'*50}") - try: - data = request.get_json() - logger.info('Complete request:') - logger.info(data) - logger.info('-'*200) - - start_time = datetime.now() - config = read_json_from_file("./configs/default_config.json") - - logger.info('Beginning turn') - resp_messages, resp_tokens_used, resp_state = run_turn( - messages=data.get("messages", []), - start_agent_name=data.get("startAgent", ""), - agent_configs=data.get("agents", []), - tool_configs=data.get("tools", []), - start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), - state=data.get("state", {}), - additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], - complete_request=data - ) - - logger.info('-'*200) - logger.info('Raw output:') - logger.info((resp_messages, resp_tokens_used, resp_state)) - - out = { - "messages": resp_messages, - "tokens_used": resp_tokens_used, - "state": resp_state, - } - - logger.info("Output:") - for k, v in out.items(): - logger.info(f"{k}: {v}") - logger.info('*'*200) - - logger.info('='*200) - logger.info(f"Processing time: {datetime.now() - start_time}") - - return jsonify(out) - - except Exception as e: - logger.error(f"Error: {e}") - return jsonify({"error": str(e)}), 500 - -@app.route("/chat_stream_init", methods=["POST"]) -@require_api_key -def chat_stream_init(): - # create a uuid for the stream - stream_id = str(uuid.uuid4()) - - # store the the request data in redis with 10 minute TTL - # using the key name `stream_request_` - # set ttl to 10 minutes - redis_client.setex(f"stream_request_{stream_id}", 600, json.dumps(request.get_json())) - - return jsonify({"stream_id": stream_id}) - -@app.route("/chat_stream/", methods=["GET"]) -@require_api_key -def chat_stream(stream_id): - # get the request data from redis - request_data = redis_client.get(f"stream_request_{stream_id}") - if not request_data: - return jsonify({"error": "Stream not found"}), 404 - - # invoke run_streamed() from agents-sdk - - def generate(): - # example of HTTP SSE event stream: - # https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events - # -------------------------------- - # id: - # event: - # data: {... event data ...} - # - # event: - # data: {... event data ...} - try: - yield "event: message\n" - yield "data: {\"role\": \"assistant\", \"content\": \"This is the first message!\"}\n\n" # double \n indicates end of message - - time.sleep(2) - - yield "event: message\n" - yield "data: {\"role\": \"assistant\", \"content\": \"This is the second message!\"}\n\n" - - yield "event: done\n" - yield "data: {... state data ...}\n\n" - except Exception as e: - yield "event: error\n" - yield "data: {... error data ...}\n\n" - - return Response(generate(), mimetype='text/event-stream') - -if __name__ == "__main__": - print("Starting Flask server...") - from waitress import serve - serve(app, host="0.0.0.0", port=4040) \ No newline at end of file diff --git a/apps/agents/.dockerignore b/apps/rowboat_agents/.dockerignore similarity index 100% rename from apps/agents/.dockerignore rename to apps/rowboat_agents/.dockerignore diff --git a/apps/agents/.env.example b/apps/rowboat_agents/.env.example similarity index 100% rename from apps/agents/.env.example rename to apps/rowboat_agents/.env.example diff --git a/apps/agents/.gitignore b/apps/rowboat_agents/.gitignore similarity index 100% rename from apps/agents/.gitignore rename to apps/rowboat_agents/.gitignore diff --git a/apps/agents/Dockerfile b/apps/rowboat_agents/Dockerfile similarity index 100% rename from apps/agents/Dockerfile rename to apps/rowboat_agents/Dockerfile diff --git a/apps/agents/NOTICE.md b/apps/rowboat_agents/NOTICE.md similarity index 100% rename from apps/agents/NOTICE.md rename to apps/rowboat_agents/NOTICE.md diff --git a/apps/agents/README.md b/apps/rowboat_agents/README.md similarity index 100% rename from apps/agents/README.md rename to apps/rowboat_agents/README.md diff --git a/apps/agents/__init__.py b/apps/rowboat_agents/__init__.py similarity index 100% rename from apps/agents/__init__.py rename to apps/rowboat_agents/__init__.py diff --git a/apps/agents/configs/default_config.json b/apps/rowboat_agents/configs/default_config.json similarity index 100% rename from apps/agents/configs/default_config.json rename to apps/rowboat_agents/configs/default_config.json diff --git a/apps/agents/poetry.lock b/apps/rowboat_agents/poetry.lock similarity index 69% rename from apps/agents/poetry.lock rename to apps/rowboat_agents/poetry.lock index 3cb1fdd3..71efeadb 100644 --- a/apps/agents/poetry.lock +++ b/apps/rowboat_agents/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -7,6 +7,7 @@ description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, @@ -19,6 +20,7 @@ description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "aiohttp-3.11.14-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e2bc827c01f75803de77b134afdbf74fa74b62970eafdf190f3244931d7a5c0d"}, {file = "aiohttp-3.11.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e365034c5cf6cf74f57420b57682ea79e19eb29033399dd3f40de4d0171998fa"}, @@ -114,7 +116,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.2.0) ; sys_platform == \"linux\" or sys_platform == \"darwin\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" @@ -123,6 +125,7 @@ description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, @@ -138,6 +141,7 @@ description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -150,6 +154,7 @@ description = "High level compatibility layer for multiple asynchronous event lo optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, @@ -163,9 +168,28 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] +[[package]] +name = "asgiref" +version = "3.8.1" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + [[package]] name = "async-timeout" version = "5.0.1" @@ -173,7 +197,7 @@ description = "Timeout context manager for asyncio programs" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version == \"3.10\" or python_version == \"3.11\" and python_full_version < \"3.11.3\"" +markers = "python_full_version < \"3.11.3\"" files = [ {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, @@ -186,18 +210,36 @@ description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] -benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] -tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + +[[package]] +name = "backports-tarfile" +version = "1.2.0" +description = "Backport of CPython tarfile module" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\"" +files = [ + {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, + {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] [[package]] name = "beautifulsoup4" @@ -206,6 +248,7 @@ description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, @@ -228,11 +271,62 @@ description = "Fast, simple object-to-object and broadcast signaling" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"}, {file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"}, ] +[[package]] +name = "build" +version = "1.2.2.post1" +description = "A simple, correct Python build frontend" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"}, + {file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "os_name == \"nt\""} +importlib-metadata = {version = ">=4.6", markers = "python_full_version < \"3.10.2\""} +packaging = ">=19.1" +pyproject_hooks = "*" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"] +test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"] +typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"] +uv = ["uv (>=0.1.18)"] +virtualenv = ["virtualenv (>=20.0.35)"] + +[[package]] +name = "cachecontrol" +version = "0.14.2" +description = "httplib2 caching for requests" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "cachecontrol-0.14.2-py3-none-any.whl", hash = "sha256:ebad2091bf12d0d200dfc2464330db638c5deb41d546f6d7aca079e87290f3b0"}, + {file = "cachecontrol-0.14.2.tar.gz", hash = "sha256:7d47d19f866409b98ff6025b6a0fca8e4c791fb31abbd95f622093894ce903a2"}, +] + +[package.dependencies] +filelock = {version = ">=3.8.0", optional = true, markers = "extra == \"filecache\""} +msgpack = ">=0.5.2,<2.0.0" +requests = ">=2.16.0" + +[package.extras] +dev = ["CacheControl[filecache,redis]", "build", "cherrypy", "codespell[tomli]", "furo", "mypy", "pytest", "pytest-cov", "ruff", "sphinx", "sphinx-copybutton", "tox", "types-redis", "types-requests"] +filecache = ["filelock (>=3.8.0)"] +redis = ["redis (>=2.10.5)"] + [[package]] name = "certifi" version = "2024.12.14" @@ -240,6 +334,7 @@ description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, @@ -252,6 +347,7 @@ description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -332,6 +428,7 @@ description = "The Real First Universal Charset Detector. Open, modern and activ optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -427,6 +524,23 @@ files = [ {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] +[[package]] +name = "cleo" +version = "2.1.0" +description = "Cleo allows you to create beautiful and testable command-line interfaces." +optional = false +python-versions = ">=3.7,<4.0" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "cleo-2.1.0-py3-none-any.whl", hash = "sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e"}, + {file = "cleo-2.1.0.tar.gz", hash = "sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523"}, +] + +[package.dependencies] +crashtest = ">=0.4.1,<0.5.0" +rapidfuzz = ">=3.0.0,<4.0.0" + [[package]] name = "click" version = "8.1.8" @@ -434,6 +548,7 @@ description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -449,11 +564,97 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "crashtest" +version = "0.4.1" +description = "Manage Python errors with ease" +optional = false +python-versions = ">=3.7,<4.0" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "crashtest-0.4.1-py3-none-any.whl", hash = "sha256:8d23eac5fa660409f57472e3851dab7ac18aba459a8d19cbbba86d3d5aecd2a5"}, + {file = "crashtest-0.4.1.tar.gz", hash = "sha256:80d7b1f316ebfbd429f648076d6275c877ba30ba48979de4191714a75266f0ce"}, +] + +[[package]] +name = "cryptography" +version = "44.0.2" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\") and sys_platform == \"linux\"" +files = [ + {file = "cryptography-44.0.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308"}, + {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688"}, + {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7"}, + {file = "cryptography-44.0.2-cp37-abi3-win32.whl", hash = "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79"}, + {file = "cryptography-44.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa"}, + {file = "cryptography-44.0.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23"}, + {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922"}, + {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4"}, + {file = "cryptography-44.0.2-cp39-abi3-win32.whl", hash = "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5"}, + {file = "cryptography-44.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390"}, + {file = "cryptography-44.0.2.tar.gz", hash = "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==44.0.2)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "distlib" +version = "0.3.9" +description = "Distribution utilities" +optional = false +python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, +] + [[package]] name = "distro" version = "1.9.0" @@ -461,6 +662,7 @@ description = "Distro - an OS platform information API" optional = false python-versions = ">=3.6" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, @@ -473,6 +675,7 @@ description = "DNS toolkit" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, @@ -487,6 +690,74 @@ idna = ["idna (>=3.7)"] trio = ["trio (>=0.23)"] wmi = ["wmi (>=1.5.1)"] +[[package]] +name = "dulwich" +version = "0.22.8" +description = "Python Git Library" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "dulwich-0.22.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:546176d18b8cc0a492b0f23f07411e38686024cffa7e9d097ae20512a2e57127"}, + {file = "dulwich-0.22.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d2434dd72b2ae09b653c9cfe6764a03c25cfbd99fbbb7c426f0478f6fb1100f"}, + {file = "dulwich-0.22.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8318bc0921d42e3e69f03716f983a301b5ee4c8dc23c7f2c5bbb28581257a9"}, + {file = "dulwich-0.22.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7a0f96a2a87f3b4f7feae79d2ac6b94107d6b7d827ac08f2f331b88c8f597a1"}, + {file = "dulwich-0.22.8-cp310-cp310-win32.whl", hash = "sha256:432a37b25733202897b8d67cdd641688444d980167c356ef4e4dd15a17a39a24"}, + {file = "dulwich-0.22.8-cp310-cp310-win_amd64.whl", hash = "sha256:f3a15e58dac8b8a76073ddca34e014f66f3672a5540a99d49ef6a9c09ab21285"}, + {file = "dulwich-0.22.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0852edc51cff4f4f62976bdaa1d82f6ef248356c681c764c0feb699bc17d5782"}, + {file = "dulwich-0.22.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:826aae8b64ac1a12321d6b272fc13934d8f62804fda2bc6ae46f93f4380798eb"}, + {file = "dulwich-0.22.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7ae726f923057d36cdbb9f4fb7da0d0903751435934648b13f1b851f0e38ea1"}, + {file = "dulwich-0.22.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6987d753227f55cf75ba29a8dab69d1d83308ce483d7a8c6d223086f7a42e125"}, + {file = "dulwich-0.22.8-cp311-cp311-win32.whl", hash = "sha256:7757b4a2aad64c6f1920082fc1fccf4da25c3923a0ae7b242c08d06861dae6e1"}, + {file = "dulwich-0.22.8-cp311-cp311-win_amd64.whl", hash = "sha256:12b243b7e912011c7225dc67480c313ac8d2990744789b876016fb593f6f3e19"}, + {file = "dulwich-0.22.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d81697f74f50f008bb221ab5045595f8a3b87c0de2c86aa55be42ba97421f3cd"}, + {file = "dulwich-0.22.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bff1da8e2e6a607c3cb45f5c2e652739589fe891245e1d5b770330cdecbde41"}, + {file = "dulwich-0.22.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9969099e15b939d3936f8bee8459eaef7ef5a86cd6173393a17fe28ca3d38aff"}, + {file = "dulwich-0.22.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:017152c51b9a613f0698db28c67cf3e0a89392d28050dbf4f4ac3f657ea4c0dc"}, + {file = "dulwich-0.22.8-cp312-cp312-win32.whl", hash = "sha256:ee70e8bb8798b503f81b53f7a103cb869c8e89141db9005909f79ab1506e26e9"}, + {file = "dulwich-0.22.8-cp312-cp312-win_amd64.whl", hash = "sha256:dc89c6f14dcdcbfee200b0557c59ae243835e42720be143526d834d0e53ed3af"}, + {file = "dulwich-0.22.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbade3342376be1cd2409539fe1b901d2d57a531106bbae204da921ef4456a74"}, + {file = "dulwich-0.22.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71420ffb6deebc59b2ce875e63d814509f9c1dc89c76db962d547aebf15670c7"}, + {file = "dulwich-0.22.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a626adbfac44646a125618266a24133763bdc992bf8bd0702910d67e6b994443"}, + {file = "dulwich-0.22.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f1476c9c4e4ede95714d06c4831883a26680e37b040b8b6230f506e5ba39f51"}, + {file = "dulwich-0.22.8-cp313-cp313-win32.whl", hash = "sha256:b2b31913932bb5bd41658dd398b33b1a2d4d34825123ad54e40912cfdfe60003"}, + {file = "dulwich-0.22.8-cp313-cp313-win_amd64.whl", hash = "sha256:7a44e5a61a7989aca1e301d39cfb62ad2f8853368682f524d6e878b4115d823d"}, + {file = "dulwich-0.22.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9cd0c67fb44a38358b9fcabee948bf11044ef6ce7a129e50962f54c176d084e"}, + {file = "dulwich-0.22.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b79b94726c3f4a9e5a830c649376fd0963236e73142a4290bac6bc9fc9cb120"}, + {file = "dulwich-0.22.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16bbe483d663944972e22d64e1f191201123c3b5580fbdaac6a4f66bfaa4fc11"}, + {file = "dulwich-0.22.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e02d403af23d93dc1f96eb2408e25efd50046e38590a88c86fa4002adc9849b0"}, + {file = "dulwich-0.22.8-cp39-cp39-win32.whl", hash = "sha256:8bdd9543a77fb01be704377f5e634b71f955fec64caa4a493dc3bfb98e3a986e"}, + {file = "dulwich-0.22.8-cp39-cp39-win_amd64.whl", hash = "sha256:3b6757c6b3ba98212b854a766a4157b9cb79a06f4e1b06b46dec4bd834945b8e"}, + {file = "dulwich-0.22.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7bb18fa09daa1586c1040b3e2777d38d4212a5cdbe47d384ba66a1ac336fcc4c"}, + {file = "dulwich-0.22.8-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2fda8e87907ed304d4a5962aea0338366144df0df60f950b8f7f125871707f"}, + {file = "dulwich-0.22.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1748cd573a0aee4d530bc223a23ccb8bb5b319645931a37bd1cfb68933b720c1"}, + {file = "dulwich-0.22.8-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a631b2309feb9a9631eabd896612ba36532e3ffedccace57f183bb868d7afc06"}, + {file = "dulwich-0.22.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:00e7d9a3d324f9e0a1b27880eec0e8e276ff76519621b66c1a429ca9eb3f5a8d"}, + {file = "dulwich-0.22.8-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f8aa3de93201f9e3e40198725389aa9554a4ee3318a865f96a8e9bc9080f0b25"}, + {file = "dulwich-0.22.8-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e8da9dd8135884975f5be0563ede02179240250e11f11942801ae31ac293f37"}, + {file = "dulwich-0.22.8-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fc5ce2435fb3abdf76f1acabe48f2e4b3f7428232cadaef9daaf50ea7fa30ee"}, + {file = "dulwich-0.22.8-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:982b21cc3100d959232cadb3da0a478bd549814dd937104ea50f43694ec27153"}, + {file = "dulwich-0.22.8-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6bde2b13a05cc0ec2ecd4597a99896663544c40af1466121f4d046119b874ce3"}, + {file = "dulwich-0.22.8-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6d446cb7d272a151934ad4b48ba691f32486d5267cf2de04ee3b5e05fc865326"}, + {file = "dulwich-0.22.8-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f6338e6cf95cd76a0191b3637dc3caed1f988ae84d8e75f876d5cd75a8dd81a"}, + {file = "dulwich-0.22.8-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e004fc532ea262f2d5f375068101ca4792becb9d4aa663b050f5ac31fda0bb5c"}, + {file = "dulwich-0.22.8-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bfdbc6fa477dee00d04e22d43a51571cd820cfaaaa886f0f155b8e29b3e3d45"}, + {file = "dulwich-0.22.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ae900c8e573f79d714c1d22b02cdadd50b64286dd7203028f0200f82089e4950"}, + {file = "dulwich-0.22.8-py3-none-any.whl", hash = "sha256:ffc7a02e62b72884de58baaa3b898b7f6427893e79b1289ffa075092efe59181"}, + {file = "dulwich-0.22.8.tar.gz", hash = "sha256:701547310415de300269331abe29cb5717aa1ea377af826bf513d0adfb1c209b"}, +] + +[package.dependencies] +urllib3 = ">=1.25" + +[package.extras] +dev = ["mypy (==1.15.0)", "ruff (==0.9.7)"] +fastimport = ["fastimport"] +https = ["urllib3 (>=1.24.1)"] +paramiko = ["paramiko"] +pgp = ["gpg"] + [[package]] name = "et-xmlfile" version = "2.0.0" @@ -494,6 +765,7 @@ description = "An implementation of lxml.xmlfile for the standard library" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"}, {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"}, @@ -506,6 +778,7 @@ description = "Like `typing._eval_type`, but lets older Python versions use newe optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a"}, {file = "eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1"}, @@ -521,7 +794,7 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -530,6 +803,56 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "fastjsonschema" +version = "2.21.1" +description = "Fastest Python implementation of JSON schema" +optional = false +python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"}, + {file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"}, +] + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + +[[package]] +name = "filelock" +version = "3.18.0" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, + {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] +typing = ["typing-extensions (>=4.12.2)"] + +[[package]] +name = "findpython" +version = "0.6.3" +description = "A utility to find python versions on your system" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "findpython-0.6.3-py3-none-any.whl", hash = "sha256:a85bb589b559cdf1b87227cc233736eb7cad894b9e68021ee498850611939ebc"}, + {file = "findpython-0.6.3.tar.gz", hash = "sha256:5863ea55556d8aadc693481a14ac4f3624952719efc1c5591abb0b4a9e965c94"}, +] + +[package.dependencies] +packaging = ">=20" + [[package]] name = "firecrawl" version = "1.9.0" @@ -537,6 +860,7 @@ description = "Python SDK for Firecrawl API" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "firecrawl-1.9.0-py3-none-any.whl", hash = "sha256:9c0931242048ddd86e85631db439011fa0545cbcca21f7c41c89d13116bb2187"}, {file = "firecrawl-1.9.0.tar.gz", hash = "sha256:8e82d3b288d57bf7c93b9118fb226a84b7c8b84699861e1d36b4791dc87a7435"}, @@ -556,6 +880,7 @@ description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "flask-3.1.0-py3-none-any.whl", hash = "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136"}, {file = "flask-3.1.0.tar.gz", hash = "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac"}, @@ -579,6 +904,7 @@ description = "A list-like structure which implements collections.abc.MutableSeq optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, @@ -681,6 +1007,7 @@ description = "Signatures for entire Python programs. Extract the structure, the optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "griffe-1.6.2-py3-none-any.whl", hash = "sha256:6399f7e663150e4278a312a8e8a14d2f3d7bd86e2ef2f8056a1058e38579c2ee"}, {file = "griffe-1.6.2.tar.gz", hash = "sha256:3a46fa7bd83280909b63c12b9a975732a927dd97809efe5b7972290b606c5d91"}, @@ -696,6 +1023,7 @@ description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "grpcio-1.71.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:c200cb6f2393468142eb50ab19613229dcc7829b5ccee8b658a36005f6669fdd"}, {file = "grpcio-1.71.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b2266862c5ad664a380fbbcdbdb8289d71464c42a8c29053820ee78ba0119e5d"}, @@ -760,6 +1088,7 @@ description = "Protobuf code generator for gRPC" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "grpcio_tools-1.71.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:f4ad7f0d756546902597053d70b3af2606fbd70d7972876cd75c1e241d22ae00"}, {file = "grpcio_tools-1.71.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:64bdb291df61cf570b5256777ad5fe2b1db6d67bc46e55dc56a0a862722ae329"}, @@ -826,6 +1155,7 @@ description = "WSGI HTTP Server for UNIX" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, @@ -848,6 +1178,7 @@ description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -860,6 +1191,7 @@ description = "Pure-Python HTTP/2 protocol implementation" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "h2-4.2.0-py3-none-any.whl", hash = "sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0"}, {file = "h2-4.2.0.tar.gz", hash = "sha256:c8a52129695e88b1a0578d8d2cc6842bbd79128ac685463b887ee278126ad01f"}, @@ -876,6 +1208,7 @@ description = "Pure-Python HPACK header encoding" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496"}, {file = "hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca"}, @@ -888,6 +1221,7 @@ description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, @@ -910,6 +1244,7 @@ description = "The next generation HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, @@ -924,7 +1259,7 @@ idna = "*" sniffio = "*" [package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -937,11 +1272,41 @@ description = "Consume Server-Sent Event (SSE) messages with HTTPX." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"}, {file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"}, ] +[[package]] +name = "hypercorn" +version = "0.17.3" +description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "hypercorn-0.17.3-py3-none-any.whl", hash = "sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547"}, + {file = "hypercorn-0.17.3.tar.gz", hash = "sha256:1b37802ee3ac52d2d85270700d565787ab16cf19e1462ccfa9f089ca17574165"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +h11 = "*" +h2 = ">=3.1.0" +priority = "*" +taskgroup = {version = "*", markers = "python_version < \"3.11\""} +tomli = {version = "*", markers = "python_version < \"3.11\""} +typing_extensions = {version = "*", markers = "python_version < \"3.11\""} +wsproto = ">=0.14.0" + +[package.extras] +docs = ["pydata_sphinx_theme", "sphinxcontrib_mermaid"] +h3 = ["aioquic (>=0.9.0,<1.0)"] +trio = ["trio (>=0.22.0)"] +uvloop = ["uvloop (>=0.18)"] + [[package]] name = "hyperframe" version = "6.1.0" @@ -949,6 +1314,7 @@ description = "Pure-Python HTTP/2 framing" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5"}, {file = "hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08"}, @@ -961,6 +1327,7 @@ description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -969,6 +1336,44 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +[[package]] +name = "importlib-metadata" +version = "8.6.1" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\"" +files = [ + {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, + {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "installer" +version = "0.7.0" +description = "A library for installing Python wheels." +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "installer-0.7.0-py3-none-any.whl", hash = "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53"}, + {file = "installer-0.7.0.tar.gz", hash = "sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631"}, +] + [[package]] name = "itsdangerous" version = "2.2.0" @@ -976,11 +1381,93 @@ description = "Safely pass data to untrusted environments and back." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] +[[package]] +name = "jaraco-classes" +version = "3.4.0" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +description = "Useful decorators and context managers" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, + {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, +] + +[package.dependencies] +"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-functools" +version = "4.1.0" +description = "Functools like those found in stdlib" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"}, + {file = "jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + +[[package]] +name = "jeepney" +version = "0.9.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\") and sys_platform == \"linux\"" +files = [ + {file = "jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683"}, + {file = "jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"}, +] + +[package.extras] +test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["trio"] + [[package]] name = "jinja2" version = "3.1.5" @@ -988,6 +1475,7 @@ description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, @@ -1006,6 +1494,7 @@ description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "jiter-0.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d08510593cb57296851080018006dfc394070178d238b767b1879dc1013b106c"}, {file = "jiter-0.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adef59d5e2394ebbad13b7ed5e0306cceb1df92e2de688824232a91588e77aa7"}, @@ -1089,11 +1578,43 @@ description = "A more powerful JSONPath implementation in modern python" optional = false python-versions = ">=3.6" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "jsonpath-python-1.0.6.tar.gz", hash = "sha256:dd5be4a72d8a2995c3f583cf82bf3cd1a9544cfdabf2d22595b67aff07349666"}, {file = "jsonpath_python-1.0.6-py3-none-any.whl", hash = "sha256:1e3b78df579f5efc23565293612decee04214609208a2335884b3ee3f786b575"}, ] +[[package]] +name = "keyring" +version = "25.6.0" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, + {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, +] + +[package.dependencies] +importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +"jaraco.classes" = "*" +"jaraco.context" = "*" +"jaraco.functools" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +completion = ["shtab (>=1.1.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] +type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"] + [[package]] name = "lxml" version = "5.3.0" @@ -1101,6 +1622,7 @@ description = "Powerful and Pythonic XML processing library combining libxml2/li optional = false python-versions = ">=3.6" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, @@ -1256,6 +1778,7 @@ description = "Convert HTML to markdown." optional = false python-versions = "*" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "markdownify-0.13.1-py3-none-any.whl", hash = "sha256:1d181d43d20902bcc69d7be85b5316ed174d0dda72ff56e14ae4c95a4a407d22"}, {file = "markdownify-0.13.1.tar.gz", hash = "sha256:ab257f9e6bd4075118828a28c9d02f8a4bfeb7421f558834aa79b2dfeb32a098"}, @@ -1272,6 +1795,7 @@ description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -1343,6 +1867,7 @@ description = "Model Context Protocol SDK" optional = false python-versions = ">=3.10" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "mcp-1.5.0-py3-none-any.whl", hash = "sha256:51c3f35ce93cb702f7513c12406bbea9665ef75a08db909200b07da9db641527"}, {file = "mcp-1.5.0.tar.gz", hash = "sha256:5b2766c05e68e01a2034875e250139839498c61792163a7b221fc170c12f5aa9"}, @@ -1363,6 +1888,19 @@ cli = ["python-dotenv (>=1.0.0)", "typer (>=0.12.4)"] rich = ["rich (>=13.9.4)"] ws = ["websockets (>=15.0.1)"] +[[package]] +name = "more-itertools" +version = "10.6.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"}, + {file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"}, +] + [[package]] name = "motor" version = "3.7.0" @@ -1370,6 +1908,7 @@ description = "Non-blocking MongoDB driver for Tornado or asyncio" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "motor-3.7.0-py3-none-any.whl", hash = "sha256:61bdf1afded179f008d423f98066348157686f25a90776ea155db5f47f57d605"}, {file = "motor-3.7.0.tar.gz", hash = "sha256:0dfa1f12c812bd90819c519b78bed626b5a9dbb29bba079ccff2bfa8627e0fec"}, @@ -1385,9 +1924,84 @@ encryption = ["pymongo[encryption] (>=4.5,<5)"] gssapi = ["pymongo[gssapi] (>=4.5,<5)"] ocsp = ["pymongo[ocsp] (>=4.5,<5)"] snappy = ["pymongo[snappy] (>=4.5,<5)"] -test = ["aiohttp (>=3.8.7)", "cffi (>=1.17.0rc1) ; python_version == \"3.13\"", "mockupdb", "pymongo[encryption] (>=4.5,<5)", "pytest (>=7)", "pytest-asyncio", "tornado (>=5)"] +test = ["aiohttp (>=3.8.7)", "cffi (>=1.17.0rc1)", "mockupdb", "pymongo[encryption] (>=4.5,<5)", "pytest (>=7)", "pytest-asyncio", "tornado (>=5)"] zstd = ["pymongo[zstd] (>=4.5,<5)"] +[[package]] +name = "msgpack" +version = "1.1.0" +description = "MessagePack serializer" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, + {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, + {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"}, + {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"}, + {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, + {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, + {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, + {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, + {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, + {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, + {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"}, + {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"}, + {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"}, + {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"}, + {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"}, + {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, +] + [[package]] name = "multidict" version = "6.2.0" @@ -1395,6 +2009,7 @@ description = "multidict implementation" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "multidict-6.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1"}, {file = "multidict-6.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2"}, @@ -1500,6 +2115,7 @@ description = "Type system extensions for programs checked with the mypy type ch optional = false python-versions = ">=3.5" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1512,6 +2128,7 @@ description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -1524,6 +2141,7 @@ description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "numpy-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440"}, {file = "numpy-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab"}, @@ -1589,6 +2207,7 @@ description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "openai-1.68.0-py3-none-any.whl", hash = "sha256:20e279b0f3a78cb4a95f3eab2a180f3ee30c6a196aeebd6bf642a4f88ab85ee1"}, {file = "openai-1.68.0.tar.gz", hash = "sha256:c570c06c9ba10f98b891ac30a3dd7b5c89ed48094c711c7a3f35fb5ade6c0757"}, @@ -1617,6 +2236,7 @@ description = "OpenAI Agents SDK" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "openai_agents-0.0.4-py3-none-any.whl", hash = "sha256:5577c3ee994fe0bd200d7283e4f7a614b3af19afeebcfb07b6ca6039a8a50a5c"}, {file = "openai_agents-0.0.4.tar.gz", hash = "sha256:297e8d5faeca753e1b303d860b7ac94d03a7e10382be738163dc6a10a3b7cc1c"}, @@ -1637,6 +2257,7 @@ description = "A Python library to read/write Excel 2010 xlsx/xlsm files" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"}, {file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"}, @@ -1652,6 +2273,7 @@ description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -1664,6 +2286,7 @@ description = "Powerful data structures for data analysis, time series, and stat optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"}, {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"}, @@ -1744,6 +2367,112 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.9.2)"] +[[package]] +name = "pbs-installer" +version = "2025.3.17" +description = "Installer for Python Build Standalone" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "pbs_installer-2025.3.17-py3-none-any.whl", hash = "sha256:d2b0563b1d5d814e479f3c43d7aee019250f68a0a113d754714fa9a721f83b47"}, + {file = "pbs_installer-2025.3.17.tar.gz", hash = "sha256:dde058f925b989c1d3bd90739c16ffd0e68732f7716e4d1e01ca480d00a67560"}, +] + +[package.dependencies] +httpx = {version = ">=0.27.0,<1", optional = true, markers = "extra == \"download\""} +zstandard = {version = ">=0.21.0", optional = true, markers = "extra == \"install\""} + +[package.extras] +all = ["pbs-installer[download,install]"] +download = ["httpx (>=0.27.0,<1)"] +install = ["zstandard (>=0.21.0)"] + +[[package]] +name = "pkginfo" +version = "1.12.1.2" +description = "Query metadata from sdists / bdists / installed packages." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "pkginfo-1.12.1.2-py3-none-any.whl", hash = "sha256:c783ac885519cab2c34927ccfa6bf64b5a704d7c69afaea583dd9b7afe969343"}, + {file = "pkginfo-1.12.1.2.tar.gz", hash = "sha256:5cd957824ac36f140260964eba3c6be6442a8359b8c48f4adf90210f33a04b7b"}, +] + +[package.extras] +testing = ["pytest", "pytest-cov", "wheel"] + +[[package]] +name = "platformdirs" +version = "4.3.7" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, + {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + +[[package]] +name = "poetry" +version = "2.1.1" +description = "Python dependency management and packaging made easy." +optional = false +python-versions = "<4.0,>=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "poetry-2.1.1-py3-none-any.whl", hash = "sha256:1d433880bd5b401327ddee789ccfe9ff197bf3b0cd240f0bc7cc99c84d14b16c"}, + {file = "poetry-2.1.1.tar.gz", hash = "sha256:d82673865bf13d6cd0dacf28c69a89670456d8df2f9e5da82bfb5f833ba00efc"}, +] + +[package.dependencies] +build = ">=1.2.1,<2.0.0" +cachecontrol = {version = ">=0.14.0,<0.15.0", extras = ["filecache"]} +cleo = ">=2.1.0,<3.0.0" +dulwich = ">=0.22.6,<0.23.0" +fastjsonschema = ">=2.18.0,<3.0.0" +findpython = ">=0.6.2,<0.7.0" +installer = ">=0.7.0,<0.8.0" +keyring = ">=25.1.0,<26.0.0" +packaging = ">=24.0" +pbs-installer = {version = ">=2025.1.6,<2026.0.0", extras = ["download", "install"]} +pkginfo = ">=1.12,<2.0" +platformdirs = ">=3.0.0,<5" +poetry-core = "2.1.1" +pyproject-hooks = ">=1.0.0,<2.0.0" +requests = ">=2.26,<3.0" +requests-toolbelt = ">=1.0.0,<2.0.0" +shellingham = ">=1.5,<2.0" +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.11.4,<1.0.0" +trove-classifiers = ">=2022.5.19" +virtualenv = ">=20.26.6,<21.0.0" +xattr = {version = ">=1.0.0,<2.0.0", markers = "sys_platform == \"darwin\""} + +[[package]] +name = "poetry-core" +version = "2.1.1" +description = "Poetry PEP 517 Build Backend" +optional = false +python-versions = "<4.0,>=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "poetry_core-2.1.1-py3-none-any.whl", hash = "sha256:bc3b0382ab4d00d5d780277fd0aad1580eb4403613b37fc60fec407b5bee1fe6"}, + {file = "poetry_core-2.1.1.tar.gz", hash = "sha256:c1a1f6f00e4254742f40988a8caf665549101cf9991122cd5de1198897768b1a"}, +] + [[package]] name = "portalocker" version = "2.10.1" @@ -1751,6 +2480,7 @@ description = "Wraps the portalocker recipe for easy usage" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, @@ -1764,6 +2494,19 @@ docs = ["sphinx (>=1.7.1)"] redis = ["redis"] tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] +[[package]] +name = "priority" +version = "2.0.0" +description = "A pure-Python implementation of the HTTP/2 priority tree" +optional = false +python-versions = ">=3.6.1" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, + {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, +] + [[package]] name = "propcache" version = "0.3.0" @@ -1771,6 +2514,7 @@ description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, @@ -1879,6 +2623,7 @@ description = "" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "protobuf-5.29.4-cp310-abi3-win32.whl", hash = "sha256:13eb236f8eb9ec34e63fc8b1d6efd2777d062fa6aaa68268fb67cf77f6839ad7"}, {file = "protobuf-5.29.4-cp310-abi3-win_amd64.whl", hash = "sha256:bcefcdf3976233f8a502d265eb65ea740c989bacc6c30a58290ed0e519eb4b8d"}, @@ -1900,6 +2645,7 @@ description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1912,6 +2658,7 @@ description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, @@ -1924,7 +2671,7 @@ typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] +timezone = ["tzdata"] [[package]] name = "pydantic-core" @@ -1933,6 +2680,7 @@ description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -2046,6 +2794,7 @@ description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c"}, {file = "pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585"}, @@ -2067,6 +2816,7 @@ description = "Python driver for MongoDB " optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "pymongo-4.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e699aa68c4a7dea2ab5a27067f7d3e08555f8d2c0dc6a0c8c60cfd9ff2e6a4b1"}, {file = "pymongo-4.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:70645abc714f06b4ad6b72d5bf73792eaad14e3a2cfe29c62a9c81ada69d9e4b"}, @@ -2135,13 +2885,26 @@ dnspython = ">=1.16.0,<3.0.0" [package.extras] aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-autobuild (>=2020.9.1)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"] -encryption = ["certifi ; os_name == \"nt\" or sys_platform == \"darwin\"", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.10.0,<2.0.0)"] -gssapi = ["pykerberos ; os_name != \"nt\"", "winkerberos (>=0.5.0) ; os_name == \"nt\""] -ocsp = ["certifi ; os_name == \"nt\" or sys_platform == \"darwin\"", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] +encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.10.0,<2.0.0)"] +gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] +ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] test = ["pytest (>=8.2)", "pytest-asyncio (>=0.24.0)"] zstd = ["zstandard"] +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +description = "Wrappers to call pyproject.toml-based build backend hooks." +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"}, + {file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"}, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -2149,6 +2912,7 @@ description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -2164,6 +2928,7 @@ description = "Create, read, and update Microsoft Word .docx files." optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe"}, {file = "python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd"}, @@ -2180,6 +2945,7 @@ description = "Read key-value pairs from a .env file and set them as environment optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, @@ -2195,6 +2961,7 @@ description = "World timezone definitions, modern and historical" optional = false python-versions = "*" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, @@ -2207,7 +2974,7 @@ description = "Python for Window Extensions" optional = false python-versions = "*" groups = ["main"] -markers = "platform_system == \"Windows\"" +markers = "(python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\") and platform_system == \"Windows\"" files = [ {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"}, {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"}, @@ -2227,6 +2994,19 @@ files = [ {file = "pywin32-310-cp39-cp39-win_amd64.whl", hash = "sha256:96867217335559ac619f00ad70e513c0fcf84b8a3af9fc2bba3b59b97da70475"}, ] +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\") and sys_platform == \"win32\"" +files = [ + {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, + {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, +] + [[package]] name = "qdrant-client" version = "1.13.3" @@ -2234,6 +3014,7 @@ description = "Client library for the Qdrant vector search engine" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "qdrant_client-1.13.3-py3-none-any.whl", hash = "sha256:f52cacbb936e547d3fceb1aaed3e3c56be0ebfd48e8ea495ea3dbc89c671d1d2"}, {file = "qdrant_client-1.13.3.tar.gz", hash = "sha256:61ca09e07c6d7ac0dfbdeb13dca4fe5f3e08fa430cb0d74d66ef5d023a70adfc"}, @@ -2256,6 +3037,114 @@ urllib3 = ">=1.26.14,<3" fastembed = ["fastembed (==0.5.1)"] fastembed-gpu = ["fastembed-gpu (==0.5.1)"] +[[package]] +name = "rapidfuzz" +version = "3.12.2" +description = "rapid fuzzy string matching" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "rapidfuzz-3.12.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b9a75e0385a861178adf59e86d6616cbd0d5adca7228dc9eeabf6f62cf5b0b1"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6906a7eb458731e3dd2495af1d0410e23a21a2a2b7ced535e6d5cd15cb69afc5"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4b3334a8958b689f292d5ce8a928140ac98919b51e084f04bf0c14276e4c6ba"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:85a54ce30345cff2c79cbcffa063f270ad1daedd0d0c3ff6e541d3c3ba4288cf"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acb63c5072c08058f8995404201a52fc4e1ecac105548a4d03c6c6934bda45a3"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5385398d390c6571f0f2a7837e6ddde0c8b912dac096dc8c87208ce9aaaa7570"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5032cbffa245b4beba0067f8ed17392ef2501b346ae3c1f1d14b950edf4b6115"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:195adbb384d89d6c55e2fd71e7fb262010f3196e459aa2f3f45f31dd7185fe72"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f43b773a4d4950606fb25568ecde5f25280daf8f97b87eb323e16ecd8177b328"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:55a43be0e0fa956a919043c19d19bd988991d15c59f179d413fe5145ed9deb43"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:71cf1ea16acdebe9e2fb62ee7a77f8f70e877bebcbb33b34e660af2eb6d341d9"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a3692d4ab36d44685f61326dca539975a4eda49b2a76f0a3df177d8a2c0de9d2"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-win32.whl", hash = "sha256:09227bd402caa4397ba1d6e239deea635703b042dd266a4092548661fb22b9c6"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:0f05b7b95f9f87254b53fa92048367a8232c26cee7fc8665e4337268c3919def"}, + {file = "rapidfuzz-3.12.2-cp310-cp310-win_arm64.whl", hash = "sha256:6938738e00d9eb6e04097b3f565097e20b0c398f9c58959a2bc64f7f6be3d9da"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e9c4d984621ae17404c58f8d06ed8b025e167e52c0e6a511dfec83c37e9220cd"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f9132c55d330f0a1d34ce6730a76805323a6250d97468a1ca766a883d6a9a25"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b343b6cb4b2c3dbc8d2d4c5ee915b6088e3b144ddf8305a57eaab16cf9fc74"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24081077b571ec4ee6d5d7ea0e49bc6830bf05b50c1005028523b9cd356209f3"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c988a4fc91856260355773bf9d32bebab2083d4c6df33fafeddf4330e5ae9139"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:780b4469ee21cf62b1b2e8ada042941fd2525e45d5fb6a6901a9798a0e41153c"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:edd84b0a323885493c893bad16098c5e3b3005d7caa995ae653da07373665d97"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efa22059c765b3d8778083805b199deaaf643db070f65426f87d274565ddf36a"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:095776b11bb45daf7c2973dd61cc472d7ea7f2eecfa454aef940b4675659b92f"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7e2574cf4aa86065600b664a1ac7b8b8499107d102ecde836aaaa403fc4f1784"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d5a3425a6c50fd8fbd991d8f085ddb504791dae6ef9cc3ab299fea2cb5374bef"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97fb05e1ddb7b71a054040af588b0634214ee87cea87900d309fafc16fd272a4"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-win32.whl", hash = "sha256:b4c5a0413589aef936892fbfa94b7ff6f7dd09edf19b5a7b83896cc9d4e8c184"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:58d9ae5cf9246d102db2a2558b67fe7e73c533e5d769099747921232d88b9be2"}, + {file = "rapidfuzz-3.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:7635fe34246cd241c8e35eb83084e978b01b83d5ef7e5bf72a704c637f270017"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1d982a651253ffe8434d9934ff0c1089111d60502228464721a2a4587435e159"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02e6466caa0222d5233b1f05640873671cd99549a5c5ba4c29151634a1e56080"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e956b3f053e474abae69ac693a52742109d860ac2375fe88e9387d3277f4c96c"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dee7d740a2d5418d4f964f39ab8d89923e6b945850db833e798a1969b19542a"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a057cdb0401e42c84b6516c9b1635f7aedd5e430c6e388bd5f6bcd1d6a0686bb"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dccf8d4fb5b86d39c581a59463c596b1d09df976da26ff04ae219604223d502f"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21d5b3793c6f5aecca595cd24164bf9d3c559e315ec684f912146fc4e769e367"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:46a616c0e13cff2de1761b011e0b14bb73b110182f009223f1453d505c9a975c"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:19fa5bc4301a1ee55400d4a38a8ecf9522b0391fc31e6da5f4d68513fe5c0026"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:544a47190a0d25971658a9365dba7095397b4ce3e897f7dd0a77ca2cf6fa984e"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f21af27c5e001f0ba1b88c36a0936437dfe034c452548d998891c21125eb640f"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b63170d9db00629b5b3f2862114d8d6ee19127eaba0eee43762d62a25817dbe0"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-win32.whl", hash = "sha256:6c7152d77b2eb6bfac7baa11f2a9c45fd5a2d848dbb310acd0953b3b789d95c9"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-win_amd64.whl", hash = "sha256:1a314d170ee272ac87579f25a6cf8d16a031e1f7a7b07663434b41a1473bc501"}, + {file = "rapidfuzz-3.12.2-cp312-cp312-win_arm64.whl", hash = "sha256:d41e8231326e94fd07c4d8f424f6bed08fead6f5e6688d1e6e787f1443ae7631"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:941f31038dba5d3dedcfcceba81d61570ad457c873a24ceb13f4f44fcb574260"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fe2dfc454ee51ba168a67b1e92b72aad251e45a074972cef13340bbad2fd9438"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78fafaf7f5a48ee35ccd7928339080a0136e27cf97396de45259eca1d331b714"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0c7989ff32c077bb8fd53253fd6ca569d1bfebc80b17557e60750e6909ba4fe"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96fa00bc105caa34b6cd93dca14a29243a3a7f0c336e4dcd36348d38511e15ac"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bccfb30c668620c5bc3490f2dc7d7da1cca0ead5a9da8b755e2e02e2ef0dff14"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f9b0adc3d894beb51f5022f64717b6114a6fabaca83d77e93ac7675911c8cc5"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:32691aa59577f42864d5535cb6225d0f47e2c7bff59cf4556e5171e96af68cc1"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:758b10380ad34c1f51753a070d7bb278001b5e6fcf544121c6df93170952d705"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:50a9c54c0147b468363119132d514c5024fbad1ed8af12bd8bd411b0119f9208"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e3ceb87c11d2d0fbe8559bb795b0c0604b84cfc8bb7b8720b5c16e9e31e00f41"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f7c9a003002434889255ff5676ca0f8934a478065ab5e702f75dc42639505bba"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-win32.whl", hash = "sha256:cf165a76870cd875567941cf861dfd361a0a6e6a56b936c5d30042ddc9def090"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-win_amd64.whl", hash = "sha256:55bcc003541f5f16ec0a73bf6de758161973f9e8d75161954380738dd147f9f2"}, + {file = "rapidfuzz-3.12.2-cp313-cp313-win_arm64.whl", hash = "sha256:69f6ecdf1452139f2b947d0c169a605de578efdb72cbb2373cb0a94edca1fd34"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c852cd8bed1516a64fd6e2d4c6f270d4356196ee03fda2af1e5a9e13c34643"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42e7f747b55529a6d0d1588695d71025e884ab48664dca54b840413dea4588d8"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a749fd2690f24ef256b264a781487746bbb95344364fe8fe356f0eef7ef206ba"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a11e1d036170bbafa43a9e63d8c309273564ec5bdfc5439062f439d1a16965a"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dfb337f1832c1231e3d5621bd0ebebb854e46036aedae3e6a49c1fc08f16f249"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e88c6e68fca301722fa3ab7fd3ca46998012c14ada577bc1e2c2fc04f2067ca6"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17e1a3a8b4b5125cfb63a6990459b25b87ea769bdaf90d05bb143f8febef076a"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b9f8177b24ccc0a843e85932b1088c5e467a7dd7a181c13f84c684b796bea815"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6c506bdc2f304051592c0d3b0e82eed309248ec10cdf802f13220251358375ea"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:30bf15c1ecec2798b713d551df17f23401a3e3653ad9ed4e83ad1c2b06e86100"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:bd9a67cfc83e8453ef17ddd1c2c4ce4a74d448a197764efb54c29f29fb41f611"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7a6eaec2ef658dd650c6eb9b36dff7a361ebd7d8bea990ce9d639b911673b2cb"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-win32.whl", hash = "sha256:d7701769f110332cde45c41759cb2a497de8d2dca55e4c519a46aed5fbb19d1a"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-win_amd64.whl", hash = "sha256:296bf0fd4f678488670e262c87a3e4f91900b942d73ae38caa42a417e53643b1"}, + {file = "rapidfuzz-3.12.2-cp39-cp39-win_arm64.whl", hash = "sha256:7957f5d768de14f6b2715303ccdf224b78416738ee95a028a2965c95f73afbfb"}, + {file = "rapidfuzz-3.12.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5fd3ce849b27d063755829cda27a9dab6dbd63be3801f2a40c60ec563a4c90f"}, + {file = "rapidfuzz-3.12.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:54e53662d71ed660c83c5109127c8e30b9e607884b7c45d2aff7929bbbd00589"}, + {file = "rapidfuzz-3.12.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b9e43cf2213e524f3309d329f1ad8dbf658db004ed44f6ae1cd2919aa997da5"}, + {file = "rapidfuzz-3.12.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29ca445e320e5a8df3bd1d75b4fa4ecfa7c681942b9ac65b55168070a1a1960e"}, + {file = "rapidfuzz-3.12.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83eb7ef732c2f8533c6b5fbe69858a722c218acc3e1fc190ab6924a8af7e7e0e"}, + {file = "rapidfuzz-3.12.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:648adc2dd2cf873efc23befcc6e75754e204a409dfa77efd0fea30d08f22ef9d"}, + {file = "rapidfuzz-3.12.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b1e6f48e1ffa0749261ee23a1c6462bdd0be5eac83093f4711de17a42ae78ad"}, + {file = "rapidfuzz-3.12.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:1ae9ded463f2ca4ba1eb762913c5f14c23d2e120739a62b7f4cc102eab32dc90"}, + {file = "rapidfuzz-3.12.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dda45f47b559be72ecbce45c7f71dc7c97b9772630ab0f3286d97d2c3025ab71"}, + {file = "rapidfuzz-3.12.2-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3745c6443890265513a3c8777f2de4cb897aeb906a406f97741019be8ad5bcc"}, + {file = "rapidfuzz-3.12.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d3ef4f047ed1bc96fa29289f9e67a637ddca5e4f4d3dc7cb7f50eb33ec1664"}, + {file = "rapidfuzz-3.12.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:54bb69ebe5ca0bd7527357e348f16a4c0c52fe0c2fcc8a041010467dcb8385f7"}, + {file = "rapidfuzz-3.12.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3f2ddd5b99b254039a8c82be5749d4d75943f62eb2c2918acf6ffd586852834f"}, + {file = "rapidfuzz-3.12.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8117dab9b26a1aaffab59b4e30f80ac4d55e61ad4139a637c149365960933bee"}, + {file = "rapidfuzz-3.12.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40c0f16d62d6553527de3dab2fb69709c4383430ea44bce8fb4711ed4cbc6ae3"}, + {file = "rapidfuzz-3.12.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f177e1eb6e4f5261a89c475e21bce7a99064a8f217d2336fb897408f46f0ceaf"}, + {file = "rapidfuzz-3.12.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df0cecc2852fcb078ed1b4482fac4fc2c2e7787f3edda8920d9a4c0f51b1c95"}, + {file = "rapidfuzz-3.12.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b3c4df0321df6f8f0b61afbaa2ced9622750ee1e619128db57a18533d139820"}, + {file = "rapidfuzz-3.12.2.tar.gz", hash = "sha256:b0ba1ccc22fff782e7152a3d3d0caca44ec4e32dc48ba01c560b8593965b5aa3"}, +] + +[package.extras] +all = ["numpy"] + [[package]] name = "redis" version = "5.2.1" @@ -2263,6 +3152,7 @@ description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"}, {file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"}, @@ -2282,6 +3172,7 @@ description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -2297,6 +3188,39 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "secretstorage" +version = "3.3.3" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\") and sys_platform == \"linux\"" +files = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + [[package]] name = "setuptools" version = "75.8.0" @@ -2304,19 +3228,33 @@ description = "Easily download, build, install, upgrade, and uninstall Python pa optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] -core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] [[package]] name = "six" @@ -2325,6 +3263,7 @@ description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2337,6 +3276,7 @@ description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -2349,6 +3289,7 @@ description = "Play and Record Sound with Python" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "sounddevice-0.5.1-py3-none-any.whl", hash = "sha256:e2017f182888c3f3c280d9fbac92e5dbddac024a7e3442f6e6116bd79dab8a9c"}, {file = "sounddevice-0.5.1-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d16cb23d92322526a86a9490c427bf8d49e273d9ccc0bd096feecd229cde6031"}, @@ -2370,6 +3311,7 @@ description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, @@ -2382,6 +3324,7 @@ description = "SSE plugin for Starlette" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99"}, {file = "sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419"}, @@ -2402,6 +3345,7 @@ description = "The little ASGI library that shines." optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227"}, {file = "starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230"}, @@ -2420,6 +3364,7 @@ description = "Pretty-print tabular data" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, @@ -2428,6 +3373,79 @@ files = [ [package.extras] widechars = ["wcwidth"] +[[package]] +name = "taskgroup" +version = "0.2.2" +description = "backport of asyncio.TaskGroup, asyncio.Runner and asyncio.timeout" +optional = false +python-versions = "*" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "taskgroup-0.2.2-py2.py3-none-any.whl", hash = "sha256:e2c53121609f4ae97303e9ea1524304b4de6faf9eb2c9280c7f87976479a52fb"}, + {file = "taskgroup-0.2.2.tar.gz", hash = "sha256:078483ac3e78f2e3f973e2edbf6941374fbea81b9c5d0a96f51d297717f4752d"}, +] + +[package.dependencies] +exceptiongroup = "*" +typing_extensions = ">=4.12.2,<5" + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.2" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, +] + [[package]] name = "tqdm" version = "4.67.1" @@ -2435,6 +3453,7 @@ description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -2450,6 +3469,19 @@ notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] +[[package]] +name = "trove-classifiers" +version = "2025.3.19.19" +description = "Canonical source for classifiers on PyPI (pypi.org)." +optional = false +python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "trove_classifiers-2025.3.19.19-py3-none-any.whl", hash = "sha256:5fc02770ecd81588a605ac98b9d85d50a5a3f9daa30af2a6b1361a1999d75d07"}, + {file = "trove_classifiers-2025.3.19.19.tar.gz", hash = "sha256:98e9d396fe908d5f43b7454fa4c43d17cd0fdadf046f45fb38a5e3af8d959ecd"}, +] + [[package]] name = "types-requests" version = "2.32.0.20250306" @@ -2457,6 +3489,7 @@ description = "Typing stubs for requests" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "types_requests-2.32.0.20250306-py3-none-any.whl", hash = "sha256:25f2cbb5c8710b2022f8bbee7b2b66f319ef14aeea2f35d80f18c9dbf3b60a0b"}, {file = "types_requests-2.32.0.20250306.tar.gz", hash = "sha256:0962352694ec5b2f95fda877ee60a159abdf84a0fc6fdace599f20acb41a03d1"}, @@ -2472,6 +3505,7 @@ description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -2484,6 +3518,7 @@ description = "Runtime inspection utilities for typing module." optional = false python-versions = "*" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, @@ -2500,6 +3535,7 @@ description = "Provider of IANA time zone data" optional = false python-versions = ">=2" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, @@ -2512,13 +3548,14 @@ description = "HTTP library with thread-safe connection pooling, file post, and optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2530,6 +3567,7 @@ description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, @@ -2541,7 +3579,29 @@ h11 = ">=0.8" typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] -standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "virtualenv" +version = "20.29.3" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170"}, + {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "waitress" @@ -2550,6 +3610,7 @@ description = "Waitress WSGI server" optional = false python-versions = ">=3.7.0" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "waitress-2.1.2-py3-none-any.whl", hash = "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a"}, {file = "waitress-2.1.2.tar.gz", hash = "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba"}, @@ -2566,6 +3627,7 @@ description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, @@ -2662,6 +3724,7 @@ description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, @@ -2680,6 +3743,7 @@ description = "A built-package format for Python" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, @@ -2688,6 +3752,109 @@ files = [ [package.extras] test = ["pytest (>=6.0.0)", "setuptools (>=65)"] +[[package]] +name = "wsproto" +version = "1.2.0" +description = "WebSockets state-machine based protocol implementation" +optional = false +python-versions = ">=3.7.0" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, + {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, +] + +[package.dependencies] +h11 = ">=0.9.0,<1" + +[[package]] +name = "xattr" +version = "1.1.4" +description = "Python wrapper for extended filesystem attributes" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "xattr-1.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:acb85b6249e9f3ea10cbb56df1021d43f4027212f0d004304bc9075dc7f54769"}, + {file = "xattr-1.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1a848ab125c0fafdc501ccd83b4c9018bba576a037a4ca5960a22f39e295552e"}, + {file = "xattr-1.1.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:467ee77471d26ae5187ee7081b82175b5ca56ead4b71467ec2e6119d1b08beed"}, + {file = "xattr-1.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fd35f46cb0154f7033f9d5d0960f226857acb0d1e0d71fd7af18ed84663007c"}, + {file = "xattr-1.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d956478e9bb98a1efd20ebc6e5703497c1d2d690d5a13c4df4abf59881eed50"}, + {file = "xattr-1.1.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f25dfdcd974b700fb04a40e14a664a80227ee58e02ea062ac241f0d7dc54b4e"}, + {file = "xattr-1.1.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33b63365c1fcbc80a79f601575bac0d6921732e0245b776876f3db3fcfefe22d"}, + {file = "xattr-1.1.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:544542be95c9b49e211f0a463758f200de88ba6d5a94d3c4f42855a484341acd"}, + {file = "xattr-1.1.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac14c9893f3ea046784b7702be30889b200d31adcd2e6781a8a190b6423f9f2d"}, + {file = "xattr-1.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bb4bbe37ba95542081890dd34fa5347bef4651e276647adaa802d5d0d7d86452"}, + {file = "xattr-1.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3da489ecef798705f9a39ea8cea4ead0d1eeed55f92c345add89740bd930bab6"}, + {file = "xattr-1.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:798dd0cbe696635a6f74b06fc430818bf9c3b24314e1502eadf67027ab60c9b0"}, + {file = "xattr-1.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2b6361626efad5eb5a6bf8172c6c67339e09397ee8140ec41258737bea9681"}, + {file = "xattr-1.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7fa20a0c9ce022d19123b1c5b848d00a68b837251835a7929fe041ee81dcd0"}, + {file = "xattr-1.1.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e20eeb08e2c57fc7e71f050b1cfae35cbb46105449853a582bf53fd23c5379e"}, + {file = "xattr-1.1.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:477370e75821bded901487e5e752cffe554d1bd3bd4839b627d4d1ee8c95a093"}, + {file = "xattr-1.1.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a8682091cd34a9f4a93c8aaea4101aae99f1506e24da00a3cc3dd2eca9566f21"}, + {file = "xattr-1.1.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2e079b3b1a274ba2121cf0da38bbe5c8d2fb1cc49ecbceb395ce20eb7d69556d"}, + {file = "xattr-1.1.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ae6579dea05bf9f335a082f711d5924a98da563cac72a2d550f5b940c401c0e9"}, + {file = "xattr-1.1.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd6038ec9df2e67af23c212693751481d5f7e858156924f14340376c48ed9ac7"}, + {file = "xattr-1.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:608b2877526674eb15df4150ef4b70b7b292ae00e65aecaae2f192af224be200"}, + {file = "xattr-1.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54dad1a6a998c6a23edfd25e99f4d38e9b942d54e518570044edf8c767687ea"}, + {file = "xattr-1.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0dab6ff72bb2b508f3850c368f8e53bd706585012676e1f71debba3310acde8"}, + {file = "xattr-1.1.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a3c54c6af7cf09432b2c461af257d5f4b1cb2d59eee045f91bacef44421a46d"}, + {file = "xattr-1.1.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e346e05a158d554639fbf7a0db169dc693c2d2260c7acb3239448f1ff4a9d67f"}, + {file = "xattr-1.1.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3ff6d9e2103d0d6e5fcd65b85a2005b66ea81c0720a37036445faadc5bbfa424"}, + {file = "xattr-1.1.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7a2ee4563c6414dfec0d1ac610f59d39d5220531ae06373eeb1a06ee37cd193f"}, + {file = "xattr-1.1.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878df1b38cfdadf3184ad8c7b0f516311128d5597b60ac0b3486948953658a83"}, + {file = "xattr-1.1.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c9b8350244a1c5454f93a8d572628ff71d7e2fc2f7480dcf4c4f0e8af3150fe"}, + {file = "xattr-1.1.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a46bf48fb662b8bd745b78bef1074a1e08f41a531168de62b5d7bd331dadb11a"}, + {file = "xattr-1.1.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83fc3c07b583777b1dda6355329f75ca6b7179fe0d1002f1afe0ef96f7e3b5de"}, + {file = "xattr-1.1.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6308b19cff71441513258699f0538394fad5d66e1d324635207a97cb076fd439"}, + {file = "xattr-1.1.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48c00ddc15ddadc9c729cd9504dabf50adb3d9c28f647d4ac9a3df45a046b1a0"}, + {file = "xattr-1.1.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a06136196f26293758e1b244200b73156a0274af9a7349fa201c71c7af3bb9e8"}, + {file = "xattr-1.1.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8fc2631a3c6cfcdc71f7f0f847461839963754e76a2015de71e7e71e3304abc0"}, + {file = "xattr-1.1.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d6e1e835f9c938d129dd45e7eb52ebf7d2d6816323dab93ce311bf331f7d2328"}, + {file = "xattr-1.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:60dea2d369a6484e8b7136224fc2971e10e2c46340d83ab780924afe78c90066"}, + {file = "xattr-1.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85c2b778b09d919523f80f244d799a142302582d76da18903dc693207c4020b0"}, + {file = "xattr-1.1.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ee0abba9e1b890d39141714ff43e9666864ca635ea8a5a2194d989e6b17fe862"}, + {file = "xattr-1.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e4174ba7f51f46b95ea7918d907c91cd579575d59e6a2f22ca36a0551026737"}, + {file = "xattr-1.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2b05e52e99d82d87528c54c2c5c8c5fb0ba435f85ac6545511aeea136e49925"}, + {file = "xattr-1.1.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a3696fad746be37de34eb73c60ea67144162bd08106a5308a90ce9dea9a3287"}, + {file = "xattr-1.1.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a3a7149439a26b68904c14fdc4587cde4ac7d80303e9ff0fefcfd893b698c976"}, + {file = "xattr-1.1.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:507b36a126ce900dbfa35d4e2c2db92570c933294cba5d161ecd6a89f7b52f43"}, + {file = "xattr-1.1.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9392b417b54923e031041940d396b1d709df1d3779c6744454e1f1c1f4dad4f5"}, + {file = "xattr-1.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e9f00315e6c02943893b77f544776b49c756ac76960bea7cb8d7e1b96aefc284"}, + {file = "xattr-1.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c8f98775065260140efb348b1ff8d50fd66ddcbf0c685b76eb1e87b380aaffb3"}, + {file = "xattr-1.1.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b471c6a515f434a167ca16c5c15ff34ee42d11956baa749173a8a4e385ff23e7"}, + {file = "xattr-1.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee0763a1b7ceb78ba2f78bee5f30d1551dc26daafcce4ac125115fa1def20519"}, + {file = "xattr-1.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:099e6e9ce7999b403d36d9cf943105a3d25d8233486b54ec9d1b78623b050433"}, + {file = "xattr-1.1.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e56faef9dde8d969f0d646fb6171883693f88ae39163ecd919ec707fbafa85"}, + {file = "xattr-1.1.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:328156d4e594c9ae63e1072503c168849e601a153ad37f0290743544332d6b6f"}, + {file = "xattr-1.1.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a57a55a27c7864d6916344c9a91776afda6c3b8b2209f8a69b79cdba93fbe128"}, + {file = "xattr-1.1.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3c19cdde08b040df1e99d2500bf8a9cff775ab0e6fa162bf8afe6d84aa93ed04"}, + {file = "xattr-1.1.4-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c72667f19d3a9acf324aed97f58861d398d87e42314731e7c6ab3ac7850c971"}, + {file = "xattr-1.1.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:67ae934d75ea2563fc48a27c5945749575c74a6de19fdd38390917ddcb0e4f24"}, + {file = "xattr-1.1.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1b0c348dd8523554dc535540d2046c0c8a535bb086561d8359f3667967b6ca"}, + {file = "xattr-1.1.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22284255d2a8e8f3da195bd8e8d43ce674dbc7c38d38cb6ecfb37fae7755d31f"}, + {file = "xattr-1.1.4-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b38aac5ef4381c26d3ce147ca98fba5a78b1e5bcd6be6755b4908659f2705c6d"}, + {file = "xattr-1.1.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:803f864af528f6f763a5be1e7b1ccab418e55ae0e4abc8bda961d162f850c991"}, + {file = "xattr-1.1.4-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:40354ebfb5cecd60a5fbb9833a8a452d147486b0ffec547823658556625d98b5"}, + {file = "xattr-1.1.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2abaf5d06be3361bfa8e0db2ee123ba8e92beab5bceed5e9d7847f2145a32e04"}, + {file = "xattr-1.1.4-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e638e5ffedc3565242b5fa3296899d35161bad771f88d66277b58f03a1ba9fe"}, + {file = "xattr-1.1.4-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0597e919d116ec39997804288d77bec3777228368efc0f2294b84a527fc4f9c2"}, + {file = "xattr-1.1.4-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee9455c501d19f065527afda974418b3ef7c61e85d9519d122cd6eb3cb7a00"}, + {file = "xattr-1.1.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:89ed62ce430f5789e15cfc1ccabc172fd8b349c3a17c52d9e6c64ecedf08c265"}, + {file = "xattr-1.1.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e25b824f4b9259cd8bb6e83c4873cf8bf080f6e4fa034a02fe778e07aba8d345"}, + {file = "xattr-1.1.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fba66faa0016dfc0af3dd7ac5782b5786a1dfb851f9f3455e266f94c2a05a04"}, + {file = "xattr-1.1.4-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ec4b0c3e0a7bcd103f3cf31dd40c349940b2d4223ce43d384a3548992138ef1"}, + {file = "xattr-1.1.4.tar.gz", hash = "sha256:b7b02ecb2270da5b7e7deaeea8f8b528c17368401c2b9d5f63e91f545b45d372"}, +] + +[package.dependencies] +cffi = ">=1.16.0" + +[package.extras] +test = ["pytest"] + [[package]] name = "yarl" version = "1.18.3" @@ -2695,6 +3862,7 @@ description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" files = [ {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, @@ -2785,7 +3953,142 @@ idna = ">=2.0" multidict = ">=4.0" propcache = ">=0.2.0" +[[package]] +name = "zipp" +version = "3.21.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\"" +files = [ + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[[package]] +name = "zstandard" +version = "0.23.0" +description = "Zstandard bindings for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9"}, + {file = "zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77da4c6bfa20dd5ea25cbf12c76f181a8e8cd7ea231c673828d0386b1740b8dc"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2170c7e0367dde86a2647ed5b6f57394ea7f53545746104c6b09fc1f4223573"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16842b846a8d2a145223f520b7e18b57c8f476924bda92aeee3a88d11cfc391"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:157e89ceb4054029a289fb504c98c6a9fe8010f1680de0201b3eb5dc20aa6d9e"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:203d236f4c94cd8379d1ea61db2fce20730b4c38d7f1c34506a31b34edc87bdd"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dc5d1a49d3f8262be192589a4b72f0d03b72dcf46c51ad5852a4fdc67be7b9e4"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:752bf8a74412b9892f4e5b58f2f890a039f57037f52c89a740757ebd807f33ea"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80080816b4f52a9d886e67f1f96912891074903238fe54f2de8b786f86baded2"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84433dddea68571a6d6bd4fbf8ff398236031149116a7fff6f777ff95cad3df9"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19a2d91963ed9e42b4e8d77cd847ae8381576585bad79dbd0a8837a9f6620a"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:59556bf80a7094d0cfb9f5e50bb2db27fefb75d5138bb16fb052b61b0e0eeeb0"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27d3ef2252d2e62476389ca8f9b0cf2bbafb082a3b6bfe9d90cbcbb5529ecf7c"}, + {file = "zstandard-0.23.0-cp310-cp310-win32.whl", hash = "sha256:5d41d5e025f1e0bccae4928981e71b2334c60f580bdc8345f824e7c0a4c2a813"}, + {file = "zstandard-0.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:519fbf169dfac1222a76ba8861ef4ac7f0530c35dd79ba5727014613f91613d4"}, + {file = "zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e"}, + {file = "zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80a539906390591dd39ebb8d773771dc4db82ace6372c4d41e2d293f8e32b8db"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:445e4cb5048b04e90ce96a79b4b63140e3f4ab5f662321975679b5f6360b90e2"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd30d9c67d13d891f2360b2a120186729c111238ac63b43dbd37a5a40670b8ca"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d20fd853fbb5807c8e84c136c278827b6167ded66c72ec6f9a14b863d809211c"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed1708dbf4d2e3a1c5c69110ba2b4eb6678262028afd6c6fbcc5a8dac9cda68e"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be9b5b8659dff1f913039c2feee1aca499cfbc19e98fa12bc85e037c17ec6ca5"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65308f4b4890aa12d9b6ad9f2844b7ee42c7f7a4fd3390425b242ffc57498f48"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98da17ce9cbf3bfe4617e836d561e433f871129e3a7ac16d6ef4c680f13a839c"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed7d27cb56b3e058d3cf684d7200703bcae623e1dcc06ed1e18ecda39fee003"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b69bb4f51daf461b15e7b3db033160937d3ff88303a7bc808c67bbc1eaf98c78"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:034b88913ecc1b097f528e42b539453fa82c3557e414b3de9d5632c80439a473"}, + {file = "zstandard-0.23.0-cp311-cp311-win32.whl", hash = "sha256:f2d4380bf5f62daabd7b751ea2339c1a21d1c9463f1feb7fc2bdcea2c29c3160"}, + {file = "zstandard-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:62136da96a973bd2557f06ddd4e8e807f9e13cbb0bfb9cc06cfe6d98ea90dfe0"}, + {file = "zstandard-0.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b4567955a6bc1b20e9c31612e615af6b53733491aeaa19a6b3b37f3b65477094"}, + {file = "zstandard-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e172f57cd78c20f13a3415cc8dfe24bf388614324d25539146594c16d78fcc8"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e166f698c5a3e914947388c162be2583e0c638a4703fc6a543e23a88dea3c1"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a289832e520c6bd4dcaad68e944b86da3bad0d339ef7989fb7e88f92e96072"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d50d31bfedd53a928fed6707b15a8dbeef011bb6366297cc435accc888b27c20"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72c68dda124a1a138340fb62fa21b9bf4848437d9ca60bd35db36f2d3345f373"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53dd9d5e3d29f95acd5de6802e909ada8d8d8cfa37a3ac64836f3bc4bc5512db"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6a41c120c3dbc0d81a8e8adc73312d668cd34acd7725f036992b1b72d22c1772"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:40b33d93c6eddf02d2c19f5773196068d875c41ca25730e8288e9b672897c105"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9206649ec587e6b02bd124fb7799b86cddec350f6f6c14bc82a2b70183e708ba"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76e79bc28a65f467e0409098fa2c4376931fd3207fbeb6b956c7c476d53746dd"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66b689c107857eceabf2cf3d3fc699c3c0fe8ccd18df2219d978c0283e4c508a"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9c236e635582742fee16603042553d276cca506e824fa2e6489db04039521e90"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35"}, + {file = "zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d"}, + {file = "zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b"}, + {file = "zstandard-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:576856e8594e6649aee06ddbfc738fec6a834f7c85bf7cadd1c53d4a58186ef9"}, + {file = "zstandard-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38302b78a850ff82656beaddeb0bb989a0322a8bbb1bf1ab10c17506681d772a"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2240ddc86b74966c34554c49d00eaafa8200a18d3a5b6ffbf7da63b11d74ee2"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ef230a8fd217a2015bc91b74f6b3b7d6522ba48be29ad4ea0ca3a3775bf7dd5"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:774d45b1fac1461f48698a9d4b5fa19a69d47ece02fa469825b442263f04021f"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f77fa49079891a4aab203d0b1744acc85577ed16d767b52fc089d83faf8d8ed"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac184f87ff521f4840e6ea0b10c0ec90c6b1dcd0bad2f1e4a9a1b4fa177982ea"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c363b53e257246a954ebc7c488304b5592b9c53fbe74d03bc1c64dda153fb847"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e7792606d606c8df5277c32ccb58f29b9b8603bf83b48639b7aedf6df4fe8171"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0817825b900fcd43ac5d05b8b3079937073d2b1ff9cf89427590718b70dd840"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9da6bc32faac9a293ddfdcb9108d4b20416219461e4ec64dfea8383cac186690"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd7699e8fd9969f455ef2926221e0233f81a2542921471382e77a9e2f2b57f4b"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d477ed829077cd945b01fc3115edd132c47e6540ddcd96ca169facff28173057"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ce8b52c5987b3e34d5674b0ab529a4602b632ebab0a93b07bfb4dfc8f8a33"}, + {file = "zstandard-0.23.0-cp313-cp313-win32.whl", hash = "sha256:a9b07268d0c3ca5c170a385a0ab9fb7fdd9f5fd866be004c4ea39e44edce47dd"}, + {file = "zstandard-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b"}, + {file = "zstandard-0.23.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ef3775758346d9ac6214123887d25c7061c92afe1f2b354f9388e9e4d48acfc"}, + {file = "zstandard-0.23.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4051e406288b8cdbb993798b9a45c59a4896b6ecee2f875424ec10276a895740"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2d1a054f8f0a191004675755448d12be47fa9bebbcffa3cdf01db19f2d30a54"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f83fa6cae3fff8e98691248c9320356971b59678a17f20656a9e59cd32cee6d8"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32ba3b5ccde2d581b1e6aa952c836a6291e8435d788f656fe5976445865ae045"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f146f50723defec2975fb7e388ae3a024eb7151542d1599527ec2aa9cacb152"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bfe8de1da6d104f15a60d4a8a768288f66aa953bbe00d027398b93fb9680b26"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:29a2bc7c1b09b0af938b7a8343174b987ae021705acabcbae560166567f5a8db"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61f89436cbfede4bc4e91b4397eaa3e2108ebe96d05e93d6ccc95ab5714be512"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53ea7cdc96c6eb56e76bb06894bcfb5dfa93b7adcf59d61c6b92674e24e2dd5e"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:a4ae99c57668ca1e78597d8b06d5af837f377f340f4cce993b551b2d7731778d"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:379b378ae694ba78cef921581ebd420c938936a153ded602c4fea612b7eaa90d"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:50a80baba0285386f97ea36239855f6020ce452456605f262b2d33ac35c7770b"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:61062387ad820c654b6a6b5f0b94484fa19515e0c5116faf29f41a6bc91ded6e"}, + {file = "zstandard-0.23.0-cp38-cp38-win32.whl", hash = "sha256:b8c0bd73aeac689beacd4e7667d48c299f61b959475cdbb91e7d3d88d27c56b9"}, + {file = "zstandard-0.23.0-cp38-cp38-win_amd64.whl", hash = "sha256:a05e6d6218461eb1b4771d973728f0133b2a4613a6779995df557f70794fd60f"}, + {file = "zstandard-0.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa014d55c3af933c1315eb4bb06dd0459661cc0b15cd61077afa6489bec63bb"}, + {file = "zstandard-0.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7f0804bb3799414af278e9ad51be25edf67f78f916e08afdb983e74161b916"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb2b1ecfef1e67897d336de3a0e3f52478182d6a47eda86cbd42504c5cbd009a"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:837bb6764be6919963ef41235fd56a6486b132ea64afe5fafb4cb279ac44f259"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1516c8c37d3a053b01c1c15b182f3b5f5eef19ced9b930b684a73bad121addf4"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48ef6a43b1846f6025dde6ed9fee0c24e1149c1c25f7fb0a0585572b2f3adc58"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11e3bf3c924853a2d5835b24f03eeba7fc9b07d8ca499e247e06ff5676461a15"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2fb4535137de7e244c230e24f9d1ec194f61721c86ebea04e1581d9d06ea1269"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c24f21fa2af4bb9f2c492a86fe0c34e6d2c63812a839590edaf177b7398f700"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8c86881813a78a6f4508ef9daf9d4995b8ac2d147dcb1a450448941398091c9"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe3b385d996ee0822fd46528d9f0443b880d4d05528fd26a9119a54ec3f91c69"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:82d17e94d735c99621bf8ebf9995f870a6b3e6d14543b99e201ae046dfe7de70"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c7c517d74bea1a6afd39aa612fa025e6b8011982a0897768a2f7c8ab4ebb78a2"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fd7e0f1cfb70eb2f95a19b472ee7ad6d9a0a992ec0ae53286870c104ca939e5"}, + {file = "zstandard-0.23.0-cp39-cp39-win32.whl", hash = "sha256:43da0f0092281bf501f9c5f6f3b4c975a8a0ea82de49ba3f7100e64d422a1274"}, + {file = "zstandard-0.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:f8346bfa098532bc1fb6c7ef06783e969d87a99dd1d2a5a18a892c1d7a643c58"}, + {file = "zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09"}, +] + +[package.dependencies] +cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""} + +[package.extras] +cffi = ["cffi (>=1.11)"] + [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "53c4530e6aa4fdf17ea0c0497db2d4cfe1c5350279c442bee03520c063d62f62" +content-hash = "fc7b2d64a9f856b5a0c1aceb6be83ac18f8f9c6f95b8db63b28e69d385dcd38b" diff --git a/apps/rowboat_agents/pyproject.toml b/apps/rowboat_agents/pyproject.toml new file mode 100644 index 00000000..42334612 --- /dev/null +++ b/apps/rowboat_agents/pyproject.toml @@ -0,0 +1,109 @@ +[tool.poetry] +name = "agents" +version = "0.1.0" +description = "RowBoat Labs Agent OS" +authors = ["Akhilesh "] +license = "MIT" +readme = "README.md" +homepage = "https://github.com/rowboatlabs/agents" +package-mode = false + +[tool.poetry.dependencies] +python = ">=3.10,<4.0" + +# Dependencies +aiohttp = "^3.9.3" +annotated-types = "^0.7.0" +anyio = "^4.8.0" +asgiref = "*" +beautifulsoup4 = "^4.12.3" +blinker = "^1.9.0" +build = "1.2.2.post1" +CacheControl = "^0.14.2" +certifi = "^2024.12.14" +cffi = "^1.17.1" +charset-normalizer = "^3.4.1" +cleo = "^2.1.0" +click = "^8.1.8" +crashtest = "^0.4.1" +distlib = "^0.3.9" +distro = "^1.9.0" +dnspython = "^2.7.0" +dulwich = "^0.22.7" +et_xmlfile = "^2.0.0" +eval_type_backport = "^0.2.2" +fastjsonschema = "^2.21.1" +filelock = "^3.17.0" +firecrawl = "^1.9.0" +Flask = "^3.1.0" +gunicorn = "^23.0.0" +h11 = "^0.14.0" +httpcore = "^1.0.7" +httpx = "^0.27.2" +hypercorn = "*" +idna = "^3.10" +installer = "^0.7.0" +itsdangerous = "^2.2.0" +"jaraco.classes" = "^3.4.0" +"jaraco.context" = "^6.0.1" +"jaraco.functools" = "^4.1.0" +Jinja2 = "^3.1.5" +jiter = "^0.6.1" +jsonpath-python = "^1.0.6" +keyring = "^25.6.0" +lxml = "^5.3.0" +markdownify = "^0.13.1" +MarkupSafe = "^3.0.2" +mcp = "*" +more-itertools = "^10.6.0" +motor = "*" +msgpack = "^1.1.0" +mypy-extensions = "^1.0.0" +nest-asyncio = "^1.6.0" +numpy = "^2.2.1" +openai = "*" +openai-agents = "*" +openpyxl = "^3.1.5" +packaging = "^24.2" +pandas = "^2.2.3" +pkginfo = "^1.12.0" +platformdirs = "^4.3.6" +poetry = "^2.0.1" +poetry-core = "^2.0.1" +pycparser = "^2.22" +pydantic = "^2.10.5" +pydantic_core = "^2.27.2" +pymongo = "^4.10.1" +pyproject_hooks = "^1.2.0" +python-dateutil = "^2.9.0.post0" +python-docx = "^1.1.2" +python-dotenv = "^1.0.1" +pytz = "^2024.2" +qdrant-client = "*" +RapidFuzz = "^3.11.0" +redis = "^5.2.1" +requests = "^2.32.3" +requests-toolbelt = "^1.0.0" +setuptools = "^75.8.0" +shellingham = "^1.5.4" +six = "^1.17.0" +sniffio = "^1.3.1" +soupsieve = "^2.6" +tabulate = "^0.9.0" +tomlkit = "^0.13.2" +tqdm = "^4.67.1" +trove-classifiers = "^2025.1.15.22" +typing-inspect = "^0.9.0" +typing_extensions = "^4.12.2" +tzdata = "^2024.2" +urllib3 = "^2.3.0" +virtualenv = "^20.29.1" +waitress = "^2.1.2" +websockets = "^13.1" +Werkzeug = "^3.1.3" +wheel = "^0.44.0" +xattr = "^1.1.4" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/apps/agents/requirements.txt b/apps/rowboat_agents/requirements.txt similarity index 94% rename from apps/agents/requirements.txt rename to apps/rowboat_agents/requirements.txt index 5bb4b2fd..a7035d18 100644 --- a/apps/agents/requirements.txt +++ b/apps/rowboat_agents/requirements.txt @@ -1,6 +1,7 @@ aiohttp==3.9.3 annotated-types==0.7.0 anyio==4.8.0 +asgiref beautifulsoup4==4.12.3 blinker==1.9.0 build==1.2.2.post1 @@ -25,6 +26,7 @@ gunicorn==23.0.0 h11==0.14.0 httpcore==1.0.7 httpx==0.27.2 +hypercorn idna==3.10 installer==0.7.0 itsdangerous==2.2.0 @@ -40,12 +42,13 @@ markdownify==0.13.1 MarkupSafe==3.0.2 mcp more-itertools==10.6.0 +motor msgpack==1.1.0 mypy-extensions==1.0.0 nest-asyncio==1.6.0 numpy==2.2.1 -openai==1.59.7 -openai-agents==0.0.4 +openai +openai-agents openpyxl==3.1.5 packaging==24.2 pandas==2.2.3 @@ -62,7 +65,9 @@ python-dateutil==2.9.0.post0 python-docx==1.1.2 python-dotenv==1.0.1 pytz==2024.2 +qdrant-client RapidFuzz==3.11.0 +redis==5.2.1 requests==2.32.3 requests-toolbelt==1.0.0 setuptools==75.8.0 @@ -83,4 +88,4 @@ waitress==2.1.2 websockets==13.1 Werkzeug==3.1.3 wheel==0.44.0 -xattr==1.1.4 +xattr==1.1.4 \ No newline at end of file diff --git a/apps/agents/src/__init__.py b/apps/rowboat_agents/src/__init__.py similarity index 100% rename from apps/agents/src/__init__.py rename to apps/rowboat_agents/src/__init__.py diff --git a/apps/agents/src/app/__init__.py b/apps/rowboat_agents/src/app/__init__.py similarity index 100% rename from apps/agents/src/app/__init__.py rename to apps/rowboat_agents/src/app/__init__.py diff --git a/apps/rowboat_agents/src/app/main.py b/apps/rowboat_agents/src/app/main.py new file mode 100644 index 00000000..ccc65d45 --- /dev/null +++ b/apps/rowboat_agents/src/app/main.py @@ -0,0 +1,200 @@ +from flask import Flask, request, jsonify, Response +from datetime import datetime +from functools import wraps +import os +import redis +import uuid +import json +import asyncio +from hypercorn.config import Config +from hypercorn.asyncio import serve + +from src.graph.core import run_turn, run_turn_streamed +from src.graph.tools import RAG_TOOL, CLOSE_CHAT_TOOL +from src.utils.common import common_logger, read_json_from_file + +from pprint import pprint + +logger = common_logger +redis_client = redis.from_url(os.environ.get('REDIS_URL', 'redis://localhost:6379')) +app = Flask(__name__) + +@app.route("/health", methods=["GET"]) +def health(): + return jsonify({"status": "ok"}) + +@app.route("/") +def home(): + return "Hello, World!" + +def require_api_key(f): + @wraps(f) + def decorated(*args, **kwargs): + auth_header = request.headers.get('Authorization') + if not auth_header or not auth_header.startswith('Bearer '): + return jsonify({'error': 'Missing or invalid authorization header'}), 401 + + token = auth_header.split('Bearer ')[1] + actual = os.environ.get('API_KEY', '').strip() + if actual and token != actual: + return jsonify({'error': 'Invalid API key'}), 403 + + return f(*args, **kwargs) + return decorated + +@app.route("/chat", methods=["POST"]) +@require_api_key +def chat(): + logger.info('='*100) + logger.info(f"{'*'*100}Running server mode{'*'*100}") + try: + data = request.get_json() + logger.info('Complete request:') + logger.info(data) + logger.info('-'*100) + + start_time = datetime.now() + config = read_json_from_file("./configs/default_config.json") + + logger.info('Beginning turn') + resp_messages, resp_tokens_used, resp_state = run_turn( + messages=data.get("messages", []), + start_agent_name=data.get("startAgent", ""), + agent_configs=data.get("agents", []), + tool_configs=data.get("tools", []), + start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), + state=data.get("state", {}), + additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], + complete_request=data + ) + + logger.info('-'*100) + logger.info('Raw output:') + logger.info((resp_messages, resp_tokens_used, resp_state)) + + out = { + "messages": resp_messages, + "tokens_used": resp_tokens_used, + "state": resp_state, + } + + logger.info("Output:") + for k, v in out.items(): + logger.info(f"{k}: {v}") + logger.info('*'*100) + + logger.info('='*100) + logger.info(f"Processing time: {datetime.now() - start_time}") + + return jsonify(out) + + except Exception as e: + logger.error(f"Error: {e}") + return jsonify({"error": str(e)}), 500 + +@app.route("/chat_stream_init", methods=["POST"]) +@require_api_key +def chat_stream_init(): + # create a uuid for the stream + stream_id = str(uuid.uuid4()) + + # store the request data in redis with 10 minute TTL + data = request.get_json() + redis_client.setex(f"stream_request_{stream_id}", 600, json.dumps(data)) + + return jsonify({"stream_id": stream_id}) + +@app.route("/chat_stream/", methods=["GET"]) +@require_api_key +def chat_stream(stream_id): + # get the request data from redis + request_data = redis_client.get(f"stream_request_{stream_id}") + if not request_data: + return jsonify({"error": "Stream not found"}), 404 + + request_data = json.loads(request_data) + config = read_json_from_file("./configs/default_config.json") + + # Preprocess messages to handle null content and role issues + for msg in request_data["messages"]: + # Handle null content in assistant messages with tool calls + if (msg.get("role") == "assistant" and + msg.get("content") is None and + msg.get("tool_calls") is not None and + len(msg.get("tool_calls")) > 0): + msg["content"] = "Calling tool" + + # Handle role issues + if msg.get("role") == "tool": + msg["role"] = "developer" + elif not msg.get("role"): + msg["role"] = "user" + + print('*'*200) + print("Request:") + print('*'*200) + pprint(request_data) + print('='*200) + + + async def process_stream(): + try: + async for event_type, event_data in run_turn_streamed( + messages=request_data.get("messages", []), + start_agent_name=request_data.get("startAgent", ""), + agent_configs=request_data.get("agents", []), + tool_configs=request_data.get("tools", []), + start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), + state=request_data.get("state", {}), + additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], + complete_request=request_data + ): + if event_type == 'message': + print('*'*200) + print("Yielding message:") + print('*'*200) + to_yield = f"event: message\ndata: {json.dumps(event_data)}\n\n" + print(to_yield) + print('='*200) + yield to_yield + elif event_type == 'done': + print('*'*200) + print("Yielding done:") + print('*'*200) + to_yield = f"event: done\ndata: {json.dumps(event_data)}\n\n" + print(to_yield) + print('='*200) + yield to_yield + + except Exception as e: + logger.error(f"Streaming error: {str(e)}") + yield f"event: error\ndata: {json.dumps({'error': str(e)})}\n\n" + + def generate(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + try: + async def get_all_chunks(): + chunks = [] + async for chunk in process_stream(): + chunks.append(chunk) + return chunks + + chunks = loop.run_until_complete(get_all_chunks()) + for chunk in chunks: + yield chunk + + except Exception as e: + logger.error(f"Error in generate: {e}") + raise + finally: + loop.close() + + return Response(generate(), mimetype='text/event-stream') + +if __name__ == "__main__": + print("Starting async server...") + config = Config() + config.bind = ["0.0.0.0:4040"] + asyncio.run(serve(app, config)) \ No newline at end of file diff --git a/apps/agents/src/graph/__init__.py b/apps/rowboat_agents/src/graph/__init__.py similarity index 100% rename from apps/agents/src/graph/__init__.py rename to apps/rowboat_agents/src/graph/__init__.py diff --git a/apps/agents/src/graph/core.py b/apps/rowboat_agents/src/graph/core.py similarity index 58% rename from apps/agents/src/graph/core.py rename to apps/rowboat_agents/src/graph/core.py index e4ef1de1..371e9aee 100644 --- a/apps/agents/src/graph/core.py +++ b/apps/rowboat_agents/src/graph/core.py @@ -1,4 +1,5 @@ from copy import deepcopy +from datetime import datetime import logging from .helpers.access import ( @@ -9,14 +10,14 @@ from .helpers.state import ( construct_state_from_response ) from .helpers.control import get_latest_assistant_msg, get_latest_non_assistant_messages, get_last_agent_name -from .swarm_wrapper import run as swarm_run, create_response, get_agents +from .swarm_wrapper import run as swarm_run, run_streamed as swarm_run_streamed, create_response, get_agents from src.utils.common import common_logger as logger +import asyncio # Create a dedicated logger for swarm wrapper logger.setLevel(logging.INFO) print("Logger level set to INFO") - def order_messages(messages): """ Sorts each message's keys in a specified order and returns a new list of ordered messages. @@ -227,3 +228,140 @@ def run_turn( tokens_used=tokens_used, all_agents=new_agents ) + +async def run_turn_streamed( + messages, + start_agent_name, + agent_configs, + tool_configs, + start_turn_with_start_agent, + state={}, + additional_tool_configs=[], + complete_request={} +): + final_state = None # Initialize outside try block + try: + # Initialize agents and get external tools + new_agents = get_agents(agent_configs=agent_configs, tool_configs=tool_configs, complete_request=complete_request) + last_agent_name = get_last_agent_name( + state=state, + agent_configs=agent_configs, + start_agent_name=start_agent_name, + msg_type="user", + latest_assistant_msg=None, + start_turn_with_start_agent=start_turn_with_start_agent + ) + last_new_agent = get_agent_by_name(last_agent_name, new_agents) + external_tools = get_external_tools(tool_configs) + + current_agent = last_new_agent + tokens_used = {"total": 0, "prompt": 0, "completion": 0} + + stream_result = await swarm_run_streamed( + agent=last_new_agent, + messages=messages, + external_tools=external_tools, + tokens_used=tokens_used + ) + + # Process streaming events + async for event in stream_result.stream_events(): + # print('='*50) + # print("Received event: ", event) + # print('-'*50) + + # Handle raw response events and accumulate tokens + if event.type == "raw_response_event": + if hasattr(event.data, 'type') and event.data.type == "response.completed": + if hasattr(event.data.response, 'usage'): + tokens_used["total"] += event.data.response.usage.total_tokens + tokens_used["prompt"] += event.data.response.usage.input_tokens + tokens_used["completion"] += event.data.response.usage.output_tokens + print('-'*50) + print(f"Found usage information. Updated cumulative tokens: {tokens_used}") + print('-'*50) + continue + + # Update current agent when it changes + elif event.type == "agent_updated_stream_event": + current_agent = event.new_agent + message = { + 'content': f"Agent changed to {current_agent.name}", + 'role': 'assistant', + 'sender': current_agent.name, + 'tool_calls': None, + 'tool_call_id': None, + 'response_type': 'internal' + } + print("Yielding message: ", message) + yield ('message', message) + continue + + # Handle run items (tools, messages, etc) + elif event.type == "run_item_stream_event": + if event.item.type == "tool_call_item": + message = { + 'content': None, + 'role': 'assistant', + 'sender': current_agent.name if current_agent else None, + 'tool_calls': [{ + 'function': { + 'name': event.item.raw_item.name, + 'arguments': event.item.raw_item.arguments + }, + 'id': event.item.raw_item.id, + 'type': 'function' + }], + 'tool_call_id': None, + 'tool_name': None, + 'response_type': 'internal' + } + print("Yielding message: ", message) + yield ('message', message) + + elif event.item.type == "tool_call_output_item": + message = { + 'content': str(event.item.output), + 'role': 'tool', + 'sender': None, + 'tool_calls': None, + 'tool_call_id': event.item.raw_item['call_id'], + 'tool_name': event.item.raw_item.get('name', None), + 'response_type': 'internal' + } + print("Yielding message: ", message) + yield ('message', message) + + elif event.item.type == "message_output_item": + content = "" + if hasattr(event.item.raw_item, 'content'): + for content_item in event.item.raw_item.content: + if hasattr(content_item, 'text'): + content += content_item.text + + message = { + 'content': content, + 'role': 'assistant', + 'sender': current_agent.name, + 'tool_calls': None, + 'tool_call_id': None, + 'tool_name': None, + 'response_type': 'external' + } + print("Yielding message: ", message) + yield ('message', message) + + print(f"\n{'='*50}\n") + + # After all events are processed, set final state + final_state = { + "last_agent_name": current_agent.name if current_agent else None, + "tokens": tokens_used + } + yield ('done', {'state': final_state}) + + except Exception as e: + import traceback + print(traceback.format_exc()) + print(f"Error in stream processing: {str(e)}") + yield ('error', {'error': str(e), 'state': final_state}) # Include final_state in error response \ No newline at end of file diff --git a/apps/agents/src/graph/guardrails.py b/apps/rowboat_agents/src/graph/guardrails.py similarity index 100% rename from apps/agents/src/graph/guardrails.py rename to apps/rowboat_agents/src/graph/guardrails.py diff --git a/apps/agents/src/graph/helpers/access.py b/apps/rowboat_agents/src/graph/helpers/access.py similarity index 100% rename from apps/agents/src/graph/helpers/access.py rename to apps/rowboat_agents/src/graph/helpers/access.py diff --git a/apps/agents/src/graph/helpers/control.py b/apps/rowboat_agents/src/graph/helpers/control.py similarity index 100% rename from apps/agents/src/graph/helpers/control.py rename to apps/rowboat_agents/src/graph/helpers/control.py diff --git a/apps/agents/src/graph/helpers/instructions.py b/apps/rowboat_agents/src/graph/helpers/instructions.py similarity index 100% rename from apps/agents/src/graph/helpers/instructions.py rename to apps/rowboat_agents/src/graph/helpers/instructions.py diff --git a/apps/agents/src/graph/helpers/state.py b/apps/rowboat_agents/src/graph/helpers/state.py similarity index 100% rename from apps/agents/src/graph/helpers/state.py rename to apps/rowboat_agents/src/graph/helpers/state.py diff --git a/apps/agents/src/graph/helpers/transfer.py b/apps/rowboat_agents/src/graph/helpers/transfer.py similarity index 100% rename from apps/agents/src/graph/helpers/transfer.py rename to apps/rowboat_agents/src/graph/helpers/transfer.py diff --git a/apps/agents/src/graph/instructions.py b/apps/rowboat_agents/src/graph/instructions.py similarity index 100% rename from apps/agents/src/graph/instructions.py rename to apps/rowboat_agents/src/graph/instructions.py diff --git a/apps/agents/src/graph/swarm_wrapper.py b/apps/rowboat_agents/src/graph/swarm_wrapper.py similarity index 89% rename from apps/agents/src/graph/swarm_wrapper.py rename to apps/rowboat_agents/src/graph/swarm_wrapper.py index 160e7be3..ea15682e 100644 --- a/apps/agents/src/graph/swarm_wrapper.py +++ b/apps/rowboat_agents/src/graph/swarm_wrapper.py @@ -184,6 +184,7 @@ def get_agents(agent_configs, tool_configs, complete_request): # Create Agent objects from config for agent_config in agent_configs: logger.debug(f"Processing config for agent: {agent_config['name']}") + print("="*100) print(f"Processing config for agent: {agent_config['name']}") # If hasRagSources, append the RAG tool to the agent's tools @@ -199,7 +200,6 @@ def get_agents(agent_configs, tool_configs, complete_request): print(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools") new_tools = [] - print(agent_config) rag_tool = get_rag_tool(agent_config, complete_request) if rag_tool: new_tools.append(rag_tool) @@ -259,6 +259,8 @@ def get_agents(agent_configs, tool_configs, complete_request): # Look up the agent's children from the old agent and create a list called handoffs in new_agent with pointers to the children in new_agents new_agent.handoffs = [new_agents[new_agent_name_to_index[child]] for child in new_agent_to_children[new_agent.name]] + print("Returning created agents") + print("="*100) return new_agents @@ -341,4 +343,49 @@ def run( logger.info(f"Completed Swarm run for agent: {agent.name}") print(f"Completed Swarm run for agent: {agent.name}") - return response \ No newline at end of file + return response + +async def run_streamed( + agent, + messages, + external_tools=None, + tokens_used=None +): + """ + Wrapper function for initializing and running the Swarm client in streaming mode. + """ + logger.info(f"Initializing Swarm streaming client for agent: {agent.name}") + print(f"Initializing Swarm streaming client for agent: {agent.name}") + + # Initialize default parameters + if external_tools is None: + external_tools = [] + if tokens_used is None: + tokens_used = {} + + # Format messages to ensure they're compatible with the OpenAI API + formatted_messages = [] + for msg in messages: + if isinstance(msg, dict) and "content" in msg: + formatted_msg = { + "role": msg.get("role", "user"), + "content": msg["content"] + } + formatted_messages.append(formatted_msg) + else: + formatted_messages.append({ + "role": "user", + "content": str(msg) + }) + + logger.info("Beginning Swarm streaming run") + print("Beginning Swarm streaming run") + + try: + # Use the Runner.run_streamed method + stream_result = Runner.run_streamed(agent, formatted_messages) + return stream_result + except Exception as e: + logger.error(f"Error during streaming run: {str(e)}") + print(f"Error during streaming run: {str(e)}") + raise \ No newline at end of file diff --git a/apps/agents/src/graph/tool_calling.py b/apps/rowboat_agents/src/graph/tool_calling.py similarity index 100% rename from apps/agents/src/graph/tool_calling.py rename to apps/rowboat_agents/src/graph/tool_calling.py diff --git a/apps/agents/src/graph/tools.py b/apps/rowboat_agents/src/graph/tools.py similarity index 100% rename from apps/agents/src/graph/tools.py rename to apps/rowboat_agents/src/graph/tools.py diff --git a/apps/agents/src/graph/types.py b/apps/rowboat_agents/src/graph/types.py similarity index 100% rename from apps/agents/src/graph/types.py rename to apps/rowboat_agents/src/graph/types.py diff --git a/apps/agents/src/utils/__init__.py b/apps/rowboat_agents/src/utils/__init__.py similarity index 100% rename from apps/agents/src/utils/__init__.py rename to apps/rowboat_agents/src/utils/__init__.py diff --git a/apps/agents/src/utils/common.py b/apps/rowboat_agents/src/utils/common.py similarity index 100% rename from apps/agents/src/utils/common.py rename to apps/rowboat_agents/src/utils/common.py diff --git a/apps/agents/tests/__init__.py b/apps/rowboat_agents/tests/__init__.py similarity index 100% rename from apps/agents/tests/__init__.py rename to apps/rowboat_agents/tests/__init__.py diff --git a/apps/agents/tests/app_client.py b/apps/rowboat_agents/tests/app_client.py similarity index 100% rename from apps/agents/tests/app_client.py rename to apps/rowboat_agents/tests/app_client.py diff --git a/apps/rowboat_agents/tests/app_client_streaming.py b/apps/rowboat_agents/tests/app_client_streaming.py new file mode 100644 index 00000000..8759fff7 --- /dev/null +++ b/apps/rowboat_agents/tests/app_client_streaming.py @@ -0,0 +1,174 @@ +from src.utils.common import common_logger, read_json_from_file +import requests +import json +import argparse +from datetime import datetime + +logger = common_logger +logger.info("Running app_client_streaming.py") + +def preprocess_messages(messages): + # Preprocess messages to handle null content and role issues + for msg in messages: + # Handle null content in assistant messages with tool calls + if (msg.get("role") == "assistant" and + msg.get("content") is None and + msg.get("tool_calls") is not None and + len(msg.get("tool_calls")) > 0): + msg["content"] = "Calling tool" + + # Handle role issues + if msg.get("role") == "tool": + msg["role"] = "developer" + elif not msg.get("role"): + msg["role"] = "user" + + return messages + +def stream_chat(host, request_data, api_key): + start_time = datetime.now() + print("\n" + "="*80) + print(f"Starting streaming chat at {start_time}") + print(f"Host: {host}") + print("="*80 + "\n") + + # First, initialize the stream + try: + print("\n" + "-"*80) + print("Initializing stream...") + init_response = requests.post( + f"{host}/chat_stream_init", + json=request_data, + headers={'Authorization': f'Bearer {api_key}'} + ) + print(f"Init Response Status: {init_response.status_code}") + print(f"Init Response Text: {init_response.text}") + print("-"*80 + "\n") + + if init_response.status_code != 200: + logger.error(f"Error initializing stream. Status code: {init_response.status_code}") + logger.error(f"Response: {init_response.text}") + return + + init_data = init_response.json() + + if 'error' in init_data: + logger.error(f"Error initializing stream: {init_data['error']}") + return + + stream_id = init_data['stream_id'] + print(f"Stream initialized successfully with ID: {stream_id}") + + except requests.exceptions.RequestException as e: + logger.error(f"Request error during stream initialization: {e}") + return + except json.JSONDecodeError as e: + logger.error(f"Failed to decode JSON response: {e}") + logger.error(f"Raw response: {init_response.text}") + return + + # Now connect to the stream + try: + print("\n" + "-"*80) + print(f"Connecting to stream {stream_id}...") + stream_response = requests.get( + f"{host}/chat_stream/{stream_id}", + headers={ + 'Authorization': f'Bearer {api_key}', + 'Accept': 'text/event-stream' + }, + stream=True + ) + + if stream_response.status_code != 200: + logger.error(f"Error connecting to stream. Status code: {stream_response.status_code}") + logger.error(f"Response: {stream_response.text}") + return + + print(f"Successfully connected to stream") + print("-"*80 + "\n") + + event_count = 0 + current_data = [] + + try: + print("\n" + "-"*80) + print("Starting to process events...") + print("-"*80 + "\n") + + for line in stream_response.iter_lines(decode_unicode=True): + if line: + if line.startswith('data: '): + data = line[6:] # Remove 'data: ' prefix + try: + event_data = json.loads(data) + event_count += 1 + print("\n" + "*"*80) + print(f"Event #{event_count}") + + if isinstance(event_data, dict): + # Pretty print the event data + print("Event Data:") + print(json.dumps(event_data, indent=2)) + + # Special handling for message events + if 'content' in event_data: + print("\nMessage Content:", event_data['content']) + if event_data.get('tool_calls'): + print("Tool Calls:", json.dumps(event_data['tool_calls'], indent=2)) + else: + print("Event Data:", event_data) + print("*"*80 + "\n") + + except json.JSONDecodeError as e: + print(f"Error decoding event data: {e}") + print(f"Raw data: {data}") + + except Exception as e: + print(f"Error processing stream: {e}") + import traceback + traceback.print_exc() + finally: + print("\n" + "-"*80) + print(f"Closing stream after processing {event_count} events") + print("-"*80 + "\n") + stream_response.close() + + except requests.exceptions.RequestException as e: + print(f"Request error during streaming: {e}") + import traceback + traceback.print_exc() + + end_time = datetime.now() + duration = end_time - start_time + print("\n" + "="*80) + print(f"Streaming session completed at {end_time}") + print(f"Total duration: {duration}") + print("="*80 + "\n") + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--sample_request', type=str, required=False, default='tmp.json', + help='Sample request JSON file name under tests/sample_requests/') + parser.add_argument('--api_key', type=str, required=False, default='test', + help='API key to use for authentication') + parser.add_argument('--host', type=str, default='http://localhost:4040', + help='Host to use for the request') + args = parser.parse_args() + + try: + print("\n" + "="*80) + print("Loading request data...") + request = read_json_from_file(f"./tests/sample_requests/{args.sample_request}").get("lastRequest", {}) + print("Request data:") + print(json.dumps(request, indent=2)) + print("Starting streaming request...") + print("="*80 + "\n") + + stream_chat(args.host, request, args.api_key) + except Exception as e: + print("\n" + "!"*80) + print(f"Error in main: {e}") + import traceback + traceback.print_exc() + print("!"*80 + "\n") diff --git a/apps/agents/tests/interactive.py b/apps/rowboat_agents/tests/interactive.py similarity index 56% rename from apps/agents/tests/interactive.py rename to apps/rowboat_agents/tests/interactive.py index 54e5d1f1..ace2c608 100644 --- a/apps/agents/tests/interactive.py +++ b/apps/rowboat_agents/tests/interactive.py @@ -2,12 +2,76 @@ import copy from datetime import datetime import json import sys +import asyncio -from src.graph.core import run_turn, order_messages +from src.graph.core import order_messages, run_turn_streamed from src.graph.tools import respond_to_tool_raise_error, respond_to_tool_close_chat, RAG_TOOL, CLOSE_CHAT_TOOL from src.utils.common import common_logger, read_json_from_file logger = common_logger +def preprocess_messages(messages): + # Preprocess messages to handle null content and role issues + for msg in messages: + # Handle null content in assistant messages with tool calls + if (msg.get("role") == "assistant" and + msg.get("content") is None and + msg.get("tool_calls") is not None and + len(msg.get("tool_calls")) > 0): + msg["content"] = "Calling tool" + + # Handle role issues + if msg.get("role") == "tool": + msg["role"] = "developer" + elif not msg.get("role"): + msg["role"] = "user" + + return messages + +async def process_turn(messages, agent_configs, tool_configs, prompt_configs, start_agent_name, state, config, complete_request): + """Processes a single turn using streaming API""" + print(f"\n{'*'*50}\nLatest Request:\n{'*'*50}") + request_json = { + "messages": [{k: v for k, v in msg.items() if k != 'current_turn'} for msg in messages], + "state": state, + "agents": agent_configs, + "tools": tool_configs, + "prompts": prompt_configs, + "startAgent": start_agent_name + } + print(json.dumps(request_json, indent=2)) + + collected_messages = [] + + async for event_type, event_data in run_turn_streamed( + messages=messages, + start_agent_name=start_agent_name, + agent_configs=agent_configs, + tool_configs=tool_configs, + start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), + state=state, + additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], + complete_request=complete_request + ): + if event_type == "message": + # Add each message to collected_messages + collected_messages.append(event_data) + + elif event_type == "done": + print(f"\n\n{'*'*50}\nLatest Response:\n{'*'*50}") + response_json = { + "messages": collected_messages, + "state": event_data.get('state', {}), + } + print("Turn completed. Here are the streamed messages and final state:") + print(json.dumps(response_json, indent=2)) + print('='*50) + + return collected_messages, event_data.get('state', {}) + + elif event_type == "error": + print(f"\nError: {event_data.get('error', 'Unknown error')}") + return [], state + if __name__ == "__main__": logger.info(f"{'*'*50}Running interactive mode{'*'*50}") @@ -16,20 +80,23 @@ if __name__ == "__main__": tool_configs = complete_request.get("tools", []) prompt_configs = complete_request.get("prompts", []) start_agent_name = complete_request.get("startAgent", "") - + return agent_configs, tool_configs, prompt_configs, start_agent_name - + external_tool_mappings = { "raise_error": respond_to_tool_raise_error, "close_chat": respond_to_tool_close_chat } - + config_file = sys.argv[sys.argv.index("--config") + 1] if "--config" in sys.argv else "default_config.json" sample_request_file = sys.argv[sys.argv.index("--sample_request") + 1] if "--sample_request" in sys.argv else "default_example.json" - + + print(f"Config file: {config_file}") + print(f"Sample request file: {sample_request_file}") + config = read_json_from_file(f"./configs/{config_file}") example_request = read_json_from_file(f"./tests/sample_requests/{sample_request_file}").get("lastRequest", {}) - + if "--load_messages" in sys.argv: messages = example_request.get("messages", []) messages = order_messages(messages) @@ -57,7 +124,7 @@ if __name__ == "__main__": agent_configs, tool_configs, prompt_configs, start_agent_name = extract_request_fields(complete_request) print(f"\nUsing agent: {last_agent_name}") - + if user_input_needed: user_inp = input('\nUSER: ') messages.append({ @@ -71,43 +138,28 @@ if __name__ == "__main__": break logger.info("Added user message to conversation") - print(f"\n{'*'*50}\nLatest Request:\n{'*'*50}") - request_json = { - "messages": [{k: v for k, v in msg.items() if k != 'current_turn'} for msg in messages], - "state": state, - "agents": agent_configs, - "tools": tool_configs, - "prompts": prompt_configs, - "startAgent": start_agent_name - } - print(json.dumps(request_json, indent=2)) - print(complete_request) - resp_messages, resp_tokens_used, resp_state = run_turn( + # Preprocess messages to replace role tool with role developer and add role user to empty roles + print("Preprocessing messages to replace role tool with role developer and add role user to empty roles") + messages = preprocess_messages(messages) + complete_request["messages"] = preprocess_messages(complete_request["messages"]) + + # Run the streaming turn + resp_messages, resp_state = asyncio.run(process_turn( messages=messages, - start_agent_name=start_agent_name, agent_configs=agent_configs, tool_configs=tool_configs, - start_turn_with_start_agent=config.get("start_turn_with_start_agent", False), + prompt_configs=prompt_configs, + start_agent_name=start_agent_name, state=state, - additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL], + config=config, complete_request=complete_request - ) + )) + state = resp_state - resp_messages = order_messages(resp_messages) - - print(f"\n{'*'*50}\nLatest Response:\n{'*'*50}") - response_json = { - "messages": resp_messages, - "state": state, - "tokens_used": resp_tokens_used - } - print(json.dumps(response_json, indent=2)) - - last_msg = resp_messages[-1] - print(f"\nBOT: {last_msg}\n") + last_msg = resp_messages[-1] if resp_messages else {} tool_calls = last_msg.get("tool_calls", []) sender = last_msg.get("sender", "") - + if config.get("return_diff_messages", True): messages.extend(resp_messages) else: @@ -134,7 +186,7 @@ if __name__ == "__main__": current_tool_duration = round((datetime.now() - tool_start_time).total_seconds() * 10) / 10 logger.info(f"Tool response duration: {current_tool_duration:.1f}s") tool_duration += current_tool_duration - + if tool_name == "close_chat": user_input_needed = False logger.info("Closing chat") @@ -142,10 +194,12 @@ if __name__ == "__main__": if should_break: break - + else: user_input_needed = True - print(f"Turn Duration: {round((datetime.now() - turn_start_time).total_seconds() * 10) / 10:.1f}s\n") - print(f"Tool Response Duration: {round(tool_duration * 10) / 10:.1f}s\n") - + print("Quick stats") + print(f"Turn Duration: {round((datetime.now() - turn_start_time).total_seconds() * 10) / 10:.1f}s") + print(f"Tool Response Duration: {round(tool_duration * 10) / 10:.1f}s") + print('='*50) + print("\n" + "-" * 80) \ No newline at end of file diff --git a/apps/agents/tests/sample_requests/default_example.json b/apps/rowboat_agents/tests/sample_requests/default_example.json similarity index 100% rename from apps/agents/tests/sample_requests/default_example.json rename to apps/rowboat_agents/tests/sample_requests/default_example.json diff --git a/apps/agents/tests/sample_requests/example1.json b/apps/rowboat_agents/tests/sample_requests/example1.json similarity index 100% rename from apps/agents/tests/sample_requests/example1.json rename to apps/rowboat_agents/tests/sample_requests/example1.json diff --git a/apps/agents/tests/sample_requests/example2.json b/apps/rowboat_agents/tests/sample_requests/example2.json similarity index 100% rename from apps/agents/tests/sample_requests/example2.json rename to apps/rowboat_agents/tests/sample_requests/example2.json diff --git a/apps/agents/tests/sample_requests/example3.json b/apps/rowboat_agents/tests/sample_requests/example3.json similarity index 100% rename from apps/agents/tests/sample_requests/example3.json rename to apps/rowboat_agents/tests/sample_requests/example3.json diff --git a/apps/rowboat_agents/tests/sample_requests/tmp1.json b/apps/rowboat_agents/tests/sample_requests/tmp1.json new file mode 100644 index 00000000..9bae6e74 --- /dev/null +++ b/apps/rowboat_agents/tests/sample_requests/tmp1.json @@ -0,0 +1,176 @@ +{ + "lastRequest": { + "messages": [ + { + "role": "system", + "content": "" + }, + { + "role": "user", + "content": "hi" + }, + { + "role": "assistant", + "sender": "Door Dash Hub", + "content": "Hello! Are you facing issues with your order items or delivery timing? How can I assist you today?", + "created_at": "2025-03-24T17:33:27.564940" + }, + { + "role": "user", + "content": "my order is missing fries" + }, + { + "content": "Agent changed to Door Dash Hub", + "role": "assistant", + "sender": "Door Dash Hub", + "tool_calls": null, + "tool_call_id": null, + "response_type": "internal" + }, + { + "content": "Agent changed to Order Issue", + "role": "assistant", + "sender": "Order Issue", + "tool_calls": null, + "tool_call_id": null, + "response_type": "internal" + }, + { + "content": "I can help with that. Could you please provide your order ID so I can check the details?", + "role": "assistant", + "sender": "Order Issue", + "tool_calls": null, + "tool_call_id": null, + "tool_name": null, + "response_type": "external" + }, + { + "role": "user", + "content": "12312" + } + ], + "state": { + "last_agent_name": "Order Issue", + "tokens": { + "total": 1521, + "prompt": 1486, + "completion": 35 + } + }, + "agents": [ + { + "name": "Door Dash Hub", + "type": "conversation", + "description": "Hub agent to manage Door Dash-related queries.", + "instructions": "## \ud83e\uddd1\u200d\ud83d\udcbc Role:\nYou are responsible for directing Door Dash-related queries to appropriate agents.\n\n---\n## \u2699\ufe0f Steps to Follow:\n1. Greet the user and ask which Door Dash-related query they need help with (e.g., 'Are you facing issues with your order items or delivery timing?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Order Issue \u2192 [@agent:Order Issue]\n - Delayed Delivery \u2192 [@agent:Delayed Delivery]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## \ud83c\udfaf Scope:\n\u2705 In Scope:\n- Issues with order items\n- Delayed delivery issues\n\n\u274c Out of Scope:\n- Issues unrelated to Door Dash\n- General knowledge queries\n\n---\n## \ud83d\udccb Guidelines:\n\u2714\ufe0f Dos:\n- Direct queries to specific Door Dash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n\ud83d\udeab Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond Door Dash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with my order items.\n - **Agent actions**: [@agent:Order Issue](#mention)\n\n- **User** : My delivery is delayed.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : I'm not sure where my order is.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : Can you reset my order settings?\n - **Agent actions**: [@agent:Escalation](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would like help with today?", + "model": "gpt-4o-mini", + "hasRagSources": false, + "controlType": "retain", + "tools": [], + "prompts": [], + "connectedAgents": [ + "Order Issue", + "Delayed Delivery", + "Escalation" + ] + }, + { + "name": "Post process", + "type": "post_process", + "description": "", + "instructions": "Ensure that the agent response is terse and to the point.", + "model": "gpt-4o-mini", + "hasRagSources": false, + "controlType": "retain", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Escalation", + "type": "escalation", + "description": "", + "instructions": "Get the user's contact information and let them know that their request has been escalated.", + "model": "gpt-4o-mini", + "hasRagSources": false, + "controlType": "retain", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Order Issue", + "type": "conversation", + "description": "Agent to assist users with missing or incorrect order items.", + "instructions": "## \ud83e\uddd1\u200d\ud83d\udcbc Role:\nAssist users with issues related to missing or incorrect order items.\n\n---\n## \u2699\ufe0f Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the issue with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## \ud83c\udfaf Scope:\n\u2705 In Scope:\n- Handling missing or incorrect order items\n\n\u274c Out of Scope:\n- Delayed delivery issues\n- General knowledge queries\n\n---\n## \ud83d\udccb Guidelines:\n\u2714\ufe0f Dos:\n- Ensure the user is aware of the order details before proceeding.\n\n\ud83d\udeab Don'ts:\n- Extend the conversation beyond order issues.\n\n# Examples\n- **User** : I received the wrong item in my order.\n - **Agent response**: I can help with that. Let me fetch your order details first.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing an item.\n - **Agent response**: Let's check your order details and resolve this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I got someone else's order.\n - **Agent response**: I apologize for the mix-up. I'll fetch your order details to sort this out.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : Can you help me with a missing item?\n - **Agent response**: Certainly, I'll look into your order details right away.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : There's an issue with my order items.\n - **Agent response**: Let's verify your order details to address this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)", + "model": "gpt-4o", + "hasRagSources": false, + "controlType": "retain", + "tools": [ + "get_order_details" + ], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Delayed Delivery", + "type": "conversation", + "description": "Agent to assist users with delayed delivery issues.", + "instructions": "## \ud83e\uddd1\u200d\ud83d\udcbc Role:\nAssist users with issues related to delayed delivery.\n\n---\n## \u2699\ufe0f Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Confirm the delay with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## \ud83c\udfaf Scope:\n\u2705 In Scope:\n- Handling delayed delivery issues\n\n\u274c Out of Scope:\n- Missing or incorrect order items\n- General knowledge queries\n\n---\n## \ud83d\udccb Guidelines:\n\u2714\ufe0f Dos:\n- Ensure the user is aware of the delivery status before proceeding.\n\n\ud83d\udeab Don'ts:\n- Extend the conversation beyond delivery issues.\n\n# Examples\n- **User** : My delivery is late.\n - **Agent response**: I can help with that. Let me fetch your delivery status first.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Where is my order? It's delayed.\n - **Agent response**: Let's check your delivery status and resolve this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : My order hasn't arrived yet.\n - **Agent response**: I apologize for the delay. I'll fetch your delivery status to sort this out.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Can you help me with a delayed delivery?\n - **Agent response**: Certainly, I'll look into your delivery status right away.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : There's an issue with my delivery timing.\n - **Agent response**: Let's verify your delivery status to address this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)", + "model": "gpt-4o", + "hasRagSources": false, + "controlType": "retain", + "tools": [ + "get_delivery_status" + ], + "prompts": [], + "connectedAgents": [] + } + ], + "tools": [ + { + "name": "get_order_details", + "description": "Tool to fetch details about the user's order.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + }, + "mockTool": true, + "mockInstructions": "Return a mock response for Door Dash order details." + }, + { + "name": "get_delivery_status", + "description": "Tool to fetch the current status of the delivery.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + } + } + ], + "prompts": [ + { + "name": "Style prompt", + "type": "style_prompt", + "prompt": "You should be empathetic and helpful." + } + ], + "startAgent": "Door Dash Hub" + } + +} \ No newline at end of file diff --git a/apps/rowboat_agents/tests/sample_requests/tmp2.json b/apps/rowboat_agents/tests/sample_requests/tmp2.json new file mode 100644 index 00000000..c0055e7d --- /dev/null +++ b/apps/rowboat_agents/tests/sample_requests/tmp2.json @@ -0,0 +1,223 @@ +{ + "lastRequest": { + "messages": [ + { + "role": "system", + "content": "" + }, + { + "role": "user", + "content": "hi" + }, + { + "role": "assistant", + "sender": "Door Dash Hub", + "content": "Hello! Are you facing issues with your order items or delivery timing? How can I assist you today?", + "created_at": "2025-03-24T17:33:27.564940" + }, + { + "role": "user", + "content": "my order is missing fries" + }, + { + "content": "Agent changed to Door Dash Hub", + "role": "assistant", + "sender": "Door Dash Hub", + "tool_calls": null, + "tool_call_id": null, + "response_type": "internal" + }, + { + "content": "Agent changed to Order Issue", + "role": "assistant", + "sender": "Order Issue", + "tool_calls": null, + "tool_call_id": null, + "response_type": "internal" + }, + { + "content": "Let's resolve this issue by checking your order details. Could you please provide the order ID?", + "role": "assistant", + "sender": "Order Issue", + "tool_calls": null, + "tool_call_id": null, + "tool_name": null, + "response_type": "external" + }, + { + "role": "user", + "content": "123412" + }, + { + "content": "Agent changed to Order Issue", + "role": "assistant", + "sender": "Order Issue", + "tool_calls": null, + "tool_call_id": null, + "response_type": "internal" + }, + { + "content": null, + "role": "assistant", + "sender": "Order Issue", + "tool_calls": [ + { + "function": { + "name": "get_order_details", + "arguments": "{\"order_id\":\"123412\"}" + }, + "id": "fc_67e37c622f208192aceec557fbd3125609b4eca638eb3571", + "type": "function" + } + ], + "tool_call_id": null, + "tool_name": null, + "response_type": "internal" + }, + { + "content": "Order Details for Order ID 123412:\n\n- **Restaurant**: Luigi's Pizzeria \n- **Items Ordered**: \n - 2x Margherita Pizza \n - 1x Garlic Bread \n - 1x Caesar Salad \n- **Estimated Delivery Time**: 7:45 PM \n- **Delivery Address**: 123 Elm Street, Apt 4B \n- **Order Status**: Out for delivery \n- **Total Amount**: $32.75 \n- **Payment Method**: Credit Card (**** **** **** 5678) \n- **Contact**: (123) 456-7890 \n- **Special Instructions**: Leave at the door.", + "role": "tool", + "sender": null, + "tool_calls": null, + "tool_call_id": "call_dqCMC5oreOoS9znDDJ7PqWha", + "tool_name": null, + "response_type": "internal" + }, + { + "content": "I checked your order details, and it seems the fries were not included. Could you confirm if there was an oversight in placing the order, or were they supposed to be included?", + "role": "assistant", + "sender": "Order Issue", + "tool_calls": null, + "tool_call_id": null, + "tool_name": null, + "response_type": "external" + }, + { + "role": "user", + "content": "Fries were supposed to be in" + } + ], + "state": { + "last_agent_name": "Order Issue", + "tokens": { + "total": 1699, + "prompt": 1643, + "completion": 56 + } + }, + "agents": [ + { + "name": "Door Dash Hub", + "type": "conversation", + "description": "Hub agent to manage Door Dash-related queries.", + "instructions": "## \ud83e\uddd1\u200d\ud83d\udcbc Role:\nYou are responsible for directing Door Dash-related queries to appropriate agents.\n\n---\n## \u2699\ufe0f Steps to Follow:\n1. Greet the user and ask which Door Dash-related query they need help with (e.g., 'Are you facing issues with your order items or delivery timing?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Order Issue \u2192 [@agent:Order Issue]\n - Delayed Delivery \u2192 [@agent:Delayed Delivery]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## \ud83c\udfaf Scope:\n\u2705 In Scope:\n- Issues with order items\n- Delayed delivery issues\n\n\u274c Out of Scope:\n- Issues unrelated to Door Dash\n- General knowledge queries\n\n---\n## \ud83d\udccb Guidelines:\n\u2714\ufe0f Dos:\n- Direct queries to specific Door Dash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n\ud83d\udeab Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond Door Dash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with my order items.\n - **Agent actions**: [@agent:Order Issue](#mention)\n\n- **User** : My delivery is delayed.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : I'm not sure where my order is.\n - **Agent actions**: Call [@agent:Delayed Delivery](#mention)\n\n- **User** : Can you reset my order settings?\n - **Agent actions**: [@agent:Escalation](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would like help with today?", + "model": "gpt-4o-mini", + "hasRagSources": false, + "controlType": "retain", + "tools": [], + "prompts": [], + "connectedAgents": [ + "Order Issue", + "Delayed Delivery", + "Escalation" + ] + }, + { + "name": "Post process", + "type": "post_process", + "description": "", + "instructions": "Ensure that the agent response is terse and to the point.", + "model": "gpt-4o-mini", + "hasRagSources": false, + "controlType": "retain", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Escalation", + "type": "escalation", + "description": "", + "instructions": "Get the user's contact information and let them know that their request has been escalated.", + "model": "gpt-4o-mini", + "hasRagSources": false, + "controlType": "retain", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Order Issue", + "type": "conversation", + "description": "Agent to assist users with missing or incorrect order items.", + "instructions": "## \ud83e\uddd1\u200d\ud83d\udcbc Role:\nAssist users with issues related to missing or incorrect order items.\n\n---\n## \u2699\ufe0f Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the issue with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## \ud83c\udfaf Scope:\n\u2705 In Scope:\n- Handling missing or incorrect order items\n\n\u274c Out of Scope:\n- Delayed delivery issues\n- General knowledge queries\n\n---\n## \ud83d\udccb Guidelines:\n\u2714\ufe0f Dos:\n- Ensure the user is aware of the order details before proceeding.\n\n\ud83d\udeab Don'ts:\n- Extend the conversation beyond order issues.\n\n# Examples\n- **User** : I received the wrong item in my order.\n - **Agent response**: I can help with that. Let me fetch your order details first.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing an item.\n - **Agent response**: Let's check your order details and resolve this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I got someone else's order.\n - **Agent response**: I apologize for the mix-up. I'll fetch your order details to sort this out.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : Can you help me with a missing item?\n - **Agent response**: Certainly, I'll look into your order details right away.\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : There's an issue with my order items.\n - **Agent response**: Let's verify your order details to address this issue.\n - **Agent actions**: Call [@tool:get_order_details](#mention)", + "model": "gpt-4o", + "hasRagSources": false, + "controlType": "retain", + "tools": [ + "get_order_details" + ], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Delayed Delivery", + "type": "conversation", + "description": "Agent to assist users with delayed delivery issues.", + "instructions": "## \ud83e\uddd1\u200d\ud83d\udcbc Role:\nAssist users with issues related to delayed delivery.\n\n---\n## \u2699\ufe0f Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Confirm the delay with the user.\n3. Provide solutions or escalate if unresolved.\n\n---\n## \ud83c\udfaf Scope:\n\u2705 In Scope:\n- Handling delayed delivery issues\n\n\u274c Out of Scope:\n- Missing or incorrect order items\n- General knowledge queries\n\n---\n## \ud83d\udccb Guidelines:\n\u2714\ufe0f Dos:\n- Ensure the user is aware of the delivery status before proceeding.\n\n\ud83d\udeab Don'ts:\n- Extend the conversation beyond delivery issues.\n\n# Examples\n- **User** : My delivery is late.\n - **Agent response**: I can help with that. Let me fetch your delivery status first.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Where is my order? It's delayed.\n - **Agent response**: Let's check your delivery status and resolve this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : My order hasn't arrived yet.\n - **Agent response**: I apologize for the delay. I'll fetch your delivery status to sort this out.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Can you help me with a delayed delivery?\n - **Agent response**: Certainly, I'll look into your delivery status right away.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : There's an issue with my delivery timing.\n - **Agent response**: Let's verify your delivery status to address this issue.\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)", + "model": "gpt-4o", + "hasRagSources": false, + "controlType": "retain", + "tools": [ + "get_delivery_status" + ], + "prompts": [], + "connectedAgents": [] + } + ], + "tools": [ + { + "name": "get_order_details", + "description": "Tool to fetch details about the user's order.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + }, + "mockTool": true, + "mockInstructions": "Return a mock response for Door Dash order details." + }, + { + "name": "get_delivery_status", + "description": "Tool to fetch the current status of the delivery.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + } + } + ], + "prompts": [ + { + "name": "Style prompt", + "type": "style_prompt", + "prompt": "You should be empathetic and helpful." + } + ], + "startAgent": "Door Dash Hub" + } +} \ No newline at end of file diff --git a/apps/rowboat_agents/tests/sample_requests/tmp3.json b/apps/rowboat_agents/tests/sample_requests/tmp3.json new file mode 100644 index 00000000..f215dc21 --- /dev/null +++ b/apps/rowboat_agents/tests/sample_requests/tmp3.json @@ -0,0 +1,270 @@ +{ + "lastRequest": { + "projectId": "4ebd5e81-010a-4bc6-91e0-0aa98173dbac", + "messages": [ + { + "content": "", + "role": "system", + "sender": null, + "tool_calls": null, + "tool_call_id": null, + "tool_name": null + }, + { + "content": "Hello! How can I assist you with your DoorDash query today? Are you inquiring about a missing item, delivery status, or subscription details?", + "role": "assistant", + "sender": "DoorDash Support Hub", + "tool_calls": null, + "tool_call_id": null, + "tool_name": null, + "response_type": "internal" + }, + { + "content": "Hello! How can I assist you with your DoorDash query today? Are you inquiring about a missing item, delivery status, or subscription details?", + "role": "assistant", + "sender": "DoorDash Support Hub >> External", + "tool_calls": null, + "tool_call_id": null, + "tool_name": null, + "response_type": "external" + }, + { + "content": "hi", + "role": "user", + "sender": null, + "tool_calls": null, + "tool_call_id": null, + "tool_name": null + } + ], + "state": { + "agent_data": [ + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nYou are responsible for directing DoorDash-related queries to appropriate agents.\n\n---\n## βš™οΈ Steps to Follow:\n1. Greet the user and ask which DoorDash-related query they need help with (e.g., 'Are you inquiring about a missing item, delivery status, or subscription details?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Missing Items β†’ [@agent:Missing Items]\n - Delivery Status β†’ [@agent:Delivery Status]\n - Subscription Info β†’ [@agent:Subscription Info]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Missing items queries\n- Delivery status queries\n- Subscription-related queries\n\n❌ Out of Scope:\n- Issues unrelated to DoorDash\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Direct queries to specific DoorDash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n🚫 Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond DoorDash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with a missing item in my order.\n - **Agent actions**: Call [@agent:Missing Items](#mention)\n\n- **User** : Can you tell me the status of my delivery?\n - **Agent actions**: Call [@agent:Delivery Status](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would you like help with today?\n\n- **User** : Can you reset my account settings?\n - **Agent actions**: Call [@agent:Escalation](#mention)\n\n- **User** : I have a question about my order.\n - **Agent response**: Could you specify if it's about a missing item, delivery status, or subscription details?\n\n- **User** : What are the available subscription plans?\n - **Agent actions**: Call [@agent:Subscription Info](#mention)", + "name": "DoorDash Support Hub" + }, + { + "instructions": "Ensure that the agent response is terse and to the point.", + "name": "Post process" + }, + { + "instructions": "Get the user's contact information and let them know that their request has been escalated.", + "name": "Escalation" + }, + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users resolve issues with missing items in their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the missing items with the user.\n3. Provide resolution options or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Resolving missing items issues\n\n❌ Out of Scope:\n- Delivery status queries\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_order_details](#mention) to fetch accurate order information.\n- Provide clear resolution options.\n\n🚫 Don'ts:\n- Assume missing items without user confirmation.\n- Extend the conversation beyond missing items.\n\n# Examples\n- **User** : I didn't receive my fries with my order.\n - **Agent response**: Let me check your order details. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing a drink.\n - **Agent response**: I apologize for the inconvenience. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get the extra sauce I ordered.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My burger is missing from the order.\n - **Agent response**: I'm sorry to hear that. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get my dessert.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)", + "name": "Missing Items" + }, + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users with queries related to the delivery status of their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Provide the user with the current delivery status.\n3. Offer additional assistance if needed.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Providing delivery status updates\n\n❌ Out of Scope:\n- Resolving missing items issues\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_delivery_status](#mention) to fetch accurate delivery information.\n- Provide clear and concise status updates.\n\n🚫 Don'ts:\n- Provide status updates without fetching current information.\n- Extend the conversation beyond delivery status.\n\n# Examples\n- **User** : Where is my order?\n - **Agent response**: Let me check the delivery status for you. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order on the way?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : When will my order arrive?\n - **Agent response**: Let me find out the delivery status. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : How long until my order gets here?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order delayed?\n - **Agent response**: Let me check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)", + "name": "Delivery Status" + }, + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nProvide information and answer questions related to subscriptions using RAG.\n\n---\n## βš™οΈ Steps to Follow:\n1. Use RAG to retrieve relevant information about subscriptions.\n2. Answer the user's questions based on the retrieved information.\n3. If the user's query is outside the scope of subscriptions, inform them politely.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Subscription plans and pricing\n- Subscription features and benefits\n\n❌ Out of Scope:\n- Non-subscription-related queries\n- Detailed account management\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use RAG to provide accurate and up-to-date information.\n- Be clear and concise in your responses.\n\n🚫 Don'ts:\n- Provide information without using RAG.\n- Extend the conversation beyond subscription topics.\n\n# Examples\n- **User** : What are the available subscription plans?\n - **Agent response**: Let me check the available subscription plans for you.\n\n- **User** : How much does the premium subscription cost?\n - **Agent response**: I'll find the current pricing for the premium subscription.\n\n- **User** : Can I change my subscription plan?\n - **Agent response**: I'll provide information on how to change your subscription plan.\n\n- **User** : What benefits do I get with a subscription?\n - **Agent response**: Let me retrieve the benefits associated with our subscription plans.\n\n- **User** : Is there a free trial available?\n - **Agent response**: I'll check if there's a free trial available for our subscriptions.", + "name": "Subscription Info" + } + ], + "last_agent_name": "DoorDash Support Hub" + }, + "agents": [ + { + "name": "DoorDash Support Hub", + "type": "conversation", + "description": "Hub agent to manage DoorDash-related queries.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nYou are responsible for directing DoorDash-related queries to appropriate agents.\n\n---\n## βš™οΈ Steps to Follow:\n1. Greet the user and ask which DoorDash-related query they need help with (e.g., 'Are you inquiring about a missing item, delivery status, or subscription details?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Missing Items β†’ [@agent:Missing Items]\n - Delivery Status β†’ [@agent:Delivery Status]\n - Subscription Info β†’ [@agent:Subscription Info]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Missing items queries\n- Delivery status queries\n- Subscription-related queries\n\n❌ Out of Scope:\n- Issues unrelated to DoorDash\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Direct queries to specific DoorDash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n🚫 Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond DoorDash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with a missing item in my order.\n - **Agent actions**: Call [@agent:Missing Items](#mention)\n\n- **User** : Can you tell me the status of my delivery?\n - **Agent actions**: Call [@agent:Delivery Status](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would you like help with today?\n\n- **User** : Can you reset my account settings?\n - **Agent actions**: Call [@agent:Escalation](#mention)\n\n- **User** : I have a question about my order.\n - **Agent response**: Could you specify if it's about a missing item, delivery status, or subscription details?\n\n- **User** : What are the available subscription plans?\n - **Agent actions**: Call [@agent:Subscription Info](#mention)", + "model": "gpt-4o", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [], + "prompts": [], + "connectedAgents": [ + "Missing Items", + "Delivery Status", + "Subscription Info", + "Escalation" + ] + }, + { + "name": "Post process", + "type": "post_process", + "description": "", + "instructions": "Ensure that the agent response is terse and to the point.", + "model": "gpt-4o-mini", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Escalation", + "type": "escalation", + "description": "", + "instructions": "Get the user's contact information and let them know that their request has been escalated.", + "model": "gpt-4o-mini", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Missing Items", + "type": "conversation", + "description": "Agent to assist users with missing items in their orders.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users resolve issues with missing items in their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the missing items with the user.\n3. Provide resolution options or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Resolving missing items issues\n\n❌ Out of Scope:\n- Delivery status queries\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_order_details](#mention) to fetch accurate order information.\n- Provide clear resolution options.\n\n🚫 Don'ts:\n- Assume missing items without user confirmation.\n- Extend the conversation beyond missing items.\n\n# Examples\n- **User** : I didn't receive my fries with my order.\n - **Agent response**: Let me check your order details. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing a drink.\n - **Agent response**: I apologize for the inconvenience. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get the extra sauce I ordered.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My burger is missing from the order.\n - **Agent response**: I'm sorry to hear that. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get my dessert.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)", + "model": "gpt-4o", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [ + "get_order_details" + ], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Delivery Status", + "type": "conversation", + "description": "Agent to assist users with delivery status queries.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users with queries related to the delivery status of their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Provide the user with the current delivery status.\n3. Offer additional assistance if needed.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Providing delivery status updates\n\n❌ Out of Scope:\n- Resolving missing items issues\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_delivery_status](#mention) to fetch accurate delivery information.\n- Provide clear and concise status updates.\n\n🚫 Don'ts:\n- Provide status updates without fetching current information.\n- Extend the conversation beyond delivery status.\n\n# Examples\n- **User** : Where is my order?\n - **Agent response**: Let me check the delivery status for you. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order on the way?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : When will my order arrive?\n - **Agent response**: Let me find out the delivery status. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : How long until my order gets here?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order delayed?\n - **Agent response**: Let me check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)", + "model": "gpt-4o", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [ + "get_delivery_status" + ], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Subscription Info", + "type": "conversation", + "description": "Agent to assist users with subscription-related queries.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nProvide information and answer questions related to subscriptions using RAG.\n\n---\n## βš™οΈ Steps to Follow:\n1. Use RAG to retrieve relevant information about subscriptions.\n2. Answer the user's questions based on the retrieved information.\n3. If the user's query is outside the scope of subscriptions, inform them politely.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Subscription plans and pricing\n- Subscription features and benefits\n\n❌ Out of Scope:\n- Non-subscription-related queries\n- Detailed account management\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use RAG to provide accurate and up-to-date information.\n- Be clear and concise in your responses.\n\n🚫 Don'ts:\n- Provide information without using RAG.\n- Extend the conversation beyond subscription topics.\n\n# Examples\n- **User** : What are the available subscription plans?\n - **Agent response**: Let me check the available subscription plans for you.\n\n- **User** : How much does the premium subscription cost?\n - **Agent response**: I'll find the current pricing for the premium subscription.\n\n- **User** : Can I change my subscription plan?\n - **Agent response**: I'll provide information on how to change your subscription plan.\n\n- **User** : What benefits do I get with a subscription?\n - **Agent response**: Let me retrieve the benefits associated with our subscription plans.\n\n- **User** : Is there a free trial available?\n - **Agent response**: I'll check if there's a free trial available for our subscriptions.", + "model": "gpt-4o", + "controlType": "relinquish_to_parent", + "ragDataSources": [ + "67e1612510540d9027909e10" + ], + "ragK": 3, + "ragReturnType": "content", + "tools": [], + "prompts": [], + "connectedAgents": [] + } + ], + "tools": [ + { + "name": "get_order_details", + "description": "Tool to fetch the user's order details.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + } + }, + { + "name": "get_delivery_status", + "description": "Tool to fetch the delivery status of an order.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + }, + "mockTool": true, + "mockInstructions": "Give a mock response for a door dash order delivery status." + } + ], + "prompts": [ + { + "name": "Style prompt", + "type": "style_prompt", + "prompt": "You should be empathetic and helpful." + }, + { + "name": "Greeting", + "type": "greeting", + "prompt": "Hello! How can I help you?" + } + ], + "startAgent": "DoorDash Support Hub", + "mcpServers": [ + { + "name": "delivery", + "url": "http://localhost:8000/sse" + } + ], + "toolWebhookUrl": "http://127.0.0.1:4020/tool_call" + }, + "lastResponse": { + "messages": [ + { + "content": "Hi there! How can I help you with your DoorDash query? Are you inquiring about a missing item, delivery status, or subscription details?", + "created_at": null, + "response_type": "internal", + "role": "assistant", + "sender": "DoorDash Support Hub" + }, + { + "content": "Hi there! How can I help you with your DoorDash query? Are you inquiring about a missing item, delivery status, or subscription details?", + "created_at": null, + "response_type": "external", + "role": "assistant", + "sender": "DoorDash Support Hub >> External" + } + ], + "state": { + "agent_data": [ + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nYou are responsible for directing DoorDash-related queries to appropriate agents.\n\n---\n## βš™οΈ Steps to Follow:\n1. Greet the user and ask which DoorDash-related query they need help with (e.g., 'Are you inquiring about a missing item, delivery status, or subscription details?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Missing Items β†’ [@agent:Missing Items]\n - Delivery Status β†’ [@agent:Delivery Status]\n - Subscription Info β†’ [@agent:Subscription Info]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Missing items queries\n- Delivery status queries\n- Subscription-related queries\n\n❌ Out of Scope:\n- Issues unrelated to DoorDash\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Direct queries to specific DoorDash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n🚫 Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond DoorDash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with a missing item in my order.\n - **Agent actions**: Call [@agent:Missing Items](#mention)\n\n- **User** : Can you tell me the status of my delivery?\n - **Agent actions**: Call [@agent:Delivery Status](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would you like help with today?\n\n- **User** : Can you reset my account settings?\n - **Agent actions**: Call [@agent:Escalation](#mention)\n\n- **User** : I have a question about my order.\n - **Agent response**: Could you specify if it's about a missing item, delivery status, or subscription details?\n\n- **User** : What are the available subscription plans?\n - **Agent actions**: Call [@agent:Subscription Info](#mention)", + "name": "DoorDash Support Hub" + }, + { + "instructions": "Ensure that the agent response is terse and to the point.", + "name": "Post process" + }, + { + "instructions": "Get the user's contact information and let them know that their request has been escalated.", + "name": "Escalation" + }, + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users resolve issues with missing items in their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the missing items with the user.\n3. Provide resolution options or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Resolving missing items issues\n\n❌ Out of Scope:\n- Delivery status queries\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_order_details](#mention) to fetch accurate order information.\n- Provide clear resolution options.\n\n🚫 Don'ts:\n- Assume missing items without user confirmation.\n- Extend the conversation beyond missing items.\n\n# Examples\n- **User** : I didn't receive my fries with my order.\n - **Agent response**: Let me check your order details. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing a drink.\n - **Agent response**: I apologize for the inconvenience. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get the extra sauce I ordered.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My burger is missing from the order.\n - **Agent response**: I'm sorry to hear that. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get my dessert.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)", + "name": "Missing Items" + }, + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users with queries related to the delivery status of their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Provide the user with the current delivery status.\n3. Offer additional assistance if needed.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Providing delivery status updates\n\n❌ Out of Scope:\n- Resolving missing items issues\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_delivery_status](#mention) to fetch accurate delivery information.\n- Provide clear and concise status updates.\n\n🚫 Don'ts:\n- Provide status updates without fetching current information.\n- Extend the conversation beyond delivery status.\n\n# Examples\n- **User** : Where is my order?\n - **Agent response**: Let me check the delivery status for you. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order on the way?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : When will my order arrive?\n - **Agent response**: Let me find out the delivery status. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : How long until my order gets here?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order delayed?\n - **Agent response**: Let me check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)", + "name": "Delivery Status" + }, + { + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nProvide information and answer questions related to subscriptions using RAG.\n\n---\n## βš™οΈ Steps to Follow:\n1. Use RAG to retrieve relevant information about subscriptions.\n2. Answer the user's questions based on the retrieved information.\n3. If the user's query is outside the scope of subscriptions, inform them politely.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Subscription plans and pricing\n- Subscription features and benefits\n\n❌ Out of Scope:\n- Non-subscription-related queries\n- Detailed account management\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use RAG to provide accurate and up-to-date information.\n- Be clear and concise in your responses.\n\n🚫 Don'ts:\n- Provide information without using RAG.\n- Extend the conversation beyond subscription topics.\n\n# Examples\n- **User** : What are the available subscription plans?\n - **Agent response**: Let me check the available subscription plans for you.\n\n- **User** : How much does the premium subscription cost?\n - **Agent response**: I'll find the current pricing for the premium subscription.\n\n- **User** : Can I change my subscription plan?\n - **Agent response**: I'll provide information on how to change your subscription plan.\n\n- **User** : What benefits do I get with a subscription?\n - **Agent response**: Let me retrieve the benefits associated with our subscription plans.\n\n- **User** : Is there a free trial available?\n - **Agent response**: I'll check if there's a free trial available for our subscriptions.", + "name": "Subscription Info" + } + ], + "last_agent_name": "DoorDash Support Hub" + }, + "tokens_used": { + "completion": 50, + "prompt": 50, + "total": 100 + } + } + } \ No newline at end of file diff --git a/apps/rowboat_agents/tests/sample_requests/tmp4.json b/apps/rowboat_agents/tests/sample_requests/tmp4.json new file mode 100644 index 00000000..9a9ac2e0 --- /dev/null +++ b/apps/rowboat_agents/tests/sample_requests/tmp4.json @@ -0,0 +1,166 @@ +{ + "lastRequest": { + "projectId": "4ebd5e81-010a-4bc6-91e0-0aa98173dbac", + "messages": [ + { + "content": "", + "role": "system", + "sender": null, + "tool_calls": null, + "tool_call_id": null, + "tool_name": null + } + ], + "state": { + "last_agent_name": "DoorDash Support Hub" + }, + "agents": [ + { + "name": "DoorDash Support Hub", + "type": "conversation", + "description": "Hub agent to manage DoorDash-related queries.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nYou are responsible for directing DoorDash-related queries to appropriate agents.\n\n---\n## βš™οΈ Steps to Follow:\n1. Greet the user and ask which DoorDash-related query they need help with (e.g., 'Are you inquiring about a missing item, delivery status, or subscription details?').\n2. If the query matches a specific task, direct the user to the corresponding agent:\n - Missing Items β†’ [@agent:Missing Items]\n - Delivery Status β†’ [@agent:Delivery Status]\n - Subscription Info β†’ [@agent:Subscription Info]\n3. If the query doesn't match any specific task, respond with 'I'm sorry, I didn't understand. Could you clarify your request?' or escalate to human support.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Missing items queries\n- Delivery status queries\n- Subscription-related queries\n\n❌ Out of Scope:\n- Issues unrelated to DoorDash\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Direct queries to specific DoorDash agents promptly.\n- Call [@agent:Escalation] agent for unrecognized queries.\n\n🚫 Don'ts:\n- Engage in detailed support.\n- Extend the conversation beyond DoorDash.\n- Provide user-facing text such as 'I will connect you now...' when calling another agent\n\n# Examples\n- **User** : I need help with a missing item in my order.\n - **Agent actions**: Call [@agent:Missing Items](#mention)\n\n- **User** : Can you tell me the status of my delivery?\n - **Agent actions**: Call [@agent:Delivery Status](#mention)\n\n- **User** : How are you today?\n - **Agent response**: I'm doing great. What would you like help with today?\n\n- **User** : Can you reset my account settings?\n - **Agent actions**: Call [@agent:Escalation](#mention)\n\n- **User** : I have a question about my order.\n - **Agent response**: Could you specify if it's about a missing item, delivery status, or subscription details?\n\n- **User** : What are the available subscription plans?\n - **Agent actions**: Call [@agent:Subscription Info](#mention)", + "model": "gpt-4o", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [], + "prompts": [], + "connectedAgents": [ + "Missing Items", + "Delivery Status", + "Subscription Info", + "Escalation" + ] + }, + { + "name": "Post process", + "type": "post_process", + "description": "", + "instructions": "Ensure that the agent response is terse and to the point.", + "model": "gpt-4o-mini", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Escalation", + "type": "escalation", + "description": "", + "instructions": "Get the user's contact information and let them know that their request has been escalated.", + "model": "gpt-4o-mini", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Missing Items", + "type": "conversation", + "description": "Agent to assist users with missing items in their orders.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users resolve issues with missing items in their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the order details using the [@tool:get_order_details] tool.\n2. Confirm the missing items with the user.\n3. Provide resolution options or escalate if unresolved.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Resolving missing items issues\n\n❌ Out of Scope:\n- Delivery status queries\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_order_details](#mention) to fetch accurate order information.\n- Provide clear resolution options.\n\n🚫 Don'ts:\n- Assume missing items without user confirmation.\n- Extend the conversation beyond missing items.\n\n# Examples\n- **User** : I didn't receive my fries with my order.\n - **Agent response**: Let me check your order details. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My order is missing a drink.\n - **Agent response**: I apologize for the inconvenience. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get the extra sauce I ordered.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : My burger is missing from the order.\n - **Agent response**: I'm sorry to hear that. Let's verify your order details. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)\n\n- **User** : I didn't get my dessert.\n - **Agent response**: Let's check your order details to confirm. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_order_details](#mention)", + "model": "gpt-4o", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [ + "get_order_details" + ], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Delivery Status", + "type": "conversation", + "description": "Agent to assist users with delivery status queries.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nHelp users with queries related to the delivery status of their orders.\n\n---\n## βš™οΈ Steps to Follow:\n1. Fetch the delivery status using the [@tool:get_delivery_status] tool.\n2. Provide the user with the current delivery status.\n3. Offer additional assistance if needed.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Providing delivery status updates\n\n❌ Out of Scope:\n- Resolving missing items issues\n- General knowledge queries\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use [@tool:get_delivery_status](#mention) to fetch accurate delivery information.\n- Provide clear and concise status updates.\n\n🚫 Don'ts:\n- Provide status updates without fetching current information.\n- Extend the conversation beyond delivery status.\n\n# Examples\n- **User** : Where is my order?\n - **Agent response**: Let me check the delivery status for you. Could you please provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order on the way?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : When will my order arrive?\n - **Agent response**: Let me find out the delivery status. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : How long until my order gets here?\n - **Agent response**: I'll check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)\n\n- **User** : Is my order delayed?\n - **Agent response**: Let me check the delivery status for you. Could you provide your order ID?\n - **Agent actions**: Call [@tool:get_delivery_status](#mention)", + "model": "gpt-4o", + "controlType": "retain", + "ragK": 3, + "ragReturnType": "chunks", + "tools": [ + "get_delivery_status" + ], + "prompts": [], + "connectedAgents": [] + }, + { + "name": "Subscription Info", + "type": "conversation", + "description": "Agent to assist users with subscription-related queries.", + "instructions": "## πŸ§‘β€πŸ’Ό Role:\nProvide information and answer questions related to subscriptions using RAG.\n\n---\n## βš™οΈ Steps to Follow:\n1. Use RAG to retrieve relevant information about subscriptions.\n2. Answer the user's questions based on the retrieved information.\n3. If the user's query is outside the scope of subscriptions, inform them politely.\n\n---\n## 🎯 Scope:\nβœ… In Scope:\n- Subscription plans and pricing\n- Subscription features and benefits\n\n❌ Out of Scope:\n- Non-subscription-related queries\n- Detailed account management\n\n---\n## πŸ“‹ Guidelines:\nβœ”οΈ Dos:\n- Use RAG to provide accurate and up-to-date information.\n- Be clear and concise in your responses.\n\n🚫 Don'ts:\n- Provide information without using RAG.\n- Extend the conversation beyond subscription topics.\n\n# Examples\n- **User** : What are the available subscription plans?\n - **Agent response**: Let me check the available subscription plans for you.\n\n- **User** : How much does the premium subscription cost?\n - **Agent response**: I'll find the current pricing for the premium subscription.\n\n- **User** : Can I change my subscription plan?\n - **Agent response**: I'll provide information on how to change your subscription plan.\n\n- **User** : What benefits do I get with a subscription?\n - **Agent response**: Let me retrieve the benefits associated with our subscription plans.\n\n- **User** : Is there a free trial available?\n - **Agent response**: I'll check if there's a free trial available for our subscriptions.", + "model": "gpt-4o", + "controlType": "relinquish_to_parent", + "ragDataSources": [ + "67e1612510540d9027909e10" + ], + "ragK": 3, + "ragReturnType": "content", + "tools": [], + "prompts": [], + "connectedAgents": [] + } + ], + "tools": [ + { + "name": "get_order_details", + "description": "Tool to fetch the user's order details.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + } + }, + { + "name": "get_delivery_status", + "description": "Tool to fetch the delivery status of an order.", + "parameters": { + "type": "object", + "properties": { + "order_id": { + "type": "string", + "description": "The unique identifier for the order." + } + }, + "required": [ + "order_id" + ] + }, + "mockTool": true, + "mockInstructions": "Give a mock response for a door dash order delivery status." + } + ], + "prompts": [ + { + "name": "Style prompt", + "type": "style_prompt", + "prompt": "You should be empathetic and helpful." + }, + { + "name": "Greeting", + "type": "greeting", + "prompt": "Hello! How can I help you?" + } + ], + "startAgent": "DoorDash Support Hub", + "mcpServers": [ + { + "name": "delivery", + "url": "http://localhost:8000/sse" + } + ], + "toolWebhookUrl": "http://127.0.0.1:4020/tool_call" + } +} \ No newline at end of file diff --git a/apps/agents/tests/sample_responses/default_example.json b/apps/rowboat_agents/tests/sample_responses/default_example.json similarity index 100% rename from apps/agents/tests/sample_responses/default_example.json rename to apps/rowboat_agents/tests/sample_responses/default_example.json diff --git a/docker-compose.yml b/docker-compose.yml index 558b5f82..cfd098ae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,7 @@ services: - AUTH0_ISSUER_BASE_URL=${AUTH0_ISSUER_BASE_URL} - AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID} - AUTH0_CLIENT_SECRET=${AUTH0_CLIENT_SECRET} - - AGENTS_API_URL=http://agents:3001 + - AGENTS_API_URL=http://rowboat_agents:3001 - AGENTS_API_KEY=${AGENTS_API_KEY} - COPILOT_API_URL=http://copilot:3002 - COPILOT_API_KEY=${COPILOT_API_KEY} @@ -37,9 +37,9 @@ services: - MAX_PROJECTS_PER_USER=${MAX_PROJECTS_PER_USER} restart: unless-stopped - agents: + rowboat_agents: build: - context: ./apps/agents + context: ./apps/rowboat_agents dockerfile: Dockerfile ports: - "3001:3001" From 77b53696b60b16d0d21c3ea4f2d645e6a793ce0b Mon Sep 17 00:00:00 2001 From: ramnique <30795890+ramnique@users.noreply.github.com> Date: Tue, 25 Mar 2025 01:42:22 +0530 Subject: [PATCH 26/49] Next.js changes for playground streaming --- apps/rowboat/app/actions/actions.ts | 14 +- apps/rowboat/app/actions/mcp_actions.ts | 9 ++ .../v1/stream-response/[streamId]/route.ts | 45 ++++++ .../rowboat/app/lib/types/agents_api_types.ts | 4 + apps/rowboat/app/lib/utils.ts | 25 +++- .../projects/[projectId]/playground/app.tsx | 8 +- .../projects/[projectId]/playground/chat.tsx | 134 ++++++++++++------ .../[projectId]/playground/messages.tsx | 58 ++------ .../app/projects/[projectId]/workflow/app.tsx | 12 +- .../projects/[projectId]/workflow/page.tsx | 4 +- apps/rowboat_agents/pyproject.toml | 1 + apps/rowboat_agents/requirements.txt | 1 + apps/rowboat_agents/src/app/main.py | 99 +++++++------ apps/rowboat_agents/src/graph/core.py | 36 ++++- 14 files changed, 290 insertions(+), 160 deletions(-) create mode 100644 apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts diff --git a/apps/rowboat/app/actions/actions.ts b/apps/rowboat/app/actions/actions.ts index ed8ced54..2004a9eb 100644 --- a/apps/rowboat/app/actions/actions.ts +++ b/apps/rowboat/app/actions/actions.ts @@ -1,5 +1,5 @@ 'use server'; -import { convertFromAgenticAPIChatMessages } from "../lib/types/agents_api_types"; +import { AgenticAPIInitStreamResponse, convertFromAgenticAPIChatMessages } from "../lib/types/agents_api_types"; import { AgenticAPIChatRequest } from "../lib/types/agents_api_types"; import { WebpageCrawlResponse } from "../lib/types/tool_types"; import { webpagesCollection } from "../lib/mongodb"; @@ -7,7 +7,7 @@ import { z } from 'zod'; import FirecrawlApp, { ScrapeResponse } from '@mendable/firecrawl-js'; import { apiV1 } from "rowboat-shared"; import { Claims, getSession } from "@auth0/nextjs-auth0"; -import { getAgenticApiResponse } from "../lib/utils"; +import { getAgenticApiResponse, getAgenticResponseStreamId } from "../lib/utils"; import { check_query_limit } from "../lib/rate_limiting"; import { QueryLimitError } from "../lib/client_utils"; import { projectAuthCheck } from "./project_actions"; @@ -85,3 +85,13 @@ export async function getAssistantResponse(request: z.infer): Promise> { + await projectAuthCheck(request.projectId); + if (!await check_query_limit(request.projectId)) { + throw new QueryLimitError(); + } + + const response = await getAgenticResponseStreamId(request); + return response; +} \ No newline at end of file diff --git a/apps/rowboat/app/actions/mcp_actions.ts b/apps/rowboat/app/actions/mcp_actions.ts index eb2352f4..9ca6668f 100644 --- a/apps/rowboat/app/actions/mcp_actions.ts +++ b/apps/rowboat/app/actions/mcp_actions.ts @@ -6,6 +6,7 @@ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { projectAuthCheck } from "./project_actions"; import { projectsCollection } from "../lib/mongodb"; import { Project } from "../lib/types/project_types"; +import { MCPServer } from "../lib/types/types"; export async function fetchMcpTools(projectId: string): Promise[]> { await projectAuthCheck(projectId); @@ -71,4 +72,12 @@ export async function updateMcpServers(projectId: string, mcpServers: z.infer[]> { + await projectAuthCheck(projectId); + const project = await projectsCollection.findOne({ + _id: projectId, + }); + return project?.mcpServers ?? []; } \ No newline at end of file diff --git a/apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts b/apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts new file mode 100644 index 00000000..dac45025 --- /dev/null +++ b/apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts @@ -0,0 +1,45 @@ +export async function GET(request: Request, { params }: { params: { streamId: string } }) { + // Replace with your actual upstream SSE endpoint. + const upstreamUrl = `${process.env.AGENTS_API_URL}/chat_stream/${params.streamId}`; + console.log('upstreamUrl', upstreamUrl); + + // Fetch the upstream SSE stream. + const upstreamResponse = await fetch(upstreamUrl, { + headers: { + 'Authorization': `Bearer ${process.env.AGENTS_API_KEY}`, + }, + cache: 'no-store', + }); + + // If the upstream request fails, return a 502 Bad Gateway. + if (!upstreamResponse.ok || !upstreamResponse.body) { + return new Response("Error connecting to upstream SSE stream", { status: 502 }); + } + + const reader = upstreamResponse.body.getReader(); + + const stream = new ReadableStream({ + async start(controller) { + try { + // Read from the upstream stream continuously. + while (true) { + const { done, value } = await reader.read(); + if (done) break; + // Immediately enqueue each received chunk. + controller.enqueue(value); + } + controller.close(); + } catch (error) { + controller.error(error); + } + }, + }); + + return new Response(stream, { + headers: { + "Content-Type": "text/event-stream", + "Cache-Control": "no-cache", + "Connection": "keep-alive", + }, + }); +} \ No newline at end of file diff --git a/apps/rowboat/app/lib/types/agents_api_types.ts b/apps/rowboat/app/lib/types/agents_api_types.ts index 42c652da..c4d111ec 100644 --- a/apps/rowboat/app/lib/types/agents_api_types.ts +++ b/apps/rowboat/app/lib/types/agents_api_types.ts @@ -64,6 +64,10 @@ export const AgenticAPIChatResponse = z.object({ state: z.unknown(), }); +export const AgenticAPIInitStreamResponse = z.object({ + streamId: z.string(), +}); + export function convertWorkflowToAgenticAPI(workflow: z.infer): { agents: z.infer[]; tools: z.infer[]; diff --git a/apps/rowboat/app/lib/utils.ts b/apps/rowboat/app/lib/utils.ts index 24568a89..2f44d4c0 100644 --- a/apps/rowboat/app/lib/utils.ts +++ b/apps/rowboat/app/lib/utils.ts @@ -1,4 +1,4 @@ -import { AgenticAPIChatResponse, AgenticAPIChatRequest, AgenticAPIChatMessage } from "./types/agents_api_types"; +import { AgenticAPIChatResponse, AgenticAPIChatRequest, AgenticAPIChatMessage, AgenticAPIInitStreamResponse } from "./types/agents_api_types"; import { z } from "zod"; import { generateObject } from "ai"; import { ApiMessage } from "./types/types"; @@ -35,6 +35,29 @@ export async function getAgenticApiResponse( }; } +export async function getAgenticResponseStreamId( + request: z.infer, +): Promise> { + // call agentic api + console.log(`sending agentic api init stream request`, JSON.stringify(request)); + const response = await fetch(process.env.AGENTS_API_URL + '/chat_stream_init', { + method: 'POST', + body: JSON.stringify(request), + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.AGENTS_API_KEY || 'test'}`, + }, + }); + if (!response.ok) { + console.error('Failed to call agentic init stream api', response); + throw new Error(`Failed to call agentic init stream api: ${response.statusText}`); + } + const responseJson = await response.json(); + console.log(`received agentic api init stream response`, JSON.stringify(responseJson)); + const result: z.infer = responseJson; + return result; +} + // create a PrefixLogger class that wraps console.log with a prefix // and allows chaining with a parent logger export class PrefixLogger { diff --git a/apps/rowboat/app/projects/[projectId]/playground/app.tsx b/apps/rowboat/app/projects/[projectId]/playground/app.tsx index 69a5202f..33c16663 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/app.tsx @@ -48,10 +48,6 @@ export function App({ setCounter(counter + 1); } - if (hidden) { - return <>; - } - function handleNewChatButtonClick() { setCounter(counter + 1); setChat({ @@ -63,6 +59,10 @@ export function App({ }); } + if (hidden) { + return <>; + } + return ( []>(chat.messages); const [loadingAssistantResponse, setLoadingAssistantResponse] = useState(false); - const [loadingUserResponse, setLoadingUserResponse] = useState(false); - const [simulationComplete, setSimulationComplete] = useState(chat.simulationComplete || false); const [agenticState, setAgenticState] = useState(chat.agenticState || { last_agent_name: workflow.startAgent, }); @@ -51,6 +49,12 @@ export function Chat({ const [lastAgenticRequest, setLastAgenticRequest] = useState(null); const [lastAgenticResponse, setLastAgenticResponse] = useState(null); const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false); + const [optimisticMessages, setOptimisticMessages] = useState[]>(chat.messages); + + // reset optimistic messages when messages change + useEffect(() => { + setOptimisticMessages(messages); + }, [messages]); // collect published tool call results const toolCallResults: Record> = {}; @@ -59,6 +63,7 @@ export function Chat({ .forEach((message) => { toolCallResults[message.tool_call_id] = message; }); + console.log('toolCallResults', toolCallResults); function handleUserMessage(prompt: string) { const updatedMessages: z.infer[] = [...messages, { @@ -87,9 +92,12 @@ export function Chat({ } }, [messages, messageSubscriber]); - // get agent response + // get assistant response useEffect(() => { + console.log('stream useEffect called'); let ignore = false; + let eventSource: EventSource | null = null; + let msgs: z.infer[] = []; async function process() { setLoadingAssistantResponse(true); @@ -116,39 +124,76 @@ export function Chat({ setLastAgenticRequest(null); setLastAgenticResponse(null); + let streamId: string | null = null; try { - const response = await getAssistantResponse(request); + const response = await getAssistantResponseStreamId(request); if (ignore) { return; } - if (simulationComplete) { - return; - } - setLastAgenticRequest(response.rawRequest); - setLastAgenticResponse(response.rawResponse); - setMessages([...messages, ...response.messages.map((message) => ({ - ...message, - version: 'v1' as const, - chatId: '', - createdAt: new Date().toISOString(), - }))]); - setAgenticState(response.state); + streamId = response.streamId; } catch (err) { if (!ignore) { setFetchResponseError(`Failed to get assistant response: ${err instanceof Error ? err.message : 'Unknown error'}`); - } - } finally { - if (!ignore) { setLoadingAssistantResponse(false); } } + + if (ignore || !streamId) { + console.log('almost there', ignore, streamId); + return; + } + + // log the stream id + console.log('πŸ”„ got assistant response', streamId); + + // read from SSE stream + eventSource = new EventSource(`/api/v1/stream-response/${streamId}`); + + eventSource.addEventListener("message", (event) => { + if (ignore) { + return; + } + + try { + const data = JSON.parse(event.data); + const msg = AgenticAPIChatMessage.parse(data); + const parsedMsg = convertFromAgenticAPIChatMessages([msg])[0]; + console.log('πŸ”„ got assistant response chunk', parsedMsg); + msgs.push(parsedMsg); + setOptimisticMessages(prev => [...prev, parsedMsg]); + } catch (err) { + console.error('Failed to parse SSE message:', err); + setFetchResponseError(`Failed to parse SSE message: ${err instanceof Error ? err.message : 'Unknown error'}`); + setOptimisticMessages(messages); + } + }); + + eventSource.addEventListener('done', (event) => { + if (eventSource) { + eventSource.close(); + } + + console.log('πŸ”„ got assistant response done', event.data); + const parsed: {state: unknown} = JSON.parse(event.data); + setAgenticState(parsed.state); + setMessages([...messages, ...msgs]); + setLoadingAssistantResponse(false); + }); + + eventSource.onerror = (error) => { + console.error('SSE Error:', error); + if (!ignore) { + setLoadingAssistantResponse(false); + setFetchResponseError('Stream connection failed'); + setOptimisticMessages(messages); + } + }; } - // if last message is not from role user - // or tool, return + // if last message is not a user message, return if (messages.length > 0) { const last = messages[messages.length - 1]; - if (last.role !== 'user' && last.role !== 'tool') { + if (last.role !== 'user') { return; } } @@ -162,8 +207,22 @@ export function Chat({ return () => { ignore = true; + console.log('stream useEffect cleanup called'); + if (eventSource) { + eventSource.close(); + } }; - }, [chat.simulated, messages, projectId, agenticState, workflow, fetchResponseError, systemMessage, simulationComplete, mcpServerUrls, toolWebhookUrl, testProfile]); + }, [ + messages, + projectId, + agenticState, + workflow, + systemMessage, + mcpServerUrls, + toolWebhookUrl, + testProfile, + fetchResponseError, + ]); const handleCopyChat = () => { const jsonString = JSON.stringify({ @@ -202,10 +261,9 @@ export function Chat({ />
    )} - {!chat.simulated &&
    +
    -
    } - {chat.simulated && !simulationComplete &&
    - -
    Simulating...
    - -
    } - {chat.simulated && simulationComplete &&

    Simulation complete.

    } +
    ; } \ No newline at end of file diff --git a/apps/rowboat/app/projects/[projectId]/playground/messages.tsx b/apps/rowboat/app/projects/[projectId]/playground/messages.tsx index f4e52110..cd4c979e 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/messages.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/messages.tsx @@ -71,17 +71,6 @@ function AssistantMessageLoading() {
    ; } -function UserMessageLoading() { - return
    -
    - User -
    -
    - -
    -
    ; -} - function ToolCalls({ toolCalls, results, @@ -101,20 +90,14 @@ function ToolCalls({ testProfile: z.infer | null; systemMessage: string | undefined; }) { - const resultsMap: Record> = {}; - return
    {toolCalls.map(toolCall => { return })}
    ; @@ -123,21 +106,13 @@ function ToolCalls({ function ToolCall({ toolCall, result, - projectId, - messages, sender, workflow, - testProfile = null, - systemMessage, }: { toolCall: z.infer['tool_calls'][number]; result: z.infer | undefined; - projectId: string; - messages: z.infer[]; sender: string | null | undefined; workflow: z.infer; - testProfile: z.infer | null; - systemMessage: string | undefined; }) { let matchingWorkflowTool: z.infer | undefined; for (const tool of workflow.tools) { @@ -160,24 +135,6 @@ function ToolCall({ />; } -function ToolCallHeader({ - toolCall, - result, -}: { - toolCall: z.infer['tool_calls'][number]; - result: z.infer | undefined; -}) { - return
    -
    - {!result && } - {result && } -
    - Function Call: {toolCall.function.name} -
    -
    -
    ; -} - function TransferToAgentToolCall({ result: availableResult, sender, @@ -211,7 +168,15 @@ function ClientToolCall({ return
    {sender &&
    {sender}
    }
    - +
    +
    + {!availableResult && } + {availableResult && } +
    + Function Call: {toolCall.function.name} +
    +
    +
    @@ -292,7 +257,6 @@ export function Messages({ messages, toolCallResults, loadingAssistantResponse, - loadingUserResponse, workflow, testProfile = null, systemMessage, @@ -302,7 +266,6 @@ export function Messages({ messages: z.infer[]; toolCallResults: Record>; loadingAssistantResponse: boolean; - loadingUserResponse: boolean; workflow: z.infer; testProfile: z.infer | null; systemMessage: string | undefined; @@ -314,7 +277,7 @@ export function Messages({ // scroll to bottom on new messages useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }) - }, [messages, loadingAssistantResponse, loadingUserResponse]); + }, [messages, loadingAssistantResponse]); return
    @@ -368,7 +331,6 @@ export function Messages({ return <>; })} {loadingAssistantResponse && } - {loadingUserResponse && }
    ; diff --git a/apps/rowboat/app/projects/[projectId]/workflow/app.tsx b/apps/rowboat/app/projects/[projectId]/workflow/app.tsx index 331e20b7..20b94273 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/app.tsx @@ -9,17 +9,15 @@ import { WorkflowSelector } from "./workflow_selector"; import { Spinner } from "@heroui/react"; import { cloneWorkflow, createWorkflow, fetchPublishedWorkflowId, fetchWorkflow } from "../../../actions/workflow_actions"; import { listDataSources } from "../../../actions/datasource_actions"; +import { listMcpServers } from "@/app/actions/mcp_actions"; +import { getProjectConfig } from "@/app/actions/project_actions"; export function App({ projectId, useRag, - mcpServerUrls, - toolWebhookUrl, }: { projectId: string; useRag: boolean; - mcpServerUrls: Array>; - toolWebhookUrl: string; }) { const [selectorKey, setSelectorKey] = useState(0); const [workflow, setWorkflow] = useState> | null>(null); @@ -27,17 +25,23 @@ export function App({ const [dataSources, setDataSources] = useState>[] | null>(null); const [loading, setLoading] = useState(false); const [autoSelectIfOnlyOneWorkflow, setAutoSelectIfOnlyOneWorkflow] = useState(true); + const [mcpServerUrls, setMcpServerUrls] = useState>>([]); + const [toolWebhookUrl, setToolWebhookUrl] = useState(''); const handleSelect = useCallback(async (workflowId: string) => { setLoading(true); const workflow = await fetchWorkflow(projectId, workflowId); const publishedWorkflowId = await fetchPublishedWorkflowId(projectId); const dataSources = await listDataSources(projectId); + const mcpServers = await listMcpServers(projectId); + const projectConfig = await getProjectConfig(projectId); // Store the selected workflow ID in local storage localStorage.setItem(`lastWorkflowId_${projectId}`, workflowId); setWorkflow(workflow); setPublishedWorkflowId(publishedWorkflowId); setDataSources(dataSources); + setMcpServerUrls(mcpServers); + setToolWebhookUrl(projectConfig.webhookUrl ?? ''); setLoading(false); }, [projectId]); diff --git a/apps/rowboat/app/projects/[projectId]/workflow/page.tsx b/apps/rowboat/app/projects/[projectId]/workflow/page.tsx index be6d588c..09ec0573 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/page.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/page.tsx @@ -13,18 +13,16 @@ export default async function Page({ }: { params: { projectId: string }; }) { + console.log('->>> workflow page being rendered'); const project = await projectsCollection.findOne({ _id: params.projectId, }); if (!project) { notFound(); } - const toolWebhookUrl = project.webhookUrl ?? ''; return ; } diff --git a/apps/rowboat_agents/pyproject.toml b/apps/rowboat_agents/pyproject.toml index 42334612..6bdc8bbe 100644 --- a/apps/rowboat_agents/pyproject.toml +++ b/apps/rowboat_agents/pyproject.toml @@ -80,6 +80,7 @@ python-docx = "^1.1.2" python-dotenv = "^1.0.1" pytz = "^2024.2" qdrant-client = "*" +Quart = "^0.20.0" RapidFuzz = "^3.11.0" redis = "^5.2.1" requests = "^2.32.3" diff --git a/apps/rowboat_agents/requirements.txt b/apps/rowboat_agents/requirements.txt index a7035d18..3d2be2cc 100644 --- a/apps/rowboat_agents/requirements.txt +++ b/apps/rowboat_agents/requirements.txt @@ -66,6 +66,7 @@ python-docx==1.1.2 python-dotenv==1.0.1 pytz==2024.2 qdrant-client +Quart==0.20.0 RapidFuzz==3.11.0 redis==5.2.1 requests==2.32.3 diff --git a/apps/rowboat_agents/src/app/main.py b/apps/rowboat_agents/src/app/main.py index ccc65d45..6526c9e3 100644 --- a/apps/rowboat_agents/src/app/main.py +++ b/apps/rowboat_agents/src/app/main.py @@ -1,13 +1,13 @@ -from flask import Flask, request, jsonify, Response +from quart import Quart, request, jsonify, Response from datetime import datetime from functools import wraps import os import redis import uuid import json -import asyncio from hypercorn.config import Config from hypercorn.asyncio import serve +import asyncio from src.graph.core import run_turn, run_turn_streamed from src.graph.tools import RAG_TOOL, CLOSE_CHAT_TOOL @@ -17,19 +17,34 @@ from pprint import pprint logger = common_logger redis_client = redis.from_url(os.environ.get('REDIS_URL', 'redis://localhost:6379')) -app = Flask(__name__) +app = Quart(__name__) + +# filter out agent transfer messages using a function +def is_agent_transfer_message(msg): + if (msg.get("role") == "assistant" and + msg.get("content") is None and + msg.get("tool_calls") is not None and + len(msg.get("tool_calls")) > 0 and + msg.get("tool_calls")[0].get("function").get("name") == "transfer_to_agent"): + return True + if (msg.get("role") == "tool" and + msg.get("tool_calls") is None and + msg.get("tool_call_id") is not None and + msg.get("tool_name") == "transfer_to_agent"): + return True + return False @app.route("/health", methods=["GET"]) -def health(): +async def health(): return jsonify({"status": "ok"}) @app.route("/") -def home(): +async def home(): return "Hello, World!" def require_api_key(f): @wraps(f) - def decorated(*args, **kwargs): + async def decorated(*args, **kwargs): auth_header = request.headers.get('Authorization') if not auth_header or not auth_header.startswith('Bearer '): return jsonify({'error': 'Missing or invalid authorization header'}), 401 @@ -39,16 +54,16 @@ def require_api_key(f): if actual and token != actual: return jsonify({'error': 'Invalid API key'}), 403 - return f(*args, **kwargs) + return await f(*args, **kwargs) return decorated @app.route("/chat", methods=["POST"]) @require_api_key -def chat(): +async def chat(): logger.info('='*100) logger.info(f"{'*'*100}Running server mode{'*'*100}") try: - data = request.get_json() + data = await request.get_json() logger.info('Complete request:') logger.info(data) logger.info('-'*100) @@ -56,9 +71,12 @@ def chat(): start_time = datetime.now() config = read_json_from_file("./configs/default_config.json") + # filter out agent transfer messages + input_messages = [msg for msg in data.get("messages", []) if not is_agent_transfer_message(msg)] + logger.info('Beginning turn') resp_messages, resp_tokens_used, resp_state = run_turn( - messages=data.get("messages", []), + messages=input_messages, start_agent_name=data.get("startAgent", ""), agent_configs=data.get("agents", []), tool_configs=data.get("tools", []), @@ -94,19 +112,27 @@ def chat(): @app.route("/chat_stream_init", methods=["POST"]) @require_api_key -def chat_stream_init(): +async def chat_stream_init(): # create a uuid for the stream stream_id = str(uuid.uuid4()) # store the request data in redis with 10 minute TTL - data = request.get_json() + data = await request.get_json() redis_client.setex(f"stream_request_{stream_id}", 600, json.dumps(data)) - return jsonify({"stream_id": stream_id}) + print('* stream init'*200) + + return jsonify({"streamId": stream_id}) + +def format_sse(data: dict, event: str = None) -> str: + msg = f"data: {json.dumps(data)}\n\n" + if event is not None: + msg = f"event: {event}\n{msg}" + return msg @app.route("/chat_stream/", methods=["GET"]) @require_api_key -def chat_stream(stream_id): +async def chat_stream(stream_id): # get the request data from redis request_data = redis_client.get(f"stream_request_{stream_id}") if not request_data: @@ -114,17 +140,18 @@ def chat_stream(stream_id): request_data = json.loads(request_data) config = read_json_from_file("./configs/default_config.json") + + # filter out agent transfer messages + input_messages = [msg for msg in request_data["messages"] if not is_agent_transfer_message(msg)] # Preprocess messages to handle null content and role issues - for msg in request_data["messages"]: - # Handle null content in assistant messages with tool calls + for msg in input_messages: if (msg.get("role") == "assistant" and msg.get("content") is None and msg.get("tool_calls") is not None and len(msg.get("tool_calls")) > 0): msg["content"] = "Calling tool" - # Handle role issues if msg.get("role") == "tool": msg["role"] = "developer" elif not msg.get("role"): @@ -135,12 +162,11 @@ def chat_stream(stream_id): print('*'*200) pprint(request_data) print('='*200) - - async def process_stream(): + async def generate(): try: async for event_type, event_data in run_turn_streamed( - messages=request_data.get("messages", []), + messages=input_messages, start_agent_name=request_data.get("startAgent", ""), agent_configs=request_data.get("agents", []), tool_configs=request_data.get("tools", []), @@ -153,43 +179,16 @@ def chat_stream(stream_id): print('*'*200) print("Yielding message:") print('*'*200) - to_yield = f"event: message\ndata: {json.dumps(event_data)}\n\n" - print(to_yield) - print('='*200) - yield to_yield + yield format_sse(event_data, "message") elif event_type == 'done': print('*'*200) print("Yielding done:") print('*'*200) - to_yield = f"event: done\ndata: {json.dumps(event_data)}\n\n" - print(to_yield) - print('='*200) - yield to_yield + yield format_sse(event_data, "done") except Exception as e: logger.error(f"Streaming error: {str(e)}") - yield f"event: error\ndata: {json.dumps({'error': str(e)})}\n\n" - - def generate(): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - - try: - async def get_all_chunks(): - chunks = [] - async for chunk in process_stream(): - chunks.append(chunk) - return chunks - - chunks = loop.run_until_complete(get_all_chunks()) - for chunk in chunks: - yield chunk - - except Exception as e: - logger.error(f"Error in generate: {e}") - raise - finally: - loop.close() + yield format_sse({"error": str(e)}, "error") return Response(generate(), mimetype='text/event-stream') diff --git a/apps/rowboat_agents/src/graph/core.py b/apps/rowboat_agents/src/graph/core.py index 371e9aee..af00f870 100644 --- a/apps/rowboat_agents/src/graph/core.py +++ b/apps/rowboat_agents/src/graph/core.py @@ -1,6 +1,7 @@ from copy import deepcopy from datetime import datetime - +import json +import uuid import logging from .helpers.access import ( get_agent_by_name, @@ -285,16 +286,45 @@ async def run_turn_streamed( # Update current agent when it changes elif event.type == "agent_updated_stream_event": current_agent = event.new_agent + tool_call_id = str(uuid.uuid4()) + + # yield the transfer invocation message = { - 'content': f"Agent changed to {current_agent.name}", + 'content': None, 'role': 'assistant', 'sender': current_agent.name, - 'tool_calls': None, + 'tool_calls': [{ + 'function': { + 'name': 'transfer_to_agent', + 'arguments': json.dumps({ + 'assistant': event.new_agent.name + }) + }, + 'id': tool_call_id, + 'type': 'function' + }], 'tool_call_id': None, + 'tool_name': None, 'response_type': 'internal' } print("Yielding message: ", message) yield ('message', message) + + # yield the transfer result + message = { + 'content': json.dumps({ + 'assistant': event.new_agent.name + }), + 'role': 'tool', + 'sender': None, + 'tool_calls': None, + 'tool_call_id': tool_call_id, + 'tool_name': 'transfer_to_agent', + } + print("Yielding message: ", message) + yield ('message', message) + + current_agent = event.new_agent continue # Handle run items (tools, messages, etc) From 695a961333917a5dc3ee9f7642b5db15586619c6 Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Wed, 26 Mar 2025 15:22:59 +0530 Subject: [PATCH 27/49] Fix tool call id --- apps/rowboat_agents/src/graph/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/rowboat_agents/src/graph/core.py b/apps/rowboat_agents/src/graph/core.py index af00f870..b0f5b633 100644 --- a/apps/rowboat_agents/src/graph/core.py +++ b/apps/rowboat_agents/src/graph/core.py @@ -267,9 +267,9 @@ async def run_turn_streamed( # Process streaming events async for event in stream_result.stream_events(): - # print('='*50) - # print("Received event: ", event) - # print('-'*50) + print('='*50) + print("Received event: ", event) + print('-'*50) # Handle raw response events and accumulate tokens if event.type == "raw_response_event": @@ -339,7 +339,7 @@ async def run_turn_streamed( 'name': event.item.raw_item.name, 'arguments': event.item.raw_item.arguments }, - 'id': event.item.raw_item.id, + 'id': event.item.raw_item.call_id, 'type': 'function' }], 'tool_call_id': None, From 277a553ee10b8f476be38980cfa7002905f7749d Mon Sep 17 00:00:00 2001 From: Ramnique Singh <30795890+ramnique@users.noreply.github.com> Date: Wed, 26 Mar 2025 17:01:49 +0530 Subject: [PATCH 28/49] docker fixes for agents --- .../v1/stream-response/[streamId]/route.ts | 2 +- apps/rowboat_agents/.dockerignore | 1 + apps/rowboat_agents/Dockerfile | 4 +- apps/rowboat_agents/poetry.lock | 42 ++++++++++++++++++- apps/rowboat_agents/src/app/main.py | 9 ---- docker-compose.yml | 1 + 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts b/apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts index dac45025..563db7bb 100644 --- a/apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts +++ b/apps/rowboat/app/api/v1/stream-response/[streamId]/route.ts @@ -6,7 +6,7 @@ export async function GET(request: Request, { params }: { params: { streamId: st // Fetch the upstream SSE stream. const upstreamResponse = await fetch(upstreamUrl, { headers: { - 'Authorization': `Bearer ${process.env.AGENTS_API_KEY}`, + 'Authorization': `Bearer ${process.env.AGENTS_API_KEY || 'test'}`, }, cache: 'no-store', }); diff --git a/apps/rowboat_agents/.dockerignore b/apps/rowboat_agents/.dockerignore index 4a45bc02..8b13b832 100644 --- a/apps/rowboat_agents/.dockerignore +++ b/apps/rowboat_agents/.dockerignore @@ -2,3 +2,4 @@ .env* __pycache__/ venv/ +.venv/ \ No newline at end of file diff --git a/apps/rowboat_agents/Dockerfile b/apps/rowboat_agents/Dockerfile index 592a5444..019c6c2d 100644 --- a/apps/rowboat_agents/Dockerfile +++ b/apps/rowboat_agents/Dockerfile @@ -20,9 +20,9 @@ RUN poetry install --no-interaction --no-ansi COPY . . # Set environment variables -ENV FLASK_APP=src.app.main +ENV QUART_APP=src.app.main ENV PYTHONUNBUFFERED=1 ENV PYTHONPATH=/app # Command to run Flask development server -CMD ["flask", "run", "--host=0.0.0.0", "--port=3001"] +CMD ["quart", "run", "--host=0.0.0.0", "--port=3001"] diff --git a/apps/rowboat_agents/poetry.lock b/apps/rowboat_agents/poetry.lock index 71efeadb..43b83c76 100644 --- a/apps/rowboat_agents/poetry.lock +++ b/apps/rowboat_agents/poetry.lock @@ -1,5 +1,18 @@ # This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +[[package]] +name = "aiofiles" +version = "24.1.0" +description = "File support for asyncio." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, + {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, +] + [[package]] name = "aiohappyeyeballs" version = "2.6.1" @@ -3037,6 +3050,33 @@ urllib3 = ">=1.26.14,<3" fastembed = ["fastembed (==0.5.1)"] fastembed-gpu = ["fastembed-gpu (==0.5.1)"] +[[package]] +name = "quart" +version = "0.20.0" +description = "A Python ASGI web framework with the same API as Flask" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "quart-0.20.0-py3-none-any.whl", hash = "sha256:003c08f551746710acb757de49d9b768986fd431517d0eb127380b656b98b8f1"}, + {file = "quart-0.20.0.tar.gz", hash = "sha256:08793c206ff832483586f5ae47018c7e40bdd75d886fee3fabbdaa70c2cf505d"}, +] + +[package.dependencies] +aiofiles = "*" +blinker = ">=1.6" +click = ">=8.0" +flask = ">=3.0" +hypercorn = ">=0.11.2" +itsdangerous = "*" +jinja2 = "*" +markupsafe = "*" +werkzeug = ">=3.0" + +[package.extras] +dotenv = ["python-dotenv"] + [[package]] name = "rapidfuzz" version = "3.12.2" @@ -4091,4 +4131,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "fc7b2d64a9f856b5a0c1aceb6be83ac18f8f9c6f95b8db63b28e69d385dcd38b" +content-hash = "fa1d4cfd411dca631759ca36e0c7a02c1fe4c11b1ee121557a92cd616867e9a7" diff --git a/apps/rowboat_agents/src/app/main.py b/apps/rowboat_agents/src/app/main.py index 6526c9e3..e282fae4 100644 --- a/apps/rowboat_agents/src/app/main.py +++ b/apps/rowboat_agents/src/app/main.py @@ -120,8 +120,6 @@ async def chat_stream_init(): data = await request.get_json() redis_client.setex(f"stream_request_{stream_id}", 600, json.dumps(data)) - print('* stream init'*200) - return jsonify({"streamId": stream_id}) def format_sse(data: dict, event: str = None) -> str: @@ -157,11 +155,8 @@ async def chat_stream(stream_id): elif not msg.get("role"): msg["role"] = "user" - print('*'*200) print("Request:") - print('*'*200) pprint(request_data) - print('='*200) async def generate(): try: @@ -176,14 +171,10 @@ async def chat_stream(stream_id): complete_request=request_data ): if event_type == 'message': - print('*'*200) print("Yielding message:") - print('*'*200) yield format_sse(event_data, "message") elif event_type == 'done': - print('*'*200) print("Yielding done:") - print('*'*200) yield format_sse(event_data, "done") except Exception as e: diff --git a/docker-compose.yml b/docker-compose.yml index cfd098ae..f54fba01 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -46,6 +46,7 @@ services: environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - API_KEY=${AGENTS_API_KEY} + - REDIS_URL=redis://redis:6379 restart: unless-stopped copilot: From d58c0cce88e3981ae2614e8b9973a77736419c60 Mon Sep 17 00:00:00 2001 From: arkml Date: Wed, 26 Mar 2025 21:05:49 +0530 Subject: [PATCH 29/49] added jwt header for calling webhook tools --- apps/rowboat_agents/poetry.lock | 21 +++++++++++++- apps/rowboat_agents/pyproject.toml | 1 + apps/rowboat_agents/requirements.txt | 1 + .../rowboat_agents/src/graph/swarm_wrapper.py | 29 ++++++++++++++++--- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/apps/rowboat_agents/poetry.lock b/apps/rowboat_agents/poetry.lock index 43b83c76..4332d3d6 100644 --- a/apps/rowboat_agents/poetry.lock +++ b/apps/rowboat_agents/poetry.lock @@ -2822,6 +2822,25 @@ azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0 toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] +[[package]] +name = "pyjwt" +version = "2.10.1" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.11\" or python_version == \"3.12\" or python_version >= \"3.13\"" +files = [ + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + [[package]] name = "pymongo" version = "4.10.1" @@ -4131,4 +4150,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "fa1d4cfd411dca631759ca36e0c7a02c1fe4c11b1ee121557a92cd616867e9a7" +content-hash = "e384375098923696153ae702a6ac3eae30c2aeaf56844a2de66072194420d042" diff --git a/apps/rowboat_agents/pyproject.toml b/apps/rowboat_agents/pyproject.toml index 6bdc8bbe..2cb85ee6 100644 --- a/apps/rowboat_agents/pyproject.toml +++ b/apps/rowboat_agents/pyproject.toml @@ -73,6 +73,7 @@ poetry-core = "^2.0.1" pycparser = "^2.22" pydantic = "^2.10.5" pydantic_core = "^2.27.2" +PyJWT = "^2.10.1" pymongo = "^4.10.1" pyproject_hooks = "^1.2.0" python-dateutil = "^2.9.0.post0" diff --git a/apps/rowboat_agents/requirements.txt b/apps/rowboat_agents/requirements.txt index 3d2be2cc..aaa4caa4 100644 --- a/apps/rowboat_agents/requirements.txt +++ b/apps/rowboat_agents/requirements.txt @@ -59,6 +59,7 @@ poetry-core==2.0.1 pycparser==2.22 pydantic==2.10.5 pydantic_core==2.27.2 +PyJWT==2.10.1 pymongo==4.10.1 pyproject_hooks==1.2.0 python-dateutil==2.9.0.post0 diff --git a/apps/rowboat_agents/src/graph/swarm_wrapper.py b/apps/rowboat_agents/src/graph/swarm_wrapper.py index ea15682e..6f428a49 100644 --- a/apps/rowboat_agents/src/graph/swarm_wrapper.py +++ b/apps/rowboat_agents/src/graph/swarm_wrapper.py @@ -1,6 +1,9 @@ import logging import json import aiohttp +import jwt +import hashlib + # Import helper functions needed for get_agents from .helpers.access import ( get_tool_config_by_name, @@ -22,6 +25,11 @@ from mcp.client.sse import sse_client from pydantic import BaseModel from typing import List, Optional, Dict from .tool_calling import call_rag_tool +from pymongo import MongoClient +import os +MONGO_URI = os.environ.get("MONGODB_URI", "mongodb://localhost:27017/rowboat").strip() +mongo_client = MongoClient(MONGO_URI) +db = mongo_client["rowboat"] class NewResponse(BaseModel): messages: List[Dict] @@ -56,7 +64,7 @@ async def mock_tool(tool_name: str, args: str, tool_config: str) -> str: response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") return response_content -async def call_webhook(tool_name: str, args: str, webhook_url: str) -> str: +async def call_webhook(tool_name: str, args: str, webhook_url: str, signing_secret: str) -> str: """ Calls the webhook with the given tool name and arguments. @@ -78,9 +86,19 @@ async def call_webhook(tool_name: str, args: str, webhook_url: str) -> str: request_body = { "content": json.dumps(content_dict) } + + # Prepare headers + headers = {} + if signing_secret: + content_str = request_body["content"] + body_hash = hashlib.sha256(content_str.encode('utf-8')).hexdigest() + payload = {"bodyHash": body_hash} + signature_jwt = jwt.encode(payload, signing_secret, algorithm="HS256") + headers["X-Signature-Jwt"] = signature_jwt + try: async with aiohttp.ClientSession() as session: - async with session.post(webhook_url, json=request_body) as response: + async with session.post(webhook_url, json=request_body, headers=headers) as response: if response.status == 200: response_json = await response.json() return response_json.get("result", "") @@ -132,8 +150,11 @@ async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool mcp_server_url = next((server.get("url", "") for server in mcp_servers if server.get("name") == mcp_server_name), "") response_content = await call_mcp(tool_name, args, mcp_server_url) else: + collection = db["projects"] + doc = collection.find_one({"_id": complete_request.get("projectId", "")}) + signing_secret = doc.get("secret", "") webhook_url = complete_request.get("toolWebhookUrl", "") - response_content = await call_webhook(tool_name, args, webhook_url) + response_content = await call_webhook(tool_name, args, webhook_url, signing_secret) return response_content @@ -380,7 +401,7 @@ async def run_streamed( logger.info("Beginning Swarm streaming run") print("Beginning Swarm streaming run") - + try: # Use the Runner.run_streamed method stream_result = Runner.run_streamed(agent, formatted_messages) From 4b3395ea3a53229cef26ad2996d9902b446d2762 Mon Sep 17 00:00:00 2001 From: arkml Date: Wed, 26 Mar 2025 23:08:23 +0530 Subject: [PATCH 30/49] added test profile support for tools --- apps/rowboat_agents/src/graph/swarm_wrapper.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/rowboat_agents/src/graph/swarm_wrapper.py b/apps/rowboat_agents/src/graph/swarm_wrapper.py index 6f428a49..48b723cc 100644 --- a/apps/rowboat_agents/src/graph/swarm_wrapper.py +++ b/apps/rowboat_agents/src/graph/swarm_wrapper.py @@ -37,7 +37,7 @@ class NewResponse(BaseModel): tokens_used: Optional[dict] = {} error_msg: Optional[str] = "" -async def mock_tool(tool_name: str, args: str, tool_config: str) -> str: +async def mock_tool(tool_name: str, args: str, description: str, mock_instructions: str) -> str: """ Handles tool execution by either using mock instructions or generating a response. @@ -51,9 +51,6 @@ async def mock_tool(tool_name: str, args: str, tool_config: str) -> str: """ print(f"Mock tool called for: {tool_name}") - # For non-mocked tools, generate a realistic response - description = tool_config.get("description", "") - mock_instructions = tool_config.get("mockInstructions", "") messages = [ {"role": "system", "content": f"You are simulating the execution of a tool called '{tool_name}'.Here is the description of the tool: {description}. Here are the instructions for the mock tool: {mock_instructions}. Generate a realistic response as if the tool was actually executed with the given parameters."}, @@ -140,9 +137,12 @@ async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool asyncio.set_event_loop(loop) response_content = None - if tool_config.get("mockTool", False): + if tool_config.get("mockTool", False) or complete_request.get("testProfile", {}).get("mockTools", False): # Call mock_tool to handle the response (it will decide whether to use mock instructions or generate a response) - response_content = await mock_tool(tool_name, args, tool_config) + if complete_request.get("testProfile", {}).get("mockPrompt", ""): + response_content = await mock_tool(tool_name, args, tool_config.get("description", ""), complete_request.get("testProfile", {}).get("mockPrompt", "")) + else: + response_content = await mock_tool(tool_name, args, tool_config.get("description", ""), tool_config.get("mockInstructions", "")) print(response_content) elif tool_config.get("isMcp", False): mcp_server_name = tool_config.get("mcpServerName", "") From 861bae11a6d27c6d58ec7dd9ec7ed8d918d71e56 Mon Sep 17 00:00:00 2001 From: Ramnique Singh <30795890+ramnique@users.noreply.github.com> Date: Thu, 27 Mar 2025 07:58:15 +0530 Subject: [PATCH 31/49] make auth optional --- .env.example | 16 +++++-- README.md | 52 ++++++++++++--------- apps/rowboat/app/actions/actions.ts | 8 ++++ apps/rowboat/app/actions/project_actions.ts | 4 ++ apps/rowboat/app/lib/feature_flags.ts | 3 +- apps/rowboat/app/page.tsx | 7 +++ apps/rowboat/app/projects/layout.tsx | 5 +- apps/rowboat/middleware.ts | 4 ++ docker-compose.yml | 1 + 9 files changed, 73 insertions(+), 27 deletions(-) diff --git a/.env.example b/.env.example index 7f47d65a..d1c2b535 100644 --- a/.env.example +++ b/.env.example @@ -2,11 +2,19 @@ # ------------------------------------------------------------ MONGODB_CONNECTION_STRING=mongodb://127.0.0.1:27017/rowboat OPENAI_API_KEY= -AUTH0_SECRET= + + +# Uncomment to enable auth using Auth0 +# ------------------------------------------------------------ +# USE_AUTH=true + +# Even though auth is disabled by default, these test values are needed for the auth0 imports +# -------------------------------------------------------------------------------------------- +AUTH0_SECRET=test_secret AUTH0_BASE_URL=http://localhost:3000 -AUTH0_ISSUER_BASE_URL= -AUTH0_CLIENT_ID= -AUTH0_CLIENT_SECRET= +AUTH0_ISSUER_BASE_URL=https://test.com +AUTH0_CLIENT_ID=test +AUTH0_CLIENT_SECRET=test # Uncomment to enable RAG: # ------------------------------------------------------------ diff --git a/README.md b/README.md index 59ff1441..da1223e7 100644 --- a/README.md +++ b/README.md @@ -42,20 +42,6 @@ Before running RowBoat, ensure you have: brew services start mongodb-community@8.0 ``` -4. **Auth0 Account and Application Setup** - - **Create an Auth0 Account**: Sign up at [Auth0](https://auth0.com). - - **Create a New Application**: Choose "Regular Web Application", select "Next.js" as the application type, and name it "RowBoat". - - **Configure Application**: - - **Allowed Callback URLs**: In the Auth0 Dashboard, go to your "RowBoat" application settings and set `http://localhost:3000/api/auth/callback` as an Allowed Callback URL. - - **Get Credentials**: Collect the following from your Auth0 application settings: - - **Domain**: Copy your Auth0 domain (ensure you append `https://` to the Domain that the Auth0 dashboard shows you) - - **Client ID**: Your application's unique identifier - - **Client Secret**: Your application's secret key - - **Generate secret**: Generate a session encryption secret in your terminal and note the output for later: - ```bash - openssl rand -hex 32 - ``` - ## Local Development Setup 1. **Clone the Repository** @@ -75,13 +61,6 @@ Before running RowBoat, ensure you have: # OpenAI Configuration OPENAI_API_KEY=your-openai-api-key - # Auth0 Configuration - AUTH0_SECRET=your-generated-secret # Generated using openssl command - AUTH0_BASE_URL=http://localhost:3000 # Your application's base URL - AUTH0_ISSUER_BASE_URL=https://example.auth0.com # Your Auth0 domain (ensure it is prefixed with https://) - AUTH0_CLIENT_ID=your-client-id - AUTH0_CLIENT_SECRET=your-client-secret - # MongoDB Configuration (choose one based on your setup) # For local MongoDB MONGODB_CONNECTION_STRING=mongodb://host.docker.internal:27017/rowboat @@ -173,6 +152,37 @@ Before running RowBoat, ensure you have: The documentation site is available at [http://localhost:8000](http://localhost:8000) +## Enable Authentication + +By default, RowBoat runs without authentication. To enable user authentication using Auth0: + +1. **Auth0 Setup** + - **Create an Auth0 Account**: Sign up at [Auth0](https://auth0.com). + - **Create a New Application**: Choose "Regular Web Application", select "Next.js" as the application type, and name it "RowBoat". + - **Configure Application**: + - **Allowed Callback URLs**: In the Auth0 Dashboard, go to your "RowBoat" application settings and set `http://localhost:3000/api/auth/callback` as an Allowed Callback URL. + - **Get Credentials**: Collect the following from your Auth0 application settings: + - **Domain**: Copy your Auth0 domain (ensure you append `https://` to the Domain that the Auth0 dashboard shows you) + - **Client ID**: Your application's unique identifier + - **Client Secret**: Your application's secret key + - **Generate secret**: Generate a session encryption secret in your terminal and note the output for later: + ```bash + openssl rand -hex 32 + ``` + +2. **Update Environment Variables** + Add the following to your `.env` file: + ```ini + USE_AUTH=true + AUTH0_SECRET=your-generated-secret # Generated using openssl command + AUTH0_BASE_URL=http://localhost:3000 # Your application's base URL + AUTH0_ISSUER_BASE_URL=https://example.auth0.com # Your Auth0 domain (ensure it is prefixed with https://) + AUTH0_CLIENT_ID=your-client-id + AUTH0_CLIENT_SECRET=your-client-secret + ``` + +After enabling authentication, users will need to sign in to access the application. + ## Enable RAG RowBoat supports RAG capabilities to enhance responses with your custom knowledge base. To enable RAG, you'll need: diff --git a/apps/rowboat/app/actions/actions.ts b/apps/rowboat/app/actions/actions.ts index 2004a9eb..a9596788 100644 --- a/apps/rowboat/app/actions/actions.ts +++ b/apps/rowboat/app/actions/actions.ts @@ -11,10 +11,18 @@ import { getAgenticApiResponse, getAgenticResponseStreamId } from "../lib/utils" import { check_query_limit } from "../lib/rate_limiting"; import { QueryLimitError } from "../lib/client_utils"; import { projectAuthCheck } from "./project_actions"; +import { USE_AUTH } from "../lib/feature_flags"; const crawler = new FirecrawlApp({ apiKey: process.env.FIRECRAWL_API_KEY || '' }); export async function authCheck(): Promise { + if (!USE_AUTH) { + return { + email: 'guestuser@rowboatlabs.com', + email_verified: true, + sub: 'guest_user', + }; + } const { user } = await getSession() || {}; if (!user) { throw new Error('User not authenticated'); diff --git a/apps/rowboat/app/actions/project_actions.ts b/apps/rowboat/app/actions/project_actions.ts index 1945751c..0090aec9 100644 --- a/apps/rowboat/app/actions/project_actions.ts +++ b/apps/rowboat/app/actions/project_actions.ts @@ -10,8 +10,12 @@ import { authCheck } from "./actions"; import { WithStringId } from "../lib/types/types"; import { ApiKey } from "../lib/types/project_types"; import { Project } from "../lib/types/project_types"; +import { USE_AUTH } from "../lib/feature_flags"; export async function projectAuthCheck(projectId: string) { + if (!USE_AUTH) { + return; + } const user = await authCheck(); const membership = await projectMembersCollection.findOne({ projectId, diff --git a/apps/rowboat/app/lib/feature_flags.ts b/apps/rowboat/app/lib/feature_flags.ts index bb48726e..37c83deb 100644 --- a/apps/rowboat/app/lib/feature_flags.ts +++ b/apps/rowboat/app/lib/feature_flags.ts @@ -1,4 +1,5 @@ export const USE_RAG = process.env.USE_RAG === 'true'; export const USE_RAG_UPLOADS = process.env.USE_RAG_UPLOADS === 'true'; export const USE_RAG_SCRAPING = process.env.USE_RAG_SCRAPING === 'true'; -export const USE_CHAT_WIDGET = process.env.USE_CHAT_WIDGET === 'true'; \ No newline at end of file +export const USE_CHAT_WIDGET = process.env.USE_CHAT_WIDGET === 'true'; +export const USE_AUTH = process.env.USE_AUTH === 'true'; \ No newline at end of file diff --git a/apps/rowboat/app/page.tsx b/apps/rowboat/app/page.tsx index 36eb5e64..af00d089 100644 --- a/apps/rowboat/app/page.tsx +++ b/apps/rowboat/app/page.tsx @@ -1,5 +1,12 @@ import { App } from "./app"; +import { redirect } from "next/navigation"; +import { USE_AUTH } from "./lib/feature_flags"; + +export const dynamic = 'force-dynamic'; export default function Home() { + if (!USE_AUTH) { + redirect("/projects"); + } return } \ No newline at end of file diff --git a/apps/rowboat/app/projects/layout.tsx b/apps/rowboat/app/projects/layout.tsx index d5ec6c00..3ac4b885 100644 --- a/apps/rowboat/app/projects/layout.tsx +++ b/apps/rowboat/app/projects/layout.tsx @@ -4,6 +4,9 @@ import Image from "next/image"; import Link from "next/link"; import { UserButton } from "../lib/components/user_button"; import { ThemeToggle } from "../lib/components/theme-toggle"; +import { USE_AUTH } from "../lib/feature_flags"; + +export const dynamic = 'force-dynamic'; export default function Layout({ children, @@ -30,7 +33,7 @@ export default function Layout({
    - + {USE_AUTH && }
    diff --git a/apps/rowboat/middleware.ts b/apps/rowboat/middleware.ts index f13b9340..d92821d8 100644 --- a/apps/rowboat/middleware.ts +++ b/apps/rowboat/middleware.ts @@ -34,6 +34,10 @@ export async function middleware(request: NextRequest, event: NextFetchEvent) { } if (request.nextUrl.pathname.startsWith('/projects')) { + // Skip auth check if USE_AUTH is not enabled + if (process.env.USE_AUTH !== 'true') { + return NextResponse.next(); + } return auth0MiddlewareHandler(request, event); } diff --git a/docker-compose.yml b/docker-compose.yml index f54fba01..a0c68c0b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - MONGODB_CONNECTION_STRING=${MONGODB_CONNECTION_STRING} + - USE_AUTH=${USE_AUTH} - AUTH0_SECRET=${AUTH0_SECRET} - AUTH0_BASE_URL=${AUTH0_BASE_URL} - AUTH0_ISSUER_BASE_URL=${AUTH0_ISSUER_BASE_URL} From de6b3cbbbb3fea2c1cfee67ca0efda2590ecfe6b Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Sun, 2 Mar 2025 18:58:10 +0530 Subject: [PATCH 32/49] Add twilio configuration user flow --- apps/rowboat/app/actions/voice_actions.ts | 280 ++++++++++++++++++ .../editable-field-with-immediate-save.tsx | 204 +++++++++++++ apps/rowboat/app/lib/mongodb.ts | 15 +- apps/rowboat/app/lib/types/voice_types.ts | 32 ++ .../app/projects/[projectId]/config/app.tsx | 178 +++++++---- .../app/projects/[projectId]/config/voice.tsx | 229 ++++++++++++++ apps/rowboat/package.json | 1 + apps/voice/Dockerfile | 27 ++ apps/voice/__init__.py | 1 + apps/voice/load_env.py | 6 + docker-compose.yml | 18 ++ 11 files changed, 926 insertions(+), 65 deletions(-) create mode 100644 apps/rowboat/app/actions/voice_actions.ts create mode 100644 apps/rowboat/app/lib/components/editable-field-with-immediate-save.tsx create mode 100644 apps/rowboat/app/lib/types/voice_types.ts create mode 100644 apps/rowboat/app/projects/[projectId]/config/voice.tsx create mode 100644 apps/voice/Dockerfile create mode 100644 apps/voice/__init__.py create mode 100644 apps/voice/load_env.py diff --git a/apps/rowboat/app/actions/voice_actions.ts b/apps/rowboat/app/actions/voice_actions.ts new file mode 100644 index 00000000..52a3622f --- /dev/null +++ b/apps/rowboat/app/actions/voice_actions.ts @@ -0,0 +1,280 @@ +'use server'; + +import { TwilioConfigParams, TwilioConfigResponse, TwilioConfig, InboundConfigResponse } from "../lib/types/voice_types"; +import { twilioConfigsCollection } from "../lib/mongodb"; +import { ObjectId } from "mongodb"; +import twilio from 'twilio'; +import { Twilio } from 'twilio'; + +// Helper function to serialize MongoDB documents +function serializeConfig(config: any) { + return { + ...config, + _id: config._id.toString(), + createdAt: config.createdAt.toISOString(), + }; +} + +// Real implementation for configuring Twilio number +export async function configureTwilioNumber(params: TwilioConfigParams): Promise { + console.log('configureTwilioNumber - Received params:', params); + try { + const client = twilio(params.account_sid, params.auth_token); + + try { + // List all phone numbers and find the matching one + const numbers = await client.incomingPhoneNumbers.list(); + console.log('Twilio numbers for this account:', numbers); + const phoneExists = numbers.some( + number => number.phoneNumber === params.phone_number + ); + + if (!phoneExists) { + throw new Error('Phone number not found in this account'); + } + } catch (error) { + console.error('Error verifying phone number:', error); + throw new Error( + error instanceof Error + ? error.message + : 'Invalid phone number or phone number does not belong to this account' + ); + } + + // Save to MongoDB after successful validation + const savedConfig = await saveTwilioConfig(params); + console.log('configureTwilioNumber - Saved config result:', savedConfig); + + return { success: true }; + } catch (error) { + console.error('Error in configureTwilioNumber:', error); + return { + success: false, + error: error instanceof Error ? error.message : 'Failed to configure Twilio number' + }; + } +} + +// Save Twilio configuration to MongoDB +export async function saveTwilioConfig(params: TwilioConfigParams): Promise { + console.log('saveTwilioConfig - Incoming params:', { + ...params, + label: { + value: params.label, + type: typeof params.label, + length: params.label?.length, + isEmpty: params.label === '' + } + }); + + // First, list all configs to see what's in the database + const allConfigs = await twilioConfigsCollection + .find({ status: 'active' as const }) + .toArray(); + console.log('saveTwilioConfig - All active configs in DB:', allConfigs); + + // Find existing config for this project + const existingConfig = await twilioConfigsCollection.findOne({ + project_id: params.project_id, + status: 'active' as const + }); + console.log('saveTwilioConfig - Existing config search by project:', { + searchCriteria: { + project_id: params.project_id, + status: 'active' + }, + found: existingConfig + }); + + const configToSave = { + phone_number: params.phone_number, + account_sid: params.account_sid, + auth_token: params.auth_token, + label: params.label || '', // Use empty string instead of undefined + project_id: params.project_id, + workflow_id: params.workflow_id, + createdAt: existingConfig?.createdAt || new Date(), + status: 'active' as const + }; + console.log('saveTwilioConfig - Config to save:', configToSave); + + try { + // Configure inbound calls first + await configureInboundCall( + params.phone_number, + params.account_sid, + params.auth_token, + params.workflow_id + ); + + // Then save/update the config in database + if (existingConfig) { + console.log('saveTwilioConfig - Updating existing config:', existingConfig._id); + const result = await twilioConfigsCollection.updateOne( + { _id: existingConfig._id }, + { $set: configToSave } + ); + console.log('saveTwilioConfig - Update result:', result); + } else { + console.log('saveTwilioConfig - No existing config found, creating new'); + const result = await twilioConfigsCollection.insertOne(configToSave); + console.log('saveTwilioConfig - Insert result:', result); + } + + const savedConfig = await twilioConfigsCollection.findOne({ + project_id: params.project_id, + status: 'active' + }); + + if (!savedConfig) { + throw new Error('Failed to save Twilio configuration'); + } + + console.log('configureTwilioNumber - Saved config result:', savedConfig); + return savedConfig; + + } catch (error) { + console.error('Error saving Twilio config:', error); + throw error; + } +} + +// Get Twilio configuration for a workflow +export async function getTwilioConfigs(projectId: string) { + console.log('getTwilioConfigs - Fetching for projectId:', projectId); + const configs = await twilioConfigsCollection + .find({ + project_id: projectId, + status: 'active' as const + }) + .sort({ createdAt: -1 }) + .limit(1) + .toArray(); + + console.log('getTwilioConfigs - Raw configs:', configs); + const serializedConfigs = configs.map(serializeConfig); + console.log('getTwilioConfigs - Serialized configs:', serializedConfigs); + return serializedConfigs; +} + +// Delete a Twilio configuration (soft delete) +export async function deleteTwilioConfig(projectId: string, configId: string) { + console.log('deleteTwilioConfig - Deleting config:', { projectId, configId }); + const result = await twilioConfigsCollection.updateOne( + { + _id: new ObjectId(configId), + project_id: projectId + }, + { + $set: { status: 'deleted' as const } + } + ); + console.log('deleteTwilioConfig - Delete result:', result); + return result; +} + +// Mock implementation for testing/development +export async function mockConfigureTwilioNumber(params: TwilioConfigParams): Promise { + await new Promise(resolve => setTimeout(resolve, 1000)); + await saveTwilioConfig(params); + return { success: true }; +} + +export async function configureInboundCall( + phone_number: string, + account_sid: string, + auth_token: string, + workflow_id: string +): Promise { + try { + // Normalize phone number format + if (!phone_number.startsWith('+')) { + phone_number = '+' + phone_number; + } + + console.log('Configuring inbound call for:', { + phone_number, + workflow_id + }); + + // Initialize Twilio client + const client = new Twilio(account_sid, auth_token); + + // Find the phone number in Twilio account + const incomingPhoneNumbers = await client.incomingPhoneNumbers.list({ phoneNumber: phone_number }); + console.log('Found Twilio numbers:', incomingPhoneNumbers.map(n => ({ + phoneNumber: n.phoneNumber, + currentVoiceUrl: n.voiceUrl, + currentStatusCallback: n.statusCallback, + sid: n.sid + }))); + + if (!incomingPhoneNumbers.length) { + throw new Error(`Phone number ${phone_number} not found in Twilio account`); + } + + const phoneSid = incomingPhoneNumbers[0].sid; + const currentVoiceUrl = incomingPhoneNumbers[0].voiceUrl; + const wasPreviouslyConfigured = Boolean(currentVoiceUrl); + + // Get base URL from environment - MUST be a public URL + const baseUrl = process.env.VOICE_API_URL; + if (!baseUrl) { + throw new Error('Voice service URL not configured. Please set VOICE_API_URL environment variable.'); + } + + // Validate URL is not localhost + if (baseUrl.includes('localhost')) { + throw new Error('Voice service must use a public URL, not localhost.'); + } + + const inboundUrl = `${baseUrl}/inbound?workflow_id=${workflow_id}`; + console.log('Setting up webhooks:', { + voiceUrl: inboundUrl, + statusCallback: `${baseUrl}/call-status`, + currentConfig: { + voiceUrl: currentVoiceUrl, + statusCallback: incomingPhoneNumbers[0].statusCallback + } + }); + + // Update the phone number configuration + const updatedNumber = await client.incomingPhoneNumbers(phoneSid).update({ + voiceUrl: inboundUrl, + voiceMethod: 'POST', + statusCallback: `${baseUrl}/call-status`, + statusCallbackMethod: 'POST' + }); + + console.log('Webhook configuration complete:', { + phoneNumber: updatedNumber.phoneNumber, + newVoiceUrl: updatedNumber.voiceUrl, + newStatusCallback: updatedNumber.statusCallback, + success: updatedNumber.voiceUrl === inboundUrl + }); + + return { + status: wasPreviouslyConfigured ? 'reconfigured' : 'configured', + phone_number: phone_number, + workflow_id: workflow_id, + previous_webhook: wasPreviouslyConfigured ? currentVoiceUrl : undefined + }; + + } catch (err: unknown) { + console.error('Error configuring inbound call:', err); + + // Type guard for error with message property + if (err instanceof Error) { + if (err.message.includes('localhost')) { + throw new Error('Voice service needs to be accessible from the internet. Please check your configuration.'); + } + // Type guard for Twilio error + if ('code' in err && err.code === 21402) { + throw new Error('Invalid voice service URL. Please make sure it\'s a public, secure URL.'); + } + } + + // If we can't determine the specific error, throw a generic one + throw new Error('Failed to configure phone number. Please check your settings and try again.'); + } +} \ No newline at end of file diff --git a/apps/rowboat/app/lib/components/editable-field-with-immediate-save.tsx b/apps/rowboat/app/lib/components/editable-field-with-immediate-save.tsx new file mode 100644 index 00000000..472053ac --- /dev/null +++ b/apps/rowboat/app/lib/components/editable-field-with-immediate-save.tsx @@ -0,0 +1,204 @@ +import { Button, Input, Textarea } from "@heroui/react"; +import { useEffect, useRef, useState } from "react"; +import { useClickAway } from "../../../hooks/use-click-away"; +import MarkdownContent from "./markdown-content"; +import clsx from "clsx"; +import { Label } from "./label"; +import { SparklesIcon } from "lucide-react"; + +interface EditableFieldProps { + value: string; + onChange: (value: string) => void; + label?: string; + placeholder?: string; + markdown?: boolean; + multiline?: boolean; + locked?: boolean; + className?: string; + validate?: (value: string) => { valid: boolean; errorMessage?: string }; + light?: boolean; + error?: string | null; + inline?: boolean; + showGenerateButton?: { + show: boolean; + setShow: (show: boolean) => void; + }; + disabled?: boolean; + type?: string; +} + +export function EditableField({ + value, + onChange, + label, + placeholder = "Click to edit...", + markdown = false, + multiline = false, + locked = false, + className = "flex flex-col gap-1 w-full", + validate, + light = false, + error, + inline = false, + showGenerateButton, + disabled = false, + type = "text", +}: EditableFieldProps) { + const [isEditing, setIsEditing] = useState(false); + const [localValue, setLocalValue] = useState(value); + const ref = useRef(null); + + const validationResult = validate?.(localValue); + const isValid = !validate || validationResult?.valid; + + useEffect(() => { + setLocalValue(value); + }, [value]); + + useClickAway(ref, () => { + if (isEditing) { + if (isValid && localValue !== value) { + onChange(localValue); + } else { + setLocalValue(value); + } + setIsEditing(false); + } + }); + + const onValueChange = (newValue: string) => { + setLocalValue(newValue); + onChange(newValue); // Always save immediately + }; + + const commonProps = { + autoFocus: true, + value: localValue, + onValueChange: onValueChange, + variant: "bordered" as const, + labelPlacement: "outside" as const, + placeholder: markdown ? '' : placeholder, + classNames: { + input: "rounded-md", + inputWrapper: "rounded-md border-medium" + }, + radius: "md" as const, + isInvalid: !isValid, + errorMessage: validationResult?.errorMessage, + onKeyDown: (e: React.KeyboardEvent) => { + if (!multiline && e.key === "Enter") { + e.preventDefault(); + if (isValid && localValue !== value) { + onChange(localValue); + } + setIsEditing(false); + } + if (e.key === "Escape") { + setLocalValue(value); + setIsEditing(false); + } + }, + }; + + if (isEditing) { + return ( +
    + {label && ( +
    +
    + )} + {multiline &&