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,309 @@
|
|
|
1
|
+
"""AggregatingServer for managing multiple servers with shared pool."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from contextlib import AsyncExitStack
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Literal, Self
|
|
9
|
+
|
|
10
|
+
from agentpool.log import get_logger
|
|
11
|
+
from agentpool_server.base import BaseServer
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import Sequence
|
|
16
|
+
from types import TracebackType
|
|
17
|
+
|
|
18
|
+
from agentpool import AgentPool
|
|
19
|
+
|
|
20
|
+
# Type-safe server status literals
|
|
21
|
+
ServerStatus = Literal["not_initialized", "initialized", "running", "failed", "stopped"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class ServerInfo:
|
|
26
|
+
"""Type-safe server information."""
|
|
27
|
+
|
|
28
|
+
name: str
|
|
29
|
+
server_type: type[BaseServer]
|
|
30
|
+
status: ServerStatus
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
logger = get_logger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class AggregatingServer(BaseServer):
|
|
37
|
+
"""Server that manages multiple protocol servers sharing one AgentPool.
|
|
38
|
+
|
|
39
|
+
Coordinates multiple server instances (AG-UI, A2A, MCP, etc.) as a single unit.
|
|
40
|
+
All servers share the same AgentPool and are started/stopped together.
|
|
41
|
+
|
|
42
|
+
This is useful when you want to expose the same pool of agents via multiple
|
|
43
|
+
protocols simultaneously (e.g., AG-UI for web clients, A2A for agent-to-agent
|
|
44
|
+
communication).
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
```python
|
|
48
|
+
async with AgentPool(config) as pool:
|
|
49
|
+
servers = [
|
|
50
|
+
AGUIServer(pool, port=8002),
|
|
51
|
+
A2AServer(pool, port=8001),
|
|
52
|
+
]
|
|
53
|
+
async with AggregatingServer(pool, servers) as agg:
|
|
54
|
+
async with agg.run_context():
|
|
55
|
+
# Both servers running, sharing the same pool
|
|
56
|
+
await asyncio.Event().wait()
|
|
57
|
+
```
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
pool: AgentPool[Any],
|
|
63
|
+
servers: Sequence[BaseServer],
|
|
64
|
+
*,
|
|
65
|
+
name: str | None = None,
|
|
66
|
+
raise_exceptions: bool = False,
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Initialize aggregating server.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
pool: AgentPool to be shared by all servers
|
|
72
|
+
servers: Sequence of servers to aggregate
|
|
73
|
+
name: Server name for logging (auto-generated if None)
|
|
74
|
+
raise_exceptions: Whether to raise exceptions during server start
|
|
75
|
+
"""
|
|
76
|
+
if not servers:
|
|
77
|
+
msg = "At least one server must be provided"
|
|
78
|
+
raise ValueError(msg)
|
|
79
|
+
|
|
80
|
+
super().__init__(pool, name=name, raise_exceptions=raise_exceptions)
|
|
81
|
+
|
|
82
|
+
self.servers = list(servers)
|
|
83
|
+
self.exit_stack = AsyncExitStack()
|
|
84
|
+
self._initialized_servers: list[BaseServer] = []
|
|
85
|
+
|
|
86
|
+
async def __aenter__(self) -> Self:
|
|
87
|
+
"""Initialize aggregating server and all child servers."""
|
|
88
|
+
await super().__aenter__()
|
|
89
|
+
|
|
90
|
+
self.log.info("Initializing aggregated servers", count=len(self.servers))
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
for server in self.servers:
|
|
94
|
+
try:
|
|
95
|
+
initialized_server = await self.exit_stack.enter_async_context(server)
|
|
96
|
+
self._initialized_servers.append(initialized_server)
|
|
97
|
+
self.log.info("Initialized server", server_name=server.name)
|
|
98
|
+
except Exception:
|
|
99
|
+
self.log.exception("Failed to initialize server", server_name=server.name)
|
|
100
|
+
if self.raise_exceptions:
|
|
101
|
+
raise
|
|
102
|
+
|
|
103
|
+
if not self._initialized_servers:
|
|
104
|
+
msg = "No servers were successfully initialized"
|
|
105
|
+
raise RuntimeError(msg) # noqa: TRY301
|
|
106
|
+
|
|
107
|
+
self.log.info(
|
|
108
|
+
"All servers initialized",
|
|
109
|
+
successful=len(self._initialized_servers),
|
|
110
|
+
failed=len(self.servers) - len(self._initialized_servers),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
except Exception:
|
|
114
|
+
await self.exit_stack.aclose()
|
|
115
|
+
raise
|
|
116
|
+
|
|
117
|
+
return self
|
|
118
|
+
|
|
119
|
+
async def __aexit__(
|
|
120
|
+
self,
|
|
121
|
+
exc_type: type[BaseException] | None,
|
|
122
|
+
exc_val: BaseException | None,
|
|
123
|
+
exc_tb: TracebackType | None,
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Cleanup all servers and base server resources."""
|
|
126
|
+
self.log.info("Shutting down aggregated servers")
|
|
127
|
+
|
|
128
|
+
await self.exit_stack.aclose()
|
|
129
|
+
self._initialized_servers.clear()
|
|
130
|
+
|
|
131
|
+
await super().__aexit__(exc_type, exc_val, exc_tb)
|
|
132
|
+
|
|
133
|
+
self.log.info("Aggregated servers shutdown complete")
|
|
134
|
+
|
|
135
|
+
async def _start_async(self) -> None:
|
|
136
|
+
"""Start all initialized servers concurrently."""
|
|
137
|
+
if not self._initialized_servers:
|
|
138
|
+
self.log.warning("No initialized servers to start")
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
self.log.info("Starting aggregated servers", count=len(self._initialized_servers))
|
|
142
|
+
|
|
143
|
+
server_tasks: list[tuple[BaseServer, asyncio.Task[None] | None]] = []
|
|
144
|
+
|
|
145
|
+
for server in self._initialized_servers:
|
|
146
|
+
try:
|
|
147
|
+
server.start_background()
|
|
148
|
+
server_tasks.append((server, server._server_task))
|
|
149
|
+
self.log.info("Started server in background", server=server.name)
|
|
150
|
+
except Exception:
|
|
151
|
+
self.log.exception("Failed to start server", server=server.name)
|
|
152
|
+
if self.raise_exceptions:
|
|
153
|
+
for started_server, _ in server_tasks:
|
|
154
|
+
try:
|
|
155
|
+
started_server.stop()
|
|
156
|
+
except Exception:
|
|
157
|
+
self.log.exception(
|
|
158
|
+
"Error stopping server", server_name=started_server.name
|
|
159
|
+
)
|
|
160
|
+
raise
|
|
161
|
+
|
|
162
|
+
if not server_tasks:
|
|
163
|
+
msg = "No servers were successfully started"
|
|
164
|
+
raise RuntimeError(msg)
|
|
165
|
+
|
|
166
|
+
self.log.info(
|
|
167
|
+
"All servers started",
|
|
168
|
+
successful=len(server_tasks),
|
|
169
|
+
failed=len(self._initialized_servers) - len(server_tasks),
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
tasks = [task for _, task in server_tasks if task is not None]
|
|
173
|
+
if tasks:
|
|
174
|
+
await self._wait_for_tasks(tasks, server_tasks)
|
|
175
|
+
|
|
176
|
+
async def _wait_for_tasks(
|
|
177
|
+
self,
|
|
178
|
+
tasks: list[asyncio.Task[None]],
|
|
179
|
+
server_tasks: Sequence[tuple[BaseServer, asyncio.Task[None] | None]],
|
|
180
|
+
) -> None:
|
|
181
|
+
"""Wait for server tasks and handle shutdown."""
|
|
182
|
+
try:
|
|
183
|
+
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
|
184
|
+
|
|
185
|
+
for task in done:
|
|
186
|
+
if task.exception():
|
|
187
|
+
self.log.error("Server task failed", error=task.exception())
|
|
188
|
+
else:
|
|
189
|
+
self.log.info("Server task completed")
|
|
190
|
+
|
|
191
|
+
# Stop all other servers gracefully
|
|
192
|
+
for server, _ in server_tasks:
|
|
193
|
+
try:
|
|
194
|
+
server.stop()
|
|
195
|
+
except Exception:
|
|
196
|
+
self.log.exception("Error stopping server")
|
|
197
|
+
|
|
198
|
+
if pending:
|
|
199
|
+
for task in pending:
|
|
200
|
+
task.cancel()
|
|
201
|
+
await asyncio.gather(*pending, return_exceptions=True)
|
|
202
|
+
|
|
203
|
+
except asyncio.CancelledError:
|
|
204
|
+
for server, _ in server_tasks:
|
|
205
|
+
try:
|
|
206
|
+
server.stop()
|
|
207
|
+
except Exception:
|
|
208
|
+
self.log.exception("Error stopping server during cancellation")
|
|
209
|
+
raise
|
|
210
|
+
|
|
211
|
+
def add_server(self, server: BaseServer) -> None:
|
|
212
|
+
"""Add a server to the aggregation.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
server: Server to add
|
|
216
|
+
|
|
217
|
+
Raises:
|
|
218
|
+
RuntimeError: If aggregating server is currently running
|
|
219
|
+
"""
|
|
220
|
+
if self.is_running:
|
|
221
|
+
msg = "Cannot add server while aggregating server is running"
|
|
222
|
+
raise RuntimeError(msg)
|
|
223
|
+
|
|
224
|
+
self.servers.append(server)
|
|
225
|
+
self.log.info("Added server to aggregation", server=server.name)
|
|
226
|
+
|
|
227
|
+
def remove_server(self, server: BaseServer) -> None:
|
|
228
|
+
"""Remove a server from the aggregation.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
server: Server to remove
|
|
232
|
+
|
|
233
|
+
Raises:
|
|
234
|
+
RuntimeError: If aggregating server is currently running
|
|
235
|
+
ValueError: If server is not in aggregation
|
|
236
|
+
"""
|
|
237
|
+
if self.is_running:
|
|
238
|
+
msg = "Cannot remove server while aggregating server is running"
|
|
239
|
+
raise RuntimeError(msg)
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
self.servers.remove(server)
|
|
243
|
+
self.log.info("Removed server from aggregation", server=server.name)
|
|
244
|
+
except ValueError as e:
|
|
245
|
+
msg = f"Server {server.name} not found in aggregation"
|
|
246
|
+
raise ValueError(msg) from e
|
|
247
|
+
|
|
248
|
+
def get_server(self, name: str) -> BaseServer | None:
|
|
249
|
+
"""Get a server by name from the aggregation.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
name: Server name to find
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
Server instance or None if not found
|
|
256
|
+
"""
|
|
257
|
+
all_servers = self.servers + self._initialized_servers
|
|
258
|
+
for server in all_servers:
|
|
259
|
+
if server.name == name:
|
|
260
|
+
return server
|
|
261
|
+
return None
|
|
262
|
+
|
|
263
|
+
def list_servers(self) -> list[ServerInfo]:
|
|
264
|
+
"""List all servers in the aggregation with their status.
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
List of type-safe ServerInfo objects
|
|
268
|
+
"""
|
|
269
|
+
return [
|
|
270
|
+
ServerInfo(
|
|
271
|
+
name=server.name,
|
|
272
|
+
server_type=type(server),
|
|
273
|
+
status=self._get_server_status(server),
|
|
274
|
+
)
|
|
275
|
+
for server in self.servers
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
def get_server_status(self) -> dict[str, ServerStatus]:
|
|
279
|
+
"""Get status of all servers.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Dict mapping server names to their type-safe status
|
|
283
|
+
"""
|
|
284
|
+
return {server.name: self._get_server_status(server) for server in self.servers}
|
|
285
|
+
|
|
286
|
+
def _get_server_status(self, server: BaseServer) -> ServerStatus:
|
|
287
|
+
"""Get type-safe status for a specific server."""
|
|
288
|
+
if server in self._initialized_servers:
|
|
289
|
+
return "running" if server.is_running else "initialized"
|
|
290
|
+
return "not_initialized"
|
|
291
|
+
|
|
292
|
+
@property
|
|
293
|
+
def initialized_server_count(self) -> int:
|
|
294
|
+
"""Number of successfully initialized servers."""
|
|
295
|
+
return len(self._initialized_servers)
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
def running_server_count(self) -> int:
|
|
299
|
+
"""Number of currently running servers."""
|
|
300
|
+
return sum(1 for server in self._initialized_servers if server.is_running)
|
|
301
|
+
|
|
302
|
+
def __repr__(self) -> str:
|
|
303
|
+
"""String representation of aggregating server."""
|
|
304
|
+
return (
|
|
305
|
+
f"AggregatingServer(name={self.name}, "
|
|
306
|
+
f"servers={len(self.servers)}, "
|
|
307
|
+
f"initialized={len(self._initialized_servers)}, "
|
|
308
|
+
f"running={self.running_server_count})"
|
|
309
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""AG-UI server module for agentpool.
|
|
2
|
+
|
|
3
|
+
This module provides server implementation for exposing AgentPool agents
|
|
4
|
+
via the AG-UI protocol with each agent on its own route.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from agentpool_server.agui_server.server import AGUIServer
|
|
10
|
+
|
|
11
|
+
__all__ = ["AGUIServer"]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""AG-UI server implementation for agentpool pool.
|
|
2
|
+
|
|
3
|
+
This module provides a server that exposes all agents in an AgentPool
|
|
4
|
+
via the AG-UI protocol, with each agent accessible at its own route.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from agentpool.log import get_logger
|
|
12
|
+
from agentpool_server.http_server import HTTPServer
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from starlette.requests import Request
|
|
17
|
+
from starlette.responses import Response
|
|
18
|
+
from starlette.routing import Route
|
|
19
|
+
|
|
20
|
+
from agentpool import AgentPool
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
DEFAULT_PORT = 8002
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AGUIServer(HTTPServer):
|
|
29
|
+
"""AG-UI server for exposing pool agents on separate routes.
|
|
30
|
+
|
|
31
|
+
Provides a unified HTTP server that exposes all agents in the pool via
|
|
32
|
+
the AG-UI protocol. Each agent is accessible at `/{agent_name}` route.
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
```python
|
|
36
|
+
pool = AgentPool(manifest)
|
|
37
|
+
|
|
38
|
+
server = AGUIServer(pool, host="localhost", port=8002)
|
|
39
|
+
|
|
40
|
+
async with server:
|
|
41
|
+
async with server.run_context():
|
|
42
|
+
# Agents accessible at:
|
|
43
|
+
# POST http://localhost:8002/agent1
|
|
44
|
+
# POST http://localhost:8002/agent2
|
|
45
|
+
await do_other_work()
|
|
46
|
+
```
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
pool: AgentPool,
|
|
52
|
+
*,
|
|
53
|
+
name: str | None = None,
|
|
54
|
+
host: str = "localhost",
|
|
55
|
+
port: int = DEFAULT_PORT,
|
|
56
|
+
raise_exceptions: bool = False,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""Initialize AG-UI server.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
pool: AgentPool containing available agents
|
|
62
|
+
name: Optional server name (auto-generated if None)
|
|
63
|
+
host: Host to bind server to
|
|
64
|
+
port: Port to bind server to
|
|
65
|
+
raise_exceptions: Whether to raise exceptions during server start
|
|
66
|
+
"""
|
|
67
|
+
super().__init__(pool, name=name, host=host, port=port, raise_exceptions=raise_exceptions)
|
|
68
|
+
|
|
69
|
+
async def get_routes(self) -> list[Route]:
|
|
70
|
+
"""Get Starlette routes for AG-UI protocol.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
List of Route objects for each agent plus root listing endpoint
|
|
74
|
+
"""
|
|
75
|
+
from pydantic_ai.ui.ag_ui import AGUIAdapter
|
|
76
|
+
from starlette.routing import Route
|
|
77
|
+
|
|
78
|
+
routes: list[Route] = []
|
|
79
|
+
|
|
80
|
+
# Create route for each agent in the pool
|
|
81
|
+
for agent_name in self.pool.agents:
|
|
82
|
+
|
|
83
|
+
async def agent_handler(request: Request, agent_name: str = agent_name) -> Response:
|
|
84
|
+
"""Handle AG-UI requests for a specific agent."""
|
|
85
|
+
from starlette.responses import JSONResponse
|
|
86
|
+
|
|
87
|
+
pool_agent = self.pool.agents.get(agent_name)
|
|
88
|
+
if pool_agent is None:
|
|
89
|
+
msg = f"Agent {agent_name!r} not found"
|
|
90
|
+
return JSONResponse({"error": msg}, status_code=404)
|
|
91
|
+
agentlet = await pool_agent.get_agentlet(None, pool_agent.model_name, str)
|
|
92
|
+
try:
|
|
93
|
+
# Use AGUIAdapter.dispatch_request() which handles the full
|
|
94
|
+
# AG-UI protocol: parsing request, running agent, streaming response
|
|
95
|
+
return await AGUIAdapter.dispatch_request(request, agent=agentlet)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
self.log.exception("Error handling AG-UI request", agent=agent_name)
|
|
98
|
+
return JSONResponse({"error": str(e)}, status_code=500)
|
|
99
|
+
|
|
100
|
+
routes.append(Route(f"/{agent_name}", agent_handler, methods=["POST"]))
|
|
101
|
+
self.log.debug("Registered AG-UI route", agent=agent_name, route=f"/{agent_name}")
|
|
102
|
+
|
|
103
|
+
# Add root endpoint that lists available agents
|
|
104
|
+
async def list_agents(request: Request) -> Response:
|
|
105
|
+
"""List all available agents."""
|
|
106
|
+
from starlette.responses import JSONResponse
|
|
107
|
+
|
|
108
|
+
agent_list = [
|
|
109
|
+
{"name": name, "route": f"/{name}", "model": agent.model_name}
|
|
110
|
+
for name, agent in self.pool.agents.items()
|
|
111
|
+
]
|
|
112
|
+
return JSONResponse({"agents": agent_list, "count": len(agent_list)})
|
|
113
|
+
|
|
114
|
+
routes.append(Route("/", list_agents, methods=["GET"]))
|
|
115
|
+
self.log.info("Created AG-UI routes", agent_count=len(self.pool.agents))
|
|
116
|
+
return routes
|
|
117
|
+
|
|
118
|
+
def get_agent_url(self, agent_name: str) -> str:
|
|
119
|
+
"""Get the endpoint URL for a specific agent."""
|
|
120
|
+
return f"{self.base_url}/{agent_name}"
|
|
121
|
+
|
|
122
|
+
def list_agent_routes(self) -> dict[str, str]:
|
|
123
|
+
"""List all agent routes.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Dictionary mapping agent names to their URLs
|
|
127
|
+
"""
|
|
128
|
+
return {name: self.get_agent_url(name) for name in self.pool.agents}
|
agentpool_server/base.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Base server class for AgentPool servers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from contextlib import asynccontextmanager
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
8
|
+
|
|
9
|
+
from agentpool.log import get_logger
|
|
10
|
+
from agentpool.utils.tasks import TaskManager
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import AsyncIterator
|
|
15
|
+
from types import TracebackType
|
|
16
|
+
|
|
17
|
+
from agentpool import AgentPool
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BaseServer:
|
|
23
|
+
"""Base class for all AgentPool servers.
|
|
24
|
+
|
|
25
|
+
Provides standardized interface for server lifecycle management:
|
|
26
|
+
- async def _start_async() - blocking server execution (implemented by subclasses)
|
|
27
|
+
- def start_background() - non-blocking server start via background task
|
|
28
|
+
- def stop() - stop background server task
|
|
29
|
+
- async with run_context() - automatic server start/stop management
|
|
30
|
+
|
|
31
|
+
Features:
|
|
32
|
+
- Centralized task management via TaskManager
|
|
33
|
+
- Configurable exception handling via raise_exceptions parameter
|
|
34
|
+
- Automatic pool lifecycle management
|
|
35
|
+
- Background task lifecycle management
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
pool: AgentPool[Any],
|
|
41
|
+
*,
|
|
42
|
+
name: str | None = None,
|
|
43
|
+
raise_exceptions: bool = False,
|
|
44
|
+
**kwargs: Any,
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Initialize base server with agent pool.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
pool: AgentPool containing available agents
|
|
50
|
+
name: Optional Server name (auto-generated from class name if None)
|
|
51
|
+
raise_exceptions: Whether to raise exceptions during server start
|
|
52
|
+
**kwargs: Additional arguments (for subclass compatibility)
|
|
53
|
+
"""
|
|
54
|
+
self.pool = pool
|
|
55
|
+
self.name = name or f"{self.__class__.__name__}-{id(self):x}"
|
|
56
|
+
self.raise_exceptions = raise_exceptions
|
|
57
|
+
self.task_manager = TaskManager()
|
|
58
|
+
self._server_task: asyncio.Task[None] | None = None
|
|
59
|
+
self._shutdown_event = asyncio.Event()
|
|
60
|
+
self.log = logger.bind(server_name=self.name)
|
|
61
|
+
|
|
62
|
+
async def __aenter__(self) -> Self:
|
|
63
|
+
"""Enter async context and initialize server resources (pool, etc.)."""
|
|
64
|
+
await self.pool.__aenter__()
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
async def __aexit__(
|
|
68
|
+
self,
|
|
69
|
+
exc_type: type[BaseException] | None,
|
|
70
|
+
exc_val: BaseException | None,
|
|
71
|
+
exc_tb: TracebackType | None,
|
|
72
|
+
) -> None:
|
|
73
|
+
"""Exit async context and cleanup server resources."""
|
|
74
|
+
# Cleanup any pending tasks
|
|
75
|
+
await self.task_manager.cleanup_tasks()
|
|
76
|
+
# Cleanup pool
|
|
77
|
+
await self.pool.__aexit__(exc_type, exc_val, exc_tb)
|
|
78
|
+
|
|
79
|
+
async def _start_async(self) -> None:
|
|
80
|
+
"""Start the server (blocking async - runs until stopped).
|
|
81
|
+
|
|
82
|
+
This method must be implemented by subclasses and should run
|
|
83
|
+
the server until it's stopped or encounters an error.
|
|
84
|
+
|
|
85
|
+
This is the internal implementation that subclasses override.
|
|
86
|
+
The public start() method handles exception management.
|
|
87
|
+
"""
|
|
88
|
+
msg = "Subclasses must implement _start_async()"
|
|
89
|
+
raise NotImplementedError(msg)
|
|
90
|
+
|
|
91
|
+
async def start(self) -> None:
|
|
92
|
+
"""Start the server (blocking async - runs until stopped).
|
|
93
|
+
|
|
94
|
+
This is the public interface that handles exception management
|
|
95
|
+
based on the raise_exceptions setting. Subclasses should implement
|
|
96
|
+
_start_async() instead of overriding this method.
|
|
97
|
+
"""
|
|
98
|
+
try:
|
|
99
|
+
self.log.info("Starting server")
|
|
100
|
+
await self._start_async()
|
|
101
|
+
except Exception as e:
|
|
102
|
+
if self.raise_exceptions:
|
|
103
|
+
raise
|
|
104
|
+
self.log.exception("Server error", exc_info=e)
|
|
105
|
+
finally:
|
|
106
|
+
await self.shutdown()
|
|
107
|
+
|
|
108
|
+
async def shutdown(self) -> None:
|
|
109
|
+
"""Shutdown server resources.
|
|
110
|
+
|
|
111
|
+
This method can be overridden by subclasses to add specific
|
|
112
|
+
cleanup logic. The base implementation handles task cleanup.
|
|
113
|
+
"""
|
|
114
|
+
try:
|
|
115
|
+
await self.task_manager.cleanup_tasks()
|
|
116
|
+
except Exception:
|
|
117
|
+
self.log.exception("Error during server shutdown")
|
|
118
|
+
finally:
|
|
119
|
+
self._shutdown_event.set()
|
|
120
|
+
self.log.info("Server shutdown complete")
|
|
121
|
+
|
|
122
|
+
def start_background(self) -> None:
|
|
123
|
+
"""Start server in background task (non-blocking).
|
|
124
|
+
|
|
125
|
+
Creates a background task that runs start() method.
|
|
126
|
+
Server will run in the background until stop() is called.
|
|
127
|
+
"""
|
|
128
|
+
if self._server_task is not None and not self._server_task.done():
|
|
129
|
+
msg = "Server is already running in background"
|
|
130
|
+
raise RuntimeError(msg)
|
|
131
|
+
|
|
132
|
+
self._shutdown_event.clear()
|
|
133
|
+
self._server_task = self.task_manager.create_task(
|
|
134
|
+
self._run_with_shutdown(), name=f"{self.name}-task"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
async def _run_with_shutdown(self) -> None:
|
|
138
|
+
"""Internal wrapper that handles shutdown signaling."""
|
|
139
|
+
try:
|
|
140
|
+
await self.start()
|
|
141
|
+
finally:
|
|
142
|
+
self._shutdown_event.set()
|
|
143
|
+
|
|
144
|
+
def stop(self) -> None:
|
|
145
|
+
"""Stop the background server task (non-blocking)."""
|
|
146
|
+
if self._server_task is not None and not self._server_task.done():
|
|
147
|
+
self._server_task.cancel()
|
|
148
|
+
|
|
149
|
+
async def wait_until_stopped(self) -> None:
|
|
150
|
+
"""Wait until the server stops (either by stop() or natural completion)."""
|
|
151
|
+
if self._server_task is None:
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
# Wait for either task completion or shutdown event
|
|
155
|
+
await self._shutdown_event.wait()
|
|
156
|
+
|
|
157
|
+
# Ensure task is cleaned up
|
|
158
|
+
if self._server_task and not self._server_task.done():
|
|
159
|
+
self._server_task.cancel()
|
|
160
|
+
|
|
161
|
+
if self._server_task:
|
|
162
|
+
await asyncio.gather(self._server_task, return_exceptions=True)
|
|
163
|
+
self._server_task = None
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def is_running(self) -> bool:
|
|
167
|
+
"""Check if server is currently running in background."""
|
|
168
|
+
return self._server_task is not None and not self._server_task.done()
|
|
169
|
+
|
|
170
|
+
@asynccontextmanager
|
|
171
|
+
async def run_context(self) -> AsyncIterator[None]:
|
|
172
|
+
"""Async context manager for automatic server start/stop.
|
|
173
|
+
|
|
174
|
+
Starts the server in background when entering context,
|
|
175
|
+
automatically stops it when exiting context.
|
|
176
|
+
|
|
177
|
+
Example:
|
|
178
|
+
async with server: # Initialize resources
|
|
179
|
+
async with server.run_context(): # Start server
|
|
180
|
+
# Server is running in background
|
|
181
|
+
await do_other_work()
|
|
182
|
+
# Server automatically stopped
|
|
183
|
+
"""
|
|
184
|
+
self.start_background()
|
|
185
|
+
try:
|
|
186
|
+
yield
|
|
187
|
+
finally:
|
|
188
|
+
self.stop()
|
|
189
|
+
await self.wait_until_stopped()
|