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,1129 @@
|
|
|
1
|
+
"""Agent pool management for collaboration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from asyncio import Lock
|
|
7
|
+
from contextlib import AsyncExitStack, asynccontextmanager, suppress
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING, Any, Literal, Self, Unpack, overload
|
|
11
|
+
|
|
12
|
+
from anyenv import ProcessManager
|
|
13
|
+
import anyio
|
|
14
|
+
from llmling_models.configs.model_configs import BaseModelConfig
|
|
15
|
+
from upathtools import UPath
|
|
16
|
+
|
|
17
|
+
from agentpool.agents import Agent
|
|
18
|
+
from agentpool.common_types import NodeName
|
|
19
|
+
from agentpool.delegation.message_flow_tracker import MessageFlowTracker
|
|
20
|
+
from agentpool.delegation.team import Team
|
|
21
|
+
from agentpool.delegation.teamrun import TeamRun
|
|
22
|
+
from agentpool.log import get_logger
|
|
23
|
+
from agentpool.messaging import MessageNode
|
|
24
|
+
from agentpool.talk import TeamTalk
|
|
25
|
+
from agentpool.talk.registry import ConnectionRegistry
|
|
26
|
+
from agentpool.tasks import TaskRegistry
|
|
27
|
+
from agentpool.utils.baseregistry import BaseRegistry
|
|
28
|
+
from agentpool_config.forward_targets import (
|
|
29
|
+
CallableConnectionConfig,
|
|
30
|
+
FileConnectionConfig,
|
|
31
|
+
NodeConnectionConfig,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from collections.abc import AsyncIterator, Sequence
|
|
37
|
+
from contextlib import AbstractAsyncContextManager
|
|
38
|
+
from types import TracebackType
|
|
39
|
+
|
|
40
|
+
from pydantic_ai import ModelSettings
|
|
41
|
+
from pydantic_ai.models import Model
|
|
42
|
+
from pydantic_ai.output import OutputSpec
|
|
43
|
+
from tokonomics.model_names import ModelId
|
|
44
|
+
from upathtools import JoinablePathLike
|
|
45
|
+
|
|
46
|
+
from agentpool.agents.acp_agent import ACPAgent
|
|
47
|
+
from agentpool.agents.agent import AgentKwargs
|
|
48
|
+
from agentpool.agents.agui_agent import AGUIAgent
|
|
49
|
+
from agentpool.agents.base_agent import BaseAgent
|
|
50
|
+
from agentpool.agents.claude_code_agent import ClaudeCodeAgent
|
|
51
|
+
from agentpool.common_types import (
|
|
52
|
+
AgentName,
|
|
53
|
+
BuiltinEventHandlerType,
|
|
54
|
+
IndividualEventHandler,
|
|
55
|
+
SessionIdType,
|
|
56
|
+
SupportsStructuredOutput,
|
|
57
|
+
)
|
|
58
|
+
from agentpool.delegation.base_team import BaseTeam
|
|
59
|
+
from agentpool.mcp_server.tool_bridge import ToolManagerBridge
|
|
60
|
+
from agentpool.models import (
|
|
61
|
+
AGUIAgentConfig,
|
|
62
|
+
AnyAgentConfig,
|
|
63
|
+
BaseACPAgentConfig,
|
|
64
|
+
ClaudeCodeAgentConfig,
|
|
65
|
+
)
|
|
66
|
+
from agentpool.models.manifest import AgentsManifest
|
|
67
|
+
from agentpool.ui.base import InputProvider
|
|
68
|
+
from agentpool_config.session import SessionQuery
|
|
69
|
+
from agentpool_config.task import Job
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
logger = get_logger(__name__)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class AgentPool[TPoolDeps = None](BaseRegistry[NodeName, MessageNode[Any, Any]]):
|
|
76
|
+
"""Pool managing message processing nodes (agents and teams).
|
|
77
|
+
|
|
78
|
+
Acts as a unified registry for all nodes, providing:
|
|
79
|
+
- Centralized node management and lookup
|
|
80
|
+
- Shared dependency injection
|
|
81
|
+
- Connection management
|
|
82
|
+
- Resource coordination
|
|
83
|
+
|
|
84
|
+
Nodes can be accessed through:
|
|
85
|
+
- nodes: All registered nodes (agents and teams)
|
|
86
|
+
- agents: Only Agent instances
|
|
87
|
+
- teams: Only Team instances
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(
|
|
91
|
+
self,
|
|
92
|
+
manifest: JoinablePathLike | AgentsManifest | None = None,
|
|
93
|
+
*,
|
|
94
|
+
shared_deps_type: type[TPoolDeps] | None = None,
|
|
95
|
+
connect_nodes: bool = True,
|
|
96
|
+
input_provider: InputProvider | None = None,
|
|
97
|
+
parallel_load: bool = True,
|
|
98
|
+
event_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] | None = None,
|
|
99
|
+
):
|
|
100
|
+
"""Initialize agent pool with immediate agent creation.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
manifest: Agent configuration manifest
|
|
104
|
+
shared_deps_type: Dependencies to share across all nodes
|
|
105
|
+
connect_nodes: Whether to set up forwarding connections
|
|
106
|
+
input_provider: Input provider for tool / step confirmations / HumanAgents
|
|
107
|
+
parallel_load: Whether to load nodes in parallel (async)
|
|
108
|
+
event_handlers: Event handlers to pass through to all agents
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
ValueError: If manifest contains invalid node configurations
|
|
112
|
+
RuntimeError: If node initialization fails
|
|
113
|
+
"""
|
|
114
|
+
super().__init__()
|
|
115
|
+
from agentpool.mcp_server.manager import MCPManager
|
|
116
|
+
from agentpool.models.manifest import AgentsManifest
|
|
117
|
+
from agentpool.observability import registry
|
|
118
|
+
from agentpool.sessions import SessionManager
|
|
119
|
+
from agentpool.skills.manager import SkillsManager
|
|
120
|
+
from agentpool.storage import StorageManager
|
|
121
|
+
|
|
122
|
+
match manifest:
|
|
123
|
+
case None:
|
|
124
|
+
self.manifest = AgentsManifest()
|
|
125
|
+
case str() | os.PathLike() | UPath():
|
|
126
|
+
self.manifest = AgentsManifest.from_file(manifest)
|
|
127
|
+
case AgentsManifest():
|
|
128
|
+
self.manifest = manifest
|
|
129
|
+
case _:
|
|
130
|
+
msg = f"Invalid config path: {manifest}"
|
|
131
|
+
raise ValueError(msg)
|
|
132
|
+
|
|
133
|
+
registry.configure_observability(self.manifest.observability)
|
|
134
|
+
self.shared_deps_type = shared_deps_type
|
|
135
|
+
self._input_provider = input_provider
|
|
136
|
+
self.exit_stack = AsyncExitStack()
|
|
137
|
+
self.parallel_load = parallel_load
|
|
138
|
+
self.storage = StorageManager(self.manifest.storage)
|
|
139
|
+
session_store = self.manifest.storage.get_session_store()
|
|
140
|
+
self.sessions = SessionManager(pool=self, store=session_store)
|
|
141
|
+
self.event_handlers = event_handlers or []
|
|
142
|
+
self.connection_registry = ConnectionRegistry()
|
|
143
|
+
servers = self.manifest.get_mcp_servers()
|
|
144
|
+
self.mcp = MCPManager(name="pool_mcp", servers=servers, owner="pool")
|
|
145
|
+
self.skills = SkillsManager(name="pool_skills", owner="pool")
|
|
146
|
+
self._tool_bridges: dict[str, ToolManagerBridge] = {}
|
|
147
|
+
self._tasks = TaskRegistry()
|
|
148
|
+
# Register tasks from manifest
|
|
149
|
+
for name, task in self.manifest.jobs.items():
|
|
150
|
+
self._tasks.register(name, task)
|
|
151
|
+
self.process_manager = ProcessManager()
|
|
152
|
+
self.pool_talk = TeamTalk[Any].from_nodes(list(self.nodes.values()))
|
|
153
|
+
|
|
154
|
+
# Create all agents from unified manifest.agents dict
|
|
155
|
+
for name, config in self.manifest.agents.items():
|
|
156
|
+
agent = self._create_agent_from_config(
|
|
157
|
+
name,
|
|
158
|
+
config,
|
|
159
|
+
deps_type=shared_deps_type,
|
|
160
|
+
)
|
|
161
|
+
agent.agent_pool = self
|
|
162
|
+
self.register(name, agent)
|
|
163
|
+
|
|
164
|
+
self._create_teams()
|
|
165
|
+
if connect_nodes:
|
|
166
|
+
self._connect_nodes()
|
|
167
|
+
|
|
168
|
+
self._enter_lock = Lock() # Initialize async safety fields
|
|
169
|
+
self._running_count = 0
|
|
170
|
+
|
|
171
|
+
async def __aenter__(self) -> Self:
|
|
172
|
+
"""Enter async context and initialize all agents."""
|
|
173
|
+
if self._running_count > 0:
|
|
174
|
+
self._running_count += 1
|
|
175
|
+
return self
|
|
176
|
+
async with self._enter_lock:
|
|
177
|
+
try:
|
|
178
|
+
# Initialize MCP manager first, then add aggregating provider
|
|
179
|
+
await self.exit_stack.enter_async_context(self.mcp)
|
|
180
|
+
await self.exit_stack.enter_async_context(self.skills)
|
|
181
|
+
aggregating_provider = self.mcp.get_aggregating_provider()
|
|
182
|
+
agents = list(self.agents.values())
|
|
183
|
+
acp_agents = list(self.acp_agents.values())
|
|
184
|
+
agui_agents = list(self.agui_agents.values())
|
|
185
|
+
claude_code_agents = list(self.claude_code_agents.values())
|
|
186
|
+
teams = list(self.teams.values())
|
|
187
|
+
for agent in agents:
|
|
188
|
+
agent.tools.add_provider(aggregating_provider)
|
|
189
|
+
# Collect remaining components to initialize (MCP already initialized)
|
|
190
|
+
components: list[AbstractAsyncContextManager[Any]] = [
|
|
191
|
+
self.storage,
|
|
192
|
+
self.sessions,
|
|
193
|
+
*agents,
|
|
194
|
+
*acp_agents,
|
|
195
|
+
*agui_agents,
|
|
196
|
+
*claude_code_agents,
|
|
197
|
+
*teams,
|
|
198
|
+
]
|
|
199
|
+
# MCP server is now managed externally - removed from pool
|
|
200
|
+
# Initialize all components
|
|
201
|
+
if self.parallel_load:
|
|
202
|
+
await asyncio.gather(
|
|
203
|
+
*(self.exit_stack.enter_async_context(c) for c in components)
|
|
204
|
+
)
|
|
205
|
+
else:
|
|
206
|
+
for component in components:
|
|
207
|
+
await self.exit_stack.enter_async_context(component)
|
|
208
|
+
|
|
209
|
+
except Exception as e:
|
|
210
|
+
await self.cleanup()
|
|
211
|
+
msg = "Failed to initialize agent pool"
|
|
212
|
+
logger.exception(msg, exc_info=e)
|
|
213
|
+
raise RuntimeError(msg) from e
|
|
214
|
+
self._running_count += 1
|
|
215
|
+
return self
|
|
216
|
+
|
|
217
|
+
async def __aexit__(
|
|
218
|
+
self,
|
|
219
|
+
exc_type: type[BaseException] | None,
|
|
220
|
+
exc_val: BaseException | None,
|
|
221
|
+
exc_tb: TracebackType | None,
|
|
222
|
+
) -> None:
|
|
223
|
+
"""Exit async context."""
|
|
224
|
+
if self._running_count == 0:
|
|
225
|
+
msg = "AgentPool.__aexit__ called more times than __aenter__"
|
|
226
|
+
raise ValueError(msg)
|
|
227
|
+
async with self._enter_lock:
|
|
228
|
+
self._running_count -= 1
|
|
229
|
+
if self._running_count == 0:
|
|
230
|
+
# Remove MCP aggregating provider from all agents
|
|
231
|
+
aggregating_provider = self.mcp.get_aggregating_provider()
|
|
232
|
+
for agent in self.agents.values():
|
|
233
|
+
agent.tools.remove_provider(aggregating_provider.name)
|
|
234
|
+
await self.cleanup()
|
|
235
|
+
|
|
236
|
+
async def create_tool_bridge(
|
|
237
|
+
self,
|
|
238
|
+
node: BaseAgent[Any, Any],
|
|
239
|
+
*,
|
|
240
|
+
name: str = "pool_tools",
|
|
241
|
+
host: str = "127.0.0.1",
|
|
242
|
+
port: int = 0,
|
|
243
|
+
transport: Literal["sse", "streamable-http"] = "sse",
|
|
244
|
+
) -> ToolManagerBridge:
|
|
245
|
+
"""Create and start a tool bridge for exposing tools to external agents.
|
|
246
|
+
|
|
247
|
+
This creates an in-process MCP server that exposes the given node's
|
|
248
|
+
tools. The returned bridge can be added to ACP agents or Claude Code
|
|
249
|
+
agents to give them access to internal toolsets.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
node: The agent node whose tools to expose
|
|
253
|
+
name: Unique name for this bridge
|
|
254
|
+
host: Host to bind the HTTP server to
|
|
255
|
+
port: Port to bind to (0 = auto-select)
|
|
256
|
+
transport: Transport protocol ('sse' or 'streamable-http')
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Started ToolManagerBridge instance
|
|
260
|
+
|
|
261
|
+
Example:
|
|
262
|
+
```python
|
|
263
|
+
async with AgentPool() as pool:
|
|
264
|
+
# Create bridge from an agent's tools
|
|
265
|
+
bridge = await pool.create_tool_bridge(
|
|
266
|
+
pool.agents["orchestrator"],
|
|
267
|
+
name="orchestrator_tools",
|
|
268
|
+
)
|
|
269
|
+
# Add to ACP agent
|
|
270
|
+
await pool.acp_agents["claude"].add_tool_bridge(bridge)
|
|
271
|
+
# Or add to Claude Code agent
|
|
272
|
+
await pool.claude_code_agents["coder"].add_tool_bridge(bridge)
|
|
273
|
+
```
|
|
274
|
+
"""
|
|
275
|
+
from agentpool.mcp_server.tool_bridge import BridgeConfig, ToolManagerBridge
|
|
276
|
+
|
|
277
|
+
if name in self._tool_bridges:
|
|
278
|
+
msg = f"Tool bridge {name!r} already exists"
|
|
279
|
+
raise ValueError(msg)
|
|
280
|
+
|
|
281
|
+
config = BridgeConfig(
|
|
282
|
+
host=host,
|
|
283
|
+
port=port,
|
|
284
|
+
transport=transport,
|
|
285
|
+
server_name=f"agentpool-{name}",
|
|
286
|
+
)
|
|
287
|
+
bridge = ToolManagerBridge(node=node, config=config)
|
|
288
|
+
await bridge.start()
|
|
289
|
+
self._tool_bridges[name] = bridge
|
|
290
|
+
return bridge
|
|
291
|
+
|
|
292
|
+
async def get_tool_bridge(self, name: str) -> ToolManagerBridge:
|
|
293
|
+
"""Get a tool bridge by name."""
|
|
294
|
+
if name not in self._tool_bridges:
|
|
295
|
+
msg = f"Tool bridge {name!r} not found"
|
|
296
|
+
raise KeyError(msg)
|
|
297
|
+
return self._tool_bridges[name]
|
|
298
|
+
|
|
299
|
+
async def remove_tool_bridge(self, name: str) -> None:
|
|
300
|
+
"""Stop and remove a tool bridge."""
|
|
301
|
+
if name in self._tool_bridges:
|
|
302
|
+
await self._tool_bridges[name].stop()
|
|
303
|
+
del self._tool_bridges[name]
|
|
304
|
+
|
|
305
|
+
@property
|
|
306
|
+
def is_running(self) -> bool:
|
|
307
|
+
"""Check if the agent pool is running."""
|
|
308
|
+
return bool(self._running_count)
|
|
309
|
+
|
|
310
|
+
async def cleanup(self) -> None:
|
|
311
|
+
"""Clean up all agents."""
|
|
312
|
+
# Clean up tool bridges first
|
|
313
|
+
for bridge in list(self._tool_bridges.values()):
|
|
314
|
+
await bridge.stop()
|
|
315
|
+
self._tool_bridges.clear()
|
|
316
|
+
# Clean up background processes
|
|
317
|
+
await self.process_manager.cleanup()
|
|
318
|
+
await self.exit_stack.aclose()
|
|
319
|
+
self.clear()
|
|
320
|
+
|
|
321
|
+
@overload
|
|
322
|
+
def create_team_run[TResult](
|
|
323
|
+
self,
|
|
324
|
+
agents: Sequence[str],
|
|
325
|
+
validator: MessageNode[Any, TResult] | None = None,
|
|
326
|
+
*,
|
|
327
|
+
name: str | None = None,
|
|
328
|
+
description: str | None = None,
|
|
329
|
+
shared_prompt: str | None = None,
|
|
330
|
+
picker: SupportsStructuredOutput | None = None,
|
|
331
|
+
num_picks: int | None = None,
|
|
332
|
+
pick_prompt: str | None = None,
|
|
333
|
+
) -> TeamRun[TPoolDeps, TResult]: ...
|
|
334
|
+
|
|
335
|
+
@overload
|
|
336
|
+
def create_team_run[TDeps, TResult](
|
|
337
|
+
self,
|
|
338
|
+
agents: Sequence[MessageNode[TDeps, Any]],
|
|
339
|
+
validator: MessageNode[Any, TResult] | None = None,
|
|
340
|
+
*,
|
|
341
|
+
name: str | None = None,
|
|
342
|
+
description: str | None = None,
|
|
343
|
+
shared_prompt: str | None = None,
|
|
344
|
+
picker: SupportsStructuredOutput | None = None,
|
|
345
|
+
num_picks: int | None = None,
|
|
346
|
+
pick_prompt: str | None = None,
|
|
347
|
+
) -> TeamRun[TDeps, TResult]: ...
|
|
348
|
+
|
|
349
|
+
@overload
|
|
350
|
+
def create_team_run[TResult](
|
|
351
|
+
self,
|
|
352
|
+
agents: Sequence[AgentName | MessageNode[Any, Any]],
|
|
353
|
+
validator: MessageNode[Any, TResult] | None = None,
|
|
354
|
+
*,
|
|
355
|
+
name: str | None = None,
|
|
356
|
+
description: str | None = None,
|
|
357
|
+
shared_prompt: str | None = None,
|
|
358
|
+
picker: SupportsStructuredOutput | None = None,
|
|
359
|
+
num_picks: int | None = None,
|
|
360
|
+
pick_prompt: str | None = None,
|
|
361
|
+
) -> TeamRun[Any, TResult]: ...
|
|
362
|
+
|
|
363
|
+
def create_team_run[TResult](
|
|
364
|
+
self,
|
|
365
|
+
agents: Sequence[AgentName | MessageNode[Any, Any]] | None = None,
|
|
366
|
+
validator: MessageNode[Any, TResult] | None = None,
|
|
367
|
+
*,
|
|
368
|
+
name: str | None = None,
|
|
369
|
+
description: str | None = None,
|
|
370
|
+
shared_prompt: str | None = None,
|
|
371
|
+
picker: SupportsStructuredOutput | None = None,
|
|
372
|
+
num_picks: int | None = None,
|
|
373
|
+
pick_prompt: str | None = None,
|
|
374
|
+
) -> TeamRun[Any, TResult]:
|
|
375
|
+
"""Create a a sequential TeamRun from a list of Agents.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
agents: List of agent names or team/agent instances (all if None)
|
|
379
|
+
validator: Node to validate the results of the TeamRun
|
|
380
|
+
name: Optional name for the team
|
|
381
|
+
description: Optional description for the team
|
|
382
|
+
shared_prompt: Optional prompt for all agents
|
|
383
|
+
picker: Agent to use for picking agents
|
|
384
|
+
num_picks: Number of agents to pick
|
|
385
|
+
pick_prompt: Prompt to use for picking agents
|
|
386
|
+
"""
|
|
387
|
+
from agentpool.delegation.teamrun import TeamRun
|
|
388
|
+
|
|
389
|
+
if agents is None:
|
|
390
|
+
agents = list(self.agents.keys())
|
|
391
|
+
team = TeamRun(
|
|
392
|
+
[self.get_agent(i) if isinstance(i, str) else i for i in agents],
|
|
393
|
+
name=name,
|
|
394
|
+
description=description,
|
|
395
|
+
validator=validator,
|
|
396
|
+
shared_prompt=shared_prompt,
|
|
397
|
+
picker=picker,
|
|
398
|
+
num_picks=num_picks,
|
|
399
|
+
pick_prompt=pick_prompt,
|
|
400
|
+
)
|
|
401
|
+
if name:
|
|
402
|
+
self[name] = team
|
|
403
|
+
return team
|
|
404
|
+
|
|
405
|
+
@overload
|
|
406
|
+
def create_team(self, agents: Sequence[str]) -> Team[TPoolDeps]: ...
|
|
407
|
+
|
|
408
|
+
@overload
|
|
409
|
+
def create_team[TDeps](
|
|
410
|
+
self,
|
|
411
|
+
agents: Sequence[MessageNode[TDeps, Any]],
|
|
412
|
+
*,
|
|
413
|
+
name: str | None = None,
|
|
414
|
+
description: str | None = None,
|
|
415
|
+
shared_prompt: str | None = None,
|
|
416
|
+
picker: SupportsStructuredOutput | None = None,
|
|
417
|
+
num_picks: int | None = None,
|
|
418
|
+
pick_prompt: str | None = None,
|
|
419
|
+
) -> Team[TDeps]: ...
|
|
420
|
+
|
|
421
|
+
@overload
|
|
422
|
+
def create_team(
|
|
423
|
+
self,
|
|
424
|
+
agents: Sequence[AgentName | MessageNode[Any, Any]],
|
|
425
|
+
*,
|
|
426
|
+
name: str | None = None,
|
|
427
|
+
description: str | None = None,
|
|
428
|
+
shared_prompt: str | None = None,
|
|
429
|
+
picker: SupportsStructuredOutput | None = None,
|
|
430
|
+
num_picks: int | None = None,
|
|
431
|
+
pick_prompt: str | None = None,
|
|
432
|
+
) -> Team[Any]: ...
|
|
433
|
+
|
|
434
|
+
def create_team(
|
|
435
|
+
self,
|
|
436
|
+
agents: Sequence[AgentName | MessageNode[Any, Any]] | None = None,
|
|
437
|
+
*,
|
|
438
|
+
name: str | None = None,
|
|
439
|
+
description: str | None = None,
|
|
440
|
+
shared_prompt: str | None = None,
|
|
441
|
+
picker: SupportsStructuredOutput | None = None,
|
|
442
|
+
num_picks: int | None = None,
|
|
443
|
+
pick_prompt: str | None = None,
|
|
444
|
+
) -> Team[Any]:
|
|
445
|
+
"""Create a group from agent names or instances.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
agents: List of agent names or instances (all if None)
|
|
449
|
+
name: Optional name for the team
|
|
450
|
+
description: Optional description for the team
|
|
451
|
+
shared_prompt: Optional prompt for all agents
|
|
452
|
+
picker: Agent to use for picking agents
|
|
453
|
+
num_picks: Number of agents to pick
|
|
454
|
+
pick_prompt: Prompt to use for picking agents
|
|
455
|
+
"""
|
|
456
|
+
from agentpool.delegation.team import Team
|
|
457
|
+
|
|
458
|
+
if agents is None:
|
|
459
|
+
agents = list(self.agents.keys())
|
|
460
|
+
|
|
461
|
+
team = Team(
|
|
462
|
+
name=name,
|
|
463
|
+
description=description,
|
|
464
|
+
agents=[self.get_agent(i) if isinstance(i, str) else i for i in agents],
|
|
465
|
+
shared_prompt=shared_prompt,
|
|
466
|
+
picker=picker,
|
|
467
|
+
num_picks=num_picks,
|
|
468
|
+
pick_prompt=pick_prompt,
|
|
469
|
+
)
|
|
470
|
+
if name:
|
|
471
|
+
self[name] = team
|
|
472
|
+
return team
|
|
473
|
+
|
|
474
|
+
@asynccontextmanager
|
|
475
|
+
async def track_message_flow(self) -> AsyncIterator[MessageFlowTracker]:
|
|
476
|
+
"""Track message flow during a context."""
|
|
477
|
+
tracker = MessageFlowTracker()
|
|
478
|
+
self.connection_registry.message_flow.connect(tracker.track)
|
|
479
|
+
try:
|
|
480
|
+
yield tracker
|
|
481
|
+
finally:
|
|
482
|
+
self.connection_registry.message_flow.disconnect(tracker.track)
|
|
483
|
+
|
|
484
|
+
async def run_event_loop(self) -> None:
|
|
485
|
+
"""Run pool in event-watching mode until interrupted."""
|
|
486
|
+
print("Starting event watch mode...")
|
|
487
|
+
print("Active nodes: ", ", ".join(list(self.nodes.keys())))
|
|
488
|
+
print("Press Ctrl+C to stop")
|
|
489
|
+
|
|
490
|
+
shutdown_event = anyio.Event()
|
|
491
|
+
with suppress(KeyboardInterrupt):
|
|
492
|
+
await shutdown_event.wait()
|
|
493
|
+
|
|
494
|
+
@property
|
|
495
|
+
def agents(self) -> dict[str, Agent[Any, Any]]:
|
|
496
|
+
"""Get regular agents dict."""
|
|
497
|
+
return {i.name: i for i in self._items.values() if isinstance(i, Agent)}
|
|
498
|
+
|
|
499
|
+
@property
|
|
500
|
+
def acp_agents(self) -> dict[str, ACPAgent]:
|
|
501
|
+
"""Get ACP agents dict."""
|
|
502
|
+
from agentpool.agents.acp_agent import ACPAgent
|
|
503
|
+
|
|
504
|
+
return {i.name: i for i in self._items.values() if isinstance(i, ACPAgent)}
|
|
505
|
+
|
|
506
|
+
@property
|
|
507
|
+
def agui_agents(self) -> dict[str, AGUIAgent]:
|
|
508
|
+
"""Get AG-UI agents dict."""
|
|
509
|
+
from agentpool.agents.agui_agent import AGUIAgent
|
|
510
|
+
|
|
511
|
+
return {i.name: i for i in self._items.values() if isinstance(i, AGUIAgent)}
|
|
512
|
+
|
|
513
|
+
@property
|
|
514
|
+
def claude_code_agents(self) -> dict[str, ClaudeCodeAgent]:
|
|
515
|
+
"""Get Claude Code agents dict."""
|
|
516
|
+
from agentpool.agents.claude_code_agent import ClaudeCodeAgent
|
|
517
|
+
|
|
518
|
+
return {i.name: i for i in self._items.values() if isinstance(i, ClaudeCodeAgent)}
|
|
519
|
+
|
|
520
|
+
@property
|
|
521
|
+
def all_agents(self) -> dict[str, BaseAgent[Any, Any]]:
|
|
522
|
+
"""Get all agents (regular, ACP, and AG-UI)."""
|
|
523
|
+
from agentpool.agents.base_agent import BaseAgent
|
|
524
|
+
|
|
525
|
+
return {i.name: i for i in self._items.values() if isinstance(i, BaseAgent)}
|
|
526
|
+
|
|
527
|
+
@property
|
|
528
|
+
def teams(self) -> dict[str, BaseTeam[Any, Any]]:
|
|
529
|
+
"""Get agents dict (backward compatibility)."""
|
|
530
|
+
from agentpool.delegation.base_team import BaseTeam
|
|
531
|
+
|
|
532
|
+
return {i.name: i for i in self._items.values() if isinstance(i, BaseTeam)}
|
|
533
|
+
|
|
534
|
+
@property
|
|
535
|
+
def nodes(self) -> dict[str, MessageNode[Any, Any]]:
|
|
536
|
+
"""Get agents dict (backward compatibility)."""
|
|
537
|
+
from agentpool import MessageNode
|
|
538
|
+
|
|
539
|
+
return {i.name: i for i in self._items.values() if isinstance(i, MessageNode)}
|
|
540
|
+
|
|
541
|
+
def _validate_item(self, item: MessageNode[Any, Any] | Any) -> MessageNode[Any, Any]:
|
|
542
|
+
"""Validate and convert items before registration.
|
|
543
|
+
|
|
544
|
+
Args:
|
|
545
|
+
item: Item to validate
|
|
546
|
+
|
|
547
|
+
Returns:
|
|
548
|
+
Validated Node
|
|
549
|
+
|
|
550
|
+
Raises:
|
|
551
|
+
AgentPoolError: If item is not a valid node
|
|
552
|
+
"""
|
|
553
|
+
if not isinstance(item, MessageNode):
|
|
554
|
+
msg = f"Item must be Agent or Team, got {type(item)}"
|
|
555
|
+
raise self._error_class(msg)
|
|
556
|
+
item.agent_pool = self
|
|
557
|
+
return item
|
|
558
|
+
|
|
559
|
+
def _create_teams(self) -> None:
|
|
560
|
+
"""Create all teams in two phases to allow nesting."""
|
|
561
|
+
# Phase 1: Create empty teams
|
|
562
|
+
|
|
563
|
+
empty_teams: dict[str, BaseTeam[Any, Any]] = {}
|
|
564
|
+
for name, config in self.manifest.teams.items():
|
|
565
|
+
if config.mode == "parallel":
|
|
566
|
+
empty_teams[name] = Team(
|
|
567
|
+
[],
|
|
568
|
+
name=name,
|
|
569
|
+
display_name=config.display_name,
|
|
570
|
+
shared_prompt=config.shared_prompt,
|
|
571
|
+
)
|
|
572
|
+
else:
|
|
573
|
+
empty_teams[name] = TeamRun(
|
|
574
|
+
[],
|
|
575
|
+
name=name,
|
|
576
|
+
display_name=config.display_name,
|
|
577
|
+
shared_prompt=config.shared_prompt,
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
# Phase 2: Resolve members
|
|
581
|
+
for name, config in self.manifest.teams.items():
|
|
582
|
+
team = empty_teams[name]
|
|
583
|
+
members: list[MessageNode[Any, Any]] = []
|
|
584
|
+
for member in config.members:
|
|
585
|
+
if member in self.agents:
|
|
586
|
+
members.append(self.agents[member])
|
|
587
|
+
elif member in empty_teams:
|
|
588
|
+
members.append(empty_teams[member])
|
|
589
|
+
else:
|
|
590
|
+
msg = f"Unknown team member: {member}"
|
|
591
|
+
raise ValueError(msg)
|
|
592
|
+
team.nodes.extend(members)
|
|
593
|
+
self[name] = team
|
|
594
|
+
|
|
595
|
+
def _connect_nodes(self) -> None:
|
|
596
|
+
"""Set up connections defined in manifest."""
|
|
597
|
+
# Merge agent and team configs into one dict of nodes with connections
|
|
598
|
+
for name, config in self.manifest.nodes.items():
|
|
599
|
+
source = self[name]
|
|
600
|
+
for target in config.connections or []:
|
|
601
|
+
match target:
|
|
602
|
+
case NodeConnectionConfig(name=name_):
|
|
603
|
+
if name_ not in self:
|
|
604
|
+
msg = f"Forward target {name_} not found for {name}"
|
|
605
|
+
raise ValueError(msg)
|
|
606
|
+
target_node = self[name_]
|
|
607
|
+
case FileConnectionConfig(path=path_obj):
|
|
608
|
+
agent_name = f"file_writer_{Path(path_obj).stem}"
|
|
609
|
+
target_node = Agent(model=target.get_model(), name=agent_name)
|
|
610
|
+
case CallableConnectionConfig(callable=fn):
|
|
611
|
+
target_node = Agent(model=target.get_model(), name=fn.__name__)
|
|
612
|
+
case _:
|
|
613
|
+
msg = f"Invalid connection config: {target}"
|
|
614
|
+
raise ValueError(msg)
|
|
615
|
+
|
|
616
|
+
source.connect_to(
|
|
617
|
+
target_node,
|
|
618
|
+
connection_type=target.connection_type,
|
|
619
|
+
name=name,
|
|
620
|
+
priority=target.priority,
|
|
621
|
+
delay=target.delay,
|
|
622
|
+
queued=target.queued,
|
|
623
|
+
queue_strategy=target.queue_strategy,
|
|
624
|
+
transform=target.transform,
|
|
625
|
+
filter_condition=target.filter_condition.check
|
|
626
|
+
if target.filter_condition
|
|
627
|
+
else None,
|
|
628
|
+
stop_condition=target.stop_condition.check if target.stop_condition else None,
|
|
629
|
+
exit_condition=target.exit_condition.check if target.exit_condition else None,
|
|
630
|
+
)
|
|
631
|
+
source.connections.set_wait_state(
|
|
632
|
+
target_node,
|
|
633
|
+
wait=target.wait_for_completion,
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
@overload
|
|
637
|
+
def get_agent[TResult = str](
|
|
638
|
+
self,
|
|
639
|
+
agent: AgentName | Agent[Any, str],
|
|
640
|
+
*,
|
|
641
|
+
return_type: type[TResult] = str, # type: ignore
|
|
642
|
+
model_override: ModelId | str | None = None,
|
|
643
|
+
session: SessionIdType | SessionQuery = None,
|
|
644
|
+
) -> Agent[TPoolDeps, TResult]: ...
|
|
645
|
+
|
|
646
|
+
@overload
|
|
647
|
+
def get_agent[TCustomDeps, TResult = str](
|
|
648
|
+
self,
|
|
649
|
+
agent: AgentName | Agent[Any, str],
|
|
650
|
+
*,
|
|
651
|
+
deps_type: type[TCustomDeps],
|
|
652
|
+
return_type: type[TResult] = str, # type: ignore
|
|
653
|
+
model_override: ModelId | str | None = None,
|
|
654
|
+
session: SessionIdType | SessionQuery = None,
|
|
655
|
+
) -> Agent[TCustomDeps, TResult]: ...
|
|
656
|
+
|
|
657
|
+
def get_agent(
|
|
658
|
+
self,
|
|
659
|
+
agent: AgentName | Agent[Any, str],
|
|
660
|
+
*,
|
|
661
|
+
deps_type: Any | None = None,
|
|
662
|
+
return_type: Any = str,
|
|
663
|
+
model_override: ModelId | str | None = None,
|
|
664
|
+
session: SessionIdType | SessionQuery = None,
|
|
665
|
+
) -> Agent[Any, Any]:
|
|
666
|
+
"""Get or configure an agent from the pool.
|
|
667
|
+
|
|
668
|
+
This method provides flexible agent configuration with dependency injection:
|
|
669
|
+
- Without deps: Agent uses pool's shared dependencies
|
|
670
|
+
- With deps: Agent uses provided custom dependencies
|
|
671
|
+
|
|
672
|
+
Args:
|
|
673
|
+
agent: Either agent name or instance
|
|
674
|
+
deps_type: Optional custom dependencies type (overrides shared deps)
|
|
675
|
+
return_type: Optional type for structured responses
|
|
676
|
+
model_override: Optional model override
|
|
677
|
+
session: Optional session ID or query to recover conversation
|
|
678
|
+
|
|
679
|
+
Returns:
|
|
680
|
+
Either:
|
|
681
|
+
- Agent[TPoolDeps] when using pool's shared deps
|
|
682
|
+
- Agent[TCustomDeps] when custom deps provided
|
|
683
|
+
|
|
684
|
+
Raises:
|
|
685
|
+
KeyError: If agent name not found
|
|
686
|
+
ValueError: If configuration is invalid
|
|
687
|
+
"""
|
|
688
|
+
from agentpool.agents import Agent
|
|
689
|
+
|
|
690
|
+
base = agent if isinstance(agent, Agent) else self.agents[agent]
|
|
691
|
+
# Use custom deps if provided, otherwise use shared deps
|
|
692
|
+
# base.context.data = deps if deps is not None else self.shared_deps
|
|
693
|
+
base.deps_type = deps_type
|
|
694
|
+
base.agent_pool = self
|
|
695
|
+
if model_override:
|
|
696
|
+
base.set_model(model_override)
|
|
697
|
+
if session:
|
|
698
|
+
base.conversation.load_history_from_database(session=session)
|
|
699
|
+
if return_type not in {str, None}:
|
|
700
|
+
base.to_structured(return_type)
|
|
701
|
+
|
|
702
|
+
return base
|
|
703
|
+
|
|
704
|
+
def get_job(self, name: str) -> Job[Any, Any]:
|
|
705
|
+
return self._tasks[name]
|
|
706
|
+
|
|
707
|
+
def register_task(self, name: str, task: Job[Any, Any]) -> None:
|
|
708
|
+
self._tasks.register(name, task)
|
|
709
|
+
|
|
710
|
+
async def add_agent[TResult = str](
|
|
711
|
+
self,
|
|
712
|
+
name: AgentName,
|
|
713
|
+
*,
|
|
714
|
+
output_type: OutputSpec[TResult] = str, # type: ignore[assignment]
|
|
715
|
+
**kwargs: Unpack[AgentKwargs],
|
|
716
|
+
) -> Agent[Any, TResult]:
|
|
717
|
+
"""Add a new permanent agent to the pool.
|
|
718
|
+
|
|
719
|
+
Args:
|
|
720
|
+
name: Name for the new agent
|
|
721
|
+
output_type: Optional type for structured responses:
|
|
722
|
+
**kwargs: Additional agent configuration
|
|
723
|
+
|
|
724
|
+
Returns:
|
|
725
|
+
An agent instance
|
|
726
|
+
"""
|
|
727
|
+
from agentpool.agents import Agent
|
|
728
|
+
|
|
729
|
+
if not kwargs.get("event_handlers"):
|
|
730
|
+
kwargs["event_handlers"] = self.event_handlers
|
|
731
|
+
agent: Agent[Any, TResult] = Agent(
|
|
732
|
+
name=name,
|
|
733
|
+
**kwargs,
|
|
734
|
+
output_type=output_type,
|
|
735
|
+
agent_pool=self,
|
|
736
|
+
)
|
|
737
|
+
# Add MCP aggregating provider from manager
|
|
738
|
+
agent.tools.add_provider(self.mcp.get_aggregating_provider())
|
|
739
|
+
agent = await self.exit_stack.enter_async_context(agent)
|
|
740
|
+
self.register(name, agent)
|
|
741
|
+
return agent
|
|
742
|
+
|
|
743
|
+
def get_mermaid_diagram(self, include_details: bool = True) -> str:
|
|
744
|
+
"""Generate mermaid flowchart of all agents and their connections.
|
|
745
|
+
|
|
746
|
+
Args:
|
|
747
|
+
include_details: Whether to show connection details (types, queues, etc)
|
|
748
|
+
"""
|
|
749
|
+
lines = ["flowchart LR"]
|
|
750
|
+
|
|
751
|
+
# Add all agents as nodes
|
|
752
|
+
for name in self.agents:
|
|
753
|
+
lines.append(f" {name}[{name}]") # noqa: PERF401
|
|
754
|
+
|
|
755
|
+
# Add all connections as edges
|
|
756
|
+
for agent in self.agents.values():
|
|
757
|
+
connections = agent.connections.get_connections()
|
|
758
|
+
for talk in connections:
|
|
759
|
+
source = talk.source.name
|
|
760
|
+
for target in talk.targets:
|
|
761
|
+
if include_details:
|
|
762
|
+
details: list[str] = []
|
|
763
|
+
details.append(talk.connection_type)
|
|
764
|
+
if talk.queued:
|
|
765
|
+
details.append(f"queued({talk.queue_strategy})")
|
|
766
|
+
if fn := talk.filter_condition:
|
|
767
|
+
details.append(f"filter:{fn.__name__}")
|
|
768
|
+
if fn := talk.stop_condition:
|
|
769
|
+
details.append(f"stop:{fn.__name__}")
|
|
770
|
+
if fn := talk.exit_condition:
|
|
771
|
+
details.append(f"exit:{fn.__name__}")
|
|
772
|
+
|
|
773
|
+
label = f"|{' '.join(details)}|" if details else ""
|
|
774
|
+
lines.append(f" {source}--{label}-->{target.name}")
|
|
775
|
+
else:
|
|
776
|
+
lines.append(f" {source}-->{target.name}")
|
|
777
|
+
|
|
778
|
+
return "\n".join(lines)
|
|
779
|
+
|
|
780
|
+
def _create_agent_from_config[TAgentDeps](
|
|
781
|
+
self,
|
|
782
|
+
name: str,
|
|
783
|
+
config: AnyAgentConfig,
|
|
784
|
+
deps_type: type[TAgentDeps] | None = None,
|
|
785
|
+
) -> BaseAgent[TAgentDeps, Any]:
|
|
786
|
+
"""Create an agent from a unified config, dispatching by type.
|
|
787
|
+
|
|
788
|
+
Args:
|
|
789
|
+
name: Agent name
|
|
790
|
+
config: Agent configuration (any type)
|
|
791
|
+
deps_type: Optional dependency type
|
|
792
|
+
|
|
793
|
+
Returns:
|
|
794
|
+
Configured agent instance
|
|
795
|
+
"""
|
|
796
|
+
from agentpool.models.acp_agents import BaseACPAgentConfig
|
|
797
|
+
from agentpool.models.agents import NativeAgentConfig
|
|
798
|
+
from agentpool.models.agui_agents import AGUIAgentConfig
|
|
799
|
+
from agentpool.models.claude_code_agents import ClaudeCodeAgentConfig
|
|
800
|
+
|
|
801
|
+
# Ensure name is set on config
|
|
802
|
+
if config.name is None:
|
|
803
|
+
config = config.model_copy(update={"name": name})
|
|
804
|
+
|
|
805
|
+
match config:
|
|
806
|
+
case NativeAgentConfig():
|
|
807
|
+
return self.create_agent(
|
|
808
|
+
name,
|
|
809
|
+
deps_type=deps_type,
|
|
810
|
+
input_provider=self._input_provider,
|
|
811
|
+
pool=self,
|
|
812
|
+
event_handlers=self.event_handlers,
|
|
813
|
+
)
|
|
814
|
+
case AGUIAgentConfig():
|
|
815
|
+
return self._create_agui_agent_from_config(config, deps_type)
|
|
816
|
+
case ClaudeCodeAgentConfig():
|
|
817
|
+
return self._create_claude_code_agent_from_config(config, deps_type)
|
|
818
|
+
case BaseACPAgentConfig():
|
|
819
|
+
return self._create_acp_agent_from_config(config, deps_type)
|
|
820
|
+
case _:
|
|
821
|
+
msg = f"Unknown agent config type: {type(config)}"
|
|
822
|
+
raise TypeError(msg)
|
|
823
|
+
|
|
824
|
+
def _create_acp_agent_from_config[TDeps](
|
|
825
|
+
self,
|
|
826
|
+
config: BaseACPAgentConfig,
|
|
827
|
+
deps_type: type[TDeps] | None = None,
|
|
828
|
+
) -> ACPAgent[TDeps]:
|
|
829
|
+
"""Create an ACPAgent from config object."""
|
|
830
|
+
from agentpool.agents.acp_agent import ACPAgent
|
|
831
|
+
|
|
832
|
+
config_handlers = config.get_event_handlers()
|
|
833
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
834
|
+
*config_handlers,
|
|
835
|
+
*self.event_handlers,
|
|
836
|
+
]
|
|
837
|
+
return ACPAgent(config=config, event_handlers=merged_handlers or None)
|
|
838
|
+
|
|
839
|
+
def _create_agui_agent_from_config[TDeps](
|
|
840
|
+
self,
|
|
841
|
+
config: AGUIAgentConfig,
|
|
842
|
+
deps_type: type[TDeps] | None = None,
|
|
843
|
+
) -> AGUIAgent[TDeps]:
|
|
844
|
+
"""Create an AGUIAgent from config object."""
|
|
845
|
+
from agentpool.agents.agui_agent import AGUIAgent
|
|
846
|
+
|
|
847
|
+
config_handlers = config.get_event_handlers()
|
|
848
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
849
|
+
*config_handlers,
|
|
850
|
+
*self.event_handlers,
|
|
851
|
+
]
|
|
852
|
+
return AGUIAgent(
|
|
853
|
+
endpoint=config.endpoint,
|
|
854
|
+
name=config.name or "agui-agent",
|
|
855
|
+
description=config.description,
|
|
856
|
+
display_name=config.display_name,
|
|
857
|
+
event_handlers=merged_handlers or None,
|
|
858
|
+
timeout=config.timeout,
|
|
859
|
+
headers=config.headers,
|
|
860
|
+
startup_command=config.startup_command,
|
|
861
|
+
startup_delay=config.startup_delay,
|
|
862
|
+
tools=[tool_config.get_tool() for tool_config in config.tools],
|
|
863
|
+
mcp_servers=config.mcp_servers,
|
|
864
|
+
tool_confirmation_mode=config.requires_tool_confirmation,
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
def _create_claude_code_agent_from_config[TDeps, TResult](
|
|
868
|
+
self,
|
|
869
|
+
config: ClaudeCodeAgentConfig,
|
|
870
|
+
deps_type: type[TDeps] | None = None,
|
|
871
|
+
) -> ClaudeCodeAgent[TDeps, TResult]:
|
|
872
|
+
"""Create a ClaudeCodeAgent from config object."""
|
|
873
|
+
from agentpool.agents.claude_code_agent import ClaudeCodeAgent
|
|
874
|
+
from agentpool.utils.result_utils import to_type
|
|
875
|
+
|
|
876
|
+
config_handlers = config.get_event_handlers()
|
|
877
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
878
|
+
*config_handlers,
|
|
879
|
+
*self.event_handlers,
|
|
880
|
+
]
|
|
881
|
+
# Resolve output type if configured
|
|
882
|
+
output_type: type | None = None
|
|
883
|
+
if config.output_type:
|
|
884
|
+
output_type = to_type(config.output_type, self.manifest.responses)
|
|
885
|
+
return ClaudeCodeAgent(
|
|
886
|
+
config=config,
|
|
887
|
+
event_handlers=merged_handlers or None,
|
|
888
|
+
input_provider=self._input_provider,
|
|
889
|
+
tool_confirmation_mode=config.requires_tool_confirmation,
|
|
890
|
+
output_type=output_type,
|
|
891
|
+
agent_pool=self,
|
|
892
|
+
)
|
|
893
|
+
|
|
894
|
+
def create_agent[TAgentDeps]( # noqa: PLR0915
|
|
895
|
+
self,
|
|
896
|
+
name: str,
|
|
897
|
+
deps_type: type[TAgentDeps] | None = None,
|
|
898
|
+
input_provider: InputProvider | None = None,
|
|
899
|
+
pool: AgentPool[Any] | None = None,
|
|
900
|
+
event_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] | None = None,
|
|
901
|
+
) -> Agent[TAgentDeps, Any]:
|
|
902
|
+
from agentpool import Agent
|
|
903
|
+
from agentpool.models.agents import NativeAgentConfig
|
|
904
|
+
from agentpool.utils.result_utils import to_type
|
|
905
|
+
from agentpool_config.system_prompts import (
|
|
906
|
+
FilePromptConfig,
|
|
907
|
+
FunctionPromptConfig,
|
|
908
|
+
LibraryPromptConfig,
|
|
909
|
+
StaticPromptConfig,
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
manifest = self.manifest
|
|
913
|
+
# Get config from inline agents or file agents
|
|
914
|
+
if name in manifest.agents:
|
|
915
|
+
config = manifest.agents[name]
|
|
916
|
+
if not isinstance(config, NativeAgentConfig):
|
|
917
|
+
msg = f"Agent {name!r} is not a native agent, use appropriate create method"
|
|
918
|
+
raise TypeError(msg)
|
|
919
|
+
elif name in manifest.file_agents:
|
|
920
|
+
config = manifest._loaded_file_agents[name]
|
|
921
|
+
else:
|
|
922
|
+
msg = f"Agent {name!r} not found in agents or file_agents"
|
|
923
|
+
raise KeyError(msg)
|
|
924
|
+
# Normalize system_prompt to a list for iteration
|
|
925
|
+
sys_prompts: list[str] = []
|
|
926
|
+
prompt_source = config.system_prompt
|
|
927
|
+
if prompt_source is not None:
|
|
928
|
+
prompts_to_process = (
|
|
929
|
+
[prompt_source] if isinstance(prompt_source, str) else prompt_source
|
|
930
|
+
)
|
|
931
|
+
for prompt in prompts_to_process:
|
|
932
|
+
match prompt:
|
|
933
|
+
case (str() as sys_prompt) | StaticPromptConfig(content=sys_prompt):
|
|
934
|
+
sys_prompts.append(sys_prompt)
|
|
935
|
+
case FilePromptConfig(path=path, variables=variables):
|
|
936
|
+
template_path = Path(path) # Load template from file
|
|
937
|
+
if not template_path.is_absolute() and config.config_file_path:
|
|
938
|
+
template_path = Path(config.config_file_path).parent / path
|
|
939
|
+
|
|
940
|
+
template_content = template_path.read_text("utf-8")
|
|
941
|
+
if variables: # Apply variables if any
|
|
942
|
+
from jinja2 import Template
|
|
943
|
+
|
|
944
|
+
template = Template(template_content)
|
|
945
|
+
content = template.render(**variables)
|
|
946
|
+
else:
|
|
947
|
+
content = template_content
|
|
948
|
+
sys_prompts.append(content)
|
|
949
|
+
case LibraryPromptConfig(reference=reference):
|
|
950
|
+
try: # Load from library
|
|
951
|
+
content = self.manifest.prompt_manager.get.sync(reference)
|
|
952
|
+
sys_prompts.append(content)
|
|
953
|
+
except Exception as e:
|
|
954
|
+
msg = f"Failed to load library prompt {reference!r} for agent {name}"
|
|
955
|
+
logger.exception(msg)
|
|
956
|
+
raise ValueError(msg) from e
|
|
957
|
+
case FunctionPromptConfig(function=function, arguments=arguments):
|
|
958
|
+
content = function(**arguments) # Call function to get prompt content
|
|
959
|
+
sys_prompts.append(content)
|
|
960
|
+
# Prepare toolsets list with config's tool provider
|
|
961
|
+
toolsets_list = config.get_toolsets()
|
|
962
|
+
if config_tool_provider := config.get_tool_provider():
|
|
963
|
+
toolsets_list.append(config_tool_provider)
|
|
964
|
+
# Convert workers config to a toolset (backwards compatibility)
|
|
965
|
+
if config.workers:
|
|
966
|
+
from agentpool_toolsets.builtin.workers import WorkersTools
|
|
967
|
+
|
|
968
|
+
workers_provider = WorkersTools(workers=list(config.workers), name="workers")
|
|
969
|
+
toolsets_list.append(workers_provider)
|
|
970
|
+
# Step 1: Get agent-specific output type (same as before)
|
|
971
|
+
agent_output_type = manifest.get_output_type(name) or str
|
|
972
|
+
# Step 2: Resolve it fully with to_type (same as before)
|
|
973
|
+
resolved_output_type = to_type(agent_output_type, manifest.responses)
|
|
974
|
+
# Merge pool-level handlers with config-level handlers
|
|
975
|
+
config_handlers = config.get_event_handlers()
|
|
976
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
977
|
+
*config_handlers,
|
|
978
|
+
*(event_handlers or []),
|
|
979
|
+
]
|
|
980
|
+
match config.model:
|
|
981
|
+
case str():
|
|
982
|
+
model: Model | str | None = config.model
|
|
983
|
+
model_settings: ModelSettings | None = None
|
|
984
|
+
case BaseModelConfig():
|
|
985
|
+
model = config.model.get_model()
|
|
986
|
+
model_settings = config.model.get_model_settings()
|
|
987
|
+
case _:
|
|
988
|
+
model = None
|
|
989
|
+
model_settings = None
|
|
990
|
+
return Agent(
|
|
991
|
+
# context=context,
|
|
992
|
+
model=model,
|
|
993
|
+
model_settings=model_settings,
|
|
994
|
+
system_prompt=sys_prompts,
|
|
995
|
+
name=name,
|
|
996
|
+
display_name=config.display_name,
|
|
997
|
+
deps_type=deps_type,
|
|
998
|
+
env=config.environment.get_provider() if config.environment else None,
|
|
999
|
+
description=config.description,
|
|
1000
|
+
retries=config.retries,
|
|
1001
|
+
session=config.get_session_config(),
|
|
1002
|
+
output_retries=config.output_retries,
|
|
1003
|
+
end_strategy=config.end_strategy,
|
|
1004
|
+
agent_config=config,
|
|
1005
|
+
input_provider=input_provider,
|
|
1006
|
+
output_type=resolved_output_type,
|
|
1007
|
+
event_handlers=merged_handlers or None,
|
|
1008
|
+
agent_pool=pool,
|
|
1009
|
+
tool_mode=config.tool_mode,
|
|
1010
|
+
knowledge=config.knowledge,
|
|
1011
|
+
toolsets=toolsets_list,
|
|
1012
|
+
auto_cache=config.auto_cache,
|
|
1013
|
+
hooks=config.hooks.get_agent_hooks() if config.hooks else None,
|
|
1014
|
+
tool_confirmation_mode=config.requires_tool_confirmation,
|
|
1015
|
+
)
|
|
1016
|
+
|
|
1017
|
+
def create_acp_agent[TDeps](
|
|
1018
|
+
self,
|
|
1019
|
+
name: str,
|
|
1020
|
+
deps_type: type[TDeps] | None = None,
|
|
1021
|
+
) -> ACPAgent[TDeps]:
|
|
1022
|
+
"""Create an ACPAgent from configuration.
|
|
1023
|
+
|
|
1024
|
+
Args:
|
|
1025
|
+
name: Name of the ACP agent in the manifest
|
|
1026
|
+
deps_type: Optional dependency type (not used by ACP agents currently)
|
|
1027
|
+
|
|
1028
|
+
Returns:
|
|
1029
|
+
Configured ACPAgent instance
|
|
1030
|
+
"""
|
|
1031
|
+
from agentpool.agents.acp_agent import ACPAgent
|
|
1032
|
+
|
|
1033
|
+
config = self.manifest.acp_agents[name]
|
|
1034
|
+
# Ensure name is set on config
|
|
1035
|
+
if config.name is None:
|
|
1036
|
+
config = config.model_copy(update={"name": name})
|
|
1037
|
+
# Merge pool-level handlers with config-level handlers
|
|
1038
|
+
config_handlers = config.get_event_handlers()
|
|
1039
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
1040
|
+
*config_handlers,
|
|
1041
|
+
*self.event_handlers,
|
|
1042
|
+
]
|
|
1043
|
+
return ACPAgent(config=config, event_handlers=merged_handlers or None)
|
|
1044
|
+
|
|
1045
|
+
def create_agui_agent[TDeps](
|
|
1046
|
+
self,
|
|
1047
|
+
name: str,
|
|
1048
|
+
deps_type: type[TDeps] | None = None,
|
|
1049
|
+
) -> AGUIAgent[TDeps]:
|
|
1050
|
+
"""Create an AGUIAgent from configuration.
|
|
1051
|
+
|
|
1052
|
+
Args:
|
|
1053
|
+
name: Name of the AG-UI agent in the manifest
|
|
1054
|
+
deps_type: Optional dependency type (not used by AG-UI agents currently)
|
|
1055
|
+
|
|
1056
|
+
Returns:
|
|
1057
|
+
Configured AGUIAgent instance
|
|
1058
|
+
"""
|
|
1059
|
+
from agentpool.agents.agui_agent import AGUIAgent
|
|
1060
|
+
|
|
1061
|
+
config = self.manifest.agui_agents[name]
|
|
1062
|
+
# Ensure name is set on config
|
|
1063
|
+
if config.name is None:
|
|
1064
|
+
config = config.model_copy(update={"name": name})
|
|
1065
|
+
# Merge pool-level handlers with config-level handlers
|
|
1066
|
+
config_handlers = config.get_event_handlers()
|
|
1067
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
1068
|
+
*config_handlers,
|
|
1069
|
+
*self.event_handlers,
|
|
1070
|
+
]
|
|
1071
|
+
return AGUIAgent(
|
|
1072
|
+
endpoint=config.endpoint,
|
|
1073
|
+
name=config.name or "agui-agent",
|
|
1074
|
+
description=config.description,
|
|
1075
|
+
display_name=config.display_name,
|
|
1076
|
+
event_handlers=merged_handlers or None,
|
|
1077
|
+
timeout=config.timeout,
|
|
1078
|
+
headers=config.headers,
|
|
1079
|
+
startup_command=config.startup_command,
|
|
1080
|
+
startup_delay=config.startup_delay,
|
|
1081
|
+
tools=[tool_config.get_tool() for tool_config in config.tools],
|
|
1082
|
+
mcp_servers=config.mcp_servers,
|
|
1083
|
+
tool_confirmation_mode=config.requires_tool_confirmation,
|
|
1084
|
+
)
|
|
1085
|
+
|
|
1086
|
+
def create_claude_code_agent[TDeps](
|
|
1087
|
+
self,
|
|
1088
|
+
name: str,
|
|
1089
|
+
deps_type: type[TDeps] | None = None,
|
|
1090
|
+
) -> ClaudeCodeAgent[TDeps, str]:
|
|
1091
|
+
"""Create a ClaudeCodeAgent from configuration.
|
|
1092
|
+
|
|
1093
|
+
Args:
|
|
1094
|
+
name: Name of the Claude Code agent in the manifest
|
|
1095
|
+
deps_type: Optional dependency type (not used by Claude Code agents currently)
|
|
1096
|
+
|
|
1097
|
+
Returns:
|
|
1098
|
+
Configured ClaudeCodeAgent instance
|
|
1099
|
+
"""
|
|
1100
|
+
from agentpool.agents.claude_code_agent import ClaudeCodeAgent
|
|
1101
|
+
|
|
1102
|
+
config = self.manifest.claude_code_agents[name]
|
|
1103
|
+
# Ensure name is set on config
|
|
1104
|
+
if config.name is None:
|
|
1105
|
+
config = config.model_copy(update={"name": name})
|
|
1106
|
+
# Merge pool-level handlers with config-level handlers
|
|
1107
|
+
config_handlers = config.get_event_handlers()
|
|
1108
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
1109
|
+
*config_handlers,
|
|
1110
|
+
*self.event_handlers,
|
|
1111
|
+
]
|
|
1112
|
+
return ClaudeCodeAgent(
|
|
1113
|
+
config=config,
|
|
1114
|
+
event_handlers=merged_handlers or None,
|
|
1115
|
+
input_provider=self._input_provider,
|
|
1116
|
+
tool_confirmation_mode=config.requires_tool_confirmation,
|
|
1117
|
+
agent_pool=self,
|
|
1118
|
+
)
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
if __name__ == "__main__":
|
|
1122
|
+
|
|
1123
|
+
async def main() -> None:
|
|
1124
|
+
path = "src/agentpool/config_resources/agents.yml"
|
|
1125
|
+
async with AgentPool(path) as pool:
|
|
1126
|
+
agent = pool.get_agent("overseer")
|
|
1127
|
+
print(agent)
|
|
1128
|
+
|
|
1129
|
+
anyio.run(main)
|