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
acp/task/debug.py
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Debugging extensions for ACP task system."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
11
|
+
|
|
12
|
+
from acp.task.state import InMemoryMessageStateStore
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
import asyncio
|
|
17
|
+
|
|
18
|
+
from acp.task.state import IncomingMessage
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__all__ = ["DebugEntry", "DebuggingMessageStateStore"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class DebugEntry:
|
|
26
|
+
"""Structured debug entry for ACP message tracking."""
|
|
27
|
+
|
|
28
|
+
timestamp: str
|
|
29
|
+
direction: Literal["outgoing", "incoming"]
|
|
30
|
+
event: Literal["register", "resolve", "reject", "begin", "complete", "fail"]
|
|
31
|
+
request_id: int | None
|
|
32
|
+
method: str
|
|
33
|
+
params: Any = None
|
|
34
|
+
result: Any = None
|
|
35
|
+
error: Any = None
|
|
36
|
+
status: str | None = None
|
|
37
|
+
duration_ms: float | None = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class DebuggingMessageStateStore(InMemoryMessageStateStore):
|
|
41
|
+
"""Enhanced message state store with structured debugging output.
|
|
42
|
+
|
|
43
|
+
Provides much richer debugging information than raw JSON logging:
|
|
44
|
+
- Request/response correlation
|
|
45
|
+
- Timing information
|
|
46
|
+
- Status tracking
|
|
47
|
+
- Structured data output
|
|
48
|
+
- Error details
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, debug_file: str | Path | None = None) -> None:
|
|
52
|
+
super().__init__()
|
|
53
|
+
self._debug_file = Path(debug_file) if debug_file else None
|
|
54
|
+
self._request_start_times: dict[int, datetime] = {}
|
|
55
|
+
|
|
56
|
+
def register_outgoing(self, request_id: int, method: str) -> asyncio.Future[Any]:
|
|
57
|
+
"""Register outgoing request with debug logging."""
|
|
58
|
+
future = super().register_outgoing(request_id, method)
|
|
59
|
+
|
|
60
|
+
# Track start time for duration calculation
|
|
61
|
+
self._request_start_times[request_id] = datetime.now()
|
|
62
|
+
entry = DebugEntry(
|
|
63
|
+
timestamp=datetime.now().isoformat(),
|
|
64
|
+
direction="outgoing",
|
|
65
|
+
event="register",
|
|
66
|
+
request_id=request_id,
|
|
67
|
+
method=method,
|
|
68
|
+
)
|
|
69
|
+
self._log_debug(entry)
|
|
70
|
+
|
|
71
|
+
return future
|
|
72
|
+
|
|
73
|
+
def resolve_outgoing(self, request_id: int, result: Any) -> None:
|
|
74
|
+
"""Resolve outgoing request with debug logging."""
|
|
75
|
+
duration = self._calculate_duration(request_id)
|
|
76
|
+
super().resolve_outgoing(request_id, result)
|
|
77
|
+
entry = DebugEntry(
|
|
78
|
+
timestamp=datetime.now().isoformat(),
|
|
79
|
+
direction="outgoing",
|
|
80
|
+
event="resolve",
|
|
81
|
+
request_id=request_id,
|
|
82
|
+
method=self._get_method_for_request(request_id),
|
|
83
|
+
result=result,
|
|
84
|
+
duration_ms=duration,
|
|
85
|
+
)
|
|
86
|
+
self._log_debug(entry)
|
|
87
|
+
self._cleanup_request_timing(request_id)
|
|
88
|
+
|
|
89
|
+
def reject_outgoing(self, request_id: int, error: Any) -> None:
|
|
90
|
+
"""Reject outgoing request with debug logging."""
|
|
91
|
+
duration = self._calculate_duration(request_id)
|
|
92
|
+
super().reject_outgoing(request_id, error)
|
|
93
|
+
entry = DebugEntry(
|
|
94
|
+
timestamp=datetime.now().isoformat(),
|
|
95
|
+
direction="outgoing",
|
|
96
|
+
event="reject",
|
|
97
|
+
request_id=request_id,
|
|
98
|
+
method=self._get_method_for_request(request_id),
|
|
99
|
+
error=str(error),
|
|
100
|
+
duration_ms=duration,
|
|
101
|
+
)
|
|
102
|
+
self._log_debug(entry)
|
|
103
|
+
self._cleanup_request_timing(request_id)
|
|
104
|
+
|
|
105
|
+
def reject_all_outgoing(self, error: Any) -> None:
|
|
106
|
+
"""Reject all outgoing requests with debug logging."""
|
|
107
|
+
# Log for each pending request
|
|
108
|
+
for request_id in list(self._outgoing.keys()):
|
|
109
|
+
duration = self._calculate_duration(request_id)
|
|
110
|
+
entry = DebugEntry(
|
|
111
|
+
timestamp=datetime.now().isoformat(),
|
|
112
|
+
direction="outgoing",
|
|
113
|
+
event="reject",
|
|
114
|
+
request_id=request_id,
|
|
115
|
+
method=self._get_method_for_request(request_id),
|
|
116
|
+
error=f"Connection error: {error}",
|
|
117
|
+
duration_ms=duration,
|
|
118
|
+
)
|
|
119
|
+
self._log_debug(entry)
|
|
120
|
+
|
|
121
|
+
super().reject_all_outgoing(error)
|
|
122
|
+
self._request_start_times.clear()
|
|
123
|
+
|
|
124
|
+
def begin_incoming(self, method: str, params: Any) -> IncomingMessage:
|
|
125
|
+
"""Begin processing incoming request with debug logging."""
|
|
126
|
+
record = super().begin_incoming(method, params)
|
|
127
|
+
entry = DebugEntry(
|
|
128
|
+
timestamp=datetime.now().isoformat(),
|
|
129
|
+
direction="incoming",
|
|
130
|
+
event="begin",
|
|
131
|
+
request_id=None,
|
|
132
|
+
method=method,
|
|
133
|
+
params=params,
|
|
134
|
+
status="pending",
|
|
135
|
+
)
|
|
136
|
+
self._log_debug(entry)
|
|
137
|
+
return record
|
|
138
|
+
|
|
139
|
+
def complete_incoming(self, record: IncomingMessage, result: Any) -> None:
|
|
140
|
+
"""Complete incoming request with debug logging."""
|
|
141
|
+
super().complete_incoming(record, result)
|
|
142
|
+
entry = DebugEntry(
|
|
143
|
+
timestamp=datetime.now().isoformat(),
|
|
144
|
+
direction="incoming",
|
|
145
|
+
event="complete",
|
|
146
|
+
request_id=None,
|
|
147
|
+
method=record.method,
|
|
148
|
+
result=result,
|
|
149
|
+
status="completed",
|
|
150
|
+
)
|
|
151
|
+
self._log_debug(entry)
|
|
152
|
+
|
|
153
|
+
def fail_incoming(self, record: IncomingMessage, error: Any) -> None:
|
|
154
|
+
"""Fail incoming request with debug logging."""
|
|
155
|
+
super().fail_incoming(record, error)
|
|
156
|
+
entry = DebugEntry(
|
|
157
|
+
timestamp=datetime.now().isoformat(),
|
|
158
|
+
direction="incoming",
|
|
159
|
+
event="fail",
|
|
160
|
+
request_id=None,
|
|
161
|
+
method=record.method,
|
|
162
|
+
error=str(error),
|
|
163
|
+
status="failed",
|
|
164
|
+
)
|
|
165
|
+
self._log_debug(entry)
|
|
166
|
+
|
|
167
|
+
def _log_debug(self, entry: DebugEntry) -> None:
|
|
168
|
+
"""Write debug entry to file if configured."""
|
|
169
|
+
if not self._debug_file:
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
# Convert to dict and filter out None values for cleaner output
|
|
174
|
+
data = {k: v for k, v in asdict(entry).items() if v is not None}
|
|
175
|
+
# Write as JSONL (one JSON object per line)
|
|
176
|
+
with self._debug_file.open("a", encoding="utf-8") as f:
|
|
177
|
+
f.write(json.dumps(data, separators=(",", ":")) + "\n")
|
|
178
|
+
|
|
179
|
+
except Exception:
|
|
180
|
+
# Don't let debug logging break the connection
|
|
181
|
+
logging.exception("Failed to write debug entry")
|
|
182
|
+
|
|
183
|
+
def _calculate_duration(self, request_id: int) -> float | None:
|
|
184
|
+
"""Calculate request duration in milliseconds."""
|
|
185
|
+
start_time = self._request_start_times.get(request_id)
|
|
186
|
+
if start_time:
|
|
187
|
+
return (datetime.now() - start_time).total_seconds() * 1000
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
def _cleanup_request_timing(self, request_id: int) -> None:
|
|
191
|
+
"""Clean up timing tracking for completed request."""
|
|
192
|
+
self._request_start_times.pop(request_id, None)
|
|
193
|
+
|
|
194
|
+
def _get_method_for_request(self, request_id: int) -> str:
|
|
195
|
+
"""Get method name for outgoing request."""
|
|
196
|
+
record = self._outgoing.get(request_id)
|
|
197
|
+
return record.method if record else "unknown"
|
acp/task/dispatcher.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Message dispatcher for ACP tasks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import Awaitable, Callable
|
|
7
|
+
from contextlib import suppress
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Protocol
|
|
9
|
+
|
|
10
|
+
from acp.task import RpcTaskKind
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from acp.task.queue import MessageQueue
|
|
15
|
+
from acp.task.state import MessageStateStore
|
|
16
|
+
from acp.task.supervisor import TaskSupervisor
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
RequestRunner = Callable[[dict[str, Any]], Awaitable[Any]]
|
|
20
|
+
NotificationRunner = Callable[[dict[str, Any]], Awaitable[None]]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MessageDispatcher(Protocol):
|
|
24
|
+
"""Protocol for message dispatchers."""
|
|
25
|
+
|
|
26
|
+
def start(self) -> None: ...
|
|
27
|
+
|
|
28
|
+
async def stop(self) -> None: ...
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DefaultMessageDispatcher(MessageDispatcher):
|
|
32
|
+
"""Background worker that consumes RPC tasks from a broker."""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
queue: MessageQueue,
|
|
38
|
+
supervisor: TaskSupervisor,
|
|
39
|
+
store: MessageStateStore,
|
|
40
|
+
request_runner: RequestRunner,
|
|
41
|
+
notification_runner: NotificationRunner,
|
|
42
|
+
) -> None:
|
|
43
|
+
self._queue = queue
|
|
44
|
+
self._supervisor = supervisor
|
|
45
|
+
self._store = store
|
|
46
|
+
self._request_runner = request_runner
|
|
47
|
+
self._notification_runner = notification_runner
|
|
48
|
+
self._task: asyncio.Task[None] | None = None
|
|
49
|
+
|
|
50
|
+
def start(self) -> None:
|
|
51
|
+
if self._task is not None:
|
|
52
|
+
raise RuntimeError("dispatcher already started")
|
|
53
|
+
self._task = self._supervisor.create(self._run(), name="acp.Dispatcher.loop")
|
|
54
|
+
|
|
55
|
+
async def _run(self) -> None:
|
|
56
|
+
try:
|
|
57
|
+
async for task in self._queue:
|
|
58
|
+
try:
|
|
59
|
+
if task.kind is RpcTaskKind.REQUEST:
|
|
60
|
+
await self._dispatch_request(task.message)
|
|
61
|
+
else:
|
|
62
|
+
await self._dispatch_notification(task.message)
|
|
63
|
+
finally:
|
|
64
|
+
self._queue.task_done()
|
|
65
|
+
except asyncio.CancelledError:
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
async def stop(self) -> None:
|
|
69
|
+
await self._queue.close()
|
|
70
|
+
if self._task is not None:
|
|
71
|
+
with suppress(asyncio.CancelledError):
|
|
72
|
+
await self._task
|
|
73
|
+
self._task = None
|
|
74
|
+
|
|
75
|
+
async def _dispatch_request(self, msg: dict[str, Any]) -> None:
|
|
76
|
+
record = self._store.begin_incoming(msg.get("method", ""), msg.get("params"))
|
|
77
|
+
|
|
78
|
+
async def runner() -> None:
|
|
79
|
+
try:
|
|
80
|
+
result = await self._request_runner(msg)
|
|
81
|
+
except Exception as exc:
|
|
82
|
+
self._store.fail_incoming(record, exc)
|
|
83
|
+
raise
|
|
84
|
+
else:
|
|
85
|
+
self._store.complete_incoming(record, result)
|
|
86
|
+
|
|
87
|
+
self._supervisor.create(runner(), name="acp.Dispatcher.request")
|
|
88
|
+
|
|
89
|
+
async def _dispatch_notification(self, message: dict[str, Any]) -> None:
|
|
90
|
+
async def runner() -> None:
|
|
91
|
+
await self._notification_runner(message)
|
|
92
|
+
|
|
93
|
+
self._supervisor.create(runner(), name="acp.Dispatcher.notification")
|
acp/task/queue.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
from typing import TYPE_CHECKING, Protocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from collections.abc import AsyncIterator
|
|
10
|
+
|
|
11
|
+
from acp.task import RpcTask
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MessageQueue(Protocol):
|
|
15
|
+
"""Protocol for message queues used in RPC task dispatch."""
|
|
16
|
+
|
|
17
|
+
async def publish(self, task: RpcTask) -> None: ...
|
|
18
|
+
|
|
19
|
+
async def close(self) -> None: ...
|
|
20
|
+
|
|
21
|
+
def task_done(self) -> None: ...
|
|
22
|
+
|
|
23
|
+
async def join(self) -> None: ...
|
|
24
|
+
|
|
25
|
+
def __aiter__(self) -> AsyncIterator[RpcTask]: ...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class InMemoryMessageQueue:
|
|
29
|
+
"""Simple in-memory broker for RPC task dispatch."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, *, maxsize: int = 0) -> None:
|
|
32
|
+
self._queue: asyncio.Queue[RpcTask | None] = asyncio.Queue(maxsize=maxsize)
|
|
33
|
+
self._closed = False
|
|
34
|
+
|
|
35
|
+
async def publish(self, task: RpcTask) -> None:
|
|
36
|
+
if self._closed:
|
|
37
|
+
raise RuntimeError("mssage queue already closed")
|
|
38
|
+
await self._queue.put(task)
|
|
39
|
+
|
|
40
|
+
async def close(self) -> None:
|
|
41
|
+
if self._closed:
|
|
42
|
+
return
|
|
43
|
+
self._closed = True
|
|
44
|
+
await self._queue.put(None)
|
|
45
|
+
|
|
46
|
+
async def join(self) -> None:
|
|
47
|
+
await self._queue.join()
|
|
48
|
+
|
|
49
|
+
def task_done(self) -> None:
|
|
50
|
+
with suppress(ValueError):
|
|
51
|
+
self._queue.task_done()
|
|
52
|
+
|
|
53
|
+
def __aiter__(self) -> AsyncIterator[RpcTask]:
|
|
54
|
+
return _QueueIterator(self)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class _QueueIterator:
|
|
58
|
+
def __init__(self, queue: InMemoryMessageQueue) -> None:
|
|
59
|
+
self._queue = queue
|
|
60
|
+
|
|
61
|
+
def __aiter__(self) -> _QueueIterator:
|
|
62
|
+
return self
|
|
63
|
+
|
|
64
|
+
async def __anext__(self) -> RpcTask:
|
|
65
|
+
item = await self._queue._queue.get()
|
|
66
|
+
if item is None:
|
|
67
|
+
self._queue.task_done()
|
|
68
|
+
raise StopAsyncIteration
|
|
69
|
+
return item
|
acp/task/sender.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Sender class for sending messages to a remote peer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
import contextlib
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import anyio
|
|
14
|
+
from anyio.abc import ByteSendStream
|
|
15
|
+
|
|
16
|
+
from acp.task.supervisor import TaskSupervisor
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = ["MessageSender", "SenderFactory"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
SenderFactory = Callable[[ByteSendStream, TaskSupervisor], "MessageSender"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(slots=True)
|
|
26
|
+
class _PendingSend:
|
|
27
|
+
payload: bytes
|
|
28
|
+
future: asyncio.Future[None]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class MessageSender:
|
|
32
|
+
"""Async message sender that queues and transmits JSON-RPC messages."""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
writer: ByteSendStream,
|
|
37
|
+
supervisor: TaskSupervisor,
|
|
38
|
+
) -> None:
|
|
39
|
+
self._writer = writer
|
|
40
|
+
self._queue: asyncio.Queue[_PendingSend | None] = asyncio.Queue()
|
|
41
|
+
self._closed = False
|
|
42
|
+
self._task = supervisor.create(
|
|
43
|
+
self._loop(), name="acp.Sender.loop", on_error=self._on_error
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
async def send(self, payload: dict[str, Any]) -> None:
|
|
47
|
+
data = (json.dumps(payload, separators=(",", ":")) + "\n").encode("utf-8")
|
|
48
|
+
future: asyncio.Future[None] = asyncio.get_running_loop().create_future()
|
|
49
|
+
await self._queue.put(_PendingSend(data, future))
|
|
50
|
+
await future
|
|
51
|
+
|
|
52
|
+
async def close(self) -> None:
|
|
53
|
+
if self._closed:
|
|
54
|
+
return
|
|
55
|
+
self._closed = True
|
|
56
|
+
await self._queue.put(None)
|
|
57
|
+
if self._task is not None:
|
|
58
|
+
with contextlib.suppress(asyncio.CancelledError):
|
|
59
|
+
await self._task
|
|
60
|
+
|
|
61
|
+
async def _loop(self) -> None:
|
|
62
|
+
try:
|
|
63
|
+
while True:
|
|
64
|
+
item = await self._queue.get()
|
|
65
|
+
if item is None:
|
|
66
|
+
return
|
|
67
|
+
try:
|
|
68
|
+
await self._writer.send(item.payload)
|
|
69
|
+
except Exception as exc:
|
|
70
|
+
if not item.future.done():
|
|
71
|
+
item.future.set_exception(exc)
|
|
72
|
+
raise
|
|
73
|
+
else:
|
|
74
|
+
if not item.future.done():
|
|
75
|
+
item.future.set_result(None)
|
|
76
|
+
except asyncio.CancelledError:
|
|
77
|
+
return
|
|
78
|
+
except anyio.ClosedResourceError:
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
def _on_error(self, task: asyncio.Task[Any], exc: BaseException) -> None:
|
|
82
|
+
logging.exception("Send loop failed", exc_info=exc)
|
acp/task/state.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Message State Store."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any, Protocol
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(slots=True)
|
|
11
|
+
class OutgoingMessage:
|
|
12
|
+
"""Represents an outgoing message with its request ID, method, and future."""
|
|
13
|
+
|
|
14
|
+
request_id: int
|
|
15
|
+
method: str
|
|
16
|
+
future: asyncio.Future[Any]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(slots=True)
|
|
20
|
+
class IncomingMessage:
|
|
21
|
+
"""Represents an incoming message with its status, result, and error."""
|
|
22
|
+
|
|
23
|
+
method: str
|
|
24
|
+
params: Any
|
|
25
|
+
status: str = "pending"
|
|
26
|
+
result: Any = None
|
|
27
|
+
error: Any = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MessageStateStore(Protocol):
|
|
31
|
+
"""Protocol for managing message states."""
|
|
32
|
+
|
|
33
|
+
def register_outgoing(self, request_id: int, method: str) -> asyncio.Future[Any]: ...
|
|
34
|
+
|
|
35
|
+
def resolve_outgoing(self, request_id: int, result: Any) -> None: ...
|
|
36
|
+
|
|
37
|
+
def reject_outgoing(self, request_id: int, error: Any) -> None: ...
|
|
38
|
+
|
|
39
|
+
def reject_all_outgoing(self, error: Any) -> None: ...
|
|
40
|
+
|
|
41
|
+
def begin_incoming(self, method: str, params: Any) -> IncomingMessage: ...
|
|
42
|
+
|
|
43
|
+
def complete_incoming(self, record: IncomingMessage, result: Any) -> None: ...
|
|
44
|
+
|
|
45
|
+
def fail_incoming(self, record: IncomingMessage, error: Any) -> None: ...
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class InMemoryMessageStateStore(MessageStateStore):
|
|
49
|
+
"""In-memory implementation of MessageStateStore."""
|
|
50
|
+
|
|
51
|
+
def __init__(self) -> None:
|
|
52
|
+
self._outgoing: dict[int, OutgoingMessage] = {}
|
|
53
|
+
self._incoming: list[IncomingMessage] = []
|
|
54
|
+
|
|
55
|
+
def register_outgoing(self, request_id: int, method: str) -> asyncio.Future[Any]:
|
|
56
|
+
future: asyncio.Future[Any] = asyncio.get_running_loop().create_future()
|
|
57
|
+
self._outgoing[request_id] = OutgoingMessage(request_id, method, future)
|
|
58
|
+
return future
|
|
59
|
+
|
|
60
|
+
def resolve_outgoing(self, request_id: int, result: Any) -> None:
|
|
61
|
+
record = self._outgoing.pop(request_id, None)
|
|
62
|
+
if record and not record.future.done():
|
|
63
|
+
record.future.set_result(result)
|
|
64
|
+
|
|
65
|
+
def reject_outgoing(self, request_id: int, error: Any) -> None:
|
|
66
|
+
record = self._outgoing.pop(request_id, None)
|
|
67
|
+
if record and not record.future.done():
|
|
68
|
+
record.future.set_exception(error)
|
|
69
|
+
|
|
70
|
+
def reject_all_outgoing(self, error: Any) -> None:
|
|
71
|
+
for record in self._outgoing.values():
|
|
72
|
+
if not record.future.done():
|
|
73
|
+
record.future.set_exception(error)
|
|
74
|
+
self._outgoing.clear()
|
|
75
|
+
|
|
76
|
+
def begin_incoming(self, method: str, params: Any) -> IncomingMessage:
|
|
77
|
+
record = IncomingMessage(method=method, params=params)
|
|
78
|
+
self._incoming.append(record)
|
|
79
|
+
return record
|
|
80
|
+
|
|
81
|
+
def complete_incoming(self, record: IncomingMessage, result: Any) -> None:
|
|
82
|
+
record.status = "completed"
|
|
83
|
+
record.result = result
|
|
84
|
+
|
|
85
|
+
def fail_incoming(self, record: IncomingMessage, error: Any) -> None:
|
|
86
|
+
record.status = "failed"
|
|
87
|
+
record.error = error
|
acp/task/supervisor.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Task Supervisor."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from contextlib import suppress
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
|
+
|
|
10
|
+
from agentpool import log
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import Coroutine
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = ["TaskSupervisor"]
|
|
18
|
+
|
|
19
|
+
logger = log.get_logger(__name__)
|
|
20
|
+
ErrorHandler = Callable[[asyncio.Task[Any], BaseException], None]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TaskSupervisor:
|
|
24
|
+
"""Track background tasks and provide graceful shutdown semantics.
|
|
25
|
+
|
|
26
|
+
Inspired by fasta2a's task manager, this supervisor keeps a registry of
|
|
27
|
+
asyncio tasks created for request handling so they can be cancelled and
|
|
28
|
+
awaited reliably when the connection closes.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, *, source: str) -> None:
|
|
32
|
+
self._source = source
|
|
33
|
+
self._tasks: set[asyncio.Task[Any]] = set()
|
|
34
|
+
self._closed = False
|
|
35
|
+
self._error_handlers: list[ErrorHandler] = []
|
|
36
|
+
|
|
37
|
+
def add_error_handler(self, handler: ErrorHandler) -> None:
|
|
38
|
+
self._error_handlers.append(handler)
|
|
39
|
+
|
|
40
|
+
def create(
|
|
41
|
+
self,
|
|
42
|
+
coroutine: Coroutine[Any, Any, Any],
|
|
43
|
+
*,
|
|
44
|
+
name: str | None = None,
|
|
45
|
+
on_error: ErrorHandler | None = None,
|
|
46
|
+
) -> asyncio.Task[Any]:
|
|
47
|
+
if self._closed:
|
|
48
|
+
msg = f"TaskSupervisor for {self._source} already closed"
|
|
49
|
+
raise RuntimeError(msg)
|
|
50
|
+
task = asyncio.create_task(coroutine, name=name)
|
|
51
|
+
self._tasks.add(task)
|
|
52
|
+
task.add_done_callback(lambda t: self._on_done(t, on_error))
|
|
53
|
+
return task
|
|
54
|
+
|
|
55
|
+
def _on_done(self, task: asyncio.Task[Any], on_error: ErrorHandler | None) -> None:
|
|
56
|
+
self._tasks.discard(task)
|
|
57
|
+
if task.cancelled():
|
|
58
|
+
return
|
|
59
|
+
try:
|
|
60
|
+
task.result()
|
|
61
|
+
except Exception as exc:
|
|
62
|
+
handled = False
|
|
63
|
+
if on_error is not None:
|
|
64
|
+
try:
|
|
65
|
+
on_error(task, exc)
|
|
66
|
+
handled = True
|
|
67
|
+
except Exception:
|
|
68
|
+
logger.exception(
|
|
69
|
+
"Error in task-specific error handler",
|
|
70
|
+
source=self._source,
|
|
71
|
+
)
|
|
72
|
+
if not handled:
|
|
73
|
+
for handler in self._error_handlers:
|
|
74
|
+
try:
|
|
75
|
+
handler(task, exc)
|
|
76
|
+
handled = True
|
|
77
|
+
except Exception:
|
|
78
|
+
msg = "Error in supervisor error handler"
|
|
79
|
+
logger.exception(msg, source=self._source)
|
|
80
|
+
if not handled:
|
|
81
|
+
logger.exception("Unhandled error in task", source=self._source)
|
|
82
|
+
|
|
83
|
+
async def shutdown(self) -> None:
|
|
84
|
+
self._closed = True
|
|
85
|
+
if not self._tasks:
|
|
86
|
+
return
|
|
87
|
+
tasks = list(self._tasks)
|
|
88
|
+
for task in tasks:
|
|
89
|
+
task.cancel()
|
|
90
|
+
for task in tasks:
|
|
91
|
+
with suppress(asyncio.CancelledError):
|
|
92
|
+
await task
|
|
93
|
+
self._tasks.clear()
|
acp/terminal_handle.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Terminal handle implementation. NOTE: not integrated yet."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from acp.acp_requests import ACPRequests
|
|
10
|
+
from acp.schema import TerminalOutputResponse, WaitForTerminalExitResponse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TerminalHandle:
|
|
14
|
+
"""Handle for a terminal session."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, terminal_id: str, requests: ACPRequests) -> None:
|
|
17
|
+
self.terminal_id = terminal_id
|
|
18
|
+
self._requests = requests
|
|
19
|
+
|
|
20
|
+
async def current_output(self) -> TerminalOutputResponse:
|
|
21
|
+
return await self._requests.terminal_output(self.terminal_id)
|
|
22
|
+
|
|
23
|
+
async def wait_for_exit(self) -> WaitForTerminalExitResponse:
|
|
24
|
+
return await self._requests.wait_for_terminal_exit(self.terminal_id)
|
|
25
|
+
|
|
26
|
+
async def kill(self) -> None:
|
|
27
|
+
return await self._requests.kill_terminal(self.terminal_id)
|
|
28
|
+
|
|
29
|
+
async def release(self) -> None:
|
|
30
|
+
return await self._requests.release_terminal(self.terminal_id)
|