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/notifications.py
ADDED
|
@@ -0,0 +1,832 @@
|
|
|
1
|
+
"""ACP notification helper for clean session update API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from typing import TYPE_CHECKING, Any, assert_never
|
|
7
|
+
|
|
8
|
+
from pydantic_ai import ModelRequest, ModelResponse, ToolReturnPart, UserPromptPart
|
|
9
|
+
|
|
10
|
+
from acp.schema import (
|
|
11
|
+
AgentMessageChunk,
|
|
12
|
+
AgentPlanUpdate,
|
|
13
|
+
AgentThoughtChunk,
|
|
14
|
+
AudioContentBlock,
|
|
15
|
+
AvailableCommand,
|
|
16
|
+
AvailableCommandsUpdate,
|
|
17
|
+
BlobResourceContents,
|
|
18
|
+
ContentToolCallContent,
|
|
19
|
+
# CurrentModelUpdate,
|
|
20
|
+
CurrentModeUpdate,
|
|
21
|
+
EmbeddedResourceContentBlock,
|
|
22
|
+
FileEditToolCallContent,
|
|
23
|
+
ImageContentBlock,
|
|
24
|
+
ResourceContentBlock,
|
|
25
|
+
SessionNotification,
|
|
26
|
+
TerminalToolCallContent,
|
|
27
|
+
TextContentBlock,
|
|
28
|
+
TextResourceContents,
|
|
29
|
+
ToolCallProgress,
|
|
30
|
+
ToolCallStart,
|
|
31
|
+
UserMessageChunk,
|
|
32
|
+
)
|
|
33
|
+
from acp.schema.tool_call import ToolCallLocation
|
|
34
|
+
from acp.tool_call_reporter import ToolCallReporter
|
|
35
|
+
from acp.utils import generate_tool_title, infer_tool_kind, to_acp_content_blocks
|
|
36
|
+
from agentpool.log import get_logger
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from collections.abc import Sequence
|
|
41
|
+
from datetime import datetime
|
|
42
|
+
|
|
43
|
+
from acp import (
|
|
44
|
+
AvailableCommand,
|
|
45
|
+
Client,
|
|
46
|
+
PlanEntry,
|
|
47
|
+
ToolCallContent,
|
|
48
|
+
ToolCallKind,
|
|
49
|
+
ToolCallStatus,
|
|
50
|
+
)
|
|
51
|
+
from acp.schema import Audience
|
|
52
|
+
|
|
53
|
+
ContentType = Sequence[ToolCallContent | str]
|
|
54
|
+
|
|
55
|
+
logger = get_logger(__name__)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ACPNotifications:
|
|
59
|
+
"""Clean API for creating and sending ACP session notifications.
|
|
60
|
+
|
|
61
|
+
Provides convenient methods for common notification patterns,
|
|
62
|
+
handling both creation and sending in a single call.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, client: Client, session_id: str) -> None:
|
|
66
|
+
"""Initialize notifications helper.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
client: ACP client and session_id
|
|
70
|
+
session_id: Session identifier
|
|
71
|
+
"""
|
|
72
|
+
self.client = client
|
|
73
|
+
self.id = session_id
|
|
74
|
+
self.log = logger.bind(session_id=session_id)
|
|
75
|
+
self._tool_call_inputs: dict[str, dict[str, Any]] = {}
|
|
76
|
+
|
|
77
|
+
async def create_tool_reporter(
|
|
78
|
+
self,
|
|
79
|
+
tool_call_id: str,
|
|
80
|
+
title: str,
|
|
81
|
+
*,
|
|
82
|
+
kind: ToolCallKind | None = None,
|
|
83
|
+
status: ToolCallStatus = "pending",
|
|
84
|
+
locations: Sequence[ToolCallLocation] | None = None,
|
|
85
|
+
content: Sequence[ToolCallContent] | None = None,
|
|
86
|
+
raw_input: Any | None = None,
|
|
87
|
+
auto_start: bool = True,
|
|
88
|
+
) -> ToolCallReporter:
|
|
89
|
+
"""Create a stateful tool call reporter.
|
|
90
|
+
|
|
91
|
+
The reporter maintains the current state and sends updates when fields change,
|
|
92
|
+
avoiding the need to repeat unchanged fields on every update.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
tool_call_id: Unique identifier for this tool call
|
|
96
|
+
title: Human-readable title describing the tool action
|
|
97
|
+
kind: Category of tool being invoked
|
|
98
|
+
status: Initial execution status
|
|
99
|
+
locations: File locations affected by this tool call
|
|
100
|
+
content: Initial content produced by the tool call
|
|
101
|
+
raw_input: Raw input parameters sent to the tool
|
|
102
|
+
auto_start: Whether to send the initial notification immediately
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
A ToolCallReporter instance for sending updates
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
```python
|
|
109
|
+
reporter = await notifications.create_tool_reporter(
|
|
110
|
+
tool_call_id="abc123",
|
|
111
|
+
title="Reading file",
|
|
112
|
+
kind="read",
|
|
113
|
+
)
|
|
114
|
+
await reporter.update(status="in_progress", message="Opening...")
|
|
115
|
+
await reporter.update(message="Processing...")
|
|
116
|
+
await reporter.complete(message="Done!")
|
|
117
|
+
```
|
|
118
|
+
"""
|
|
119
|
+
reporter = ToolCallReporter(
|
|
120
|
+
notifications=self,
|
|
121
|
+
tool_call_id=tool_call_id,
|
|
122
|
+
title=title,
|
|
123
|
+
kind=kind,
|
|
124
|
+
status=status,
|
|
125
|
+
locations=locations,
|
|
126
|
+
content=content,
|
|
127
|
+
raw_input=raw_input,
|
|
128
|
+
)
|
|
129
|
+
if auto_start:
|
|
130
|
+
await reporter.start()
|
|
131
|
+
return reporter
|
|
132
|
+
|
|
133
|
+
async def tool_call(
|
|
134
|
+
self,
|
|
135
|
+
tool_name: str,
|
|
136
|
+
*,
|
|
137
|
+
tool_input: dict[str, Any],
|
|
138
|
+
tool_output: Any,
|
|
139
|
+
status: ToolCallStatus = "completed",
|
|
140
|
+
tool_call_id: str | None = None,
|
|
141
|
+
) -> None:
|
|
142
|
+
"""Send tool execution as ACP tool call update.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
tool_name: Name of the tool that was executed
|
|
146
|
+
tool_input: Input parameters passed to the tool
|
|
147
|
+
tool_output: Output returned by the tool
|
|
148
|
+
status: Execution status
|
|
149
|
+
tool_call_id: Tool call identifier
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
SessionNotification with tool call update
|
|
153
|
+
"""
|
|
154
|
+
# Create tool call content from output
|
|
155
|
+
content: list[ContentToolCallContent] = []
|
|
156
|
+
if tool_output is not None:
|
|
157
|
+
# Handle pre-converted raw content blocks
|
|
158
|
+
if isinstance(tool_output, list) and all(
|
|
159
|
+
isinstance(item, (TextContentBlock, ImageContentBlock, AudioContentBlock))
|
|
160
|
+
for item in tool_output
|
|
161
|
+
):
|
|
162
|
+
# Wrap raw blocks in ContentToolCallContent
|
|
163
|
+
content = [ContentToolCallContent(content=block) for block in tool_output]
|
|
164
|
+
else:
|
|
165
|
+
# Fallback to string conversion
|
|
166
|
+
output_text = str(tool_output)
|
|
167
|
+
content.append(ContentToolCallContent.text(text=output_text))
|
|
168
|
+
|
|
169
|
+
# Extract file locations if present
|
|
170
|
+
locations = [
|
|
171
|
+
ToolCallLocation(path=value)
|
|
172
|
+
for key, value in tool_input.items()
|
|
173
|
+
if key in {"path", "file_path", "filepath"} and isinstance(value, str)
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
# Generate a descriptive title from tool name and inputs
|
|
177
|
+
title = generate_tool_title(tool_name, tool_input)
|
|
178
|
+
|
|
179
|
+
# Use appropriate notification type based on status
|
|
180
|
+
if status == "pending":
|
|
181
|
+
await self.tool_call_start(
|
|
182
|
+
tool_call_id=tool_call_id or f"{tool_name}_{hash(str(tool_input))}",
|
|
183
|
+
title=title,
|
|
184
|
+
kind=infer_tool_kind(tool_name),
|
|
185
|
+
locations=locations or None,
|
|
186
|
+
content=content or None,
|
|
187
|
+
raw_input=tool_input,
|
|
188
|
+
)
|
|
189
|
+
else:
|
|
190
|
+
# For in_progress, completed, and failed statuses
|
|
191
|
+
await self.tool_call_progress(
|
|
192
|
+
tool_call_id=tool_call_id or f"{tool_name}_{hash(str(tool_input))}",
|
|
193
|
+
title=title,
|
|
194
|
+
status=status,
|
|
195
|
+
locations=locations or None,
|
|
196
|
+
content=content or None,
|
|
197
|
+
raw_output=tool_output,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
async def tool_call_start(
|
|
201
|
+
self,
|
|
202
|
+
tool_call_id: str,
|
|
203
|
+
title: str,
|
|
204
|
+
*,
|
|
205
|
+
kind: ToolCallKind | None = None,
|
|
206
|
+
locations: Sequence[ToolCallLocation] | None = None,
|
|
207
|
+
content: ContentType | None = None,
|
|
208
|
+
raw_input: dict[str, Any] | None = None,
|
|
209
|
+
) -> None:
|
|
210
|
+
"""Send a tool call start notification.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
tool_call_id: Tool call identifier
|
|
214
|
+
title: Optional title for the start notification
|
|
215
|
+
kind: Optional tool call kind
|
|
216
|
+
locations: Optional sequence of file/path locations
|
|
217
|
+
content: Optional sequence of content blocks
|
|
218
|
+
raw_input: Optional raw input data
|
|
219
|
+
"""
|
|
220
|
+
start = ToolCallStart(
|
|
221
|
+
tool_call_id=tool_call_id,
|
|
222
|
+
status="pending",
|
|
223
|
+
title=title,
|
|
224
|
+
kind=kind,
|
|
225
|
+
locations=locations,
|
|
226
|
+
content=[
|
|
227
|
+
ContentToolCallContent.text(text=i) if isinstance(i, str) else i
|
|
228
|
+
for i in content or []
|
|
229
|
+
],
|
|
230
|
+
raw_input=raw_input,
|
|
231
|
+
)
|
|
232
|
+
notification = SessionNotification(session_id=self.id, update=start)
|
|
233
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
234
|
+
|
|
235
|
+
async def tool_call_progress(
|
|
236
|
+
self,
|
|
237
|
+
tool_call_id: str,
|
|
238
|
+
status: ToolCallStatus,
|
|
239
|
+
*,
|
|
240
|
+
title: str | None = None,
|
|
241
|
+
raw_output: Any | None = None,
|
|
242
|
+
kind: ToolCallKind | None = None,
|
|
243
|
+
locations: Sequence[ToolCallLocation] | None = None,
|
|
244
|
+
content: ContentType | None = None,
|
|
245
|
+
) -> None:
|
|
246
|
+
"""Send a generic progress notification.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
tool_call_id: Tool call identifier
|
|
250
|
+
status: Progress status
|
|
251
|
+
title: Optional title for the progress update
|
|
252
|
+
raw_output: Optional raw output text
|
|
253
|
+
kind: Optional kind of tool call
|
|
254
|
+
locations: Optional sequence of file/path locations
|
|
255
|
+
content: Optional sequence of content blocks or strings to display
|
|
256
|
+
"""
|
|
257
|
+
progress = ToolCallProgress(
|
|
258
|
+
tool_call_id=tool_call_id,
|
|
259
|
+
status=status,
|
|
260
|
+
title=title,
|
|
261
|
+
raw_output=raw_output,
|
|
262
|
+
kind=kind,
|
|
263
|
+
locations=locations,
|
|
264
|
+
content=[
|
|
265
|
+
ContentToolCallContent.text(i) if isinstance(i, str) else i for i in content or []
|
|
266
|
+
],
|
|
267
|
+
)
|
|
268
|
+
notification = SessionNotification(session_id=self.id, update=progress)
|
|
269
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
270
|
+
|
|
271
|
+
async def tool_call_update(
|
|
272
|
+
self,
|
|
273
|
+
tool_call_id: str,
|
|
274
|
+
*,
|
|
275
|
+
title: str | None = None,
|
|
276
|
+
status: ToolCallStatus | None = None,
|
|
277
|
+
kind: ToolCallKind | None = None,
|
|
278
|
+
locations: Sequence[ToolCallLocation] | None = None,
|
|
279
|
+
content: ContentType | None = None,
|
|
280
|
+
raw_output: Any | None = None,
|
|
281
|
+
) -> None:
|
|
282
|
+
"""Send a tool call update with only the provided fields.
|
|
283
|
+
|
|
284
|
+
Unlike tool_call_progress, all fields are optional. Only fields
|
|
285
|
+
that are explicitly provided (not None) will be included in the
|
|
286
|
+
notification, following the ACP spec which states that only
|
|
287
|
+
changed fields need to be sent.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
tool_call_id: Tool call identifier (required)
|
|
291
|
+
title: Update the human-readable title
|
|
292
|
+
status: Update execution status
|
|
293
|
+
kind: Update tool kind
|
|
294
|
+
locations: Update file locations
|
|
295
|
+
content: Update content blocks
|
|
296
|
+
raw_output: Update raw output
|
|
297
|
+
"""
|
|
298
|
+
update = ToolCallProgress(
|
|
299
|
+
tool_call_id=tool_call_id,
|
|
300
|
+
status=status,
|
|
301
|
+
title=title,
|
|
302
|
+
raw_output=raw_output,
|
|
303
|
+
kind=kind,
|
|
304
|
+
locations=locations,
|
|
305
|
+
content=[
|
|
306
|
+
ContentToolCallContent.text(i) if isinstance(i, str) else i for i in content or []
|
|
307
|
+
]
|
|
308
|
+
if content
|
|
309
|
+
else None,
|
|
310
|
+
)
|
|
311
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
312
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
313
|
+
|
|
314
|
+
async def file_edit_progress(
|
|
315
|
+
self,
|
|
316
|
+
tool_call_id: str,
|
|
317
|
+
path: str,
|
|
318
|
+
old_text: str,
|
|
319
|
+
new_text: str,
|
|
320
|
+
*,
|
|
321
|
+
status: ToolCallStatus = "completed",
|
|
322
|
+
title: str | None = None,
|
|
323
|
+
changed_lines: Sequence[int] | None = None,
|
|
324
|
+
) -> None:
|
|
325
|
+
"""Send a notification with file edit content.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
tool_call_id: Tool call identifier
|
|
329
|
+
path: File path being edited
|
|
330
|
+
old_text: Original file content
|
|
331
|
+
new_text: New file content
|
|
332
|
+
status: Progress status (default: 'completed')
|
|
333
|
+
title: Optional title
|
|
334
|
+
changed_lines: List of line numbers where changes occurred (1-based)
|
|
335
|
+
"""
|
|
336
|
+
content = FileEditToolCallContent(path=path, old_text=old_text, new_text=new_text)
|
|
337
|
+
|
|
338
|
+
# Create locations for changed lines or fallback to file location
|
|
339
|
+
if changed_lines:
|
|
340
|
+
locations = [ToolCallLocation(path=path, line=i) for i in changed_lines]
|
|
341
|
+
else:
|
|
342
|
+
locations = [ToolCallLocation(path=path)]
|
|
343
|
+
|
|
344
|
+
await self.tool_call_progress(
|
|
345
|
+
tool_call_id=tool_call_id,
|
|
346
|
+
status=status,
|
|
347
|
+
title=title,
|
|
348
|
+
locations=locations,
|
|
349
|
+
content=[content],
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
async def terminal_progress(
|
|
353
|
+
self,
|
|
354
|
+
tool_call_id: str,
|
|
355
|
+
terminal_id: str,
|
|
356
|
+
*,
|
|
357
|
+
status: ToolCallStatus = "completed",
|
|
358
|
+
title: str | None = None,
|
|
359
|
+
raw_output: str | None = None,
|
|
360
|
+
) -> None:
|
|
361
|
+
"""Send a notification with terminal content.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
tool_call_id: Tool call identifier
|
|
365
|
+
terminal_id: Terminal identifier
|
|
366
|
+
status: Progress status (default: 'completed')
|
|
367
|
+
title: Optional title
|
|
368
|
+
raw_output: Optional raw output text
|
|
369
|
+
"""
|
|
370
|
+
terminal_content = TerminalToolCallContent(terminal_id=terminal_id)
|
|
371
|
+
await self.tool_call_progress(
|
|
372
|
+
tool_call_id=tool_call_id,
|
|
373
|
+
status=status,
|
|
374
|
+
title=title,
|
|
375
|
+
raw_output=raw_output,
|
|
376
|
+
content=[terminal_content],
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
async def update_plan(self, entries: Sequence[PlanEntry]) -> None:
|
|
380
|
+
"""Send a plan notification.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
entries: List of plan entries to send
|
|
384
|
+
"""
|
|
385
|
+
plan = AgentPlanUpdate(entries=entries)
|
|
386
|
+
notification = SessionNotification(session_id=self.id, update=plan)
|
|
387
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
388
|
+
|
|
389
|
+
async def update_commands(self, commands: list[AvailableCommand]) -> None:
|
|
390
|
+
"""Send a command update notification.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
commands: List of available commands to send
|
|
394
|
+
"""
|
|
395
|
+
update = AvailableCommandsUpdate(available_commands=commands)
|
|
396
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
397
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
398
|
+
|
|
399
|
+
async def send_agent_text(
|
|
400
|
+
self,
|
|
401
|
+
message: str,
|
|
402
|
+
*,
|
|
403
|
+
audience: Audience | None = None,
|
|
404
|
+
last_modified: datetime | str | None = None,
|
|
405
|
+
priority: float | None = None,
|
|
406
|
+
) -> None:
|
|
407
|
+
"""Send a text message notification.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
message: Text message to send
|
|
411
|
+
audience: Audience to send the message to
|
|
412
|
+
last_modified: Last modified timestamp
|
|
413
|
+
priority: Priority of the message
|
|
414
|
+
"""
|
|
415
|
+
update = AgentMessageChunk.text(
|
|
416
|
+
text=message,
|
|
417
|
+
audience=audience,
|
|
418
|
+
last_modified=last_modified,
|
|
419
|
+
priority=priority,
|
|
420
|
+
)
|
|
421
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
422
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
423
|
+
|
|
424
|
+
async def send_agent_thought(
|
|
425
|
+
self,
|
|
426
|
+
message: str,
|
|
427
|
+
*,
|
|
428
|
+
audience: Audience | None = None,
|
|
429
|
+
last_modified: datetime | str | None = None,
|
|
430
|
+
priority: float | None = None,
|
|
431
|
+
) -> None:
|
|
432
|
+
"""Send a text message notification.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
message: Text message to send
|
|
436
|
+
audience: Audience to send the message to
|
|
437
|
+
last_modified: Last modified date of the message
|
|
438
|
+
priority: Priority of the message
|
|
439
|
+
"""
|
|
440
|
+
update = AgentThoughtChunk.text(
|
|
441
|
+
text=message,
|
|
442
|
+
audience=audience,
|
|
443
|
+
last_modified=last_modified,
|
|
444
|
+
priority=priority,
|
|
445
|
+
)
|
|
446
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
447
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
448
|
+
|
|
449
|
+
async def send_user_message(
|
|
450
|
+
self,
|
|
451
|
+
message: str,
|
|
452
|
+
*,
|
|
453
|
+
audience: Audience | None = None,
|
|
454
|
+
last_modified: datetime | str | None = None,
|
|
455
|
+
priority: float | None = None,
|
|
456
|
+
) -> None:
|
|
457
|
+
"""Send a user message notification.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
message: Text message to send
|
|
461
|
+
audience: Audience to send the message to
|
|
462
|
+
last_modified: Last modified date of the message
|
|
463
|
+
priority: Priority of the message
|
|
464
|
+
"""
|
|
465
|
+
update = UserMessageChunk.text(
|
|
466
|
+
text=message,
|
|
467
|
+
audience=audience,
|
|
468
|
+
last_modified=last_modified,
|
|
469
|
+
priority=priority,
|
|
470
|
+
)
|
|
471
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
472
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
473
|
+
|
|
474
|
+
async def send_user_image(
|
|
475
|
+
self,
|
|
476
|
+
data: str | bytes,
|
|
477
|
+
mime_type: str,
|
|
478
|
+
*,
|
|
479
|
+
uri: str | None = None,
|
|
480
|
+
audience: Audience | None = None,
|
|
481
|
+
last_modified: datetime | str | None = None,
|
|
482
|
+
priority: float | None = None,
|
|
483
|
+
) -> None:
|
|
484
|
+
"""Send a user image notification.
|
|
485
|
+
|
|
486
|
+
Args:
|
|
487
|
+
data: Base64-encoded image data
|
|
488
|
+
mime_type: MIME type of the image
|
|
489
|
+
uri: Optional URI of the image
|
|
490
|
+
audience: Optional audience for the content block
|
|
491
|
+
last_modified: Optional last modified timestamp for the content block
|
|
492
|
+
priority: Optional priority for the content block
|
|
493
|
+
"""
|
|
494
|
+
update = UserMessageChunk.image(
|
|
495
|
+
data=data,
|
|
496
|
+
mime_type=mime_type,
|
|
497
|
+
uri=uri,
|
|
498
|
+
audience=audience,
|
|
499
|
+
last_modified=last_modified,
|
|
500
|
+
priority=priority,
|
|
501
|
+
)
|
|
502
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
503
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
504
|
+
|
|
505
|
+
async def send_user_audio(
|
|
506
|
+
self,
|
|
507
|
+
data: str | bytes,
|
|
508
|
+
mime_type: str,
|
|
509
|
+
*,
|
|
510
|
+
audience: Audience | None = None,
|
|
511
|
+
last_modified: datetime | str | None = None,
|
|
512
|
+
priority: float | None = None,
|
|
513
|
+
) -> None:
|
|
514
|
+
"""Send a user audio notification.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
data: Base64-encoded audio data
|
|
518
|
+
mime_type: MIME type of the audio
|
|
519
|
+
uri: Optional URI for the audio
|
|
520
|
+
audience: Optional audience for the content block
|
|
521
|
+
last_modified: Optional last modified timestamp for the content block
|
|
522
|
+
priority: Optional priority for the content block
|
|
523
|
+
"""
|
|
524
|
+
update = UserMessageChunk.audio(
|
|
525
|
+
data=data,
|
|
526
|
+
mime_type=mime_type,
|
|
527
|
+
audience=audience,
|
|
528
|
+
last_modified=last_modified,
|
|
529
|
+
priority=priority,
|
|
530
|
+
)
|
|
531
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
532
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
533
|
+
|
|
534
|
+
async def send_user_resource(
|
|
535
|
+
self,
|
|
536
|
+
uri: str,
|
|
537
|
+
name: str,
|
|
538
|
+
*,
|
|
539
|
+
description: str | None = None,
|
|
540
|
+
mime_type: str | None = None,
|
|
541
|
+
size: int | None = None,
|
|
542
|
+
title: str | None = None,
|
|
543
|
+
audience: Audience | None = None,
|
|
544
|
+
last_modified: datetime | str | None = None,
|
|
545
|
+
priority: float | None = None,
|
|
546
|
+
) -> None:
|
|
547
|
+
"""Send a user resource link notification.
|
|
548
|
+
|
|
549
|
+
Args:
|
|
550
|
+
uri: URI of the resource
|
|
551
|
+
name: Name of the resource
|
|
552
|
+
description: Optional description of the resource
|
|
553
|
+
mime_type: Optional MIME type of the resource
|
|
554
|
+
size: Optional size of the resource in bytes
|
|
555
|
+
title: Optional title of the resource
|
|
556
|
+
audience: Optional audience for the content block
|
|
557
|
+
last_modified: Optional last modified timestamp for the content block
|
|
558
|
+
priority: Optional priority for the content block
|
|
559
|
+
"""
|
|
560
|
+
update = UserMessageChunk.resource(
|
|
561
|
+
uri=uri,
|
|
562
|
+
name=name,
|
|
563
|
+
description=description,
|
|
564
|
+
mime_type=mime_type,
|
|
565
|
+
size=size,
|
|
566
|
+
title=title,
|
|
567
|
+
audience=audience,
|
|
568
|
+
last_modified=last_modified,
|
|
569
|
+
priority=priority,
|
|
570
|
+
)
|
|
571
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
572
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
573
|
+
|
|
574
|
+
async def replay(self, messages: Sequence[ModelRequest | ModelResponse]) -> None:
|
|
575
|
+
"""Replay a sequence of model messages as notifications.
|
|
576
|
+
|
|
577
|
+
Args:
|
|
578
|
+
messages: Sequence of ModelRequest and ModelResponse objects to replay
|
|
579
|
+
"""
|
|
580
|
+
for message in messages:
|
|
581
|
+
try:
|
|
582
|
+
match message:
|
|
583
|
+
case ModelRequest():
|
|
584
|
+
await self._replay_request(message)
|
|
585
|
+
case ModelResponse():
|
|
586
|
+
await self._replay_response(message)
|
|
587
|
+
case _ as unreachable:
|
|
588
|
+
assert_never(unreachable)
|
|
589
|
+
except Exception as e:
|
|
590
|
+
self.log.exception("Failed to replay message", error=str(e))
|
|
591
|
+
|
|
592
|
+
async def _replay_request(self, request: ModelRequest) -> None:
|
|
593
|
+
"""Replay a ModelRequest by converting it to appropriate ACP notifications."""
|
|
594
|
+
for part in request.parts:
|
|
595
|
+
match part:
|
|
596
|
+
case UserPromptPart(content=content):
|
|
597
|
+
# Handle both str and Sequence[UserContent] types
|
|
598
|
+
if isinstance(content, str):
|
|
599
|
+
await self.send_user_message(content)
|
|
600
|
+
else:
|
|
601
|
+
# Convert multi-modal content to appropriate ACP content blocks
|
|
602
|
+
|
|
603
|
+
converted_content = to_acp_content_blocks(content)
|
|
604
|
+
# Send each content block as separate notifications
|
|
605
|
+
for block in converted_content:
|
|
606
|
+
match block:
|
|
607
|
+
case TextContentBlock(text=text):
|
|
608
|
+
await self.send_user_message(text)
|
|
609
|
+
case ImageContentBlock() as img_block:
|
|
610
|
+
await self.send_user_image(
|
|
611
|
+
data=img_block.data,
|
|
612
|
+
mime_type=img_block.mime_type,
|
|
613
|
+
uri=img_block.uri,
|
|
614
|
+
audience=img_block.annotations.audience
|
|
615
|
+
if img_block.annotations
|
|
616
|
+
else None,
|
|
617
|
+
last_modified=img_block.annotations.last_modified
|
|
618
|
+
if img_block.annotations
|
|
619
|
+
else None,
|
|
620
|
+
priority=img_block.annotations.priority
|
|
621
|
+
if img_block.annotations
|
|
622
|
+
else None,
|
|
623
|
+
)
|
|
624
|
+
case AudioContentBlock() as audio_block:
|
|
625
|
+
await self.send_user_audio(
|
|
626
|
+
data=audio_block.data,
|
|
627
|
+
mime_type=audio_block.mime_type,
|
|
628
|
+
audience=audio_block.annotations.audience
|
|
629
|
+
if audio_block.annotations
|
|
630
|
+
else None,
|
|
631
|
+
last_modified=audio_block.annotations.last_modified
|
|
632
|
+
if audio_block.annotations
|
|
633
|
+
else None,
|
|
634
|
+
priority=audio_block.annotations.priority
|
|
635
|
+
if audio_block.annotations
|
|
636
|
+
else None,
|
|
637
|
+
)
|
|
638
|
+
case ResourceContentBlock() as resource_block:
|
|
639
|
+
await self.send_user_resource(
|
|
640
|
+
uri=resource_block.uri,
|
|
641
|
+
name=resource_block.name,
|
|
642
|
+
description=resource_block.description,
|
|
643
|
+
mime_type=resource_block.mime_type,
|
|
644
|
+
size=resource_block.size,
|
|
645
|
+
title=resource_block.title,
|
|
646
|
+
audience=resource_block.annotations.audience
|
|
647
|
+
if resource_block.annotations
|
|
648
|
+
else None,
|
|
649
|
+
last_modified=resource_block.annotations.last_modified
|
|
650
|
+
if resource_block.annotations
|
|
651
|
+
else None,
|
|
652
|
+
priority=resource_block.annotations.priority
|
|
653
|
+
if resource_block.annotations
|
|
654
|
+
else None,
|
|
655
|
+
)
|
|
656
|
+
case EmbeddedResourceContentBlock() as embedded_block:
|
|
657
|
+
# Handle embedded resources with proper
|
|
658
|
+
# pattern matching
|
|
659
|
+
match embedded_block.resource:
|
|
660
|
+
case TextResourceContents(text=text):
|
|
661
|
+
await self.send_user_message(text)
|
|
662
|
+
case BlobResourceContents() as blob_resource:
|
|
663
|
+
blob_size = len(blob_resource.blob) * 3 // 4
|
|
664
|
+
size_mb = blob_size / (1024 * 1024)
|
|
665
|
+
mime = blob_resource.mime_type or "unknown"
|
|
666
|
+
msg = f"Embedded resource: {mime} ({size_mb:.2f} MB)"
|
|
667
|
+
await self.send_user_message(msg)
|
|
668
|
+
case _ as unreachable:
|
|
669
|
+
assert_never(unreachable) # ty: ignore[type-assertion-failure]
|
|
670
|
+
case _ as unreachable:
|
|
671
|
+
assert_never(unreachable) # ty: ignore[type-assertion-failure]
|
|
672
|
+
|
|
673
|
+
case ToolReturnPart(
|
|
674
|
+
content=content, tool_name=tool_name, tool_call_id=tool_call_id
|
|
675
|
+
):
|
|
676
|
+
converted_content = to_acp_content_blocks(content)
|
|
677
|
+
tool_input = self._tool_call_inputs.get(tool_call_id, {})
|
|
678
|
+
await self.tool_call(
|
|
679
|
+
tool_name=tool_name,
|
|
680
|
+
tool_input=tool_input,
|
|
681
|
+
tool_output=converted_content,
|
|
682
|
+
status="completed",
|
|
683
|
+
tool_call_id=tool_call_id,
|
|
684
|
+
)
|
|
685
|
+
# Clean up stored input
|
|
686
|
+
self._tool_call_inputs.pop(tool_call_id, None)
|
|
687
|
+
|
|
688
|
+
case _:
|
|
689
|
+
typ = type(part).__name__
|
|
690
|
+
self.log.debug("Unhandled request part type", part_type=typ)
|
|
691
|
+
|
|
692
|
+
async def _replay_response(self, response: ModelResponse) -> None:
|
|
693
|
+
"""Replay a ModelResponse by converting it to appropriate ACP notifications."""
|
|
694
|
+
from pydantic_ai import TextPart, ThinkingPart, ToolCallPart
|
|
695
|
+
|
|
696
|
+
for part in response.parts:
|
|
697
|
+
match part:
|
|
698
|
+
case TextPart(content=content):
|
|
699
|
+
await self.send_agent_text(content)
|
|
700
|
+
|
|
701
|
+
case ThinkingPart(content=content):
|
|
702
|
+
await self.send_agent_thought(content)
|
|
703
|
+
|
|
704
|
+
case ToolCallPart(tool_call_id=tool_call_id):
|
|
705
|
+
# Store tool call inputs for later use with ToolReturnPart
|
|
706
|
+
tool_input = part.args_as_dict()
|
|
707
|
+
self._tool_call_inputs[tool_call_id] = tool_input
|
|
708
|
+
# Skip sending notification - ACP protocol overrides previous
|
|
709
|
+
# tool call state
|
|
710
|
+
|
|
711
|
+
case _:
|
|
712
|
+
typ = type(part).__name__
|
|
713
|
+
self.log.debug("Unhandled response part type", part_type=typ)
|
|
714
|
+
|
|
715
|
+
async def send_agent_image(
|
|
716
|
+
self,
|
|
717
|
+
data: str | bytes,
|
|
718
|
+
mime_type: str,
|
|
719
|
+
*,
|
|
720
|
+
uri: str | None = None,
|
|
721
|
+
audience: Audience | None = None,
|
|
722
|
+
last_modified: datetime | str | None = None,
|
|
723
|
+
priority: float | None = None,
|
|
724
|
+
) -> None:
|
|
725
|
+
"""Send an image message notification.
|
|
726
|
+
|
|
727
|
+
Args:
|
|
728
|
+
data: Base64-encoded image data
|
|
729
|
+
mime_type: MIME type of the image (e.g., 'image/png')
|
|
730
|
+
uri: Optional URI reference for the image
|
|
731
|
+
audience: Optional audience for the image
|
|
732
|
+
last_modified: Optional last modified timestamp for the image
|
|
733
|
+
priority: Optional priority for the image
|
|
734
|
+
"""
|
|
735
|
+
update = AgentMessageChunk.image(
|
|
736
|
+
data=data,
|
|
737
|
+
mime_type=mime_type,
|
|
738
|
+
uri=uri,
|
|
739
|
+
audience=audience,
|
|
740
|
+
last_modified=last_modified,
|
|
741
|
+
priority=priority,
|
|
742
|
+
)
|
|
743
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
744
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
745
|
+
|
|
746
|
+
async def update_session_mode(self, mode_id: str) -> None:
|
|
747
|
+
"""Send a session mode update notification.
|
|
748
|
+
|
|
749
|
+
Args:
|
|
750
|
+
mode_id: Unique identifier for the session mode
|
|
751
|
+
"""
|
|
752
|
+
update = CurrentModeUpdate(current_mode_id=mode_id)
|
|
753
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
754
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
755
|
+
|
|
756
|
+
# async def update_session_model(self, model_id: str) -> None:
|
|
757
|
+
# """Send a session model update notification.
|
|
758
|
+
|
|
759
|
+
# Args:
|
|
760
|
+
# model_id: Unique identifier for the model
|
|
761
|
+
# """
|
|
762
|
+
# update = CurrentModelUpdate(current_model_id=model_id)
|
|
763
|
+
# notification = SessionNotification(session_id=self.id, update=update)
|
|
764
|
+
# await self.client.session_update(notification)
|
|
765
|
+
|
|
766
|
+
async def send_agent_audio(
|
|
767
|
+
self,
|
|
768
|
+
data: str | bytes,
|
|
769
|
+
mime_type: str,
|
|
770
|
+
*,
|
|
771
|
+
audience: Audience | None = None,
|
|
772
|
+
last_modified: datetime | str | None = None,
|
|
773
|
+
priority: float | None = None,
|
|
774
|
+
) -> None:
|
|
775
|
+
"""Send an audio message notification.
|
|
776
|
+
|
|
777
|
+
Args:
|
|
778
|
+
data: Base64-encoded audio data
|
|
779
|
+
mime_type: MIME type of the audio (e.g., 'audio/wav')
|
|
780
|
+
audience: Optional audience for the audio
|
|
781
|
+
last_modified: Optional last modified timestamp for the audio
|
|
782
|
+
priority: Optional priority for the audio
|
|
783
|
+
"""
|
|
784
|
+
update = AgentMessageChunk.audio(
|
|
785
|
+
data=data,
|
|
786
|
+
mime_type=mime_type,
|
|
787
|
+
last_modified=last_modified,
|
|
788
|
+
priority=priority,
|
|
789
|
+
audience=audience,
|
|
790
|
+
)
|
|
791
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
792
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
793
|
+
|
|
794
|
+
async def send_agent_resource(
|
|
795
|
+
self,
|
|
796
|
+
name: str,
|
|
797
|
+
uri: str,
|
|
798
|
+
*,
|
|
799
|
+
title: str | None = None,
|
|
800
|
+
description: str | None = None,
|
|
801
|
+
mime_type: str | None = None,
|
|
802
|
+
size: int | None = None,
|
|
803
|
+
audience: Audience | None = None,
|
|
804
|
+
last_modified: datetime | str | None = None,
|
|
805
|
+
priority: float | None = None,
|
|
806
|
+
) -> None:
|
|
807
|
+
"""Send a resource reference message notification.
|
|
808
|
+
|
|
809
|
+
Args:
|
|
810
|
+
name: Name of the resource
|
|
811
|
+
uri: URI of the resource
|
|
812
|
+
title: Optional title for the resource
|
|
813
|
+
description: Optional description of the resource
|
|
814
|
+
mime_type: Optional MIME type of the resource
|
|
815
|
+
size: Optional size of the resource in bytes
|
|
816
|
+
audience: Optional audience for the resource
|
|
817
|
+
last_modified: Optional last modified timestamp for the resource
|
|
818
|
+
priority: Optional priority for the resource
|
|
819
|
+
"""
|
|
820
|
+
update = AgentMessageChunk.resource(
|
|
821
|
+
name=name,
|
|
822
|
+
uri=uri,
|
|
823
|
+
title=title,
|
|
824
|
+
description=description,
|
|
825
|
+
mime_type=mime_type,
|
|
826
|
+
size=size,
|
|
827
|
+
audience=audience,
|
|
828
|
+
last_modified=last_modified,
|
|
829
|
+
priority=priority,
|
|
830
|
+
)
|
|
831
|
+
notification = SessionNotification(session_id=self.id, update=update)
|
|
832
|
+
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|