agentpool 2.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of agentpool might be problematic. Click here for more details.
- acp/README.md +64 -0
- acp/__init__.py +172 -0
- acp/__main__.py +10 -0
- acp/acp_requests.py +285 -0
- acp/agent/__init__.py +6 -0
- acp/agent/connection.py +256 -0
- acp/agent/implementations/__init__.py +6 -0
- acp/agent/implementations/debug_server/__init__.py +1 -0
- acp/agent/implementations/debug_server/cli.py +79 -0
- acp/agent/implementations/debug_server/debug.html +234 -0
- acp/agent/implementations/debug_server/debug_server.py +496 -0
- acp/agent/implementations/testing.py +91 -0
- acp/agent/protocol.py +65 -0
- acp/bridge/README.md +162 -0
- acp/bridge/__init__.py +6 -0
- acp/bridge/__main__.py +91 -0
- acp/bridge/bridge.py +246 -0
- acp/bridge/py.typed +0 -0
- acp/bridge/settings.py +15 -0
- acp/client/__init__.py +7 -0
- acp/client/connection.py +251 -0
- acp/client/implementations/__init__.py +7 -0
- acp/client/implementations/default_client.py +185 -0
- acp/client/implementations/headless_client.py +266 -0
- acp/client/implementations/noop_client.py +110 -0
- acp/client/protocol.py +61 -0
- acp/connection.py +280 -0
- acp/exceptions.py +46 -0
- acp/filesystem.py +524 -0
- acp/notifications.py +832 -0
- acp/py.typed +0 -0
- acp/schema/__init__.py +265 -0
- acp/schema/agent_plan.py +30 -0
- acp/schema/agent_requests.py +126 -0
- acp/schema/agent_responses.py +256 -0
- acp/schema/base.py +39 -0
- acp/schema/capabilities.py +230 -0
- acp/schema/client_requests.py +247 -0
- acp/schema/client_responses.py +96 -0
- acp/schema/common.py +81 -0
- acp/schema/content_blocks.py +188 -0
- acp/schema/mcp.py +82 -0
- acp/schema/messages.py +171 -0
- acp/schema/notifications.py +82 -0
- acp/schema/protocol_stuff.md +3 -0
- acp/schema/session_state.py +160 -0
- acp/schema/session_updates.py +419 -0
- acp/schema/slash_commands.py +51 -0
- acp/schema/terminal.py +15 -0
- acp/schema/tool_call.py +347 -0
- acp/stdio.py +250 -0
- acp/task/__init__.py +53 -0
- acp/task/debug.py +197 -0
- acp/task/dispatcher.py +93 -0
- acp/task/queue.py +69 -0
- acp/task/sender.py +82 -0
- acp/task/state.py +87 -0
- acp/task/supervisor.py +93 -0
- acp/terminal_handle.py +30 -0
- acp/tool_call_reporter.py +199 -0
- acp/tool_call_state.py +178 -0
- acp/transports.py +104 -0
- acp/utils.py +240 -0
- agentpool/__init__.py +63 -0
- agentpool/__main__.py +7 -0
- agentpool/agents/__init__.py +30 -0
- agentpool/agents/acp_agent/__init__.py +5 -0
- agentpool/agents/acp_agent/acp_agent.py +837 -0
- agentpool/agents/acp_agent/acp_converters.py +294 -0
- agentpool/agents/acp_agent/client_handler.py +317 -0
- agentpool/agents/acp_agent/session_state.py +44 -0
- agentpool/agents/agent.py +1264 -0
- agentpool/agents/agui_agent/__init__.py +19 -0
- agentpool/agents/agui_agent/agui_agent.py +677 -0
- agentpool/agents/agui_agent/agui_converters.py +423 -0
- agentpool/agents/agui_agent/chunk_transformer.py +204 -0
- agentpool/agents/agui_agent/event_types.py +83 -0
- agentpool/agents/agui_agent/helpers.py +192 -0
- agentpool/agents/architect.py +71 -0
- agentpool/agents/base_agent.py +177 -0
- agentpool/agents/claude_code_agent/__init__.py +11 -0
- agentpool/agents/claude_code_agent/claude_code_agent.py +1021 -0
- agentpool/agents/claude_code_agent/converters.py +243 -0
- agentpool/agents/context.py +105 -0
- agentpool/agents/events/__init__.py +61 -0
- agentpool/agents/events/builtin_handlers.py +129 -0
- agentpool/agents/events/event_emitter.py +320 -0
- agentpool/agents/events/events.py +561 -0
- agentpool/agents/events/tts_handlers.py +186 -0
- agentpool/agents/interactions.py +419 -0
- agentpool/agents/slashed_agent.py +244 -0
- agentpool/agents/sys_prompts.py +178 -0
- agentpool/agents/tool_wrapping.py +184 -0
- agentpool/base_provider.py +28 -0
- agentpool/common_types.py +226 -0
- agentpool/config_resources/__init__.py +16 -0
- agentpool/config_resources/acp_assistant.yml +24 -0
- agentpool/config_resources/agents.yml +109 -0
- agentpool/config_resources/agents_template.yml +18 -0
- agentpool/config_resources/agui_test.yml +18 -0
- agentpool/config_resources/claude_code_agent.yml +16 -0
- agentpool/config_resources/claude_style_subagent.md +30 -0
- agentpool/config_resources/external_acp_agents.yml +77 -0
- agentpool/config_resources/opencode_style_subagent.md +19 -0
- agentpool/config_resources/tts_test_agents.yml +78 -0
- agentpool/delegation/__init__.py +8 -0
- agentpool/delegation/base_team.py +504 -0
- agentpool/delegation/message_flow_tracker.py +39 -0
- agentpool/delegation/pool.py +1129 -0
- agentpool/delegation/team.py +325 -0
- agentpool/delegation/teamrun.py +343 -0
- agentpool/docs/__init__.py +5 -0
- agentpool/docs/gen_examples.py +42 -0
- agentpool/docs/utils.py +370 -0
- agentpool/functional/__init__.py +20 -0
- agentpool/functional/py.typed +0 -0
- agentpool/functional/run.py +80 -0
- agentpool/functional/structure.py +136 -0
- agentpool/hooks/__init__.py +20 -0
- agentpool/hooks/agent_hooks.py +247 -0
- agentpool/hooks/base.py +119 -0
- agentpool/hooks/callable.py +140 -0
- agentpool/hooks/command.py +180 -0
- agentpool/hooks/prompt.py +122 -0
- agentpool/jinja_filters.py +132 -0
- agentpool/log.py +224 -0
- agentpool/mcp_server/__init__.py +17 -0
- agentpool/mcp_server/client.py +429 -0
- agentpool/mcp_server/constants.py +32 -0
- agentpool/mcp_server/conversions.py +172 -0
- agentpool/mcp_server/helpers.py +47 -0
- agentpool/mcp_server/manager.py +232 -0
- agentpool/mcp_server/message_handler.py +164 -0
- agentpool/mcp_server/registries/__init__.py +1 -0
- agentpool/mcp_server/registries/official_registry_client.py +345 -0
- agentpool/mcp_server/registries/pulsemcp_client.py +88 -0
- agentpool/mcp_server/tool_bridge.py +548 -0
- agentpool/messaging/__init__.py +58 -0
- agentpool/messaging/compaction.py +928 -0
- agentpool/messaging/connection_manager.py +319 -0
- agentpool/messaging/context.py +66 -0
- agentpool/messaging/event_manager.py +426 -0
- agentpool/messaging/events.py +39 -0
- agentpool/messaging/message_container.py +209 -0
- agentpool/messaging/message_history.py +491 -0
- agentpool/messaging/messagenode.py +377 -0
- agentpool/messaging/messages.py +655 -0
- agentpool/messaging/processing.py +76 -0
- agentpool/mime_utils.py +95 -0
- agentpool/models/__init__.py +21 -0
- agentpool/models/acp_agents/__init__.py +22 -0
- agentpool/models/acp_agents/base.py +308 -0
- agentpool/models/acp_agents/mcp_capable.py +790 -0
- agentpool/models/acp_agents/non_mcp.py +842 -0
- agentpool/models/agents.py +450 -0
- agentpool/models/agui_agents.py +89 -0
- agentpool/models/claude_code_agents.py +238 -0
- agentpool/models/file_agents.py +116 -0
- agentpool/models/file_parsing.py +367 -0
- agentpool/models/manifest.py +658 -0
- agentpool/observability/__init__.py +9 -0
- agentpool/observability/observability_registry.py +97 -0
- agentpool/prompts/__init__.py +1 -0
- agentpool/prompts/base.py +27 -0
- agentpool/prompts/builtin_provider.py +75 -0
- agentpool/prompts/conversion_manager.py +95 -0
- agentpool/prompts/convert.py +96 -0
- agentpool/prompts/manager.py +204 -0
- agentpool/prompts/parts/zed.md +33 -0
- agentpool/prompts/prompts.py +581 -0
- agentpool/py.typed +0 -0
- agentpool/queries/tree-sitter-language-pack/README.md +7 -0
- agentpool/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
- agentpool/queries/tree-sitter-language-pack/c-tags.scm +9 -0
- agentpool/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
- agentpool/queries/tree-sitter-language-pack/clojure-tags.scm +7 -0
- agentpool/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
- agentpool/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
- agentpool/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
- agentpool/queries/tree-sitter-language-pack/d-tags.scm +26 -0
- agentpool/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
- agentpool/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
- agentpool/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
- agentpool/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
- agentpool/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
- agentpool/queries/tree-sitter-language-pack/go-tags.scm +42 -0
- agentpool/queries/tree-sitter-language-pack/java-tags.scm +20 -0
- agentpool/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
- agentpool/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
- agentpool/queries/tree-sitter-language-pack/matlab-tags.scm +10 -0
- agentpool/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
- agentpool/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
- agentpool/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
- agentpool/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
- agentpool/queries/tree-sitter-language-pack/python-tags.scm +14 -0
- agentpool/queries/tree-sitter-language-pack/r-tags.scm +21 -0
- agentpool/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
- agentpool/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
- agentpool/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
- agentpool/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
- agentpool/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
- agentpool/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
- agentpool/queries/tree-sitter-languages/README.md +24 -0
- agentpool/queries/tree-sitter-languages/c-tags.scm +9 -0
- agentpool/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
- agentpool/queries/tree-sitter-languages/cpp-tags.scm +15 -0
- agentpool/queries/tree-sitter-languages/dart-tags.scm +91 -0
- agentpool/queries/tree-sitter-languages/elisp-tags.scm +8 -0
- agentpool/queries/tree-sitter-languages/elixir-tags.scm +54 -0
- agentpool/queries/tree-sitter-languages/elm-tags.scm +19 -0
- agentpool/queries/tree-sitter-languages/fortran-tags.scm +15 -0
- agentpool/queries/tree-sitter-languages/go-tags.scm +30 -0
- agentpool/queries/tree-sitter-languages/haskell-tags.scm +3 -0
- agentpool/queries/tree-sitter-languages/hcl-tags.scm +77 -0
- agentpool/queries/tree-sitter-languages/java-tags.scm +20 -0
- agentpool/queries/tree-sitter-languages/javascript-tags.scm +88 -0
- agentpool/queries/tree-sitter-languages/julia-tags.scm +60 -0
- agentpool/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
- agentpool/queries/tree-sitter-languages/matlab-tags.scm +10 -0
- agentpool/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
- agentpool/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
- agentpool/queries/tree-sitter-languages/php-tags.scm +26 -0
- agentpool/queries/tree-sitter-languages/python-tags.scm +12 -0
- agentpool/queries/tree-sitter-languages/ql-tags.scm +26 -0
- agentpool/queries/tree-sitter-languages/ruby-tags.scm +64 -0
- agentpool/queries/tree-sitter-languages/rust-tags.scm +60 -0
- agentpool/queries/tree-sitter-languages/scala-tags.scm +65 -0
- agentpool/queries/tree-sitter-languages/typescript-tags.scm +41 -0
- agentpool/queries/tree-sitter-languages/zig-tags.scm +3 -0
- agentpool/repomap.py +1231 -0
- agentpool/resource_providers/__init__.py +17 -0
- agentpool/resource_providers/aggregating.py +54 -0
- agentpool/resource_providers/base.py +172 -0
- agentpool/resource_providers/codemode/__init__.py +9 -0
- agentpool/resource_providers/codemode/code_executor.py +215 -0
- agentpool/resource_providers/codemode/default_prompt.py +19 -0
- agentpool/resource_providers/codemode/helpers.py +83 -0
- agentpool/resource_providers/codemode/progress_executor.py +212 -0
- agentpool/resource_providers/codemode/provider.py +150 -0
- agentpool/resource_providers/codemode/remote_mcp_execution.py +143 -0
- agentpool/resource_providers/codemode/remote_provider.py +171 -0
- agentpool/resource_providers/filtering.py +42 -0
- agentpool/resource_providers/mcp_provider.py +246 -0
- agentpool/resource_providers/plan_provider.py +196 -0
- agentpool/resource_providers/pool.py +69 -0
- agentpool/resource_providers/static.py +289 -0
- agentpool/running/__init__.py +20 -0
- agentpool/running/decorators.py +56 -0
- agentpool/running/discovery.py +101 -0
- agentpool/running/executor.py +284 -0
- agentpool/running/injection.py +111 -0
- agentpool/running/py.typed +0 -0
- agentpool/running/run_nodes.py +87 -0
- agentpool/server.py +122 -0
- agentpool/sessions/__init__.py +13 -0
- agentpool/sessions/manager.py +302 -0
- agentpool/sessions/models.py +71 -0
- agentpool/sessions/session.py +239 -0
- agentpool/sessions/store.py +163 -0
- agentpool/skills/__init__.py +5 -0
- agentpool/skills/manager.py +120 -0
- agentpool/skills/registry.py +210 -0
- agentpool/skills/skill.py +36 -0
- agentpool/storage/__init__.py +17 -0
- agentpool/storage/manager.py +419 -0
- agentpool/storage/serialization.py +136 -0
- agentpool/talk/__init__.py +13 -0
- agentpool/talk/registry.py +128 -0
- agentpool/talk/stats.py +159 -0
- agentpool/talk/talk.py +604 -0
- agentpool/tasks/__init__.py +20 -0
- agentpool/tasks/exceptions.py +25 -0
- agentpool/tasks/registry.py +33 -0
- agentpool/testing.py +129 -0
- agentpool/text_templates/__init__.py +39 -0
- agentpool/text_templates/system_prompt.jinja +30 -0
- agentpool/text_templates/tool_call_default.jinja +13 -0
- agentpool/text_templates/tool_call_markdown.jinja +25 -0
- agentpool/text_templates/tool_call_simple.jinja +5 -0
- agentpool/tools/__init__.py +16 -0
- agentpool/tools/base.py +269 -0
- agentpool/tools/exceptions.py +9 -0
- agentpool/tools/manager.py +255 -0
- agentpool/tools/tool_call_info.py +87 -0
- agentpool/ui/__init__.py +2 -0
- agentpool/ui/base.py +89 -0
- agentpool/ui/mock_provider.py +81 -0
- agentpool/ui/stdlib_provider.py +150 -0
- agentpool/utils/__init__.py +44 -0
- agentpool/utils/baseregistry.py +185 -0
- agentpool/utils/count_tokens.py +62 -0
- agentpool/utils/dag.py +184 -0
- agentpool/utils/importing.py +206 -0
- agentpool/utils/inspection.py +334 -0
- agentpool/utils/model_capabilities.py +25 -0
- agentpool/utils/network.py +28 -0
- agentpool/utils/now.py +22 -0
- agentpool/utils/parse_time.py +87 -0
- agentpool/utils/result_utils.py +35 -0
- agentpool/utils/signatures.py +305 -0
- agentpool/utils/streams.py +112 -0
- agentpool/utils/tasks.py +186 -0
- agentpool/vfs_registry.py +250 -0
- agentpool-2.1.9.dist-info/METADATA +336 -0
- agentpool-2.1.9.dist-info/RECORD +474 -0
- agentpool-2.1.9.dist-info/WHEEL +4 -0
- agentpool-2.1.9.dist-info/entry_points.txt +14 -0
- agentpool-2.1.9.dist-info/licenses/LICENSE +22 -0
- agentpool_cli/__init__.py +34 -0
- agentpool_cli/__main__.py +66 -0
- agentpool_cli/agent.py +175 -0
- agentpool_cli/cli_types.py +23 -0
- agentpool_cli/common.py +163 -0
- agentpool_cli/create.py +175 -0
- agentpool_cli/history.py +217 -0
- agentpool_cli/log.py +78 -0
- agentpool_cli/py.typed +0 -0
- agentpool_cli/run.py +84 -0
- agentpool_cli/serve_acp.py +177 -0
- agentpool_cli/serve_api.py +69 -0
- agentpool_cli/serve_mcp.py +74 -0
- agentpool_cli/serve_vercel.py +233 -0
- agentpool_cli/store.py +171 -0
- agentpool_cli/task.py +84 -0
- agentpool_cli/utils.py +104 -0
- agentpool_cli/watch.py +54 -0
- agentpool_commands/__init__.py +180 -0
- agentpool_commands/agents.py +199 -0
- agentpool_commands/base.py +45 -0
- agentpool_commands/commands.py +58 -0
- agentpool_commands/completers.py +110 -0
- agentpool_commands/connections.py +175 -0
- agentpool_commands/markdown_utils.py +31 -0
- agentpool_commands/models.py +62 -0
- agentpool_commands/prompts.py +78 -0
- agentpool_commands/py.typed +0 -0
- agentpool_commands/read.py +77 -0
- agentpool_commands/resources.py +210 -0
- agentpool_commands/session.py +48 -0
- agentpool_commands/tools.py +269 -0
- agentpool_commands/utils.py +189 -0
- agentpool_commands/workers.py +163 -0
- agentpool_config/__init__.py +53 -0
- agentpool_config/builtin_tools.py +265 -0
- agentpool_config/commands.py +237 -0
- agentpool_config/conditions.py +301 -0
- agentpool_config/converters.py +30 -0
- agentpool_config/durable.py +331 -0
- agentpool_config/event_handlers.py +600 -0
- agentpool_config/events.py +153 -0
- agentpool_config/forward_targets.py +251 -0
- agentpool_config/hook_conditions.py +331 -0
- agentpool_config/hooks.py +241 -0
- agentpool_config/jinja.py +206 -0
- agentpool_config/knowledge.py +41 -0
- agentpool_config/loaders.py +350 -0
- agentpool_config/mcp_server.py +243 -0
- agentpool_config/nodes.py +202 -0
- agentpool_config/observability.py +191 -0
- agentpool_config/output_types.py +55 -0
- agentpool_config/pool_server.py +267 -0
- agentpool_config/prompt_hubs.py +105 -0
- agentpool_config/prompts.py +185 -0
- agentpool_config/py.typed +0 -0
- agentpool_config/resources.py +33 -0
- agentpool_config/session.py +119 -0
- agentpool_config/skills.py +17 -0
- agentpool_config/storage.py +288 -0
- agentpool_config/system_prompts.py +190 -0
- agentpool_config/task.py +162 -0
- agentpool_config/teams.py +52 -0
- agentpool_config/tools.py +112 -0
- agentpool_config/toolsets.py +1033 -0
- agentpool_config/workers.py +86 -0
- agentpool_prompts/__init__.py +1 -0
- agentpool_prompts/braintrust_hub.py +235 -0
- agentpool_prompts/fabric.py +75 -0
- agentpool_prompts/langfuse_hub.py +79 -0
- agentpool_prompts/promptlayer_provider.py +59 -0
- agentpool_prompts/py.typed +0 -0
- agentpool_server/__init__.py +9 -0
- agentpool_server/a2a_server/__init__.py +5 -0
- agentpool_server/a2a_server/a2a_types.py +41 -0
- agentpool_server/a2a_server/server.py +190 -0
- agentpool_server/a2a_server/storage.py +81 -0
- agentpool_server/acp_server/__init__.py +22 -0
- agentpool_server/acp_server/acp_agent.py +786 -0
- agentpool_server/acp_server/acp_tools.py +43 -0
- agentpool_server/acp_server/commands/__init__.py +18 -0
- agentpool_server/acp_server/commands/acp_commands.py +594 -0
- agentpool_server/acp_server/commands/debug_commands.py +376 -0
- agentpool_server/acp_server/commands/docs_commands/__init__.py +39 -0
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +169 -0
- agentpool_server/acp_server/commands/docs_commands/get_schema.py +176 -0
- agentpool_server/acp_server/commands/docs_commands/get_source.py +110 -0
- agentpool_server/acp_server/commands/docs_commands/git_diff.py +111 -0
- agentpool_server/acp_server/commands/docs_commands/helpers.py +33 -0
- agentpool_server/acp_server/commands/docs_commands/url_to_markdown.py +90 -0
- agentpool_server/acp_server/commands/spawn.py +210 -0
- agentpool_server/acp_server/converters.py +235 -0
- agentpool_server/acp_server/input_provider.py +338 -0
- agentpool_server/acp_server/server.py +288 -0
- agentpool_server/acp_server/session.py +969 -0
- agentpool_server/acp_server/session_manager.py +313 -0
- agentpool_server/acp_server/syntax_detection.py +250 -0
- agentpool_server/acp_server/zed_tools.md +90 -0
- agentpool_server/aggregating_server.py +309 -0
- agentpool_server/agui_server/__init__.py +11 -0
- agentpool_server/agui_server/server.py +128 -0
- agentpool_server/base.py +189 -0
- agentpool_server/http_server.py +164 -0
- agentpool_server/mcp_server/__init__.py +6 -0
- agentpool_server/mcp_server/server.py +314 -0
- agentpool_server/mcp_server/zed_wrapper.py +110 -0
- agentpool_server/openai_api_server/__init__.py +5 -0
- agentpool_server/openai_api_server/completions/__init__.py +1 -0
- agentpool_server/openai_api_server/completions/helpers.py +81 -0
- agentpool_server/openai_api_server/completions/models.py +98 -0
- agentpool_server/openai_api_server/responses/__init__.py +1 -0
- agentpool_server/openai_api_server/responses/helpers.py +74 -0
- agentpool_server/openai_api_server/responses/models.py +96 -0
- agentpool_server/openai_api_server/server.py +242 -0
- agentpool_server/py.typed +0 -0
- agentpool_storage/__init__.py +9 -0
- agentpool_storage/base.py +310 -0
- agentpool_storage/file_provider.py +378 -0
- agentpool_storage/formatters.py +129 -0
- agentpool_storage/memory_provider.py +396 -0
- agentpool_storage/models.py +108 -0
- agentpool_storage/py.typed +0 -0
- agentpool_storage/session_store.py +262 -0
- agentpool_storage/sql_provider/__init__.py +21 -0
- agentpool_storage/sql_provider/cli.py +146 -0
- agentpool_storage/sql_provider/models.py +249 -0
- agentpool_storage/sql_provider/queries.py +15 -0
- agentpool_storage/sql_provider/sql_provider.py +444 -0
- agentpool_storage/sql_provider/utils.py +234 -0
- agentpool_storage/text_log_provider.py +275 -0
- agentpool_toolsets/__init__.py +15 -0
- agentpool_toolsets/builtin/__init__.py +33 -0
- agentpool_toolsets/builtin/agent_management.py +239 -0
- agentpool_toolsets/builtin/chain.py +288 -0
- agentpool_toolsets/builtin/code.py +398 -0
- agentpool_toolsets/builtin/debug.py +291 -0
- agentpool_toolsets/builtin/execution_environment.py +381 -0
- agentpool_toolsets/builtin/file_edit/__init__.py +11 -0
- agentpool_toolsets/builtin/file_edit/file_edit.py +747 -0
- agentpool_toolsets/builtin/file_edit/fuzzy_matcher/__init__.py +5 -0
- agentpool_toolsets/builtin/file_edit/fuzzy_matcher/example_usage.py +311 -0
- agentpool_toolsets/builtin/file_edit/fuzzy_matcher/streaming_fuzzy_matcher.py +443 -0
- agentpool_toolsets/builtin/history.py +36 -0
- agentpool_toolsets/builtin/integration.py +85 -0
- agentpool_toolsets/builtin/skills.py +77 -0
- agentpool_toolsets/builtin/subagent_tools.py +324 -0
- agentpool_toolsets/builtin/tool_management.py +90 -0
- agentpool_toolsets/builtin/user_interaction.py +52 -0
- agentpool_toolsets/builtin/workers.py +128 -0
- agentpool_toolsets/composio_toolset.py +96 -0
- agentpool_toolsets/config_creation.py +192 -0
- agentpool_toolsets/entry_points.py +47 -0
- agentpool_toolsets/fsspec_toolset/__init__.py +7 -0
- agentpool_toolsets/fsspec_toolset/diagnostics.py +115 -0
- agentpool_toolsets/fsspec_toolset/grep.py +450 -0
- agentpool_toolsets/fsspec_toolset/helpers.py +631 -0
- agentpool_toolsets/fsspec_toolset/streaming_diff_parser.py +249 -0
- agentpool_toolsets/fsspec_toolset/toolset.py +1384 -0
- agentpool_toolsets/mcp_run_toolset.py +61 -0
- agentpool_toolsets/notifications.py +146 -0
- agentpool_toolsets/openapi.py +118 -0
- agentpool_toolsets/py.typed +0 -0
- agentpool_toolsets/search_toolset.py +202 -0
- agentpool_toolsets/semantic_memory_toolset.py +536 -0
- agentpool_toolsets/streaming_tools.py +265 -0
- agentpool_toolsets/vfs_toolset.py +124 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Module containing the AGUIAgent class and supporting utilities."""
|
|
2
|
+
|
|
3
|
+
from agentpool.agents.agui_agent.agui_agent import AGUIAgent
|
|
4
|
+
from agentpool.agents.agui_agent.agui_converters import (
|
|
5
|
+
ToolCallAccumulator,
|
|
6
|
+
agui_to_native_event,
|
|
7
|
+
to_agui_input_content,
|
|
8
|
+
to_agui_tool,
|
|
9
|
+
)
|
|
10
|
+
from agentpool.agents.agui_agent.chunk_transformer import ChunkTransformer
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AGUIAgent",
|
|
14
|
+
"ChunkTransformer",
|
|
15
|
+
"ToolCallAccumulator",
|
|
16
|
+
"agui_to_native_event",
|
|
17
|
+
"to_agui_input_content",
|
|
18
|
+
"to_agui_tool",
|
|
19
|
+
]
|
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
"""AG-UI remote agent implementation.
|
|
2
|
+
|
|
3
|
+
This module provides a MessageNode adapter that connects to remote AG-UI protocol servers,
|
|
4
|
+
enabling remote agent execution with streaming support.
|
|
5
|
+
|
|
6
|
+
Supports client-side tool execution: tools can be defined locally and sent to the
|
|
7
|
+
remote AG-UI agent. When the agent requests tool execution, the tools are executed
|
|
8
|
+
locally and results sent back.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
15
|
+
from uuid import uuid4
|
|
16
|
+
|
|
17
|
+
from anyenv.processes import hard_kill
|
|
18
|
+
import anyio
|
|
19
|
+
import httpx
|
|
20
|
+
from pydantic_ai import (
|
|
21
|
+
ModelRequest,
|
|
22
|
+
ModelResponse,
|
|
23
|
+
TextPart,
|
|
24
|
+
ThinkingPart,
|
|
25
|
+
ToolCallPart,
|
|
26
|
+
ToolReturnPart,
|
|
27
|
+
UserPromptPart,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from agentpool.agents.agui_agent.chunk_transformer import ChunkTransformer
|
|
31
|
+
from agentpool.agents.agui_agent.helpers import execute_tool_calls, parse_sse_stream
|
|
32
|
+
from agentpool.agents.base_agent import BaseAgent
|
|
33
|
+
from agentpool.agents.events import RunStartedEvent, StreamCompleteEvent
|
|
34
|
+
from agentpool.log import get_logger
|
|
35
|
+
from agentpool.messaging import ChatMessage
|
|
36
|
+
from agentpool.messaging.processing import prepare_prompts
|
|
37
|
+
from agentpool.talk.stats import MessageStats
|
|
38
|
+
from agentpool.tools import ToolManager
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from asyncio.subprocess import Process
|
|
43
|
+
from collections.abc import AsyncIterator, Sequence
|
|
44
|
+
from types import TracebackType
|
|
45
|
+
|
|
46
|
+
from ag_ui.core import Message, ToolMessage
|
|
47
|
+
from evented.configs import EventConfig
|
|
48
|
+
|
|
49
|
+
from agentpool.agents.base_agent import ToolConfirmationMode
|
|
50
|
+
from agentpool.agents.context import AgentContext
|
|
51
|
+
from agentpool.agents.events import RichAgentStreamEvent
|
|
52
|
+
from agentpool.common_types import (
|
|
53
|
+
BuiltinEventHandlerType,
|
|
54
|
+
IndividualEventHandler,
|
|
55
|
+
PromptCompatible,
|
|
56
|
+
ToolType,
|
|
57
|
+
)
|
|
58
|
+
from agentpool.delegation import AgentPool
|
|
59
|
+
from agentpool.messaging import MessageHistory
|
|
60
|
+
from agentpool.tools import Tool
|
|
61
|
+
from agentpool.ui.base import InputProvider
|
|
62
|
+
from agentpool_config.mcp_server import MCPServerConfig
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
logger = get_logger(__name__)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_client(headers: dict[str, str], timeout: float) -> httpx.AsyncClient:
|
|
69
|
+
headers = {**headers, "Accept": "text/event-stream", "Content-Type": "application/json"}
|
|
70
|
+
return httpx.AsyncClient(timeout=httpx.Timeout(timeout), headers=headers)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
74
|
+
"""MessageNode that wraps a remote AG-UI protocol server.
|
|
75
|
+
|
|
76
|
+
Connects to AG-UI compatible endpoints via HTTP/SSE and provides the same
|
|
77
|
+
interface as native agents, enabling composition with other nodes via
|
|
78
|
+
connections, teams, etc.
|
|
79
|
+
|
|
80
|
+
The agent manages:
|
|
81
|
+
- HTTP client lifecycle (create on enter, close on exit)
|
|
82
|
+
- AG-UI protocol communication via SSE streams
|
|
83
|
+
- Event conversion to native agentpool events
|
|
84
|
+
- Message accumulation and final response generation
|
|
85
|
+
- Client-side tool execution (tools defined locally, executed when requested)
|
|
86
|
+
- Subscriber system for event hooks
|
|
87
|
+
- Chunk transformation for compatibility with different server modes
|
|
88
|
+
|
|
89
|
+
Client-Side Tools:
|
|
90
|
+
Tools can be registered with this agent and sent to the remote AG-UI server.
|
|
91
|
+
When the server requests a tool call, the tool is executed locally and the
|
|
92
|
+
result is sent back. This enables human-in-the-loop workflows and local
|
|
93
|
+
capability exposure to remote agents.
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
```python
|
|
97
|
+
# Connect to existing server
|
|
98
|
+
async with AGUIAgent(
|
|
99
|
+
endpoint="http://localhost:8000/agent/run",
|
|
100
|
+
name="tool-agent",
|
|
101
|
+
tools=[my_tool_function],
|
|
102
|
+
) as agent:
|
|
103
|
+
# Remote agent can request execution of my_tool_function
|
|
104
|
+
result = await agent.run("Use the tool to help me")
|
|
105
|
+
|
|
106
|
+
# Start server automatically (useful for testing)
|
|
107
|
+
async with AGUIAgent(
|
|
108
|
+
endpoint="http://localhost:8000/agent/run",
|
|
109
|
+
name="test-agent",
|
|
110
|
+
startup_command="ag ui agent config.yml",
|
|
111
|
+
startup_delay=2.0,
|
|
112
|
+
) as agent:
|
|
113
|
+
result = await agent.run("Test prompt")
|
|
114
|
+
```
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
def __init__(
|
|
118
|
+
self,
|
|
119
|
+
endpoint: str,
|
|
120
|
+
*,
|
|
121
|
+
name: str = "agui-agent",
|
|
122
|
+
description: str | None = None,
|
|
123
|
+
display_name: str | None = None,
|
|
124
|
+
timeout: float = 60.0,
|
|
125
|
+
headers: dict[str, str] | None = None,
|
|
126
|
+
startup_command: str | None = None,
|
|
127
|
+
startup_delay: float = 2.0,
|
|
128
|
+
tools: Sequence[ToolType] | None = None,
|
|
129
|
+
mcp_servers: Sequence[str | MCPServerConfig] | None = None,
|
|
130
|
+
agent_pool: AgentPool[Any] | None = None,
|
|
131
|
+
enable_logging: bool = True,
|
|
132
|
+
event_configs: Sequence[EventConfig] | None = None,
|
|
133
|
+
event_handlers: Sequence[IndividualEventHandler | BuiltinEventHandlerType] | None = None,
|
|
134
|
+
tool_confirmation_mode: ToolConfirmationMode = "per_tool",
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Initialize AG-UI agent client.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
endpoint: HTTP endpoint for the AG-UI agent
|
|
140
|
+
name: Agent name for identification
|
|
141
|
+
description: Agent description
|
|
142
|
+
display_name: Human-readable display name
|
|
143
|
+
timeout: Request timeout in seconds
|
|
144
|
+
headers: Additional HTTP headers
|
|
145
|
+
startup_command: Optional shell command to start server automatically.
|
|
146
|
+
Useful for testing - server lifecycle is managed by the agent.
|
|
147
|
+
Example: "ag ui agent config.yml"
|
|
148
|
+
startup_delay: Seconds to wait after starting server before connecting (default: 2.0)
|
|
149
|
+
tools: Tools to expose to the remote agent (executed locally when called)
|
|
150
|
+
mcp_servers: MCP servers to connect
|
|
151
|
+
agent_pool: Agent pool for multi-agent coordination
|
|
152
|
+
enable_logging: Whether to enable database logging
|
|
153
|
+
event_configs: Event trigger configurations
|
|
154
|
+
event_handlers: Sequence of event handlers to register
|
|
155
|
+
tool_confirmation_mode: Tool confirmation mode
|
|
156
|
+
"""
|
|
157
|
+
super().__init__(
|
|
158
|
+
name=name,
|
|
159
|
+
description=description,
|
|
160
|
+
display_name=display_name,
|
|
161
|
+
mcp_servers=mcp_servers,
|
|
162
|
+
agent_pool=agent_pool,
|
|
163
|
+
enable_logging=enable_logging,
|
|
164
|
+
event_configs=event_configs,
|
|
165
|
+
tool_confirmation_mode=tool_confirmation_mode,
|
|
166
|
+
event_handlers=event_handlers,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# AG-UI specific configuration
|
|
170
|
+
self.endpoint = endpoint
|
|
171
|
+
self.timeout = timeout
|
|
172
|
+
self.headers = headers or {}
|
|
173
|
+
|
|
174
|
+
# Startup command configuration
|
|
175
|
+
self._startup_command = startup_command
|
|
176
|
+
self._startup_delay = startup_delay
|
|
177
|
+
self._startup_process: Process | None = None
|
|
178
|
+
|
|
179
|
+
# Client state
|
|
180
|
+
self._client: httpx.AsyncClient | None = None
|
|
181
|
+
self._thread_id: str | None = None
|
|
182
|
+
self._run_id: str | None = None
|
|
183
|
+
|
|
184
|
+
# Override tools with provided tools
|
|
185
|
+
self.tools = ToolManager(tools)
|
|
186
|
+
|
|
187
|
+
# Chunk transformer for normalizing CHUNK events
|
|
188
|
+
self._chunk_transformer = ChunkTransformer()
|
|
189
|
+
|
|
190
|
+
def get_context(self, data: Any = None) -> AgentContext:
|
|
191
|
+
"""Create a new context for this agent.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
data: Optional custom data to attach to the context
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
A new AgentContext instance
|
|
198
|
+
"""
|
|
199
|
+
from agentpool.agents.context import AgentContext
|
|
200
|
+
from agentpool.models.agui_agents import AGUIAgentConfig
|
|
201
|
+
from agentpool.models.manifest import AgentsManifest
|
|
202
|
+
|
|
203
|
+
cfg = AGUIAgentConfig(
|
|
204
|
+
name=self.name,
|
|
205
|
+
description=self.description,
|
|
206
|
+
display_name=self.display_name,
|
|
207
|
+
endpoint=self.endpoint,
|
|
208
|
+
timeout=self.timeout,
|
|
209
|
+
headers=self.headers,
|
|
210
|
+
input_provider=self._input_provider,
|
|
211
|
+
startup_command=self._startup_command,
|
|
212
|
+
startup_delay=self._startup_delay,
|
|
213
|
+
)
|
|
214
|
+
defn = self.agent_pool.manifest if self.agent_pool else AgentsManifest()
|
|
215
|
+
return AgentContext(node=self, pool=self.agent_pool, config=cfg, definition=defn, data=data)
|
|
216
|
+
|
|
217
|
+
async def __aenter__(self) -> Self:
|
|
218
|
+
"""Enter async context - initialize client and base resources."""
|
|
219
|
+
await super().__aenter__()
|
|
220
|
+
self._client = get_client(self.headers, self.timeout)
|
|
221
|
+
self._thread_id = self.conversation_id
|
|
222
|
+
if self._startup_command: # Start server if startup command is provided
|
|
223
|
+
await self._start_server()
|
|
224
|
+
self.log.debug("AG-UI client initialized", endpoint=self.endpoint)
|
|
225
|
+
return self
|
|
226
|
+
|
|
227
|
+
async def __aexit__(
|
|
228
|
+
self,
|
|
229
|
+
exc_type: type[BaseException] | None,
|
|
230
|
+
exc_val: BaseException | None,
|
|
231
|
+
exc_tb: TracebackType | None,
|
|
232
|
+
) -> None:
|
|
233
|
+
"""Exit async context - cleanup client and base resources."""
|
|
234
|
+
if self._client:
|
|
235
|
+
await self._client.aclose()
|
|
236
|
+
self._client = None
|
|
237
|
+
self._thread_id = None
|
|
238
|
+
self._run_id = None
|
|
239
|
+
if self._startup_process: # Stop server if we started it
|
|
240
|
+
await self._stop_server()
|
|
241
|
+
self.log.debug("AG-UI client closed")
|
|
242
|
+
await super().__aexit__(exc_type, exc_val, exc_tb)
|
|
243
|
+
|
|
244
|
+
def register_tool(self, tool: ToolType) -> Tool:
|
|
245
|
+
"""Register a tool for client-side execution.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
tool: Tool instance or callable to register
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Registered Tool instance
|
|
252
|
+
"""
|
|
253
|
+
return self.tools.register_tool(tool)
|
|
254
|
+
|
|
255
|
+
async def set_tool_confirmation_mode(self, mode: ToolConfirmationMode) -> None:
|
|
256
|
+
"""Set the tool confirmation mode for this agent.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
mode: Tool confirmation mode:
|
|
260
|
+
- "always": Always require confirmation for all tools
|
|
261
|
+
- "never": Never require confirmation
|
|
262
|
+
- "per_tool": Use individual tool settings
|
|
263
|
+
"""
|
|
264
|
+
self.tool_confirmation_mode = mode
|
|
265
|
+
self.log.info("Tool confirmation mode changed", mode=mode)
|
|
266
|
+
|
|
267
|
+
async def _start_server(self) -> None:
|
|
268
|
+
"""Start the AG-UI server subprocess."""
|
|
269
|
+
if not self._startup_command:
|
|
270
|
+
return
|
|
271
|
+
|
|
272
|
+
self.log.info("Starting AG-UI server", command=self._startup_command)
|
|
273
|
+
self._startup_process = await asyncio.create_subprocess_shell(
|
|
274
|
+
self._startup_command,
|
|
275
|
+
stdout=asyncio.subprocess.PIPE,
|
|
276
|
+
stderr=asyncio.subprocess.PIPE,
|
|
277
|
+
start_new_session=True, # Create new process group
|
|
278
|
+
)
|
|
279
|
+
self.log.debug("Waiting for server startup", delay=self._startup_delay)
|
|
280
|
+
await anyio.sleep(self._startup_delay)
|
|
281
|
+
# Check if process is still running
|
|
282
|
+
if self._startup_process.returncode is not None:
|
|
283
|
+
stderr = ""
|
|
284
|
+
if self._startup_process.stderr:
|
|
285
|
+
stderr = (await self._startup_process.stderr.read()).decode()
|
|
286
|
+
msg = f"Startup process exited with code {self._startup_process.returncode}: {stderr}"
|
|
287
|
+
raise RuntimeError(msg)
|
|
288
|
+
|
|
289
|
+
self.log.info("AG-UI server started")
|
|
290
|
+
|
|
291
|
+
async def _stop_server(self) -> None:
|
|
292
|
+
"""Stop the AG-UI server subprocess."""
|
|
293
|
+
if not self._startup_process:
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
self.log.info("Stopping AG-UI server")
|
|
297
|
+
try:
|
|
298
|
+
await hard_kill(self._startup_process) # Use cross-platform hard kill helper
|
|
299
|
+
except Exception: # Log but don't fail if kill has issues
|
|
300
|
+
self.log.exception("Error during process termination")
|
|
301
|
+
finally:
|
|
302
|
+
self._startup_process = None
|
|
303
|
+
self.log.info("AG-UI server stopped")
|
|
304
|
+
|
|
305
|
+
async def run(
|
|
306
|
+
self,
|
|
307
|
+
*prompts: PromptCompatible,
|
|
308
|
+
message_id: str | None = None,
|
|
309
|
+
input_provider: InputProvider | None = None,
|
|
310
|
+
message_history: MessageHistory | None = None,
|
|
311
|
+
**kwargs: Any,
|
|
312
|
+
) -> ChatMessage[str]:
|
|
313
|
+
"""Execute prompt against AG-UI agent.
|
|
314
|
+
|
|
315
|
+
Sends the prompt to the AG-UI server and waits for completion.
|
|
316
|
+
Events are collected via run_stream and event handlers are called.
|
|
317
|
+
The final text content is returned as a ChatMessage.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
prompts: Prompts to send (will be joined with spaces)
|
|
321
|
+
message_id: Optional message id for the returned message
|
|
322
|
+
input_provider: Optional input provider for tool confirmation requests
|
|
323
|
+
message_history: Optional MessageHistory to use instead of agent's own
|
|
324
|
+
**kwargs: Additional arguments (ignored for compatibility)
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
ChatMessage containing the agent's aggregated text response
|
|
328
|
+
"""
|
|
329
|
+
final_message: ChatMessage[str] | None = None
|
|
330
|
+
async for event in self.run_stream(
|
|
331
|
+
*prompts,
|
|
332
|
+
message_id=message_id,
|
|
333
|
+
input_provider=input_provider,
|
|
334
|
+
message_history=message_history,
|
|
335
|
+
):
|
|
336
|
+
if isinstance(event, StreamCompleteEvent):
|
|
337
|
+
final_message = event.message
|
|
338
|
+
|
|
339
|
+
if final_message is None:
|
|
340
|
+
raise RuntimeError("No final message received from stream")
|
|
341
|
+
return final_message
|
|
342
|
+
|
|
343
|
+
async def run_stream( # noqa: PLR0915
|
|
344
|
+
self,
|
|
345
|
+
*prompts: PromptCompatible,
|
|
346
|
+
message_id: str | None = None,
|
|
347
|
+
input_provider: InputProvider | None = None,
|
|
348
|
+
message_history: MessageHistory | None = None,
|
|
349
|
+
**kwargs: Any,
|
|
350
|
+
) -> AsyncIterator[RichAgentStreamEvent[str]]:
|
|
351
|
+
"""Execute prompt with streaming events.
|
|
352
|
+
|
|
353
|
+
Sends the prompt to the remote AG-UI agent along with any registered tools.
|
|
354
|
+
When the agent requests a tool call, the tool is executed locally and the
|
|
355
|
+
result is sent back in a continuation request.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
prompts: Prompts to send
|
|
359
|
+
message_id: Optional message ID
|
|
360
|
+
input_provider: Optional input provider for tool confirmation requests
|
|
361
|
+
message_history: Optional MessageHistory to use instead of agent's own
|
|
362
|
+
**kwargs: Additional arguments (ignored for compatibility)
|
|
363
|
+
|
|
364
|
+
Yields:
|
|
365
|
+
Native streaming events converted from AG-UI protocol
|
|
366
|
+
"""
|
|
367
|
+
# Update input provider if provided
|
|
368
|
+
if input_provider is not None:
|
|
369
|
+
self._input_provider = input_provider
|
|
370
|
+
from ag_ui.core import (
|
|
371
|
+
RunAgentInput,
|
|
372
|
+
TextMessageChunkEvent,
|
|
373
|
+
TextMessageContentEvent,
|
|
374
|
+
ThinkingTextMessageContentEvent,
|
|
375
|
+
ToolCallArgsEvent as AGUIToolCallArgsEvent,
|
|
376
|
+
ToolCallEndEvent as AGUIToolCallEndEvent,
|
|
377
|
+
ToolCallStartEvent as AGUIToolCallStartEvent,
|
|
378
|
+
UserMessage,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
from agentpool.agents.agui_agent.agui_converters import (
|
|
382
|
+
ToolCallAccumulator,
|
|
383
|
+
agui_to_native_event,
|
|
384
|
+
to_agui_input_content,
|
|
385
|
+
to_agui_tool,
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
if not self._client or not self._thread_id:
|
|
389
|
+
msg = "Agent not initialized - use async context manager"
|
|
390
|
+
raise RuntimeError(msg)
|
|
391
|
+
|
|
392
|
+
# Reset cancellation state
|
|
393
|
+
self._cancelled = False
|
|
394
|
+
self._current_stream_task = asyncio.current_task()
|
|
395
|
+
|
|
396
|
+
conversation = message_history if message_history is not None else self.conversation
|
|
397
|
+
user_msg, processed_prompts, _original_message = await prepare_prompts(*prompts)
|
|
398
|
+
self._run_id = str(uuid4()) # New run ID for each run
|
|
399
|
+
self._chunk_transformer.reset() # Reset chunk transformer
|
|
400
|
+
# Track messages in pydantic-ai format: ModelRequest -> ModelResponse -> ModelRequest...
|
|
401
|
+
# This mirrors pydantic-ai's new_messages() which includes the initial user request.
|
|
402
|
+
model_messages: list[ModelResponse | ModelRequest] = []
|
|
403
|
+
# Start with the user's request (same as pydantic-ai's new_messages())
|
|
404
|
+
initial_request = ModelRequest(parts=[UserPromptPart(content=processed_prompts)])
|
|
405
|
+
model_messages.append(initial_request)
|
|
406
|
+
current_response_parts: list[TextPart | ThinkingPart | ToolCallPart] = []
|
|
407
|
+
text_chunks: list[str] = [] # For final content string
|
|
408
|
+
|
|
409
|
+
run_started = RunStartedEvent(
|
|
410
|
+
thread_id=self._thread_id or self.conversation_id,
|
|
411
|
+
run_id=self._run_id or str(uuid4()),
|
|
412
|
+
agent_name=self.name,
|
|
413
|
+
)
|
|
414
|
+
for handler in self.event_handler._wrapped_handlers:
|
|
415
|
+
await handler(None, run_started)
|
|
416
|
+
yield run_started
|
|
417
|
+
|
|
418
|
+
# Get pending parts from conversation and convert them
|
|
419
|
+
pending_parts = conversation.get_pending_parts()
|
|
420
|
+
pending_content = to_agui_input_content(pending_parts)
|
|
421
|
+
# Convert user message content to AGUI format using processed prompts
|
|
422
|
+
user_content = to_agui_input_content(processed_prompts)
|
|
423
|
+
# Combine pending parts with new content
|
|
424
|
+
final_content = [*pending_content, *user_content]
|
|
425
|
+
user_message = UserMessage(id=str(uuid4()), content=final_content)
|
|
426
|
+
# Convert registered tools to AG-UI format
|
|
427
|
+
available_tools = await self.tools.get_tools(state="enabled")
|
|
428
|
+
agui_tools = [to_agui_tool(t) for t in available_tools]
|
|
429
|
+
tools_by_name = {t.name: t for t in available_tools}
|
|
430
|
+
# Build initial messages list
|
|
431
|
+
messages: list[Message] = [user_message]
|
|
432
|
+
tool_accumulator = ToolCallAccumulator()
|
|
433
|
+
pending_tool_results: list[ToolMessage] = []
|
|
434
|
+
self.log.debug("Sending prompt to AG-UI agent", tool_names=[t.name for t in agui_tools])
|
|
435
|
+
# Loop to handle tool calls - agent may request multiple rounds
|
|
436
|
+
try:
|
|
437
|
+
while True:
|
|
438
|
+
# Check for cancellation at start of each iteration
|
|
439
|
+
if self._cancelled:
|
|
440
|
+
self.log.info("Stream cancelled by user")
|
|
441
|
+
break
|
|
442
|
+
|
|
443
|
+
request_data = RunAgentInput(
|
|
444
|
+
thread_id=self._thread_id or self.conversation_id,
|
|
445
|
+
run_id=self._run_id,
|
|
446
|
+
state={},
|
|
447
|
+
messages=messages,
|
|
448
|
+
tools=agui_tools,
|
|
449
|
+
context=[],
|
|
450
|
+
forwarded_props={},
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
data = request_data.model_dump(by_alias=True)
|
|
454
|
+
tool_calls_pending: list[tuple[str, str, dict[str, Any]]] = []
|
|
455
|
+
|
|
456
|
+
try:
|
|
457
|
+
async with self._client.stream("POST", self.endpoint, json=data) as response:
|
|
458
|
+
response.raise_for_status()
|
|
459
|
+
async for raw_event in parse_sse_stream(response):
|
|
460
|
+
# Check for cancellation during streaming
|
|
461
|
+
if self._cancelled:
|
|
462
|
+
self.log.info("Stream cancelled during event processing")
|
|
463
|
+
break
|
|
464
|
+
|
|
465
|
+
# Transform chunks to proper START/CONTENT/END sequences
|
|
466
|
+
transformed_events = self._chunk_transformer.transform(raw_event)
|
|
467
|
+
|
|
468
|
+
for event in transformed_events:
|
|
469
|
+
# Handle events for accumulation and tool calls
|
|
470
|
+
match event:
|
|
471
|
+
case TextMessageContentEvent(delta=delta):
|
|
472
|
+
text_chunks.append(delta)
|
|
473
|
+
current_response_parts.append(TextPart(content=delta))
|
|
474
|
+
case TextMessageChunkEvent(delta=delta) if delta:
|
|
475
|
+
text_chunks.append(delta)
|
|
476
|
+
current_response_parts.append(TextPart(content=delta))
|
|
477
|
+
case ThinkingTextMessageContentEvent(delta=delta):
|
|
478
|
+
current_response_parts.append(ThinkingPart(content=delta))
|
|
479
|
+
case AGUIToolCallStartEvent(
|
|
480
|
+
tool_call_id=tc_id, tool_call_name=name
|
|
481
|
+
) if name:
|
|
482
|
+
tool_accumulator.start(tc_id, name)
|
|
483
|
+
self.log.debug(
|
|
484
|
+
"Tool call started",
|
|
485
|
+
tool_call_id=tc_id,
|
|
486
|
+
tool=name,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
case AGUIToolCallArgsEvent(tool_call_id=tc_id, delta=delta):
|
|
490
|
+
tool_accumulator.add_args(tc_id, delta)
|
|
491
|
+
|
|
492
|
+
case AGUIToolCallEndEvent(tool_call_id=tc_id):
|
|
493
|
+
if result := tool_accumulator.complete(tc_id):
|
|
494
|
+
tool_name, args = result
|
|
495
|
+
tool_calls_pending.append((tc_id, tool_name, args))
|
|
496
|
+
current_response_parts.append(
|
|
497
|
+
ToolCallPart(
|
|
498
|
+
tool_name=tool_name,
|
|
499
|
+
args=args,
|
|
500
|
+
tool_call_id=tc_id,
|
|
501
|
+
)
|
|
502
|
+
)
|
|
503
|
+
self.log.debug(
|
|
504
|
+
"Tool call completed",
|
|
505
|
+
tool_call_id=tc_id,
|
|
506
|
+
tool=tool_name,
|
|
507
|
+
args=args,
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
# Convert to native event and distribute to handlers
|
|
511
|
+
if native_event := agui_to_native_event(event):
|
|
512
|
+
# Check for queued custom events first
|
|
513
|
+
while not self._event_queue.empty():
|
|
514
|
+
try:
|
|
515
|
+
custom_event = self._event_queue.get_nowait()
|
|
516
|
+
for handler in self.event_handler._wrapped_handlers:
|
|
517
|
+
await handler(None, custom_event)
|
|
518
|
+
yield custom_event
|
|
519
|
+
except asyncio.QueueEmpty:
|
|
520
|
+
break
|
|
521
|
+
# Distribute to handlers
|
|
522
|
+
for handler in self.event_handler._wrapped_handlers:
|
|
523
|
+
await handler(None, native_event)
|
|
524
|
+
yield native_event
|
|
525
|
+
|
|
526
|
+
# Flush any pending chunk events at end of stream
|
|
527
|
+
for event in self._chunk_transformer.flush():
|
|
528
|
+
if native_event := agui_to_native_event(event):
|
|
529
|
+
for handler in self.event_handler._wrapped_handlers:
|
|
530
|
+
await handler(None, native_event)
|
|
531
|
+
yield native_event
|
|
532
|
+
|
|
533
|
+
except httpx.HTTPError:
|
|
534
|
+
self.log.exception("HTTP error during AG-UI run")
|
|
535
|
+
raise
|
|
536
|
+
|
|
537
|
+
# If cancelled, break out of the while loop
|
|
538
|
+
if self._cancelled:
|
|
539
|
+
break
|
|
540
|
+
|
|
541
|
+
# If no tool calls pending, we're done
|
|
542
|
+
if not tool_calls_pending:
|
|
543
|
+
break
|
|
544
|
+
|
|
545
|
+
# Execute pending tool calls locally and collect results
|
|
546
|
+
pending_tool_results = await execute_tool_calls(
|
|
547
|
+
tool_calls_pending,
|
|
548
|
+
tools_by_name,
|
|
549
|
+
confirmation_mode=self.tool_confirmation_mode,
|
|
550
|
+
input_provider=self._input_provider,
|
|
551
|
+
context=self.get_context(),
|
|
552
|
+
)
|
|
553
|
+
# If no results (all tools were server-side), we're done
|
|
554
|
+
if not pending_tool_results:
|
|
555
|
+
break
|
|
556
|
+
|
|
557
|
+
# Flush current response parts to model_messages
|
|
558
|
+
if current_response_parts:
|
|
559
|
+
model_messages.append(ModelResponse(parts=current_response_parts))
|
|
560
|
+
current_response_parts = []
|
|
561
|
+
|
|
562
|
+
# Create ModelRequest with tool return parts
|
|
563
|
+
tc_id_to_name = {tc_id: name for tc_id, name, _ in tool_calls_pending}
|
|
564
|
+
tool_return_parts: list[ToolReturnPart] = [
|
|
565
|
+
ToolReturnPart(
|
|
566
|
+
tool_name=tc_id_to_name.get(r.tool_call_id, "unknown"),
|
|
567
|
+
content=r.content,
|
|
568
|
+
tool_call_id=r.tool_call_id,
|
|
569
|
+
)
|
|
570
|
+
for r in pending_tool_results
|
|
571
|
+
]
|
|
572
|
+
model_messages.append(ModelRequest(parts=tool_return_parts))
|
|
573
|
+
|
|
574
|
+
# Add tool results to messages for next iteration
|
|
575
|
+
messages = [*pending_tool_results]
|
|
576
|
+
self.log.debug("Continuing with tool results", count=len(pending_tool_results))
|
|
577
|
+
|
|
578
|
+
except asyncio.CancelledError:
|
|
579
|
+
self.log.info("Stream cancelled via task cancellation")
|
|
580
|
+
self._cancelled = True
|
|
581
|
+
|
|
582
|
+
# Handle cancellation - emit partial message
|
|
583
|
+
if self._cancelled:
|
|
584
|
+
# Flush any remaining response parts
|
|
585
|
+
if current_response_parts:
|
|
586
|
+
model_messages.append(ModelResponse(parts=current_response_parts))
|
|
587
|
+
|
|
588
|
+
text_content = "".join(text_chunks)
|
|
589
|
+
final_message = ChatMessage[str](
|
|
590
|
+
content=text_content,
|
|
591
|
+
role="assistant",
|
|
592
|
+
name=self.name,
|
|
593
|
+
message_id=message_id or str(uuid4()),
|
|
594
|
+
conversation_id=self.conversation_id,
|
|
595
|
+
messages=model_messages,
|
|
596
|
+
finish_reason="stop",
|
|
597
|
+
)
|
|
598
|
+
complete_event = StreamCompleteEvent(message=final_message)
|
|
599
|
+
for handler in self.event_handler._wrapped_handlers:
|
|
600
|
+
await handler(None, complete_event)
|
|
601
|
+
yield complete_event
|
|
602
|
+
self._current_stream_task = None
|
|
603
|
+
return
|
|
604
|
+
|
|
605
|
+
# Flush any remaining response parts
|
|
606
|
+
if current_response_parts:
|
|
607
|
+
model_messages.append(ModelResponse(parts=current_response_parts))
|
|
608
|
+
|
|
609
|
+
# Final drain of event queue after stream completes
|
|
610
|
+
while not self._event_queue.empty():
|
|
611
|
+
try:
|
|
612
|
+
queued_event = self._event_queue.get_nowait()
|
|
613
|
+
for handler in self.event_handler._wrapped_handlers:
|
|
614
|
+
await handler(None, queued_event)
|
|
615
|
+
yield queued_event
|
|
616
|
+
except asyncio.QueueEmpty:
|
|
617
|
+
break
|
|
618
|
+
|
|
619
|
+
text_content = "".join(text_chunks)
|
|
620
|
+
final_message = ChatMessage[str](
|
|
621
|
+
content=text_content,
|
|
622
|
+
role="assistant",
|
|
623
|
+
name=self.name,
|
|
624
|
+
message_id=message_id or str(uuid4()),
|
|
625
|
+
conversation_id=self.conversation_id,
|
|
626
|
+
messages=model_messages,
|
|
627
|
+
)
|
|
628
|
+
complete_event = StreamCompleteEvent(message=final_message)
|
|
629
|
+
for handler in self.event_handler._wrapped_handlers:
|
|
630
|
+
await handler(None, complete_event)
|
|
631
|
+
yield complete_event
|
|
632
|
+
# Record to conversation history
|
|
633
|
+
conversation.add_chat_messages([user_msg, final_message])
|
|
634
|
+
|
|
635
|
+
async def run_iter(
|
|
636
|
+
self,
|
|
637
|
+
*prompt_groups: Sequence[PromptCompatible],
|
|
638
|
+
message_id: str | None = None,
|
|
639
|
+
**kwargs: Any,
|
|
640
|
+
) -> AsyncIterator[ChatMessage[str]]:
|
|
641
|
+
"""Execute multiple prompt groups sequentially.
|
|
642
|
+
|
|
643
|
+
Args:
|
|
644
|
+
prompt_groups: Groups of prompts to execute
|
|
645
|
+
message_id: Optional message ID base
|
|
646
|
+
**kwargs: Additional arguments (ignored for compatibility)
|
|
647
|
+
|
|
648
|
+
Yields:
|
|
649
|
+
ChatMessage for each completed prompt group
|
|
650
|
+
"""
|
|
651
|
+
for i, prompts in enumerate(prompt_groups):
|
|
652
|
+
mid = f"{message_id or 'msg'}_{i}" if message_id else None
|
|
653
|
+
yield await self.run(*prompts, message_id=mid)
|
|
654
|
+
|
|
655
|
+
@property
|
|
656
|
+
def model_name(self) -> str | None:
|
|
657
|
+
"""Get model name (AG-UI doesn't expose this)."""
|
|
658
|
+
return None
|
|
659
|
+
|
|
660
|
+
async def get_stats(self) -> MessageStats:
|
|
661
|
+
"""Get message statistics for this node."""
|
|
662
|
+
return MessageStats()
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
if __name__ == "__main__":
|
|
666
|
+
|
|
667
|
+
async def main() -> None:
|
|
668
|
+
"""Example usage."""
|
|
669
|
+
endpoint = "http://localhost:8000/agent/run"
|
|
670
|
+
async with AGUIAgent(endpoint=endpoint, name="test-agent") as agent:
|
|
671
|
+
result = await agent.run("What is 2+2?")
|
|
672
|
+
print(f"Result: {result.content}")
|
|
673
|
+
print("\nStreaming:")
|
|
674
|
+
async for event in agent.run_stream("Tell me a short joke"):
|
|
675
|
+
print(f"Event: {event}")
|
|
676
|
+
|
|
677
|
+
anyio.run(main)
|