agentpool 2.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of agentpool might be problematic. Click here for more details.
- acp/README.md +64 -0
- acp/__init__.py +172 -0
- acp/__main__.py +10 -0
- acp/acp_requests.py +285 -0
- acp/agent/__init__.py +6 -0
- acp/agent/connection.py +256 -0
- acp/agent/implementations/__init__.py +6 -0
- acp/agent/implementations/debug_server/__init__.py +1 -0
- acp/agent/implementations/debug_server/cli.py +79 -0
- acp/agent/implementations/debug_server/debug.html +234 -0
- acp/agent/implementations/debug_server/debug_server.py +496 -0
- acp/agent/implementations/testing.py +91 -0
- acp/agent/protocol.py +65 -0
- acp/bridge/README.md +162 -0
- acp/bridge/__init__.py +6 -0
- acp/bridge/__main__.py +91 -0
- acp/bridge/bridge.py +246 -0
- acp/bridge/py.typed +0 -0
- acp/bridge/settings.py +15 -0
- acp/client/__init__.py +7 -0
- acp/client/connection.py +251 -0
- acp/client/implementations/__init__.py +7 -0
- acp/client/implementations/default_client.py +185 -0
- acp/client/implementations/headless_client.py +266 -0
- acp/client/implementations/noop_client.py +110 -0
- acp/client/protocol.py +61 -0
- acp/connection.py +280 -0
- acp/exceptions.py +46 -0
- acp/filesystem.py +524 -0
- acp/notifications.py +832 -0
- acp/py.typed +0 -0
- acp/schema/__init__.py +265 -0
- acp/schema/agent_plan.py +30 -0
- acp/schema/agent_requests.py +126 -0
- acp/schema/agent_responses.py +256 -0
- acp/schema/base.py +39 -0
- acp/schema/capabilities.py +230 -0
- acp/schema/client_requests.py +247 -0
- acp/schema/client_responses.py +96 -0
- acp/schema/common.py +81 -0
- acp/schema/content_blocks.py +188 -0
- acp/schema/mcp.py +82 -0
- acp/schema/messages.py +171 -0
- acp/schema/notifications.py +82 -0
- acp/schema/protocol_stuff.md +3 -0
- acp/schema/session_state.py +160 -0
- acp/schema/session_updates.py +419 -0
- acp/schema/slash_commands.py +51 -0
- acp/schema/terminal.py +15 -0
- acp/schema/tool_call.py +347 -0
- acp/stdio.py +250 -0
- acp/task/__init__.py +53 -0
- acp/task/debug.py +197 -0
- acp/task/dispatcher.py +93 -0
- acp/task/queue.py +69 -0
- acp/task/sender.py +82 -0
- acp/task/state.py +87 -0
- acp/task/supervisor.py +93 -0
- acp/terminal_handle.py +30 -0
- acp/tool_call_reporter.py +199 -0
- acp/tool_call_state.py +178 -0
- acp/transports.py +104 -0
- acp/utils.py +240 -0
- agentpool/__init__.py +63 -0
- agentpool/__main__.py +7 -0
- agentpool/agents/__init__.py +30 -0
- agentpool/agents/acp_agent/__init__.py +5 -0
- agentpool/agents/acp_agent/acp_agent.py +837 -0
- agentpool/agents/acp_agent/acp_converters.py +294 -0
- agentpool/agents/acp_agent/client_handler.py +317 -0
- agentpool/agents/acp_agent/session_state.py +44 -0
- agentpool/agents/agent.py +1264 -0
- agentpool/agents/agui_agent/__init__.py +19 -0
- agentpool/agents/agui_agent/agui_agent.py +677 -0
- agentpool/agents/agui_agent/agui_converters.py +423 -0
- agentpool/agents/agui_agent/chunk_transformer.py +204 -0
- agentpool/agents/agui_agent/event_types.py +83 -0
- agentpool/agents/agui_agent/helpers.py +192 -0
- agentpool/agents/architect.py +71 -0
- agentpool/agents/base_agent.py +177 -0
- agentpool/agents/claude_code_agent/__init__.py +11 -0
- agentpool/agents/claude_code_agent/claude_code_agent.py +1021 -0
- agentpool/agents/claude_code_agent/converters.py +243 -0
- agentpool/agents/context.py +105 -0
- agentpool/agents/events/__init__.py +61 -0
- agentpool/agents/events/builtin_handlers.py +129 -0
- agentpool/agents/events/event_emitter.py +320 -0
- agentpool/agents/events/events.py +561 -0
- agentpool/agents/events/tts_handlers.py +186 -0
- agentpool/agents/interactions.py +419 -0
- agentpool/agents/slashed_agent.py +244 -0
- agentpool/agents/sys_prompts.py +178 -0
- agentpool/agents/tool_wrapping.py +184 -0
- agentpool/base_provider.py +28 -0
- agentpool/common_types.py +226 -0
- agentpool/config_resources/__init__.py +16 -0
- agentpool/config_resources/acp_assistant.yml +24 -0
- agentpool/config_resources/agents.yml +109 -0
- agentpool/config_resources/agents_template.yml +18 -0
- agentpool/config_resources/agui_test.yml +18 -0
- agentpool/config_resources/claude_code_agent.yml +16 -0
- agentpool/config_resources/claude_style_subagent.md +30 -0
- agentpool/config_resources/external_acp_agents.yml +77 -0
- agentpool/config_resources/opencode_style_subagent.md +19 -0
- agentpool/config_resources/tts_test_agents.yml +78 -0
- agentpool/delegation/__init__.py +8 -0
- agentpool/delegation/base_team.py +504 -0
- agentpool/delegation/message_flow_tracker.py +39 -0
- agentpool/delegation/pool.py +1129 -0
- agentpool/delegation/team.py +325 -0
- agentpool/delegation/teamrun.py +343 -0
- agentpool/docs/__init__.py +5 -0
- agentpool/docs/gen_examples.py +42 -0
- agentpool/docs/utils.py +370 -0
- agentpool/functional/__init__.py +20 -0
- agentpool/functional/py.typed +0 -0
- agentpool/functional/run.py +80 -0
- agentpool/functional/structure.py +136 -0
- agentpool/hooks/__init__.py +20 -0
- agentpool/hooks/agent_hooks.py +247 -0
- agentpool/hooks/base.py +119 -0
- agentpool/hooks/callable.py +140 -0
- agentpool/hooks/command.py +180 -0
- agentpool/hooks/prompt.py +122 -0
- agentpool/jinja_filters.py +132 -0
- agentpool/log.py +224 -0
- agentpool/mcp_server/__init__.py +17 -0
- agentpool/mcp_server/client.py +429 -0
- agentpool/mcp_server/constants.py +32 -0
- agentpool/mcp_server/conversions.py +172 -0
- agentpool/mcp_server/helpers.py +47 -0
- agentpool/mcp_server/manager.py +232 -0
- agentpool/mcp_server/message_handler.py +164 -0
- agentpool/mcp_server/registries/__init__.py +1 -0
- agentpool/mcp_server/registries/official_registry_client.py +345 -0
- agentpool/mcp_server/registries/pulsemcp_client.py +88 -0
- agentpool/mcp_server/tool_bridge.py +548 -0
- agentpool/messaging/__init__.py +58 -0
- agentpool/messaging/compaction.py +928 -0
- agentpool/messaging/connection_manager.py +319 -0
- agentpool/messaging/context.py +66 -0
- agentpool/messaging/event_manager.py +426 -0
- agentpool/messaging/events.py +39 -0
- agentpool/messaging/message_container.py +209 -0
- agentpool/messaging/message_history.py +491 -0
- agentpool/messaging/messagenode.py +377 -0
- agentpool/messaging/messages.py +655 -0
- agentpool/messaging/processing.py +76 -0
- agentpool/mime_utils.py +95 -0
- agentpool/models/__init__.py +21 -0
- agentpool/models/acp_agents/__init__.py +22 -0
- agentpool/models/acp_agents/base.py +308 -0
- agentpool/models/acp_agents/mcp_capable.py +790 -0
- agentpool/models/acp_agents/non_mcp.py +842 -0
- agentpool/models/agents.py +450 -0
- agentpool/models/agui_agents.py +89 -0
- agentpool/models/claude_code_agents.py +238 -0
- agentpool/models/file_agents.py +116 -0
- agentpool/models/file_parsing.py +367 -0
- agentpool/models/manifest.py +658 -0
- agentpool/observability/__init__.py +9 -0
- agentpool/observability/observability_registry.py +97 -0
- agentpool/prompts/__init__.py +1 -0
- agentpool/prompts/base.py +27 -0
- agentpool/prompts/builtin_provider.py +75 -0
- agentpool/prompts/conversion_manager.py +95 -0
- agentpool/prompts/convert.py +96 -0
- agentpool/prompts/manager.py +204 -0
- agentpool/prompts/parts/zed.md +33 -0
- agentpool/prompts/prompts.py +581 -0
- agentpool/py.typed +0 -0
- agentpool/queries/tree-sitter-language-pack/README.md +7 -0
- agentpool/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
- agentpool/queries/tree-sitter-language-pack/c-tags.scm +9 -0
- agentpool/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
- agentpool/queries/tree-sitter-language-pack/clojure-tags.scm +7 -0
- agentpool/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
- agentpool/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
- agentpool/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
- agentpool/queries/tree-sitter-language-pack/d-tags.scm +26 -0
- agentpool/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
- agentpool/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
- agentpool/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
- agentpool/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
- agentpool/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
- agentpool/queries/tree-sitter-language-pack/go-tags.scm +42 -0
- agentpool/queries/tree-sitter-language-pack/java-tags.scm +20 -0
- agentpool/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
- agentpool/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
- agentpool/queries/tree-sitter-language-pack/matlab-tags.scm +10 -0
- agentpool/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
- agentpool/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
- agentpool/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
- agentpool/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
- agentpool/queries/tree-sitter-language-pack/python-tags.scm +14 -0
- agentpool/queries/tree-sitter-language-pack/r-tags.scm +21 -0
- agentpool/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
- agentpool/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
- agentpool/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
- agentpool/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
- agentpool/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
- agentpool/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
- agentpool/queries/tree-sitter-languages/README.md +24 -0
- agentpool/queries/tree-sitter-languages/c-tags.scm +9 -0
- agentpool/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
- agentpool/queries/tree-sitter-languages/cpp-tags.scm +15 -0
- agentpool/queries/tree-sitter-languages/dart-tags.scm +91 -0
- agentpool/queries/tree-sitter-languages/elisp-tags.scm +8 -0
- agentpool/queries/tree-sitter-languages/elixir-tags.scm +54 -0
- agentpool/queries/tree-sitter-languages/elm-tags.scm +19 -0
- agentpool/queries/tree-sitter-languages/fortran-tags.scm +15 -0
- agentpool/queries/tree-sitter-languages/go-tags.scm +30 -0
- agentpool/queries/tree-sitter-languages/haskell-tags.scm +3 -0
- agentpool/queries/tree-sitter-languages/hcl-tags.scm +77 -0
- agentpool/queries/tree-sitter-languages/java-tags.scm +20 -0
- agentpool/queries/tree-sitter-languages/javascript-tags.scm +88 -0
- agentpool/queries/tree-sitter-languages/julia-tags.scm +60 -0
- agentpool/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
- agentpool/queries/tree-sitter-languages/matlab-tags.scm +10 -0
- agentpool/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
- agentpool/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
- agentpool/queries/tree-sitter-languages/php-tags.scm +26 -0
- agentpool/queries/tree-sitter-languages/python-tags.scm +12 -0
- agentpool/queries/tree-sitter-languages/ql-tags.scm +26 -0
- agentpool/queries/tree-sitter-languages/ruby-tags.scm +64 -0
- agentpool/queries/tree-sitter-languages/rust-tags.scm +60 -0
- agentpool/queries/tree-sitter-languages/scala-tags.scm +65 -0
- agentpool/queries/tree-sitter-languages/typescript-tags.scm +41 -0
- agentpool/queries/tree-sitter-languages/zig-tags.scm +3 -0
- agentpool/repomap.py +1231 -0
- agentpool/resource_providers/__init__.py +17 -0
- agentpool/resource_providers/aggregating.py +54 -0
- agentpool/resource_providers/base.py +172 -0
- agentpool/resource_providers/codemode/__init__.py +9 -0
- agentpool/resource_providers/codemode/code_executor.py +215 -0
- agentpool/resource_providers/codemode/default_prompt.py +19 -0
- agentpool/resource_providers/codemode/helpers.py +83 -0
- agentpool/resource_providers/codemode/progress_executor.py +212 -0
- agentpool/resource_providers/codemode/provider.py +150 -0
- agentpool/resource_providers/codemode/remote_mcp_execution.py +143 -0
- agentpool/resource_providers/codemode/remote_provider.py +171 -0
- agentpool/resource_providers/filtering.py +42 -0
- agentpool/resource_providers/mcp_provider.py +246 -0
- agentpool/resource_providers/plan_provider.py +196 -0
- agentpool/resource_providers/pool.py +69 -0
- agentpool/resource_providers/static.py +289 -0
- agentpool/running/__init__.py +20 -0
- agentpool/running/decorators.py +56 -0
- agentpool/running/discovery.py +101 -0
- agentpool/running/executor.py +284 -0
- agentpool/running/injection.py +111 -0
- agentpool/running/py.typed +0 -0
- agentpool/running/run_nodes.py +87 -0
- agentpool/server.py +122 -0
- agentpool/sessions/__init__.py +13 -0
- agentpool/sessions/manager.py +302 -0
- agentpool/sessions/models.py +71 -0
- agentpool/sessions/session.py +239 -0
- agentpool/sessions/store.py +163 -0
- agentpool/skills/__init__.py +5 -0
- agentpool/skills/manager.py +120 -0
- agentpool/skills/registry.py +210 -0
- agentpool/skills/skill.py +36 -0
- agentpool/storage/__init__.py +17 -0
- agentpool/storage/manager.py +419 -0
- agentpool/storage/serialization.py +136 -0
- agentpool/talk/__init__.py +13 -0
- agentpool/talk/registry.py +128 -0
- agentpool/talk/stats.py +159 -0
- agentpool/talk/talk.py +604 -0
- agentpool/tasks/__init__.py +20 -0
- agentpool/tasks/exceptions.py +25 -0
- agentpool/tasks/registry.py +33 -0
- agentpool/testing.py +129 -0
- agentpool/text_templates/__init__.py +39 -0
- agentpool/text_templates/system_prompt.jinja +30 -0
- agentpool/text_templates/tool_call_default.jinja +13 -0
- agentpool/text_templates/tool_call_markdown.jinja +25 -0
- agentpool/text_templates/tool_call_simple.jinja +5 -0
- agentpool/tools/__init__.py +16 -0
- agentpool/tools/base.py +269 -0
- agentpool/tools/exceptions.py +9 -0
- agentpool/tools/manager.py +255 -0
- agentpool/tools/tool_call_info.py +87 -0
- agentpool/ui/__init__.py +2 -0
- agentpool/ui/base.py +89 -0
- agentpool/ui/mock_provider.py +81 -0
- agentpool/ui/stdlib_provider.py +150 -0
- agentpool/utils/__init__.py +44 -0
- agentpool/utils/baseregistry.py +185 -0
- agentpool/utils/count_tokens.py +62 -0
- agentpool/utils/dag.py +184 -0
- agentpool/utils/importing.py +206 -0
- agentpool/utils/inspection.py +334 -0
- agentpool/utils/model_capabilities.py +25 -0
- agentpool/utils/network.py +28 -0
- agentpool/utils/now.py +22 -0
- agentpool/utils/parse_time.py +87 -0
- agentpool/utils/result_utils.py +35 -0
- agentpool/utils/signatures.py +305 -0
- agentpool/utils/streams.py +112 -0
- agentpool/utils/tasks.py +186 -0
- agentpool/vfs_registry.py +250 -0
- agentpool-2.1.9.dist-info/METADATA +336 -0
- agentpool-2.1.9.dist-info/RECORD +474 -0
- agentpool-2.1.9.dist-info/WHEEL +4 -0
- agentpool-2.1.9.dist-info/entry_points.txt +14 -0
- agentpool-2.1.9.dist-info/licenses/LICENSE +22 -0
- agentpool_cli/__init__.py +34 -0
- agentpool_cli/__main__.py +66 -0
- agentpool_cli/agent.py +175 -0
- agentpool_cli/cli_types.py +23 -0
- agentpool_cli/common.py +163 -0
- agentpool_cli/create.py +175 -0
- agentpool_cli/history.py +217 -0
- agentpool_cli/log.py +78 -0
- agentpool_cli/py.typed +0 -0
- agentpool_cli/run.py +84 -0
- agentpool_cli/serve_acp.py +177 -0
- agentpool_cli/serve_api.py +69 -0
- agentpool_cli/serve_mcp.py +74 -0
- agentpool_cli/serve_vercel.py +233 -0
- agentpool_cli/store.py +171 -0
- agentpool_cli/task.py +84 -0
- agentpool_cli/utils.py +104 -0
- agentpool_cli/watch.py +54 -0
- agentpool_commands/__init__.py +180 -0
- agentpool_commands/agents.py +199 -0
- agentpool_commands/base.py +45 -0
- agentpool_commands/commands.py +58 -0
- agentpool_commands/completers.py +110 -0
- agentpool_commands/connections.py +175 -0
- agentpool_commands/markdown_utils.py +31 -0
- agentpool_commands/models.py +62 -0
- agentpool_commands/prompts.py +78 -0
- agentpool_commands/py.typed +0 -0
- agentpool_commands/read.py +77 -0
- agentpool_commands/resources.py +210 -0
- agentpool_commands/session.py +48 -0
- agentpool_commands/tools.py +269 -0
- agentpool_commands/utils.py +189 -0
- agentpool_commands/workers.py +163 -0
- agentpool_config/__init__.py +53 -0
- agentpool_config/builtin_tools.py +265 -0
- agentpool_config/commands.py +237 -0
- agentpool_config/conditions.py +301 -0
- agentpool_config/converters.py +30 -0
- agentpool_config/durable.py +331 -0
- agentpool_config/event_handlers.py +600 -0
- agentpool_config/events.py +153 -0
- agentpool_config/forward_targets.py +251 -0
- agentpool_config/hook_conditions.py +331 -0
- agentpool_config/hooks.py +241 -0
- agentpool_config/jinja.py +206 -0
- agentpool_config/knowledge.py +41 -0
- agentpool_config/loaders.py +350 -0
- agentpool_config/mcp_server.py +243 -0
- agentpool_config/nodes.py +202 -0
- agentpool_config/observability.py +191 -0
- agentpool_config/output_types.py +55 -0
- agentpool_config/pool_server.py +267 -0
- agentpool_config/prompt_hubs.py +105 -0
- agentpool_config/prompts.py +185 -0
- agentpool_config/py.typed +0 -0
- agentpool_config/resources.py +33 -0
- agentpool_config/session.py +119 -0
- agentpool_config/skills.py +17 -0
- agentpool_config/storage.py +288 -0
- agentpool_config/system_prompts.py +190 -0
- agentpool_config/task.py +162 -0
- agentpool_config/teams.py +52 -0
- agentpool_config/tools.py +112 -0
- agentpool_config/toolsets.py +1033 -0
- agentpool_config/workers.py +86 -0
- agentpool_prompts/__init__.py +1 -0
- agentpool_prompts/braintrust_hub.py +235 -0
- agentpool_prompts/fabric.py +75 -0
- agentpool_prompts/langfuse_hub.py +79 -0
- agentpool_prompts/promptlayer_provider.py +59 -0
- agentpool_prompts/py.typed +0 -0
- agentpool_server/__init__.py +9 -0
- agentpool_server/a2a_server/__init__.py +5 -0
- agentpool_server/a2a_server/a2a_types.py +41 -0
- agentpool_server/a2a_server/server.py +190 -0
- agentpool_server/a2a_server/storage.py +81 -0
- agentpool_server/acp_server/__init__.py +22 -0
- agentpool_server/acp_server/acp_agent.py +786 -0
- agentpool_server/acp_server/acp_tools.py +43 -0
- agentpool_server/acp_server/commands/__init__.py +18 -0
- agentpool_server/acp_server/commands/acp_commands.py +594 -0
- agentpool_server/acp_server/commands/debug_commands.py +376 -0
- agentpool_server/acp_server/commands/docs_commands/__init__.py +39 -0
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +169 -0
- agentpool_server/acp_server/commands/docs_commands/get_schema.py +176 -0
- agentpool_server/acp_server/commands/docs_commands/get_source.py +110 -0
- agentpool_server/acp_server/commands/docs_commands/git_diff.py +111 -0
- agentpool_server/acp_server/commands/docs_commands/helpers.py +33 -0
- agentpool_server/acp_server/commands/docs_commands/url_to_markdown.py +90 -0
- agentpool_server/acp_server/commands/spawn.py +210 -0
- agentpool_server/acp_server/converters.py +235 -0
- agentpool_server/acp_server/input_provider.py +338 -0
- agentpool_server/acp_server/server.py +288 -0
- agentpool_server/acp_server/session.py +969 -0
- agentpool_server/acp_server/session_manager.py +313 -0
- agentpool_server/acp_server/syntax_detection.py +250 -0
- agentpool_server/acp_server/zed_tools.md +90 -0
- agentpool_server/aggregating_server.py +309 -0
- agentpool_server/agui_server/__init__.py +11 -0
- agentpool_server/agui_server/server.py +128 -0
- agentpool_server/base.py +189 -0
- agentpool_server/http_server.py +164 -0
- agentpool_server/mcp_server/__init__.py +6 -0
- agentpool_server/mcp_server/server.py +314 -0
- agentpool_server/mcp_server/zed_wrapper.py +110 -0
- agentpool_server/openai_api_server/__init__.py +5 -0
- agentpool_server/openai_api_server/completions/__init__.py +1 -0
- agentpool_server/openai_api_server/completions/helpers.py +81 -0
- agentpool_server/openai_api_server/completions/models.py +98 -0
- agentpool_server/openai_api_server/responses/__init__.py +1 -0
- agentpool_server/openai_api_server/responses/helpers.py +74 -0
- agentpool_server/openai_api_server/responses/models.py +96 -0
- agentpool_server/openai_api_server/server.py +242 -0
- agentpool_server/py.typed +0 -0
- agentpool_storage/__init__.py +9 -0
- agentpool_storage/base.py +310 -0
- agentpool_storage/file_provider.py +378 -0
- agentpool_storage/formatters.py +129 -0
- agentpool_storage/memory_provider.py +396 -0
- agentpool_storage/models.py +108 -0
- agentpool_storage/py.typed +0 -0
- agentpool_storage/session_store.py +262 -0
- agentpool_storage/sql_provider/__init__.py +21 -0
- agentpool_storage/sql_provider/cli.py +146 -0
- agentpool_storage/sql_provider/models.py +249 -0
- agentpool_storage/sql_provider/queries.py +15 -0
- agentpool_storage/sql_provider/sql_provider.py +444 -0
- agentpool_storage/sql_provider/utils.py +234 -0
- agentpool_storage/text_log_provider.py +275 -0
- agentpool_toolsets/__init__.py +15 -0
- agentpool_toolsets/builtin/__init__.py +33 -0
- agentpool_toolsets/builtin/agent_management.py +239 -0
- agentpool_toolsets/builtin/chain.py +288 -0
- agentpool_toolsets/builtin/code.py +398 -0
- agentpool_toolsets/builtin/debug.py +291 -0
- agentpool_toolsets/builtin/execution_environment.py +381 -0
- agentpool_toolsets/builtin/file_edit/__init__.py +11 -0
- agentpool_toolsets/builtin/file_edit/file_edit.py +747 -0
- agentpool_toolsets/builtin/file_edit/fuzzy_matcher/__init__.py +5 -0
- agentpool_toolsets/builtin/file_edit/fuzzy_matcher/example_usage.py +311 -0
- agentpool_toolsets/builtin/file_edit/fuzzy_matcher/streaming_fuzzy_matcher.py +443 -0
- agentpool_toolsets/builtin/history.py +36 -0
- agentpool_toolsets/builtin/integration.py +85 -0
- agentpool_toolsets/builtin/skills.py +77 -0
- agentpool_toolsets/builtin/subagent_tools.py +324 -0
- agentpool_toolsets/builtin/tool_management.py +90 -0
- agentpool_toolsets/builtin/user_interaction.py +52 -0
- agentpool_toolsets/builtin/workers.py +128 -0
- agentpool_toolsets/composio_toolset.py +96 -0
- agentpool_toolsets/config_creation.py +192 -0
- agentpool_toolsets/entry_points.py +47 -0
- agentpool_toolsets/fsspec_toolset/__init__.py +7 -0
- agentpool_toolsets/fsspec_toolset/diagnostics.py +115 -0
- agentpool_toolsets/fsspec_toolset/grep.py +450 -0
- agentpool_toolsets/fsspec_toolset/helpers.py +631 -0
- agentpool_toolsets/fsspec_toolset/streaming_diff_parser.py +249 -0
- agentpool_toolsets/fsspec_toolset/toolset.py +1384 -0
- agentpool_toolsets/mcp_run_toolset.py +61 -0
- agentpool_toolsets/notifications.py +146 -0
- agentpool_toolsets/openapi.py +118 -0
- agentpool_toolsets/py.typed +0 -0
- agentpool_toolsets/search_toolset.py +202 -0
- agentpool_toolsets/semantic_memory_toolset.py +536 -0
- agentpool_toolsets/streaming_tools.py +265 -0
- agentpool_toolsets/vfs_toolset.py +124 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"""Parallel, unordered group of agents / nodes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from time import perf_counter
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
from uuid import uuid4
|
|
9
|
+
|
|
10
|
+
from anyenv.async_run import as_generated
|
|
11
|
+
import anyio
|
|
12
|
+
from toprompt import to_prompt
|
|
13
|
+
|
|
14
|
+
from agentpool.common_types import SupportsRunStream
|
|
15
|
+
from agentpool.delegation.base_team import BaseTeam
|
|
16
|
+
from agentpool.log import get_logger
|
|
17
|
+
from agentpool.messaging import AgentResponse, ChatMessage, TeamResponse
|
|
18
|
+
from agentpool.messaging.processing import finalize_message, prepare_prompts
|
|
19
|
+
from agentpool.utils.now import get_now
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from collections.abc import AsyncIterator
|
|
26
|
+
|
|
27
|
+
from toprompt import AnyPromptType
|
|
28
|
+
|
|
29
|
+
from agentpool import MessageNode
|
|
30
|
+
from agentpool.agents.events import RichAgentStreamEvent
|
|
31
|
+
from agentpool.common_types import PromptCompatible
|
|
32
|
+
from agentpool.talk import Talk
|
|
33
|
+
from agentpool_config.task import Job
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def normalize_stream_for_teams(
|
|
37
|
+
node: MessageNode[Any, Any],
|
|
38
|
+
*args: Any,
|
|
39
|
+
**kwargs: Any,
|
|
40
|
+
) -> AsyncIterator[tuple[MessageNode[Any, Any], RichAgentStreamEvent[Any]]]:
|
|
41
|
+
"""Normalize any streaming node to yield (node, event) tuples for team composition.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
node: The streaming node (Agent, Team, etc.)
|
|
45
|
+
*args: Arguments to pass to run_stream
|
|
46
|
+
**kwargs: Keyword arguments to pass to run_stream
|
|
47
|
+
|
|
48
|
+
Yields:
|
|
49
|
+
Tuples of (node, event) where node is the MessageNode instance
|
|
50
|
+
and event is the streaming event from that node.
|
|
51
|
+
"""
|
|
52
|
+
if not isinstance(node, SupportsRunStream):
|
|
53
|
+
msg = f"Node {node.name} does not support streaming"
|
|
54
|
+
raise TypeError(msg)
|
|
55
|
+
|
|
56
|
+
stream = node.run_stream(*args, **kwargs)
|
|
57
|
+
async for item in stream:
|
|
58
|
+
if isinstance(item, tuple):
|
|
59
|
+
# Already normalized (from Team or other composite node)
|
|
60
|
+
yield item
|
|
61
|
+
else:
|
|
62
|
+
# Raw event (from Agent) - wrap it with the source node
|
|
63
|
+
yield (node, item)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
67
|
+
"""Group of agents that can execute together."""
|
|
68
|
+
|
|
69
|
+
async def execute(self, *prompts: PromptCompatible | None, **kwargs: Any) -> TeamResponse:
|
|
70
|
+
"""Run all agents in parallel with monitoring."""
|
|
71
|
+
from agentpool.talk.talk import Talk
|
|
72
|
+
|
|
73
|
+
self._team_talk.clear()
|
|
74
|
+
start_time = get_now()
|
|
75
|
+
responses: list[AgentResponse[Any]] = []
|
|
76
|
+
errors: dict[str, Exception] = {}
|
|
77
|
+
final_prompt = list(prompts)
|
|
78
|
+
if self.shared_prompt:
|
|
79
|
+
final_prompt.insert(0, self.shared_prompt)
|
|
80
|
+
combined_prompt = "\n".join([await to_prompt(p) for p in final_prompt])
|
|
81
|
+
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
82
|
+
# Create Talk connections for monitoring this execution
|
|
83
|
+
execution_talks: list[Talk[Any]] = []
|
|
84
|
+
for node in all_nodes:
|
|
85
|
+
# No actual forwarding, just for tracking
|
|
86
|
+
talk = Talk[Any](node, [], connection_type="run", queued=True, queue_strategy="latest")
|
|
87
|
+
execution_talks.append(talk)
|
|
88
|
+
self._team_talk.append(talk) # Add to base class's TeamTalk
|
|
89
|
+
|
|
90
|
+
async def _run(node: MessageNode[TDeps, Any]) -> None:
|
|
91
|
+
try:
|
|
92
|
+
start = perf_counter()
|
|
93
|
+
message = await node.run(*final_prompt, **kwargs)
|
|
94
|
+
timing = perf_counter() - start
|
|
95
|
+
r = AgentResponse(agent_name=node.name, message=message, timing=timing)
|
|
96
|
+
responses.append(r)
|
|
97
|
+
# Update talk stats for this agent
|
|
98
|
+
talk = next(t for t in execution_talks if t.source == node)
|
|
99
|
+
talk._stats.messages.append(message)
|
|
100
|
+
except Exception as e: # noqa: BLE001
|
|
101
|
+
errors[node.name] = e
|
|
102
|
+
|
|
103
|
+
# Run all agents in parallel
|
|
104
|
+
await asyncio.gather(*[_run(node) for node in all_nodes])
|
|
105
|
+
return TeamResponse(responses=responses, start_time=start_time, errors=errors)
|
|
106
|
+
|
|
107
|
+
def __prompt__(self) -> str:
|
|
108
|
+
"""Format team info for prompts."""
|
|
109
|
+
members = ", ".join(a.name for a in self.nodes)
|
|
110
|
+
desc = f" - {self.description}" if self.description else ""
|
|
111
|
+
return f"Parallel Team {self.name!r}{desc}\nMembers: {members}"
|
|
112
|
+
|
|
113
|
+
async def run_iter(
|
|
114
|
+
self,
|
|
115
|
+
*prompts: AnyPromptType,
|
|
116
|
+
**kwargs: Any,
|
|
117
|
+
) -> AsyncIterator[ChatMessage[Any]]:
|
|
118
|
+
"""Yield messages as they arrive from parallel execution."""
|
|
119
|
+
queue: asyncio.Queue[ChatMessage[Any] | None] = asyncio.Queue()
|
|
120
|
+
failures: dict[str, Exception] = {}
|
|
121
|
+
|
|
122
|
+
async def _run(node: MessageNode[TDeps, Any]) -> None:
|
|
123
|
+
try:
|
|
124
|
+
message = await node.run(*prompts, **kwargs)
|
|
125
|
+
await queue.put(message)
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.exception("Error executing node", name=node.name)
|
|
128
|
+
failures[node.name] = e
|
|
129
|
+
# Put None to maintain queue count
|
|
130
|
+
await queue.put(None)
|
|
131
|
+
|
|
132
|
+
# Get nodes to run
|
|
133
|
+
combined_prompt = "\n".join([await to_prompt(p) for p in prompts])
|
|
134
|
+
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
135
|
+
|
|
136
|
+
# Start all agents
|
|
137
|
+
tasks = [asyncio.create_task(_run(n), name=f"run_{n.name}") for n in all_nodes]
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
# Yield messages as they arrive
|
|
141
|
+
for _ in all_nodes:
|
|
142
|
+
if msg := await queue.get():
|
|
143
|
+
yield msg
|
|
144
|
+
|
|
145
|
+
# If any failures occurred, raise error with details
|
|
146
|
+
if failures:
|
|
147
|
+
error_details = "\n".join(f"- {name}: {error}" for name, error in failures.items())
|
|
148
|
+
error_msg = f"Some nodes failed to execute:\n{error_details}"
|
|
149
|
+
raise RuntimeError(error_msg)
|
|
150
|
+
|
|
151
|
+
finally:
|
|
152
|
+
# Clean up any remaining tasks
|
|
153
|
+
for task in tasks:
|
|
154
|
+
if not task.done():
|
|
155
|
+
task.cancel()
|
|
156
|
+
|
|
157
|
+
async def run(
|
|
158
|
+
self,
|
|
159
|
+
*prompts: PromptCompatible | None,
|
|
160
|
+
wait_for_connections: bool | None = None,
|
|
161
|
+
store_history: bool = False,
|
|
162
|
+
**kwargs: Any,
|
|
163
|
+
) -> ChatMessage[list[Any]]:
|
|
164
|
+
"""Run all agents in parallel and return combined message."""
|
|
165
|
+
# Prepare prompts and create user message
|
|
166
|
+
user_msg, processed_prompts, original_message = await prepare_prompts(*prompts)
|
|
167
|
+
self.message_received.emit(user_msg)
|
|
168
|
+
|
|
169
|
+
# Execute team logic
|
|
170
|
+
result = await self.execute(*processed_prompts, **kwargs)
|
|
171
|
+
message_id = str(uuid4()) # Always generate unique response ID
|
|
172
|
+
message = ChatMessage(
|
|
173
|
+
content=[r.message.content for r in result if r.message],
|
|
174
|
+
messages=[m for r in result if r.message for m in r.message.messages],
|
|
175
|
+
role="assistant",
|
|
176
|
+
name=self.name,
|
|
177
|
+
message_id=message_id,
|
|
178
|
+
conversation_id=user_msg.conversation_id,
|
|
179
|
+
metadata={
|
|
180
|
+
"agent_names": [r.agent_name for r in result],
|
|
181
|
+
"errors": {name: str(error) for name, error in result.errors.items()},
|
|
182
|
+
"start_time": result.start_time.isoformat(),
|
|
183
|
+
},
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Teams typically don't store history by default, but allow it
|
|
187
|
+
if store_history:
|
|
188
|
+
# Teams could implement their own history management here if needed
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
# Finalize and route message
|
|
192
|
+
return await finalize_message(
|
|
193
|
+
message,
|
|
194
|
+
user_msg,
|
|
195
|
+
self,
|
|
196
|
+
self.connections,
|
|
197
|
+
original_message,
|
|
198
|
+
wait_for_connections,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
async def run_stream(
|
|
202
|
+
self,
|
|
203
|
+
*prompts: PromptCompatible,
|
|
204
|
+
**kwargs: Any,
|
|
205
|
+
) -> AsyncIterator[tuple[MessageNode[Any, Any], RichAgentStreamEvent[Any]]]:
|
|
206
|
+
"""Stream responses from all team members in parallel.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
prompts: Input prompts to process in parallel
|
|
210
|
+
kwargs: Additional arguments passed to each agent
|
|
211
|
+
|
|
212
|
+
Yields:
|
|
213
|
+
Tuples of (agent, event) where agent is the Agent instance
|
|
214
|
+
and event is the streaming event from that agent.
|
|
215
|
+
"""
|
|
216
|
+
# Get nodes to run
|
|
217
|
+
combined_prompt = "\n".join([await to_prompt(p) for p in prompts])
|
|
218
|
+
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
219
|
+
|
|
220
|
+
# Create list of streams that yield (agent, event) tuples
|
|
221
|
+
agent_streams = [
|
|
222
|
+
normalize_stream_for_teams(agent, *prompts, **kwargs)
|
|
223
|
+
for agent in all_nodes
|
|
224
|
+
if isinstance(agent, SupportsRunStream)
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
# Merge all agent streams
|
|
228
|
+
async for agent_event_tuple in as_generated(agent_streams):
|
|
229
|
+
yield agent_event_tuple
|
|
230
|
+
|
|
231
|
+
async def run_job[TJobResult](
|
|
232
|
+
self,
|
|
233
|
+
job: Job[TDeps, TJobResult],
|
|
234
|
+
*,
|
|
235
|
+
store_history: bool = True,
|
|
236
|
+
include_agent_tools: bool = True,
|
|
237
|
+
) -> list[AgentResponse[TJobResult]]:
|
|
238
|
+
"""Execute a job across all team members in parallel.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
job: Job configuration to execute
|
|
242
|
+
store_history: Whether to add job execution to conversation history
|
|
243
|
+
include_agent_tools: Whether to include agent's tools alongside job tools
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
List of responses from all agents
|
|
247
|
+
|
|
248
|
+
Raises:
|
|
249
|
+
JobError: If job execution fails for any agent
|
|
250
|
+
ValueError: If job configuration is invalid
|
|
251
|
+
"""
|
|
252
|
+
from agentpool import Agent
|
|
253
|
+
from agentpool.tasks import JobError
|
|
254
|
+
|
|
255
|
+
responses: list[AgentResponse[TJobResult]] = []
|
|
256
|
+
errors: dict[str, Exception] = {}
|
|
257
|
+
start_time = get_now()
|
|
258
|
+
|
|
259
|
+
# Validate dependencies for all agents
|
|
260
|
+
if job.required_dependency is not None:
|
|
261
|
+
invalid_agents = [
|
|
262
|
+
agent.name
|
|
263
|
+
for agent in self.iter_agents()
|
|
264
|
+
if agent.deps_type is None
|
|
265
|
+
or not issubclass(agent.deps_type, job.required_dependency)
|
|
266
|
+
]
|
|
267
|
+
if invalid_agents:
|
|
268
|
+
msg = (
|
|
269
|
+
f"Agents {', '.join(invalid_agents)} don't have required "
|
|
270
|
+
f"dependency type: {job.required_dependency}"
|
|
271
|
+
)
|
|
272
|
+
raise JobError(msg)
|
|
273
|
+
|
|
274
|
+
try:
|
|
275
|
+
# Load knowledge for all agents if provided
|
|
276
|
+
if job.knowledge:
|
|
277
|
+
# TODO: resources
|
|
278
|
+
tools = [t.name for t in job.get_tools()]
|
|
279
|
+
await self.distribute(content="", tools=tools)
|
|
280
|
+
|
|
281
|
+
prompt = await job.get_prompt()
|
|
282
|
+
|
|
283
|
+
async def _run(agent: MessageNode[TDeps, TJobResult]) -> None:
|
|
284
|
+
assert isinstance(agent, Agent)
|
|
285
|
+
try:
|
|
286
|
+
async with agent.tools.temporary_tools(
|
|
287
|
+
job.get_tools(), exclusive=not include_agent_tools
|
|
288
|
+
):
|
|
289
|
+
start = perf_counter()
|
|
290
|
+
resp = AgentResponse(
|
|
291
|
+
agent_name=agent.name,
|
|
292
|
+
message=await agent.run(prompt, store_history=store_history),
|
|
293
|
+
timing=perf_counter() - start,
|
|
294
|
+
)
|
|
295
|
+
responses.append(resp)
|
|
296
|
+
except Exception as e: # noqa: BLE001
|
|
297
|
+
errors[agent.name] = e
|
|
298
|
+
|
|
299
|
+
# Run job in parallel on all agents
|
|
300
|
+
await asyncio.gather(*[_run(node) for node in self.nodes])
|
|
301
|
+
return TeamResponse(responses=responses, start_time=start_time, errors=errors)
|
|
302
|
+
|
|
303
|
+
except Exception as e:
|
|
304
|
+
msg = "Job execution failed"
|
|
305
|
+
logger.exception(msg)
|
|
306
|
+
raise JobError(msg) from e
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
if __name__ == "__main__":
|
|
310
|
+
|
|
311
|
+
async def main() -> None:
|
|
312
|
+
from agentpool import Agent, TeamRun
|
|
313
|
+
|
|
314
|
+
agent_a = Agent(name="A", model="test")
|
|
315
|
+
agent_b = Agent(name="B", model="test")
|
|
316
|
+
agent_c = Agent(name="C", model="test")
|
|
317
|
+
# Test Team containing TeamRun (parallel containing sequential)
|
|
318
|
+
inner_run = TeamRun([agent_a, agent_b], name="Sequential")
|
|
319
|
+
outer_team = Team([inner_run, agent_c], name="Parallel")
|
|
320
|
+
|
|
321
|
+
print("Testing Team containing TeamRun...")
|
|
322
|
+
async for node, event in outer_team.run_stream("test"):
|
|
323
|
+
print(f"{node.name}: {type(event).__name__}")
|
|
324
|
+
|
|
325
|
+
anyio.run(main)
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"""Sequential, ordered group of agents / nodes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from itertools import pairwise
|
|
7
|
+
from time import perf_counter
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Literal, overload
|
|
9
|
+
from uuid import uuid4
|
|
10
|
+
|
|
11
|
+
import anyio
|
|
12
|
+
from pydantic_ai import PartDeltaEvent, TextPartDelta
|
|
13
|
+
|
|
14
|
+
from agentpool.common_types import SupportsRunStream
|
|
15
|
+
from agentpool.delegation.base_team import BaseTeam
|
|
16
|
+
from agentpool.delegation.team import normalize_stream_for_teams
|
|
17
|
+
from agentpool.log import get_logger
|
|
18
|
+
from agentpool.messaging import AgentResponse, ChatMessage, TeamResponse
|
|
19
|
+
from agentpool.messaging.processing import finalize_message, prepare_prompts
|
|
20
|
+
from agentpool.talk.talk import Talk, TeamTalk
|
|
21
|
+
from agentpool.utils.now import get_now
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from collections.abc import AsyncIterator, Sequence
|
|
26
|
+
from datetime import datetime
|
|
27
|
+
|
|
28
|
+
from agentpool import MessageNode
|
|
29
|
+
from agentpool.agents.events import RichAgentStreamEvent
|
|
30
|
+
from agentpool.common_types import PromptCompatible, SupportsStructuredOutput
|
|
31
|
+
from agentpool.delegation import AgentPool
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
logger = get_logger(__name__)
|
|
35
|
+
|
|
36
|
+
ResultMode = Literal["last", "concat"]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True, kw_only=True)
|
|
40
|
+
class ExtendedTeamTalk(TeamTalk):
|
|
41
|
+
"""TeamTalk that also provides TeamRunStats interface."""
|
|
42
|
+
|
|
43
|
+
errors: list[tuple[str, str, datetime]] = field(default_factory=list)
|
|
44
|
+
|
|
45
|
+
def clear(self) -> None:
|
|
46
|
+
"""Reset all tracking data."""
|
|
47
|
+
super().clear() # Clear base TeamTalk
|
|
48
|
+
self.errors.clear()
|
|
49
|
+
|
|
50
|
+
def add_error(self, agent: str, error: str) -> None:
|
|
51
|
+
"""Track errors from AgentResponses."""
|
|
52
|
+
self.errors.append((agent, error, get_now()))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
56
|
+
"""Handles team operations with monitoring."""
|
|
57
|
+
|
|
58
|
+
@overload # validator set: it defines the output
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
agents: Sequence[MessageNode[TDeps, Any]],
|
|
62
|
+
*,
|
|
63
|
+
name: str | None = None,
|
|
64
|
+
description: str | None = None,
|
|
65
|
+
display_name: str | None = None,
|
|
66
|
+
shared_prompt: str | None = None,
|
|
67
|
+
validator: MessageNode[Any, TResult],
|
|
68
|
+
picker: SupportsStructuredOutput | None = None,
|
|
69
|
+
num_picks: int | None = None,
|
|
70
|
+
pick_prompt: str | None = None,
|
|
71
|
+
agent_pool: AgentPool | None = None,
|
|
72
|
+
) -> None: ...
|
|
73
|
+
|
|
74
|
+
@overload
|
|
75
|
+
def __init__( # no validator, but all nodes same output type.
|
|
76
|
+
self,
|
|
77
|
+
agents: Sequence[MessageNode[TDeps, TResult]],
|
|
78
|
+
*,
|
|
79
|
+
name: str | None = None,
|
|
80
|
+
description: str | None = None,
|
|
81
|
+
display_name: str | None = None,
|
|
82
|
+
shared_prompt: str | None = None,
|
|
83
|
+
validator: None = None,
|
|
84
|
+
picker: SupportsStructuredOutput | None = None,
|
|
85
|
+
num_picks: int | None = None,
|
|
86
|
+
pick_prompt: str | None = None,
|
|
87
|
+
agent_pool: AgentPool | None = None,
|
|
88
|
+
) -> None: ...
|
|
89
|
+
|
|
90
|
+
@overload
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
agents: Sequence[MessageNode[TDeps, Any]],
|
|
94
|
+
*,
|
|
95
|
+
name: str | None = None,
|
|
96
|
+
description: str | None = None,
|
|
97
|
+
display_name: str | None = None,
|
|
98
|
+
shared_prompt: str | None = None,
|
|
99
|
+
validator: MessageNode[Any, TResult] | None = None,
|
|
100
|
+
picker: SupportsStructuredOutput | None = None,
|
|
101
|
+
num_picks: int | None = None,
|
|
102
|
+
pick_prompt: str | None = None,
|
|
103
|
+
agent_pool: AgentPool | None = None,
|
|
104
|
+
) -> None: ...
|
|
105
|
+
|
|
106
|
+
def __init__(
|
|
107
|
+
self,
|
|
108
|
+
agents: Sequence[MessageNode[TDeps, Any]],
|
|
109
|
+
*,
|
|
110
|
+
name: str | None = None,
|
|
111
|
+
description: str | None = None,
|
|
112
|
+
display_name: str | None = None,
|
|
113
|
+
shared_prompt: str | None = None,
|
|
114
|
+
validator: MessageNode[Any, TResult] | None = None,
|
|
115
|
+
picker: SupportsStructuredOutput | None = None,
|
|
116
|
+
num_picks: int | None = None,
|
|
117
|
+
pick_prompt: str | None = None,
|
|
118
|
+
agent_pool: AgentPool | None = None,
|
|
119
|
+
# result_mode: ResultMode = "last",
|
|
120
|
+
) -> None:
|
|
121
|
+
super().__init__(
|
|
122
|
+
agents,
|
|
123
|
+
name=name,
|
|
124
|
+
description=description,
|
|
125
|
+
display_name=display_name,
|
|
126
|
+
shared_prompt=shared_prompt,
|
|
127
|
+
picker=picker,
|
|
128
|
+
num_picks=num_picks,
|
|
129
|
+
pick_prompt=pick_prompt,
|
|
130
|
+
agent_pool=agent_pool,
|
|
131
|
+
)
|
|
132
|
+
self.validator = validator
|
|
133
|
+
self.result_mode = "last"
|
|
134
|
+
|
|
135
|
+
def __prompt__(self) -> str:
|
|
136
|
+
"""Format team info for prompts."""
|
|
137
|
+
members = " -> ".join(a.name for a in self.nodes)
|
|
138
|
+
desc = f" - {self.description}" if self.description else ""
|
|
139
|
+
return f"Sequential Team {self.name!r}{desc}\nPipeline: {members}"
|
|
140
|
+
|
|
141
|
+
async def run(
|
|
142
|
+
self,
|
|
143
|
+
*prompts: PromptCompatible | None,
|
|
144
|
+
wait_for_connections: bool | None = None,
|
|
145
|
+
store_history: bool = False,
|
|
146
|
+
**kwargs: Any,
|
|
147
|
+
) -> ChatMessage[TResult]:
|
|
148
|
+
"""Run agents sequentially and return combined message."""
|
|
149
|
+
# Prepare prompts and create user message
|
|
150
|
+
user_msg, processed_prompts, original_message = await prepare_prompts(*prompts)
|
|
151
|
+
self.message_received.emit(user_msg)
|
|
152
|
+
# Execute sequential logic
|
|
153
|
+
message_id = str(uuid4()) # Always generate unique response ID
|
|
154
|
+
result = await self.execute(*processed_prompts, **kwargs)
|
|
155
|
+
all_messages = [r.message for r in result if r.message]
|
|
156
|
+
assert all_messages, "Error during execution, returned None for TeamRun"
|
|
157
|
+
# Determine content based on mode
|
|
158
|
+
match self.result_mode:
|
|
159
|
+
case "last":
|
|
160
|
+
content = all_messages[-1].content
|
|
161
|
+
# case "concat":
|
|
162
|
+
# content = "\n".join(msg.format() for msg in all_messages)
|
|
163
|
+
case _:
|
|
164
|
+
msg = f"Invalid result mode: {self.result_mode}"
|
|
165
|
+
raise ValueError(msg)
|
|
166
|
+
|
|
167
|
+
message = ChatMessage(
|
|
168
|
+
content=content,
|
|
169
|
+
messages=[m for chat_message in all_messages for m in chat_message.messages],
|
|
170
|
+
role="assistant",
|
|
171
|
+
name=self.name,
|
|
172
|
+
associated_messages=all_messages,
|
|
173
|
+
message_id=message_id,
|
|
174
|
+
conversation_id=user_msg.conversation_id,
|
|
175
|
+
metadata={
|
|
176
|
+
"execution_order": [r.agent_name for r in result],
|
|
177
|
+
"start_time": result.start_time.isoformat(),
|
|
178
|
+
"errors": {name: str(error) for name, error in result.errors.items()},
|
|
179
|
+
},
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
if store_history:
|
|
183
|
+
pass # Teams could implement their own history management here if needed
|
|
184
|
+
return await finalize_message( # Finalize and route message
|
|
185
|
+
message,
|
|
186
|
+
user_msg,
|
|
187
|
+
self,
|
|
188
|
+
self.connections,
|
|
189
|
+
original_message,
|
|
190
|
+
wait_for_connections,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
async def execute(
|
|
194
|
+
self,
|
|
195
|
+
*prompts: PromptCompatible | None,
|
|
196
|
+
**kwargs: Any,
|
|
197
|
+
) -> TeamResponse[TResult]:
|
|
198
|
+
"""Start execution with optional monitoring."""
|
|
199
|
+
self._team_talk.clear()
|
|
200
|
+
start_time = get_now()
|
|
201
|
+
prompts_ = list(prompts)
|
|
202
|
+
if self.shared_prompt:
|
|
203
|
+
prompts_.insert(0, self.shared_prompt)
|
|
204
|
+
responses = [i async for i in self.execute_iter(*prompts_) if isinstance(i, AgentResponse)]
|
|
205
|
+
return TeamResponse(responses, start_time)
|
|
206
|
+
|
|
207
|
+
async def run_iter(
|
|
208
|
+
self,
|
|
209
|
+
*prompts: PromptCompatible,
|
|
210
|
+
**kwargs: Any,
|
|
211
|
+
) -> AsyncIterator[ChatMessage[Any]]:
|
|
212
|
+
"""Yield messages from the execution chain."""
|
|
213
|
+
async for item in self.execute_iter(*prompts, **kwargs):
|
|
214
|
+
match item:
|
|
215
|
+
case AgentResponse():
|
|
216
|
+
if item.message:
|
|
217
|
+
yield item.message
|
|
218
|
+
case Talk():
|
|
219
|
+
pass
|
|
220
|
+
|
|
221
|
+
async def execute_iter(
|
|
222
|
+
self,
|
|
223
|
+
*prompt: PromptCompatible,
|
|
224
|
+
**kwargs: Any,
|
|
225
|
+
) -> AsyncIterator[Talk[Any] | AgentResponse[Any]]:
|
|
226
|
+
from toprompt import to_prompt
|
|
227
|
+
|
|
228
|
+
connections: list[Talk[Any]] = []
|
|
229
|
+
try:
|
|
230
|
+
combined_prompt = "\n".join([await to_prompt(p) for p in prompt])
|
|
231
|
+
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
232
|
+
if self.validator:
|
|
233
|
+
all_nodes.append(self.validator)
|
|
234
|
+
first = all_nodes[0]
|
|
235
|
+
connections = [s.connect_to(t, queued=True) for s, t in pairwise(all_nodes)]
|
|
236
|
+
for conn in connections:
|
|
237
|
+
self._team_talk.append(conn)
|
|
238
|
+
|
|
239
|
+
# First agent
|
|
240
|
+
start = perf_counter()
|
|
241
|
+
message = await first.run(*prompt, **kwargs)
|
|
242
|
+
timing = perf_counter() - start
|
|
243
|
+
response = AgentResponse[Any](first.name, message=message, timing=timing)
|
|
244
|
+
yield response
|
|
245
|
+
|
|
246
|
+
# Process through chain
|
|
247
|
+
for connection in connections:
|
|
248
|
+
target = connection.targets[0]
|
|
249
|
+
target_name = target.name
|
|
250
|
+
yield connection
|
|
251
|
+
|
|
252
|
+
# Let errors propagate - they break the chain
|
|
253
|
+
start = perf_counter()
|
|
254
|
+
messages = await connection.trigger()
|
|
255
|
+
|
|
256
|
+
if target == all_nodes[-1]:
|
|
257
|
+
last_talk = Talk[Any](target, [], connection_type="run")
|
|
258
|
+
if response.message:
|
|
259
|
+
last_talk.stats.messages.append(response.message)
|
|
260
|
+
self._team_talk.append(last_talk)
|
|
261
|
+
|
|
262
|
+
timing = perf_counter() - start
|
|
263
|
+
msg = messages[0]
|
|
264
|
+
response = AgentResponse[Any](target_name, message=msg, timing=timing)
|
|
265
|
+
yield response
|
|
266
|
+
|
|
267
|
+
finally: # Always clean up connections
|
|
268
|
+
for connection in connections:
|
|
269
|
+
connection.disconnect()
|
|
270
|
+
|
|
271
|
+
async def run_stream(
|
|
272
|
+
self,
|
|
273
|
+
*prompts: PromptCompatible,
|
|
274
|
+
require_all: bool = True,
|
|
275
|
+
**kwargs: Any,
|
|
276
|
+
) -> AsyncIterator[tuple[MessageNode[Any, Any], RichAgentStreamEvent[Any]]]:
|
|
277
|
+
"""Stream responses through the chain of team members.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
prompts: Input prompts to process through the chain
|
|
281
|
+
require_all: If True, fail if any agent fails. If False,
|
|
282
|
+
continue with remaining agents.
|
|
283
|
+
kwargs: Additional arguments passed to each agent
|
|
284
|
+
|
|
285
|
+
Yields:
|
|
286
|
+
Tuples of (agent, event) where agent is the Agent instance
|
|
287
|
+
and event is the streaming event.
|
|
288
|
+
"""
|
|
289
|
+
from agentpool.agents.events import StreamCompleteEvent
|
|
290
|
+
|
|
291
|
+
current_message = prompts
|
|
292
|
+
collected_content = []
|
|
293
|
+
for agent in self.nodes:
|
|
294
|
+
try:
|
|
295
|
+
agent_content = []
|
|
296
|
+
|
|
297
|
+
# Use wrapper to normalize all streaming nodes to (agent, event) tuples
|
|
298
|
+
if not isinstance(agent, SupportsRunStream):
|
|
299
|
+
msg = f"Agent {agent.name} does not support streaming"
|
|
300
|
+
raise TypeError(msg) # noqa: TRY301
|
|
301
|
+
|
|
302
|
+
stream = normalize_stream_for_teams(agent, *current_message, **kwargs)
|
|
303
|
+
|
|
304
|
+
async for agent_event_tuple in stream:
|
|
305
|
+
actual_agent, event = agent_event_tuple
|
|
306
|
+
match event:
|
|
307
|
+
case PartDeltaEvent(delta=TextPartDelta(content_delta=delta)):
|
|
308
|
+
agent_content.append(delta)
|
|
309
|
+
collected_content.append(delta)
|
|
310
|
+
yield (actual_agent, event) # Yield tuple with agent context
|
|
311
|
+
case StreamCompleteEvent(message=message):
|
|
312
|
+
# Use complete response as input for next agent
|
|
313
|
+
current_message = (message.content,)
|
|
314
|
+
yield (actual_agent, event) # Yield tuple with agent context
|
|
315
|
+
case _:
|
|
316
|
+
yield (actual_agent, event) # Yield tuple with agent context
|
|
317
|
+
|
|
318
|
+
except Exception as e:
|
|
319
|
+
if require_all:
|
|
320
|
+
msg = f"Chain broken at {agent.name}: {e}"
|
|
321
|
+
logger.exception(msg)
|
|
322
|
+
raise ValueError(msg) from e
|
|
323
|
+
logger.warning("Chain handler failed", name=agent.name, error=e)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
if __name__ == "__main__":
|
|
327
|
+
|
|
328
|
+
async def main() -> None:
|
|
329
|
+
from agentpool import Agent, Team
|
|
330
|
+
|
|
331
|
+
agent1 = Agent(name="Agent1", model="test")
|
|
332
|
+
agent2 = Agent(name="Agent2", model="test")
|
|
333
|
+
agent3 = Agent(name="Agent3", model="test")
|
|
334
|
+
inner_team = Team([agent1, agent2], name="Parallel")
|
|
335
|
+
outer_run = TeamRun([inner_team, agent3], name="Sequential")
|
|
336
|
+
print("Testing TeamRun containing Team...")
|
|
337
|
+
try:
|
|
338
|
+
async for node, event in outer_run.run_stream("test"):
|
|
339
|
+
print(f"{node.name}: {type(event).__name__}")
|
|
340
|
+
except Exception as e: # noqa: BLE001
|
|
341
|
+
print(f"Error: {e}")
|
|
342
|
+
|
|
343
|
+
anyio.run(main)
|