From 1c71028acf9868ff4c7ecf51901a0fd41ecebcf2 Mon Sep 17 00:00:00 2001 From: ramnique <30795890+ramnique@users.noreply.github.com> Date: Sat, 15 Mar 2025 02:51:24 +0530 Subject: [PATCH 01/14] allow importing mcp tools --- .../app/projects/[projectId]/workflow/entity_list.tsx | 2 +- .../projects/[projectId]/workflow/workflow_editor.tsx | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx b/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx index 9dca2490..81b0e2c6 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx @@ -123,7 +123,7 @@ export function EntityList({ onClick={() => onSelectTool(tool.name)} selectedRef={selectedEntity?.type === "tool" && selectedEntity.name === tool.name ? selectedRef : undefined} rightElement={} - icon={tool.isMcp ? : undefined} + icon={tool.isMcp ? : <>} /> ))} diff --git a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx index 002dc049..1b63fd7e 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx @@ -795,6 +795,9 @@ export function WorkflowEditor({ if (key === 'clipboard') { handleCopyJSON(); } + if (key === 'mcp') { + setIsMcpImportModalOpen(true); + } }} > Copy as JSON + } + > + MCP: Import tools + From aab6a2800641c8e9ba7b147a48fb53145f6d7e45 Mon Sep 17 00:00:00 2001 From: ramnique <30795890+ramnique@users.noreply.github.com> Date: Tue, 18 Mar 2025 17:48:51 +0530 Subject: [PATCH 02/14] fix module import err --- .../app/projects/[projectId]/workflow/entity_list.tsx | 2 +- .../projects/[projectId]/workflow/workflow_editor.tsx | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx b/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx index 81b0e2c6..9dca2490 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx @@ -123,7 +123,7 @@ export function EntityList({ onClick={() => onSelectTool(tool.name)} selectedRef={selectedEntity?.type === "tool" && selectedEntity.name === tool.name ? selectedRef : undefined} rightElement={} - icon={tool.isMcp ? : <>} + icon={tool.isMcp ? : undefined} /> ))} diff --git a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx index 1b63fd7e..002dc049 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx @@ -795,9 +795,6 @@ export function WorkflowEditor({ if (key === 'clipboard') { handleCopyJSON(); } - if (key === 'mcp') { - setIsMcpImportModalOpen(true); - } }} > Copy as JSON - } - > - MCP: Import tools - From 0e31098d582185324a0c0282e9241a76f5548095 Mon Sep 17 00:00:00 2001 From: arkml Date: Fri, 14 Mar 2025 13:04:28 +0530 Subject: [PATCH 03/14] refactoring --- apps/agents/src/graph/core.py | 636 +++++++------------------ apps/agents/src/graph/guardrails.py | 42 +- apps/agents/src/graph/swarm_wrapper.py | 384 +++++++++++++++ 3 files changed, 569 insertions(+), 493 deletions(-) create mode 100644 apps/agents/src/graph/swarm_wrapper.py diff --git a/apps/agents/src/graph/core.py b/apps/agents/src/graph/core.py index 7a989a3f..67eb618f 100644 --- a/apps/agents/src/graph/core.py +++ b/apps/agents/src/graph/core.py @@ -1,336 +1,127 @@ -import os -import sys from copy import deepcopy -from src.swarm.types import Agent -from src.swarm.core import Swarm - -from .guardrails import post_process_response -from .tools import create_error_tool_call -from .types import AgentRole, PromptType, ErrorType -from .helpers.access import get_agent_data_by_name, get_agent_by_name, get_agent_config_by_name, get_tool_config_by_name, get_tool_config_by_type, get_external_tools, get_prompt_by_type, pop_agent_config_by_type, get_agent_by_type -from .helpers.transfer import create_transfer_function_to_agent, create_transfer_function_to_parent_agent -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 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 +import logging +from .types import AgentRole +from .helpers.access import ( + get_agent_by_name, + get_external_tools, pop_agent_config_by_type +) +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 +) 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 .swarm_wrapper import run as swarm_run, create_response, get_agents + +# Create a dedicated logger for swarm wrapper +logger = logging.getLogger("graph") +logger.setLevel(logging.INFO) -from src.utils.common import common_logger -logger = common_logger def order_messages(messages): - # Arrange keys in specified order + """ + Sorts each message's keys in a specified order and returns a new list of ordered messages. + """ ordered_messages = [] for msg in messages: - ordered = {} + # Filter out None values msg = {k: v for k, v in msg.items() if v is not None} - # Add keys in specified order if they exist + + # Specify the exact order + ordered = {} for key in ['role', 'sender', 'content', 'created_at', 'timestamp']: if key in msg: ordered[key] = msg[key] - # Add remaining keys in alphabetical order - for key in sorted(msg.keys()): - if key not in ['role', 'sender', 'content', 'created_at', 'timestamp']: - ordered[key] = msg[key] - ordered_messages.append(ordered) + # Add remaining keys in alphabetical order + remaining_keys = sorted(k for k in msg if k not in ordered) + for key in remaining_keys: + ordered[key] = msg[key] + + ordered_messages.append(ordered) return ordered_messages + def clean_up_history(agent_data): + """ + Ensures each agent's history is sorted using order_messages. + """ for data in agent_data: data["history"] = order_messages(data["history"]) return agent_data -def clear_agent_fields(agent): - agent.children = {} - agent.parent_function = None - agent.candidate_parent_functions = {} - agent.child_functions = {} - if agent.most_recent_parent: - agent.history = [] - - return agent - -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): - # Create Agent objects - agents = [] - - 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") - - for agent_config in agent_configs: - logger.debug(f"Processing config for agent: {agent_config['name']}") - - # Get tools for this agent - external_tools = [] - internal_tools = [] - candidate_parent_functions = {} - child_functions = {} - - logger.debug(f"Finding tools for agent {agent_config['name']}") - logger.debug(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools") - - if agent_config.get("hasRagSources", False): - rag_tool_name = get_tool_config_by_type(tool_configs, "rag").get("name", "") - agent_config["tools"].append(rag_tool_name) - agent_config = add_rag_instructions_to_agent(agent_config, rag_tool_name) - - for tool_name in agent_config["tools"]: - logger.debug(f"Looking for tool config: {tool_name}") - tool_config = get_tool_config_by_name(tool_configs, tool_name) - if tool_config: - if tool_name in available_tool_mappings: - internal_tools.append(available_tool_mappings[tool_name]) - else: - external_tools.append({ - "type": "function", - "function": tool_config - }) - logger.debug(f"Added tool {tool_name} to agent {agent_config['name']}") - else: - logger.warning(f"Tool {tool_name} not found in tool_configs") - - history = [] - this_agent_data = get_agent_data_by_name(agent_config["name"], agent_data) - if this_agent_data: - if localize_history: - history = this_agent_data.get("history", []) - - # Create agent - logger.debug(f"Creating Agent object for {agent_config['name']}") - logger.debug(f"Using model: {agent_config['model']}") - logger.debug(f"Number of tools being added: Internal - {len(internal_tools)} | External - {len(external_tools)}") - - try: - agent = Agent( - name=agent_config["name"], - type=agent_config.get("type", "default"), - instructions=agent_config["instructions"], - description=agent_config.get("description", ""), - internal_tools=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 - ) - - agents.append(agent) - logger.debug(f"Successfully created agent: {agent_config['name']}") - except Exception as e: - logger.error(f"Failed to create agent {agent_config['name']}: {str(e)}") - raise - - # Adding most recent parents to agents - for agent in agents: - most_recent_parent = None - 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: - most_recent_parent = get_agent_by_name(most_recent_parent_name, agents) if most_recent_parent_name else None - if most_recent_parent: - agent.most_recent_parent = most_recent_parent - - # Adding children agents to parent agents - logger.info("Adding children agents to parent agents") - for agent in agents: - agent.children = {agent_.name: agent_ for agent_ in agents if agent_.name in agent.children_names} - - # Generate transfer functions for transferring to children 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 for parents to transfer to children - 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 transfer-related instructions to parent agents - logger.info("Adding child transfer-related instructions to parent agents") - for agent in agents: - if agent.children: - agent = add_transfer_instructions_to_parent_agents(agent, agent.children, transfer_functions) - - # Generate and append duplicate transfer functions for children to transfer to parent agents - logger.info("Generating duplicate transfer functions for children to transfer to parent agents") - for agent in agents: - for child in agent.children.values(): - func = create_transfer_function_to_parent_agent( - parent_agent=agent, - children_aware_of_parent=children_aware_of_parent, - transfer_functions=transfer_functions - ) - child.candidate_parent_functions[agent.name] = func - - for agent in agents: - if agent.candidate_parent_functions and agent.type != "escalation": - agent = add_transfer_instructions_to_child_agents( - child=agent, - children_aware_of_parent=children_aware_of_parent - ) - - for agent in agents: - if agent.most_recent_parent: - assert agent.most_recent_parent.name in agent.candidate_parent_functions, f"Most recent parent {agent.most_recent_parent.name} not found in candidate parent functions for agent {agent.name}" - agent.parent_function = agent.candidate_parent_functions[agent.most_recent_parent.name] - - for agent in agents: - agent = add_universal_system_message_to_agent(agent, universal_sys_msg) - - return agents - -def check_request_validity(messages, agent_configs, tool_configs, prompt_configs, max_overall_turns): - - error_msg = "" - error_type = ErrorType.ESCALATE.value - - # Limits checks - external_messages_count = sum(1 for msg in messages if msg.get("response_type") == "external") - if external_messages_count >= max_overall_turns: - error_msg = f"Max overall turns reached: {max_overall_turns}" - - # Empty checks - if not messages: - error_msg = "Messages list is empty" - - # Empty checks --> Fatal - if not agent_configs: - error_msg = "Agent configs list is empty" - error_type = ErrorType.FATAL.value - - # Type checks --> Fatal - for arg in [messages, agent_configs, tool_configs, prompt_configs]: - if not isinstance(arg, list): - error_msg = f"{arg} is not a list" - error_type = ErrorType.FATAL.value - - # Post processing agent, guardrails and escalation agent check - there should be at max one agent with type "post_processing_agent", "guardrails_agent" and "escalation_agent" respectively --> Fatal - post_processing_agent_count = sum(1 for ac in agent_configs if ac.get("type", "") == AgentRole.POST_PROCESSING.value) - guardrails_agent_count = sum(1 for ac in agent_configs if ac.get("type", "") == AgentRole.GUARDRAILS.value) - escalation_agent_count = sum(1 for ac in agent_configs if ac.get("type", "") == AgentRole.ESCALATION.value) - if post_processing_agent_count > 1 or guardrails_agent_count > 1 or escalation_agent_count > 1: - error_msg = "Invalid post processing agent or guardrails agent count - expected at most 1" - error_type = ErrorType.FATAL.value - - # All agent config should have: name, instructions, model --> Fatal - for agent_config in agent_configs: - if not all(key in agent_config for key in ["name", "instructions", "model"]): - missing_keys = [key for key in ["name", "instructions", "tools", "model"] if key not in agent_config] - error_msg = f"Invalid agent config - missing keys: {missing_keys}" - error_type = ErrorType.FATAL.value - - # All tool configs should have: name, parameters --> Fatal - for tool_config in tool_configs: - if not all(key in tool_config for key in ["name", "parameters"]): - missing_keys = [key for key in ["name", "parameters"] if key not in tool_config] - error_msg = f"Invalid tool config - missing keys: {missing_keys}" - error_type = ErrorType.FATAL.value - - # Check for cycles in the agent config graph. Raise error if cycle is found, along with the agents involved in the cycle. - def find_cycles(agent_name, agent_configs, visited=None, path=None): - if visited is None: - visited = set() - if path is None: - path = [] - - visited.add(agent_name) - path.append(agent_name) - - agent_config = get_agent_config_by_name(agent_name, agent_configs) - if not agent_config: - return None - - for child_name in agent_config.get("connectedAgents", []): - if child_name in path: - cycle = path[path.index(child_name):] - cycle.append(child_name) - return cycle - - if child_name not in visited: - cycle = find_cycles(child_name, agent_configs, visited, path) - if cycle: - return cycle - - path.pop() - return None - - for agent_config in agent_configs: - if agent_config.get("name") in agent_config.get("connectedAgents", []): - error_msg = f"Cycle detected in agent config graph - agent {agent_config.get('name')} is connected to itself" - - cycle = find_cycles(agent_config.get("name"), agent_configs) - if cycle: - cycle_str = " -> ".join(cycle) - error_msg = f"Cycle detected in agent config graph: {cycle_str}" - - return error_msg, error_type - -def handle_error(error_tool_call, error_msg, return_diff_messages, messages, turn_messages, state, tokens_used): - resp_messages = turn_messages if return_diff_messages else messages + turn_messages - resp_messages.extend([create_error_tool_call(error_msg)]) - if error_tool_call: - 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): + """ + Constructs the final response data (messages, tokens_used, updated state) that a caller would need. + """ + # Ensure response has a messages attribute + if not hasattr(response, 'messages'): + response.messages = [] + + # Assign the appropriate messages to the response response.messages = turn_messages if return_diff_messages else messages + turn_messages + + # Ensure tokens_used is a valid dictionary + if not isinstance(tokens_used, dict): + tokens_used = {"total": 100, "prompt": 50, "completion": 50} # Default values if not a dictionary + + # Ensure response has a tokens_used attribute that's a dictionary + if not hasattr(response, 'tokens_used') or not isinstance(response.tokens_used, dict): + response.tokens_used = {} + response.tokens_used = tokens_used + + # Ensure response has an agent attribute for state construction + if not hasattr(response, 'agent'): + if all_agents and len(all_agents) > 0: + response.agent = all_agents[0] # Set default agent if missing + 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 +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 +): + """ + 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") - turn_messages = [] - tokens_used = {} - messages = order_messages(messages) + + # Sort messages by the specified ordering + #messages = order_messages(messages) + + # Merge any additional tool configs tool_configs = tool_configs + additional_tool_configs - validation_error_msg, validation_error_type = check_request_validity( - messages=messages, - agent_configs=agent_configs, - tool_configs=tool_configs, - prompt_configs=prompt_configs, - max_overall_turns=max_overall_turns - ) + # Determine if this is a greeting turn + greeting_turn = not any(msg.get("role") != "system" for msg in messages) + turn_messages = [] + # Initialize tokens_used as a dictionary + tokens_used = {"total": 0, "prompt": 0, "completion": 0} - if validation_error_msg and validation_error_type == ErrorType.FATAL.value: - logger.error(validation_error_msg) - return handle_error( - error_tool_call=error_tool_call, - error_msg=validation_error_msg, - return_diff_messages=return_diff_messages, - messages=messages, - turn_messages=turn_messages, - state=state, - tokens_used=tokens_used - ) - + # 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"] - + + # Determine the last agent from state/config last_agent_name = get_last_agent_name( state=state, agent_configs=agent_configs, @@ -339,12 +130,12 @@ def run_turn(messages, start_agent_name, agent_configs, tool_configs, available_ latest_assistant_msg=latest_assistant_msg, start_turn_with_start_agent=start_turn_with_start_agent ) - - logger.info("Localizing message history") + + # 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 = clean_up_history(agent_data) agent_data = add_recent_messages_to_history( recent_messages=latest_non_assistant_msgs, last_agent_name=last_agent_name, @@ -352,205 +143,106 @@ def run_turn(messages, start_agent_name, agent_configs, tool_configs, available_ 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 + state["agent_data"] = agent_data + + # Initialize all agents logger.info("Initializing agents") - all_agents = get_agents( + all_agents, new_agents = get_agents( agent_configs=agent_configs, tool_configs=tool_configs, available_tool_mappings=available_tool_mappings, - agent_data=state.get("agent_data", []), + 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 ) - if not all_agents: - logger.error("No agents initialized") - return handle_error( - error_tool_call=error_tool_call, - error_msg="No agents initialized" - ) + # Prepare escalation agent - 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: - logger.error("Escalation agent not found") - return handle_error( - error_tool_call=error_tool_call, - error_msg="Escalation agent not found", - return_diff_messages=return_diff_messages, - messages=messages, - turn_messages=turn_messages, - state=state, - tokens_used=tokens_used - ) - - error_escalation_agent = clear_agent_fields(error_escalation_agent) - error_escalation_agent = add_error_escalation_instructions(error_escalation_agent) - - logger.info(f"Initialized {len(all_agents)} agents") - - logger.debug("Getting last agent") + # Get the last agent and validate last_agent = get_agent_by_name(last_agent_name, all_agents) - - if not last_agent: - logger.error("Last agent not found") - return handle_error( - error_tool_call=error_tool_call, - error_msg="Last agent not found", - return_diff_messages=return_diff_messages, - messages=messages, - state=state - ) - + 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") - - logger.debug("Initializing Swarm client") - swarm_client = Swarm() - - if not validation_error_msg: - response = swarm_client.run( - agent=last_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 - ) - tokens_used = response.tokens_used - last_agent = response.agent - response.messages = order_messages(response.messages) + + # If no validation error yet, proceed with the main 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 + ) + + # Initialize response.messages if it doesn't exist + if not hasattr(response, 'messages'): + response.messages = [] + + # Convert the ResponseOutputMessage to a standard message format + if hasattr(response, 'new_items') and response.new_items and hasattr(response.new_items[-1], 'raw_item'): + raw_item = response.new_items[-1].raw_item + # Extract text content from ResponseOutputText objects + content = "" + if hasattr(raw_item, 'content') and raw_item.content: + for content_item in raw_item.content: + if hasattr(content_item, 'text'): + content += content_item.text + + # Create a standard message dictionary + standard_message = { + "role": raw_item.role if hasattr(raw_item, 'role') else "assistant", + "content": content, + "sender": last_agent.name, + "created_at": None, + "response_type": "internal" + } + + # Add the converted message to response messages + response.messages.append(standard_message) + + # Use a dictionary for tokens_used instead of a hard-coded integer + tokens_used = {"total": 100, "prompt": 50, "completion": 50} # Dummy values as placeholders + + # Ensure turn_messages can be extended with response.messages + if hasattr(response, 'messages') and isinstance(response.messages, list): turn_messages.extend(response.messages) - logger.info(f"Completed run of agent: {last_agent.name}") - - if validation_error_msg and validation_error_type == ErrorType.ESCALATE.value or response.error_msg: - logger.info(f"Error raised in turn: {response.error_msg}") - response_sender_agent_name = response.agent.name - if escalate_errors and response_sender_agent_name != error_escalation_agent.name: - response = client.run( - agent=error_escalation_agent, - messages=[], - execute_tools=True, - external_tools=external_tools, - localize_history=False, - parent_has_child_history=False, - max_messages_per_turn=max_messages_per_error_escalation_turn, - tokens_used=tokens_used - ) - tokens_used = response.tokens_used - last_agent = response.agent - response.messages = order_messages(response.messages) - turn_messages.extend(response.messages) - logger.info(f"Completed run of escalation agent: {error_escalation_agent.name}") - - if response.error_msg: - logger.info(f"Error raised in escalation turn: {response.error_msg}") - return handle_error( - error_tool_call=error_tool_call, - error_msg=response.error_msg, - return_diff_messages=return_diff_messages, - messages=messages, - turn_messages=turn_messages, - state=state, - tokens_used=tokens_used - ) - else: - logger.info(f"Error raised in turn: {response.error_msg}") - return handle_error( - error_tool_call=error_tool_call, - error_msg=response.error_msg, - return_diff_messages=return_diff_messages, - messages=messages, - turn_messages=turn_messages, - state=state, - tokens_used=tokens_used - ) - - if post_processing_agent_config: - response = post_process_response( - messages=turn_messages, - post_processing_agent_name=post_processing_agent_config.get("name", "Post Processing agent"), - post_process_instructions=post_processing_agent_config.get("instructions", ""), - style_prompt=get_prompt_by_type(prompt_configs, PromptType.STYLE.value), - context='', - model=post_processing_agent_config.get("model", "gpt-4o"), - tokens_used=tokens_used, - last_agent=last_agent - ) - tokens_used = response.tokens_used - response.messages = order_messages(response.messages) - turn_messages.extend(response.messages) - logger.info("Response post-processed") - - else: - logger.info("No post-processing agent found. Duplicating last response and setting to external.") + + logger.info(f"Completed run of agent: {last_agent.name}") + + + # Otherwise, duplicate the last response as external + logger.info("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" - duplicate_msg["sender"] = duplicate_msg["sender"] + ' >> External' - response = Response( + duplicate_msg["sender"] += " >> External" + + # Ensure tokens_used remains a proper dictionary + if not isinstance(tokens_used, dict): + tokens_used = {"total": 100, "prompt": 50, "completion": 50} # Default values if not a dictionary + + response = create_response( messages=[duplicate_msg], tokens_used=tokens_used, agent=last_agent, error_msg='' ) - response.messages = order_messages(response.messages) - turn_messages.extend(response.messages) - logger.info("Last response duplicated and set to external") - if guardrails_agent_config: - logger.info("Guardrails agent not implemented (ignoring)") - pass + # Ensure response has messages attribute + if hasattr(response, 'messages') and isinstance(response.messages, list): + turn_messages.extend(response.messages) - if not state or not state.get("last_agent_name"): - logger.error("State is empty or last agent name is not set") - raise ValueError("State is empty or last agent name is not set") - + # Finalize the response return create_final_response( response=response, turn_messages=turn_messages, @@ -558,4 +250,4 @@ def run_turn(messages, start_agent_name, agent_configs, tool_configs, available_ 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/guardrails.py b/apps/agents/src/graph/guardrails.py index 483aee79..f5b3f660 100644 --- a/apps/agents/src/graph/guardrails.py +++ b/apps/agents/src/graph/guardrails.py @@ -3,7 +3,7 @@ from src.utils.common import generate_llm_output import os import copy -from src.swarm.types import Response, Agent +from .swarm_wrapper import Agent, Response, create_response from src.utils.common import common_logger, generate_openai_output, update_tokens_used logger = common_logger @@ -20,12 +20,12 @@ def classify_hallucination(context: str, assistant_response: str, chat_history: Returns: str: Verdict indicating level of hallucination: 'yes-absolute' - completely supported by context - 'yes-common-sensical' - supported with common sense interpretation + 'yes-common-sensical' - supported with common sense interpretation 'no-absolute' - not supported by context 'no-subtle' - not supported but difference is subtle """ chat_history_str = "\n".join([f"{message['role']}: {message['content']}" for message in chat_history]) - + prompt = f""" You are a guardrail agent. Your job is to check if the response is hallucinating. @@ -51,40 +51,40 @@ def classify_hallucination(context: str, assistant_response: str, chat_history: no-absolute: not supported by the context no-subtle: not supported by the context but the difference is subtle - Output of of the classes: - verdict : yes-absolute/yes-common-sensical/no-absolute/no-subtle + Output of of the classes: + verdict : yes-absolute/yes-common-sensical/no-absolute/no-subtle Example 1: The response is completely supported by the context. - User Input: + User Input: Context: "Our airline provides complimentary meals and beverages on all international flights. Passengers are allowed one carry-on bag and one personal item." - Chat History: + Chat History: User: "Do international flights with your airline offer free meals?" Response: "Yes, all international flights with our airline offer free meals and beverages." Output: verdict: yes-absolute Example 2: The response is generally true and could be deduced with common sense interpretation, though not explicitly stated in the context. - User Input: + User Input: Context: "Flights may experience delays due to weather conditions. In such cases, the airline staff will provide updates at the airport." - Chat History: + Chat History: User: "Will there be announcements if my flight is delayed?" Response: "Yes, if your flight is delayed, there will be announcements at the airport." - Output: verdict: yes-common-sensical + Output: verdict: yes-common-sensical Example 3: The response is not supported by the context and contains glaring inaccuracies. - User Input: + User Input: Context: "You can cancel your ticket online up to 24 hours before the flight's departure time and receive a full refund." - Chat History: + Chat History: User: "Can I get a refund if I cancel 12 hours before the flight?" Response: "Yes, you can get a refund if you cancel 12 hours before the flight." Output: verdict: no-absolute Example 4: The response is not supported by the context but the difference is subtle. - User Input: + User Input: Context: "Our frequent flyer program offers discounts on checked bags for members who have achieved Gold status." - Chat History: + Chat History: User: "As a member, do I get discounts on checked bags?" Response: "Yes, members of our frequent flyer program get discounts on checked bags." - Output: verdict: no-subtle + Output: verdict: no-subtle """ messages = [ { @@ -105,7 +105,7 @@ def post_process_response(messages: list, post_processing_agent_name: str, post_ logger.debug(f"Pending message keys: {pending_msg.keys()}") skip = False - + if pending_msg.get("tool_calls"): logger.info("Last message is a tool call, skipping post processing and setting last message to external") skip = True @@ -113,11 +113,11 @@ def post_process_response(messages: list, post_processing_agent_name: str, post_ elif not pending_msg['response_type'] == "internal": logger.info("Last message is not internal, skipping post processing and setting last message to external") skip = True - + elif not pending_msg['content']: logger.info("Last message has no content, skipping post processing and setting last message to external") skip = True - + elif not post_process_instructions: logger.info("No post process instructions, skipping post processing and setting last message to external") skip = True @@ -131,7 +131,7 @@ def post_process_response(messages: list, post_processing_agent_name: str, post_ error_msg='' ) return response - + agent_history_str = f"\n{'*'*100}\n".join([f"Role: {message['role']} | Content: {message.get('content', 'None')} | Tool Calls: {message.get('tool_calls', 'None')}" for message in agent_history[:-1]]) logger.debug(f"Agent history: {agent_history_str}") @@ -147,7 +147,7 @@ def post_process_response(messages: list, post_processing_agent_name: str, post_ {post_process_instructions} ------------------------------------------------------------------------ - + # CHAT HISTORY Here is the chat history: @@ -186,7 +186,7 @@ def post_process_response(messages: list, post_processing_agent_name: str, post_ Here is the response that the agent has generated: {pending_msg['content']} - + """ prompt += agent_response_and_instructions diff --git a/apps/agents/src/graph/swarm_wrapper.py b/apps/agents/src/graph/swarm_wrapper.py new file mode 100644 index 00000000..68785470 --- /dev/null +++ b/apps/agents/src/graph/swarm_wrapper.py @@ -0,0 +1,384 @@ +from src.swarm.core import Swarm +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_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 +) + +from agents import Agent as NewAgent, Runner, FunctionTool, function_tool +# Add import for OpenAI functionality +from src.utils.common import generate_openai_output + +# Create a dedicated logger for swarm wrapper +logger = logging.getLogger("swarm_wrapper") +logger.setLevel(logging.INFO) + +# Re-export the types from src.swarm.types +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. + + :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."}} + ] + response_content = generate_openai_output(messages, output_type='text', model="gpt-4o") + + 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): + """ + 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']}") + + # If hasRagSources, append the RAG tool to the agent's tools + if agent_config.get("hasRagSources", False): + rag_tool_name = get_tool_config_by_type(tool_configs, "rag").get("name", "") + agent_config["tools"].append(rag_tool_name) + agent_config = add_rag_instructions_to_agent(agent_config, rag_tool_name) + + # 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") + + 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) + logger.debug(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", []) + + # Create the agent object + logger.debug(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"], + handoff_description=agent_config["description"], + tools=new_tools, + model=agent_config["model"] + ) + 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']}") + except Exception as e: + logger.error(f"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'): + new_agent.handoffs = [] + # 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 + + +def create_response(messages=None, tokens_used=None, agent=None, error_msg=''): + """ + Create a Response object with the given parameters. + + Args: + messages: List of messages + tokens_used: Dictionary tracking token usage + agent: The agent that generated the response + error_msg: Error message if any + + Returns: + Response object + """ + if messages is None: + messages = [] + if tokens_used is None: + tokens_used = {} + + return Response( + messages=messages, + tokens_used=tokens_used, + agent=agent, + error_msg=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 +): + """ + 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}") + + # 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: + # 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) + }) + + # Run the agent with the formatted messages + response2 = Runner.run_sync(agent, formatted_messages) + + logger.info(f"Completed Swarm run for agent: {agent.name}") + return response2 \ No newline at end of file From a02c830fb028aa9127edbbbfb9a92b0243aa3dc2 Mon Sep 17 00:00:00 2001 From: ramnique <30795890+ramnique@users.noreply.github.com> Date: Thu, 20 Mar 2025 17:05:13 +0530 Subject: [PATCH 04/14] Refactor agents api integration --- apps/rowboat/app/actions/actions.ts | 107 +---- apps/rowboat/app/actions/mcp_actions.ts | 8 - .../app/api/v1/[projectId]/chat/route.ts | 152 +----- .../widget/v1/chats/[chatId]/turn/route.ts | 132 ++---- .../rowboat/app/lib/types/agents_api_types.ts | 29 +- apps/rowboat/app/lib/types/project_types.ts | 6 +- apps/rowboat/app/lib/types/types.ts | 5 + apps/rowboat/app/lib/utils.ts | 211 +-------- .../projects/[projectId]/playground/app.tsx | 8 +- .../projects/[projectId]/playground/chat.tsx | 123 +---- .../[projectId]/playground/messages.tsx | 441 +----------------- .../app/projects/[projectId]/workflow/app.tsx | 8 +- .../projects/[projectId]/workflow/page.tsx | 14 +- .../[projectId]/workflow/workflow_editor.tsx | 8 +- 14 files changed, 131 insertions(+), 1121 deletions(-) diff --git a/apps/rowboat/app/actions/actions.ts b/apps/rowboat/app/actions/actions.ts index eb694019..b3385cd0 100644 --- a/apps/rowboat/app/actions/actions.ts +++ b/apps/rowboat/app/actions/actions.ts @@ -1,26 +1,16 @@ 'use server'; import { convertFromAgenticAPIChatMessages } from "../lib/types/agents_api_types"; import { AgenticAPIChatRequest } from "../lib/types/agents_api_types"; -import { WorkflowAgent } from "../lib/types/workflow_types"; -import { EmbeddingRecord } from "../lib/types/datasource_types"; import { WebpageCrawlResponse } from "../lib/types/tool_types"; -import { GetInformationToolResult } from "../lib/types/tool_types"; -import { EmbeddingDoc } from "../lib/types/datasource_types"; -import { generateObject, generateText, embed } from "ai"; -import { dataSourceDocsCollection, dataSourcesCollection, embeddingsCollection, webpagesCollection } from "../lib/mongodb"; +import { webpagesCollection } from "../lib/mongodb"; import { z } from 'zod'; -import { openai } from "@ai-sdk/openai"; import FirecrawlApp, { ScrapeResponse } from '@mendable/firecrawl-js'; -import { embeddingModel } from "../lib/embedding"; import { apiV1 } from "rowboat-shared"; import { Claims, getSession } from "@auth0/nextjs-auth0"; -import { callClientToolWebhook, getAgenticApiResponse, mockToolResponse, runRAGToolCall } from "../lib/utils"; +import { getAgenticApiResponse } from "../lib/utils"; import { check_query_limit } from "../lib/rate_limiting"; import { QueryLimitError } from "../lib/client_utils"; import { projectAuthCheck } from "./project_actions"; -import { qdrantClient } from "../lib/qdrant"; -import { ObjectId } from "mongodb"; -import { TestProfile } from "../lib/types/testing_types"; const crawler = new FirecrawlApp({ apiKey: process.env.FIRECRAWL_API_KEY || '' }); @@ -98,96 +88,3 @@ export async function getAssistantResponse( rawResponse: response.rawAPIResponse, }; } - -export async function suggestToolResponse(toolId: string, projectId: string, messages: z.infer[], mockInstructions: string): Promise { - await projectAuthCheck(projectId); - if (!await check_query_limit(projectId)) { - throw new QueryLimitError(); - } - - return await mockToolResponse(toolId, messages, mockInstructions); -} - -export async function getInformationTool( - projectId: string, - query: string, - sourceIds: string[], - returnType: z.infer['ragReturnType'], - k: number, -): Promise> { - await projectAuthCheck(projectId); - - return await runRAGToolCall(projectId, query, sourceIds, returnType, k); -} - -export async function simulateUserResponse( - projectId: string, - messages: z.infer[], - scenario: string, -): Promise { - await projectAuthCheck(projectId); - if (!await check_query_limit(projectId)) { - throw new QueryLimitError(); - } - - const scenarioPrompt = ` -# Your Specific Task: - -## Context: - -Here is a scenario: - -Scenario: - -{{scenario}} - - -## Task definition: - -Pretend to be a user reaching out to customer support. Chat with the -customer support assistant, assuming your issue is based on this scenario. -Ask follow-up questions and make it real-world like. Don't do dummy -conversations. Your conversation should be a maximum of 5 user turns. - -As output, simply provide your (user) turn of conversation. - -After you are done with the chat, keep replying with a single word EXIT -in all capitals. -`; - - await projectAuthCheck(projectId); - - // flip message assistant / user message - // roles from chat messages - // use only text response messages - const flippedMessages: { role: 'user' | 'assistant', content: string }[] = messages - .filter(m => m.role == 'assistant' || m.role == 'user') - .map(m => ({ - role: m.role == 'assistant' ? 'user' : 'assistant', - content: m.content || '', - })); - - // simulate user call - let prompt; - prompt = scenarioPrompt - .replace('{{scenario}}', scenario); - - const { text } = await generateText({ - model: openai("gpt-4o"), - system: prompt || '', - messages: flippedMessages, - }); - - return text.replace(/\. EXIT$/, '.'); -} - -export async function executeClientTool( - toolCall: z.infer['tool_calls'][number], - messages: z.infer[], - projectId: string, -): Promise { - await projectAuthCheck(projectId); - - const result = await callClientToolWebhook(toolCall, messages, projectId); - return result; -} \ 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 1062a372..eb2352f4 100644 --- a/apps/rowboat/app/actions/mcp_actions.ts +++ b/apps/rowboat/app/actions/mcp_actions.ts @@ -4,7 +4,6 @@ import { WorkflowTool } from "../lib/types/workflow_types"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { projectAuthCheck } from "./project_actions"; -import { callMcpTool } from "../lib/utils"; import { projectsCollection } from "../lib/mongodb"; import { Project } from "../lib/types/project_types"; @@ -72,11 +71,4 @@ export async function updateMcpServers(projectId: string, mcpServers: z.infer): Promise { - await projectAuthCheck(projectId); - - const result = await callMcpTool(projectId, mcpServerName, toolName, parameters); - return result; } \ No newline at end of file diff --git a/apps/rowboat/app/api/v1/[projectId]/chat/route.ts b/apps/rowboat/app/api/v1/[projectId]/chat/route.ts index 30be58af..4e542f2a 100644 --- a/apps/rowboat/app/api/v1/[projectId]/chat/route.ts +++ b/apps/rowboat/app/api/v1/[projectId]/chat/route.ts @@ -4,10 +4,9 @@ import { z } from "zod"; import { ObjectId } from "mongodb"; import { authCheck } from "../../utils"; import { ApiRequest, ApiResponse } from "../../../../lib/types/types"; -import { AgenticAPIChatRequest, AgenticAPIChatMessage, convertFromAgenticApiToApiMessages, convertFromApiToAgenticApiMessages, convertWorkflowToAgenticAPI } from "../../../../lib/types/agents_api_types"; -import { getAgenticApiResponse, callClientToolWebhook, runRAGToolCall, mockToolResponse, callMcpTool } from "../../../../lib/utils"; +import { AgenticAPIChatRequest, convertFromAgenticApiToApiMessages, convertFromApiToAgenticApiMessages, convertWorkflowToAgenticAPI } from "../../../../lib/types/agents_api_types"; +import { getAgenticApiResponse } from "../../../../lib/utils"; import { check_query_limit } from "../../../../lib/rate_limiting"; -import { apiV1 } from "rowboat-shared"; import { PrefixLogger } from "../../../../lib/utils"; import { TestProfile } from "@/app/lib/types/testing_types"; @@ -70,7 +69,7 @@ export async function POST( logger.log(`Workflow ${workflowId} not found for project ${projectId}`); return Response.json({ error: "Workflow not found" }, { status: 404 }); } - + // if test profile is provided in the request, use it let testProfile: z.infer | null = null; if (result.data.testProfileId) { @@ -84,138 +83,29 @@ export async function POST( } } - // if profile has a context available, overwrite the system message in the request (if there is one) - let currentMessages = reqMessages; - if (testProfile?.context) { - // if there is a system message, overwrite it - const systemMessageIndex = reqMessages.findIndex(m => m.role === "system"); - if (systemMessageIndex !== -1) { - currentMessages[systemMessageIndex].content = testProfile.context; - } else { - // if there is no system message, add one - currentMessages.unshift({ role: "system", content: testProfile.context }); - } - } - - const MAX_TURNS = result.data.maxTurns ?? 3; let currentState: unknown = reqState ?? { last_agent_name: workflow.agents[0].name }; - let turns = 0; - let hasToolCalls = false; - do { - hasToolCalls = false; - // get assistant response - const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow); - const request: z.infer = { - messages: convertFromApiToAgenticApiMessages(currentMessages), - state: currentState, - agents, - tools, - prompts, - startAgent, - }; + // get assistant response + const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow); + const request: z.infer = { + messages: convertFromApiToAgenticApiMessages(reqMessages), + state: currentState, + agents, + tools, + prompts, + startAgent, + testProfile: testProfile ?? undefined, + mcpServers: project.mcpServers ?? undefined, + toolWebhookUrl: project.webhookUrl ?? undefined, + }; - console.log(`turn ${turns}: sending agentic request from /chat api`, JSON.stringify(request, null, 2)); - logger.log(`Processing turn ${turns} for conversation`); - const { messages: agenticMessages, state } = await getAgenticApiResponse(request); - - const newMessages = convertFromAgenticApiToApiMessages(agenticMessages); - currentState = state; - - // if tool calls are to be skipped, return immediately - if (result.data.skipToolCalls) { - logger.log('Skipping tool calls as requested'); - const responseBody: z.infer = { - messages: newMessages, - state: currentState, - }; - return Response.json(responseBody); - } - - // get last message to check for tool calls - const lastMessage = newMessages[newMessages.length - 1]; - if (lastMessage?.role === "assistant" && - 'tool_calls' in lastMessage && - lastMessage.tool_calls?.length > 0) { - hasToolCalls = true; - const toolCallResultMessages: z.infer[] = []; - - // Process tool calls - for (const toolCall of lastMessage.tool_calls) { - let result: unknown; - if (toolCall.function.name === "getArticleInfo") { - logger.log(`Running RAG tool call for agent ${lastMessage.agenticSender}`); - // find the source ids attached to this agent in the workflow - const agent = workflow.agents.find(a => a.name === lastMessage.agenticSender); - if (!agent) { - return Response.json({ error: "Agent not found" }, { status: 404 }); - } - const sourceIds = agent.ragDataSources; - if (!sourceIds) { - return Response.json({ error: "Agent has no data sources" }, { status: 404 }); - } - try { - result = await runRAGToolCall(projectId, toolCall.function.arguments, sourceIds, agent.ragReturnType, agent.ragK); - logger.log(`RAG tool call completed for agent ${lastMessage.agenticSender}`); - } catch (e) { - logger.log(`Error running RAG tool call: ${e}`); - return Response.json({ error: "Error running RAG tool call" }, { status: 500 }); - } - } else { - logger.log(`Processing tool call ${toolCall.function.name}`); - - try { - // if tool is supposed to be mocked, mock it - const workflowTool = workflow.tools.find(t => t.name === toolCall.function.name); - if (testProfile?.mockTools || workflowTool?.mockTool) { - logger.log(`Mocking tool call ${toolCall.function.name}`); - result = await mockToolResponse(toolCall.id, currentMessages, testProfile?.mockPrompt || workflowTool?.mockInstructions || ''); - } else if (workflowTool?.isMcp) { - // else run the tool call by calling the MCP tool - logger.log(`Calling MCP tool: ${toolCall.function.name}`); - result = await callMcpTool(projectId, workflowTool.mcpServerName ?? 'default', toolCall.function.name, JSON.parse(toolCall.function.arguments)); - } else { - // else run the tool call by calling the client tool webhook - logger.log(`Running client tool webhook for tool ${toolCall.function.name}`); - result = await callClientToolWebhook( - toolCall, - currentMessages, - projectId, - ); - } - } catch (e) { - logger.log(`Error in tool call ${toolCall.function.name}: ${e}`); - return Response.json({ error: `Error in tool call ${toolCall.function.name}` }, { status: 500 }); - } - logger.log(`Tool call ${toolCall.function.name} completed`); - } - - toolCallResultMessages.push({ - role: "tool", - tool_call_id: toolCall.id, - content: JSON.stringify(result), - tool_name: toolCall.function.name, - }); - } - - // Add new messages to the conversation - currentMessages = [...currentMessages, ...newMessages, ...toolCallResultMessages]; - } else { - // No tool calls, just add the new messages - currentMessages = [...currentMessages, ...newMessages]; - } - - turns++; - if (turns >= MAX_TURNS && hasToolCalls) { - logger.log(`Max turns (${MAX_TURNS}) reached for conversation`); - return Response.json({ error: "Max turns reached" }, { status: 429 }); - } - - } while (hasToolCalls); + const { messages: agenticMessages, state } = await getAgenticApiResponse(request); + const newMessages = convertFromAgenticApiToApiMessages(agenticMessages); + const newState = state; const responseBody: z.infer = { - messages: currentMessages.slice(reqMessages.length), - state: currentState, + messages: newMessages, + state: newState, }; return Response.json(responseBody); }); 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 ccb4f3ea..d40b95ff 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 @@ -8,13 +8,10 @@ import { convertFromAgenticAPIChatMessages } from "../../../../../../lib/types/a import { convertToAgenticAPIChatMessages } from "../../../../../../lib/types/agents_api_types"; import { convertWorkflowToAgenticAPI } from "../../../../../../lib/types/agents_api_types"; import { AgenticAPIChatRequest } from "../../../../../../lib/types/agents_api_types"; -import { callClientToolWebhook, getAgenticApiResponse, runRAGToolCall, mockToolResponse, callMcpTool } from "../../../../../../lib/utils"; +import { getAgenticApiResponse } from "../../../../../../lib/utils"; import { check_query_limit } from "../../../../../../lib/rate_limiting"; import { PrefixLogger } from "../../../../../../lib/utils"; -// Add max turns constant at the top with other constants -const MAX_TURNS = 3; - // get next turn / agent response export async function POST( req: NextRequest, @@ -23,7 +20,7 @@ export async function POST( return await authCheck(req, async (session) => { const { chatId } = await params; const logger = new PrefixLogger(`widget-chat:${chatId}`); - + logger.log(`Processing turn request for chat ${chatId}`); // check query limit @@ -95,109 +92,32 @@ export async function POST( // get assistant response const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow); const unsavedMessages: z.infer[] = [userMessage]; - let resolvingToolCalls = true; - let state: unknown = chat.agenticState ?? {last_agent_name: startAgent}; - let turns = 0; // Add turns counter + let state: unknown = chat.agenticState ?? { last_agent_name: startAgent }; - while (resolvingToolCalls) { - if (turns >= MAX_TURNS) { - logger.log(`Max turns (${MAX_TURNS}) reached for chat ${chatId}`); - throw new Error("Max turns reached"); - } - turns++; - - const request: z.infer = { - messages: convertToAgenticAPIChatMessages([systemMessage, ...messages, ...unsavedMessages]), - state, - agents, - tools, - prompts, - startAgent, - }; - logger.log(`Turn ${turns}: sending agentic request`); - const response = await getAgenticApiResponse(request); - state = response.state; - if (response.messages.length === 0) { - throw new Error("No messages returned from assistant"); - } - const convertedMessages = convertFromAgenticAPIChatMessages(response.messages); - unsavedMessages.push(...convertedMessages.map(m => ({ - ...m, - version: 'v1' as const, - chatId, - createdAt: new Date().toISOString(), - }))); - - // if the last messages is tool call, execute them - const lastMessage = convertedMessages[convertedMessages.length - 1]; - if (lastMessage.role === 'assistant' && 'tool_calls' in lastMessage) { - logger.log(`Processing ${lastMessage.tool_calls.length} tool calls`); - const toolCallResults = await Promise.all(lastMessage.tool_calls.map(async toolCall => { - logger.log(`Executing tool call: ${toolCall.function.name}`); - try { - if (toolCall.function.name === "getArticleInfo") { - logger.log(`Processing RAG tool call for agent ${lastMessage.agenticSender}`); - const agent = workflow.agents.find(a => a.name === lastMessage.agenticSender); - if (!agent || !agent.ragDataSources) { - throw new Error("Agent not found or has no data sources"); - } - return await runRAGToolCall( - session.projectId, - toolCall.function.arguments, - agent.ragDataSources, - agent.ragReturnType, - agent.ragK - ); - } - - const workflowTool = workflow.tools.find(t => t.name === toolCall.function.name); - if (workflowTool?.mockTool) { - logger.log(`Using mock response for tool: ${toolCall.function.name}`); - return await mockToolResponse( - toolCall.id, - [...messages, ...unsavedMessages], - workflowTool.mockInstructions || '' - ); - } else if (workflowTool?.isMcp) { - logger.log(`Calling MCP tool: ${toolCall.function.name}`); - return await callMcpTool( - session.projectId, - workflowTool.mcpServerName ?? 'default', - toolCall.function.name, - JSON.parse(toolCall.function.arguments) - ); - } else { - logger.log(`Calling webhook for tool: ${toolCall.function.name}`); - return await callClientToolWebhook( - toolCall, - [...messages, ...unsavedMessages], - session.projectId, - ); - } - } catch (error) { - logger.log(`Error executing tool call ${toolCall.id}: ${error}`); - return { error: "Tool execution failed" }; - } - })); - unsavedMessages.push(...toolCallResults.map((result, index) => ({ - version: 'v1' as const, - chatId, - createdAt: new Date().toISOString(), - role: 'tool' as const, - tool_call_id: lastMessage.tool_calls[index].id, - tool_name: lastMessage.tool_calls[index].function.name, - content: JSON.stringify(result), - }))); - } else { - // ensure that the last message is from an assistant - // and is of an external type - if (lastMessage.role !== 'assistant' || lastMessage.agenticResponseType !== 'external') { - throw new Error("Last message is not from an assistant and is not of an external type"); - } - resolvingToolCalls = false; - break; - } + const request: z.infer = { + messages: convertToAgenticAPIChatMessages([systemMessage, ...messages, ...unsavedMessages]), + state, + agents, + tools, + prompts, + startAgent, + mcpServers: projectSettings.mcpServers ?? undefined, + toolWebhookUrl: projectSettings.webhookUrl ?? undefined, + testProfile: undefined, + }; + logger.log(`Sending agentic request`); + const response = await getAgenticApiResponse(request); + state = response.state; + if (response.messages.length === 0) { + throw new Error("No messages returned from assistant"); } + const convertedMessages = convertFromAgenticAPIChatMessages(response.messages); + unsavedMessages.push(...convertedMessages.map(m => ({ + ...m, + version: 'v1' as const, + chatId, + createdAt: new Date().toISOString(), + }))); logger.log(`Saving ${unsavedMessages.length} new messages and updating chat state`); await chatMessagesCollection.insertMany(unsavedMessages); diff --git a/apps/rowboat/app/lib/types/agents_api_types.ts b/apps/rowboat/app/lib/types/agents_api_types.ts index 5fd45758..1e6b132a 100644 --- a/apps/rowboat/app/lib/types/agents_api_types.ts +++ b/apps/rowboat/app/lib/types/agents_api_types.ts @@ -1,7 +1,9 @@ import { z } from "zod"; -import { ConnectedEntity, sanitizeTextWithMentions, Workflow, WorkflowAgent, WorkflowPrompt, WorkflowTool } from "./workflow_types"; +import { sanitizeTextWithMentions, Workflow, WorkflowAgent, WorkflowPrompt, WorkflowTool } from "./workflow_types"; import { apiV1 } from "rowboat-shared"; import { ApiMessage } from "./types"; +import { TestProfile } from "./testing_types"; +import { MCPServer } from "./types"; export const AgenticAPIChatMessage = z.object({ role: z.union([z.literal('user'), z.literal('assistant'), z.literal('tool'), z.literal('system')]), @@ -30,12 +32,8 @@ export const AgenticAPIAgent = WorkflowAgent locked: true, toggleAble: true, global: true, - ragDataSources: true, - ragReturnType: true, - ragK: true, }) .extend({ - hasRagSources: z.boolean().default(false).optional(), tools: z.array(z.string()), prompts: z.array(z.string()), connectedAgents: z.array(z.string()), @@ -43,10 +41,10 @@ export const AgenticAPIAgent = WorkflowAgent export const AgenticAPIPrompt = WorkflowPrompt; -export const AgenticAPITool = WorkflowTool.omit({ - mockTool: true, - autoSubmitMockedResponse: true, -}); +export const AgenticAPITool = WorkflowTool + .omit({ + autoSubmitMockedResponse: true, + }) export const AgenticAPIChatRequest = z.object({ messages: z.array(AgenticAPIChatMessage), @@ -55,6 +53,9 @@ export const AgenticAPIChatRequest = z.object({ tools: z.array(AgenticAPITool), prompts: z.array(WorkflowPrompt), startAgent: z.string(), + testProfile: TestProfile.optional(), + mcpServers: z.array(MCPServer).optional(), + toolWebhookUrl: z.string().optional(), }); export const AgenticAPIChatResponse = z.object({ @@ -82,8 +83,10 @@ export function convertWorkflowToAgenticAPI(workflow: z.infer): description: agent.description, instructions: sanitized, model: agent.model, - hasRagSources: agent.ragDataSources ? agent.ragDataSources.length > 0 : false, controlType: agent.controlType, + ragDataSources: agent.ragDataSources, + ragK: agent.ragK, + ragReturnType: agent.ragReturnType, tools: entities.filter(e => e.type == 'tool').map(e => e.name), prompts: entities.filter(e => e.type == 'prompt').map(e => e.name), connectedAgents: entities.filter(e => e.type === 'agent').map(e => e.name), @@ -91,10 +94,8 @@ export function convertWorkflowToAgenticAPI(workflow: z.infer): return agenticAgent; }), tools: workflow.tools.map(tool => { - const { mockTool, autoSubmitMockedResponse, ...rest } = tool; - return { - ...rest, - }; + const { autoSubmitMockedResponse, ...rest } = tool; + return rest; }), prompts: workflow.prompts .map(p => { diff --git a/apps/rowboat/app/lib/types/project_types.ts b/apps/rowboat/app/lib/types/project_types.ts index 54192314..6016e609 100644 --- a/apps/rowboat/app/lib/types/project_types.ts +++ b/apps/rowboat/app/lib/types/project_types.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import { MCPServer } from "./types"; export const Project = z.object({ _id: z.string().uuid(), @@ -12,10 +13,7 @@ export const Project = z.object({ publishedWorkflowId: z.string().optional(), nextWorkflowNumber: z.number().optional(), testRunCounter: z.number().default(0), - mcpServers: z.array(z.object({ - name: z.string(), - url: z.string(), - })).optional(), + mcpServers: z.array(MCPServer).optional(), }); export const ProjectMember = z.object({ diff --git a/apps/rowboat/app/lib/types/types.ts b/apps/rowboat/app/lib/types/types.ts index b3f59ce9..911d857c 100644 --- a/apps/rowboat/app/lib/types/types.ts +++ b/apps/rowboat/app/lib/types/types.ts @@ -2,6 +2,11 @@ import { CoreMessage, ToolCallPart } from "ai"; import { z } from "zod"; import { apiV1 } from "rowboat-shared"; +export const MCPServer = z.object({ + name: z.string(), + url: z.string(), +}); + export const PlaygroundChat = z.object({ createdAt: z.string().datetime(), projectId: z.string(), diff --git a/apps/rowboat/app/lib/utils.ts b/apps/rowboat/app/lib/utils.ts index 8a0b522e..24568a89 100644 --- a/apps/rowboat/app/lib/utils.ts +++ b/apps/rowboat/app/lib/utils.ts @@ -1,136 +1,8 @@ -import { convertFromAgenticAPIChatMessages } from "./types/agents_api_types"; -import { ClientToolCallRequest } from "./types/tool_types"; -import { ClientToolCallJwt, GetInformationToolResult } from "./types/tool_types"; -import { ClientToolCallRequestBody } from "./types/tool_types"; -import { AgenticAPIChatResponse } from "./types/agents_api_types"; -import { AgenticAPIChatRequest } from "./types/agents_api_types"; -import { Workflow, WorkflowAgent } from "./types/workflow_types"; -import { AgenticAPIChatMessage } from "./types/agents_api_types"; +import { AgenticAPIChatResponse, AgenticAPIChatRequest, AgenticAPIChatMessage } from "./types/agents_api_types"; import { z } from "zod"; -import { dataSourceDocsCollection, dataSourcesCollection, projectsCollection } from "./mongodb"; -import { apiV1 } from "rowboat-shared"; -import { SignJWT } from "jose"; -import crypto from "crypto"; -import { ObjectId } from "mongodb"; -import { embeddingModel } from "./embedding"; -import { embed, generateObject } from "ai"; -import { qdrantClient } from "./qdrant"; -import { EmbeddingRecord } from "./types/datasource_types"; +import { generateObject } from "ai"; import { ApiMessage } from "./types/types"; import { openai } from "@ai-sdk/openai"; -import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; -import { Client } from "@modelcontextprotocol/sdk/client/index.js"; - -export async function callMcpTool( - projectId: string, - mcpServerName: string, - toolName: string, - parameters: Record, -): Promise { - const project = await projectsCollection.findOne({ - "_id": projectId, - }); - if (!project) { - throw new Error('Project not found'); - } - - const mcpServer = project.mcpServers?.find(s => s.name === mcpServerName); - if (!mcpServer) { - throw new Error('MCP server not found'); - } - - const transport = new SSEClientTransport(new URL(mcpServer.url)); - - const client = new Client( - { - name: "rowboat-client", - version: "1.0.0" - }, - { - capabilities: { - prompts: {}, - resources: {}, - tools: {} - } - } - ); - - await client.connect(transport); - - const result = await client.callTool({ - name: toolName, - arguments: parameters, - }); - - await client.close(); - - return result; -} - -export async function callClientToolWebhook( - toolCall: z.infer['tool_calls'][number], - messages: z.infer[], - projectId: string, -): Promise { - const project = await projectsCollection.findOne({ - "_id": projectId, - }); - if (!project) { - throw new Error('Project not found'); - } - - if (!project.webhookUrl) { - throw new Error('Webhook URL not found'); - } - - // prepare request body - const content = JSON.stringify({ - toolCall, - messages, - } as z.infer); - const requestId = crypto.randomUUID(); - const bodyHash = crypto - .createHash('sha256') - .update(content, 'utf8') - .digest('hex'); - - // sign request - const jwt = await new SignJWT({ - requestId, - projectId, - bodyHash, - } as z.infer) - .setProtectedHeader({ - alg: 'HS256', - typ: 'JWT', - }) - .setIssuer('rowboat') - .setAudience(project.webhookUrl) - .setSubject(`tool-call-${toolCall.id}`) - .setJti(requestId) - .setIssuedAt() - .setExpirationTime("5 minutes") - .sign(new TextEncoder().encode(project.secret)); - - // make request - const request: z.infer = { - requestId, - content, - }; - const response = await fetch(project.webhookUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-signature-jwt': jwt, - }, - body: JSON.stringify(request), - }); - if (!response.ok) { - throw new Error(`Failed to call webhook: ${response.status}: ${response.statusText}`); - } - const responseBody = await response.json(); - return responseBody; -} export async function getAgenticApiResponse( request: z.infer, @@ -163,85 +35,6 @@ export async function getAgenticApiResponse( }; } -export async function runRAGToolCall( - projectId: string, - query: string, - sourceIds: string[], - returnType: z.infer['ragReturnType'], - k: number, -): Promise> { - // create embedding for question - const embedResult = await embed({ - model: embeddingModel, - value: query, - }); - - // fetch all data sources for this project - const sources = await dataSourcesCollection.find({ - projectId: projectId, - active: true, - }).toArray(); - const validSourceIds = sources - .filter(s => sourceIds.includes(s._id.toString())) // id should be in sourceIds - .filter(s => s.active) // should be active - .map(s => s._id.toString()); - - // if no sources found, return empty response - if (validSourceIds.length === 0) { - return { - results: [], - }; - } - - // perform qdrant vector search - const qdrantResults = await qdrantClient.query("embeddings", { - query: embedResult.embedding, - filter: { - must: [ - { key: "projectId", match: { value: projectId } }, - { key: "sourceId", match: { any: validSourceIds } }, - ], - }, - limit: k, - with_payload: true, - }); - - // if return type is chunks, return the chunks - let results = qdrantResults.points.map((point) => { - const { title, name, content, docId, sourceId } = point.payload as z.infer['payload']; - return { - title, - name, - content, - docId, - sourceId, - }; - }); - - if (returnType === 'chunks') { - return { - results, - }; - } - - // otherwise, fetch the doc contents from mongodb - const docs = await dataSourceDocsCollection.find({ - _id: { $in: results.map(r => new ObjectId(r.docId)) }, - }).toArray(); - - // map the results to the docs - results = results.map(r => { - const doc = docs.find(d => d._id.toString() === r.docId); - return { - ...r, - content: doc?.content || '', - }; - }); - - return { - results, - }; -} // 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 bab4dce6..69a5202f 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/app.tsx @@ -1,7 +1,7 @@ 'use client'; import { useState } from "react"; import { z } from "zod"; -import { PlaygroundChat } from "../../../lib/types/types"; +import { MCPServer, PlaygroundChat } from "../../../lib/types/types"; import { Workflow } from "../../../lib/types/workflow_types"; import { Chat } from "./chat"; import { ActionButton, Pane } from "../workflow/pane"; @@ -17,11 +17,15 @@ export function App({ projectId, workflow, messageSubscriber, + mcpServerUrls, + toolWebhookUrl, }: { hidden?: boolean; projectId: string; workflow: z.infer; messageSubscriber?: (messages: z.infer[]) => void; + mcpServerUrls: Array>; + toolWebhookUrl: string; }) { const [counter, setCounter] = useState(0); const [testProfile, setTestProfile] = useState | null>(null); @@ -84,6 +88,8 @@ export function App({ onTestProfileChange={handleTestProfileChange} systemMessage={systemMessage} onSystemMessageChange={handleSystemMessageChange} + mcpServerUrls={mcpServerUrls} + toolWebhookUrl={toolWebhookUrl} /> diff --git a/apps/rowboat/app/projects/[projectId]/playground/chat.tsx b/apps/rowboat/app/projects/[projectId]/playground/chat.tsx index 62152ff0..f7f51345 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/chat.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/chat.tsx @@ -1,9 +1,9 @@ 'use client'; -import { getAssistantResponse, simulateUserResponse } from "../../../actions/actions"; +import { getAssistantResponse } from "../../../actions/actions"; import { useEffect, useState } from "react"; import { Messages } from "./messages"; import z from "zod"; -import { PlaygroundChat } from "../../../lib/types/types"; +import { MCPServer, PlaygroundChat } from "../../../lib/types/types"; import { convertToAgenticAPIChatMessages } from "../../../lib/types/agents_api_types"; import { convertWorkflowToAgenticAPI } from "../../../lib/types/agents_api_types"; import { AgenticAPIChatRequest } from "../../../lib/types/agents_api_types"; @@ -15,7 +15,7 @@ import { CopyAsJsonButton } from "./copy-as-json-button"; import { TestProfile } from "@/app/lib/types/testing_types"; import { ProfileSelector } from "@/app/projects/[projectId]/test/[[...slug]]/components/selectors/profile-selector"; import { WithStringId } from "@/app/lib/types/types"; -import { XCircleIcon, XIcon } from "lucide-react"; +import { XIcon } from "lucide-react"; export function Chat({ chat, @@ -26,6 +26,8 @@ export function Chat({ onTestProfileChange, systemMessage, onSystemMessageChange, + mcpServerUrls, + toolWebhookUrl, }: { chat: z.infer; projectId: string; @@ -35,6 +37,8 @@ export function Chat({ onTestProfileChange: (profile: WithStringId> | null) => void; systemMessage: string; onSystemMessageChange: (message: string) => void; + mcpServerUrls: Array>; + toolWebhookUrl: string; }) { const [messages, setMessages] = useState[]>(chat.messages); const [loadingAssistantResponse, setLoadingAssistantResponse] = useState(false); @@ -68,15 +72,6 @@ export function Chat({ setFetchResponseError(null); } - function handleToolCallResults(results: z.infer[]) { - setMessages([...messages, ...results.map((result) => ({ - ...result, - version: 'v1' as const, - chatId: '', - createdAt: new Date().toISOString(), - }))]); - } - // reset state when workflow changes useEffect(() => { setMessages([]); @@ -113,6 +108,9 @@ export function Chat({ tools, prompts, startAgent, + mcpServers: mcpServerUrls, + toolWebhookUrl: toolWebhookUrl, + testProfile: testProfile ?? undefined, }; setLastAgenticRequest(null); setLastAgenticResponse(null); @@ -164,105 +162,7 @@ export function Chat({ return () => { ignore = true; }; - }, [chat.simulated, messages, projectId, agenticState, workflow, fetchResponseError, systemMessage, simulationComplete]); - - // simulate user turn - useEffect(() => { - let ignore = false; - - async function process() { - if (chat.simulationScenario === undefined) { - return; - } - - // fetch next user prompt - setLoadingUserResponse(true); - try { - - const response = await simulateUserResponse(projectId, messages, chat.simulationScenario) - if (ignore) { - return; - } - if (simulationComplete) { - return; - } - if (response.trim() === 'EXIT') { - setSimulationComplete(true); - return; - } - setMessages([...messages, { - role: 'user', - content: response, - version: 'v1' as const, - chatId: '', - createdAt: new Date().toISOString(), - }]); - setFetchResponseError(null); - } catch (err) { - setFetchResponseError(`Failed to simulate user response: ${err instanceof Error ? err.message : 'Unknown error'}`); - } finally { - setLoadingUserResponse(false); - } - } - - // proceed only if chat is simulated - if (!chat.simulated) { - return; - } - - // dont proceed if simulation is complete - if (chat.simulated && simulationComplete) { - return; - } - - // check if there are no messages yet OR - // check if the last message is an assistant - // message containing a text response. If so, - // call the simulate user turn api to fetch - // user response - let last = messages[messages.length - 1]; - if (last && last.role !== 'assistant') { - return; - } - if (last && 'tool_calls' in last) { - return; - } - - process(); - - return () => { - ignore = true; - }; - }, [chat.simulated, messages, projectId, simulationComplete, chat.simulationScenario]); - - // save chat on every assistant message - // useEffect(() => { - // let ignore = false; - - // function process() { - // savePlaygroundChat(projectId, { - // ...chat, - // messages, - // simulationComplete, - // agenticState, - // }, chatId) - // .then((insertedChatId) => { - // if (!chatId) { - // setChatId(insertedChatId); - // } - // }); - // } - - // if (messages.length === 0) { - // return; - // } - - // const lastMessage = messages[messages.length - 1]; - // if (lastMessage && lastMessage.role !== 'assistant') { - // return; - // } - // process(); - // }, [chatId, chat, messages, projectId, simulationComplete, agenticState]); + }, [chat.simulated, messages, projectId, agenticState, workflow, fetchResponseError, systemMessage, simulationComplete, mcpServerUrls, toolWebhookUrl, testProfile]); const handleCopyChat = () => { const jsonString = JSON.stringify({ @@ -303,7 +203,6 @@ export function Chat({ projectId={projectId} messages={messages} toolCallResults={toolCallResults} - handleToolCallResults={handleToolCallResults} loadingAssistantResponse={loadingAssistantResponse} loadingUserResponse={loadingUserResponse} workflow={workflow} diff --git a/apps/rowboat/app/projects/[projectId]/playground/messages.tsx b/apps/rowboat/app/projects/[projectId]/playground/messages.tsx index 8c42b527..f4e52110 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/messages.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/messages.tsx @@ -1,17 +1,14 @@ 'use client'; -import { Button, Spinner, Textarea } from "@heroui/react"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { Spinner } from "@heroui/react"; +import { useEffect, useMemo, useRef, useState } from "react"; import z from "zod"; import { Workflow } from "../../../lib/types/workflow_types"; import { WorkflowTool } from "../../../lib/types/workflow_types"; -import { GetInformationToolResult } from "../../../lib/types/tool_types"; -import { executeClientTool, getInformationTool, suggestToolResponse } from "../../../actions/actions"; import MarkdownContent from "../../../lib/components/markdown-content"; import { apiV1 } from "rowboat-shared"; import { EditableField } from "../../../lib/components/editable-field"; import { MessageSquareIcon, EllipsisIcon, CircleCheckIcon, ChevronRightIcon, ChevronDownIcon, XIcon } from "lucide-react"; import { TestProfile } from "@/app/lib/types/testing_types"; -import { executeMcpTool } from "@/app/actions/mcp_actions"; function UserMessage({ content }: { content: string }) { return
@@ -88,7 +85,6 @@ function UserMessageLoading() { function ToolCalls({ toolCalls, results, - handleResults, projectId, messages, sender, @@ -98,7 +94,6 @@ function ToolCalls({ }: { toolCalls: z.infer['tool_calls']; results: Record>; - handleResults: (results: z.infer[]) => void; projectId: string; messages: z.infer[]; sender: string | null | undefined; @@ -108,21 +103,12 @@ function ToolCalls({ }) { const resultsMap: Record> = {}; - function handleToolCallResult(result: z.infer) { - resultsMap[result.tool_call_id] = result; - if (Object.keys(resultsMap).length === toolCalls.length) { - const results = Object.values(resultsMap); - handleResults(results); - } - } - return
{toolCalls.map(toolCall => { return ['tool_calls'][number]; result: z.infer | undefined; - handleResult: (result: z.infer) => void; projectId: string; messages: z.infer[]; sender: string | null | undefined; @@ -163,63 +147,17 @@ function ToolCall({ } } - switch (toolCall.function.name) { - case 'getArticleInfo': - return ; - default: - if (toolCall.function.name.startsWith('transfer_to_')) { - return ; - } - if (!matchingWorkflowTool || - matchingWorkflowTool.mockTool || - (testProfile && testProfile.mockTools)) { - return ; - } - if (matchingWorkflowTool?.isMcp) { - return ; - } - return ; + if (toolCall.function.name.startsWith('transfer_to_')) { + return ; } + return ; } function ToolCallHeader({ @@ -240,105 +178,11 @@ function ToolCallHeader({
; } -function GetInformationToolCall({ - toolCall, - result: availableResult, - handleResult, - projectId, - messages, - sender, - workflow, -}: { - toolCall: z.infer['tool_calls'][number]; - result: z.infer | undefined; - handleResult: (result: z.infer) => void; - projectId: string; - messages: z.infer[]; - sender: string | null | undefined; - workflow: z.infer; -}) { - const [result, setResult] = useState | undefined>(availableResult); - const args = JSON.parse(toolCall.function.arguments) as { question: string }; - let typedResult: z.infer | undefined; - if (result) { - typedResult = JSON.parse(result.content) as z.infer; - } - - useEffect(() => { - if (result) { - return; - } - let ignore = false; - - async function process() { - const result: z.infer = { - role: 'tool', - tool_call_id: toolCall.id, - tool_name: toolCall.function.name, - content: '', - }; - // find target agent - const agent = workflow.agents.find(agent => agent.name == sender); - if (!agent || !agent.ragDataSources) { - result.content = JSON.stringify({ - results: [], - }); - } else { - const matches = await getInformationTool(projectId, args.question, agent.ragDataSources, agent.ragReturnType, agent.ragK); - if (ignore) { - return; - } - result.content = JSON.stringify(matches); - } - setResult(result); - handleResult(result); - } - process(); - - return () => { - ignore = true; - }; - }, [result, toolCall.id, toolCall.function.name, projectId, args.question, workflow.agents, sender, handleResult]); - - return
- {sender &&
{sender}
} -
- - -
- {result ? 'Fetched' : 'Fetch'} information for question: {args['question']} - {result &&
- {typedResult && typedResult.results.length === 0 &&
No matches found.
} - {typedResult && typedResult.results.length > 0 &&
    - {typedResult.results.map((result, index) => { - return
  • - -
  • - })} -
} -
} -
-
-
; -} - function TransferToAgentToolCall({ - toolCall, result: availableResult, - handleResult, - projectId, - messages, sender, }: { - toolCall: z.infer['tool_calls'][number]; result: z.infer | undefined; - handleResult: (result: z.infer) => void; - projectId: string; - messages: z.infer[]; sender: string | null | undefined; }) { const typedResult = availableResult ? JSON.parse(availableResult.content) as { assistant: string } : undefined; @@ -355,282 +199,28 @@ function TransferToAgentToolCall({
; } -function McpToolCall({ - toolCall, - result: availableResult, - handleResult, - projectId, - messages, - sender, - workflowTool, -}: { - toolCall: z.infer['tool_calls'][number]; - result: z.infer | undefined; - handleResult: (result: z.infer) => void; - projectId: string; - messages: z.infer[]; - sender: string | null | undefined; - workflowTool: z.infer; -}) { - const [result, setResult] = useState | undefined>(availableResult); - - useEffect(() => { - if (result) { - return; - } - let ignore = false; - - async function process() { - let response; - try { - response = await executeMcpTool( - projectId, - workflowTool.mcpServerName || '', - workflowTool.name, - JSON.parse(toolCall.function.arguments), - ); - } catch (e) { - response = { - error: (e as Error).message, - }; - } - if (ignore) { - return; - } - - const result: z.infer = { - role: 'tool', - tool_call_id: toolCall.id, - tool_name: toolCall.function.name, - content: JSON.stringify(response), - }; - setResult(result); - handleResult(result); - } - process(); - - return () => { - ignore = true; - }; - }, [result, toolCall, projectId, messages, handleResult, workflowTool.mcpServerName, workflowTool.name]); - - return
- {sender &&
{sender}
} -
- - -
- - {result && } -
-
-
; -} - function ClientToolCall({ toolCall, result: availableResult, - handleResult, - projectId, - messages, sender, }: { toolCall: z.infer['tool_calls'][number]; result: z.infer | undefined; - handleResult: (result: z.infer) => void; - projectId: string; - messages: z.infer[]; sender: string | null | undefined; }) { - const [result, setResult] = useState | undefined>(availableResult); - - useEffect(() => { - if (result) { - return; - } - let ignore = false; - - async function process() { - let response; - try { - response = await executeClientTool( - toolCall, - messages, - projectId, - ); - } catch (e) { - response = { - error: (e as Error).message, - }; - } - if (ignore) { - return; - } - - const result: z.infer = { - role: 'tool', - tool_call_id: toolCall.id, - tool_name: toolCall.function.name, - content: JSON.stringify(response), - }; - setResult(result); - handleResult(result); - } - process(); - - return () => { - ignore = true; - }; - }, [result, toolCall, projectId, messages, handleResult]); - return
{sender &&
{sender}
}
- +
- {result && } + {availableResult && }
; } -function MockToolCall({ - toolCall, - result: availableResult, - handleResult, - projectId, - messages, - sender, - testProfile = null, - workflowTool, - systemMessage, -}: { - toolCall: z.infer['tool_calls'][number]; - result: z.infer | undefined; - handleResult: (result: z.infer) => void; - projectId: string; - messages: z.infer[]; - sender: string | null | undefined; - testProfile: z.infer | null; - workflowTool: z.infer | undefined; - systemMessage: string | undefined; -}) { - const [result, setResult] = useState | undefined>(availableResult); - const [response, setResponse] = useState(''); - const [generatingResponse, setGeneratingResponse] = useState(false); - - const handleSubmit = useCallback(() => { - let parsed; - try { - parsed = JSON.parse(response); - } catch (e) { - alert('Invalid JSON'); - return; - } - const result: z.infer = { - role: 'tool', - tool_call_id: toolCall.id, - tool_name: toolCall.function.name, - content: JSON.stringify(parsed), - }; - setResult(result); - handleResult(result); - }, [toolCall.id, toolCall.function.name, handleResult, response]); - - useEffect(() => { - if (result) { - return; - } - if (response) { - return; - } - let ignore = false; - - async function process() { - setGeneratingResponse(true); - - const response = await suggestToolResponse( - toolCall.id, - projectId, - [{ - role: 'system', - content: systemMessage || '', - createdAt: new Date().toISOString(), - version: 'v1', - chatId: '', - }, ...messages], - testProfile?.mockPrompt || workflowTool?.mockInstructions || '', - ); - if (ignore) { - return; - } - setResponse(response); - setGeneratingResponse(false); - } - process(); - - return () => { - ignore = true; - }; - }, [result, response, toolCall.id, projectId, messages, testProfile, systemMessage, workflowTool?.mockInstructions]); - - // auto submit if autoSubmitMockedResponse is true - useEffect(() => { - if (!workflowTool?.autoSubmitMockedResponse) { - return; - } - if (result) { - return; - } - if (response) { - handleSubmit(); - } - }, [workflowTool?.autoSubmitMockedResponse, response, handleSubmit, result]); - - return
- {sender &&
{sender}
} -
-
- {!result && } - {result && } - - Function Call: {toolCall.function.name} - -
- -
- - {result && } -
- - {!result && !workflowTool?.autoSubmitMockedResponse &&
-
Response:
- - -
} -
-
; -} - 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 05/14] 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 06/14] 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 07/14] 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 08/14] 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 09/14] 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 10/14] 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 11/14] 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 12/14] 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 13/14] 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 14/14] 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: