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,423 @@
|
|
|
1
|
+
"""AG-UI to native event converters.
|
|
2
|
+
|
|
3
|
+
This module provides conversion from AG-UI protocol events to native agentpool
|
|
4
|
+
streaming events, enabling AGUIAgent to yield the same event types as native agents.
|
|
5
|
+
|
|
6
|
+
Also provides conversion of native Tool objects to AG-UI Tool format for
|
|
7
|
+
client-side tool execution.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import base64
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
14
|
+
|
|
15
|
+
import anyenv
|
|
16
|
+
from pydantic_ai import (
|
|
17
|
+
AudioUrl,
|
|
18
|
+
BinaryContent,
|
|
19
|
+
BinaryImage,
|
|
20
|
+
CachePoint,
|
|
21
|
+
DocumentUrl,
|
|
22
|
+
FileUrl,
|
|
23
|
+
ImageUrl,
|
|
24
|
+
PartDeltaEvent,
|
|
25
|
+
TextPartDelta,
|
|
26
|
+
ThinkingPartDelta,
|
|
27
|
+
VideoUrl,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from agentpool.agents.events import (
|
|
31
|
+
CustomEvent,
|
|
32
|
+
PlanUpdateEvent,
|
|
33
|
+
RunErrorEvent,
|
|
34
|
+
RunStartedEvent,
|
|
35
|
+
ToolCallProgressEvent,
|
|
36
|
+
ToolCallStartEvent as NativeToolCallStartEvent,
|
|
37
|
+
)
|
|
38
|
+
from agentpool.resource_providers.plan_provider import PlanEntry
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from collections.abc import Sequence
|
|
43
|
+
|
|
44
|
+
from ag_ui.core import BaseEvent, InputContent, Tool as AGUITool
|
|
45
|
+
from pydantic_ai import UserContent
|
|
46
|
+
|
|
47
|
+
from agentpool.agents.events import RichAgentStreamEvent
|
|
48
|
+
from agentpool.tools.base import Tool
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def agui_to_native_event(event: BaseEvent) -> RichAgentStreamEvent[Any] | None: # noqa: PLR0911
|
|
52
|
+
"""Convert AG-UI event to native streaming event.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
event: AG-UI Event from SSE stream
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Corresponding native event, or None if no mapping exists
|
|
59
|
+
"""
|
|
60
|
+
from ag_ui.core import (
|
|
61
|
+
ActivityDeltaEvent,
|
|
62
|
+
ActivitySnapshotEvent,
|
|
63
|
+
CustomEvent as AGUICustomEvent,
|
|
64
|
+
MessagesSnapshotEvent,
|
|
65
|
+
RawEvent,
|
|
66
|
+
RunErrorEvent as AGUIRunErrorEvent,
|
|
67
|
+
RunStartedEvent as AGUIRunStartedEvent,
|
|
68
|
+
StateDeltaEvent,
|
|
69
|
+
StateSnapshotEvent,
|
|
70
|
+
TextMessageChunkEvent,
|
|
71
|
+
TextMessageContentEvent,
|
|
72
|
+
TextMessageEndEvent,
|
|
73
|
+
TextMessageStartEvent,
|
|
74
|
+
ThinkingEndEvent,
|
|
75
|
+
ThinkingStartEvent,
|
|
76
|
+
ThinkingTextMessageContentEvent,
|
|
77
|
+
ThinkingTextMessageEndEvent,
|
|
78
|
+
ThinkingTextMessageStartEvent,
|
|
79
|
+
ToolCallArgsEvent,
|
|
80
|
+
ToolCallChunkEvent,
|
|
81
|
+
ToolCallEndEvent,
|
|
82
|
+
ToolCallResultEvent,
|
|
83
|
+
ToolCallStartEvent,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
match event:
|
|
87
|
+
# === Lifecycle Events ===
|
|
88
|
+
|
|
89
|
+
case AGUIRunStartedEvent(thread_id=thread_id, run_id=run_id):
|
|
90
|
+
return RunStartedEvent(thread_id=thread_id, run_id=run_id)
|
|
91
|
+
|
|
92
|
+
case AGUIRunErrorEvent(message=message, code=code):
|
|
93
|
+
return RunErrorEvent(message=message, code=code)
|
|
94
|
+
|
|
95
|
+
# === Text Message Events ===
|
|
96
|
+
|
|
97
|
+
case TextMessageContentEvent(delta=delta):
|
|
98
|
+
return PartDeltaEvent(index=0, delta=TextPartDelta(content_delta=delta))
|
|
99
|
+
|
|
100
|
+
case TextMessageChunkEvent(delta=delta) if delta:
|
|
101
|
+
return PartDeltaEvent(index=0, delta=TextPartDelta(content_delta=delta))
|
|
102
|
+
|
|
103
|
+
case TextMessageStartEvent() | TextMessageEndEvent():
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
# === Thinking/Reasoning Events ===
|
|
107
|
+
|
|
108
|
+
case ThinkingTextMessageContentEvent(delta=delta):
|
|
109
|
+
return PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=delta))
|
|
110
|
+
|
|
111
|
+
case ThinkingStartEvent() | ThinkingEndEvent():
|
|
112
|
+
# These mark thinking blocks but don't carry content
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
case ThinkingTextMessageStartEvent() | ThinkingTextMessageEndEvent():
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
# === Tool Call Events ===
|
|
119
|
+
|
|
120
|
+
case ToolCallStartEvent(tool_call_id=str() as tc_id, tool_call_name=name):
|
|
121
|
+
return NativeToolCallStartEvent(tool_call_id=tc_id, tool_name=name, title=name)
|
|
122
|
+
|
|
123
|
+
case ToolCallChunkEvent(tool_call_id=str() as tc_id, tool_call_name=str() as name):
|
|
124
|
+
return NativeToolCallStartEvent(tool_call_id=tc_id, tool_name=name, title=name)
|
|
125
|
+
|
|
126
|
+
case ToolCallArgsEvent(tool_call_id=tool_call_id, delta=_):
|
|
127
|
+
return ToolCallProgressEvent(tool_call_id=tool_call_id, status="in_progress")
|
|
128
|
+
|
|
129
|
+
case ToolCallResultEvent(tool_call_id=tc_id, content=content, message_id=_):
|
|
130
|
+
return ToolCallProgressEvent(tool_call_id=tc_id, status="completed", message=content)
|
|
131
|
+
|
|
132
|
+
case ToolCallEndEvent(tool_call_id=tool_call_id):
|
|
133
|
+
return ToolCallProgressEvent(tool_call_id=tool_call_id, status="completed")
|
|
134
|
+
|
|
135
|
+
# === Activity Events -> PlanUpdateEvent ===
|
|
136
|
+
|
|
137
|
+
case ActivitySnapshotEvent(
|
|
138
|
+
message_id=_, activity_type=activity_type, content=content, replace=_
|
|
139
|
+
):
|
|
140
|
+
# Map activity content to plan entries if it looks like a plan
|
|
141
|
+
if activity_type.upper() == "PLAN" and isinstance(content, list):
|
|
142
|
+
entries = _content_to_plan_entries(content)
|
|
143
|
+
if entries:
|
|
144
|
+
return PlanUpdateEvent(entries=entries)
|
|
145
|
+
# For other activity types, wrap as custom event
|
|
146
|
+
return CustomEvent(
|
|
147
|
+
event_data={"activity_type": activity_type, "content": content},
|
|
148
|
+
event_type=f"activity_{activity_type.lower()}",
|
|
149
|
+
source="ag-ui",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
case ActivityDeltaEvent(message_id=_, activity_type=activity_type, patch=patch):
|
|
153
|
+
return CustomEvent(
|
|
154
|
+
event_data={"activity_type": activity_type, "patch": patch},
|
|
155
|
+
event_type=f"activity_delta_{activity_type.lower()}",
|
|
156
|
+
source="ag-ui",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# === State Management Events ===
|
|
160
|
+
|
|
161
|
+
case StateSnapshotEvent(snapshot=snapshot):
|
|
162
|
+
return CustomEvent(event_data=snapshot, event_type="state_snapshot", source="ag-ui")
|
|
163
|
+
|
|
164
|
+
case StateDeltaEvent(delta=delta):
|
|
165
|
+
return CustomEvent(event_data=delta, event_type="state_delta", source="ag-ui")
|
|
166
|
+
|
|
167
|
+
case MessagesSnapshotEvent(messages=messages):
|
|
168
|
+
data = [m.model_dump() if hasattr(m, "model_dump") else m for m in messages]
|
|
169
|
+
return CustomEvent(event_data=data, event_type="messages_snapshot", source="ag-ui")
|
|
170
|
+
|
|
171
|
+
# === Special Events ===
|
|
172
|
+
|
|
173
|
+
case RawEvent(event=raw_event, source=source):
|
|
174
|
+
return CustomEvent(event_data=raw_event, event_type="raw", source=source or "ag-ui")
|
|
175
|
+
|
|
176
|
+
case AGUICustomEvent(name=name, value=value):
|
|
177
|
+
return CustomEvent(event_data=value, event_type=name, source="ag-ui")
|
|
178
|
+
|
|
179
|
+
case _:
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _content_to_plan_entries(content: list[Any]) -> list[PlanEntry]:
|
|
184
|
+
"""Convert AG-UI activity content to PlanEntry list.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
content: List of plan items from ActivitySnapshotEvent
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
List of PlanEntry objects
|
|
191
|
+
"""
|
|
192
|
+
entries: list[PlanEntry] = []
|
|
193
|
+
for item in content:
|
|
194
|
+
if isinstance(item, dict):
|
|
195
|
+
# Try to extract plan entry fields
|
|
196
|
+
entry_content = item.get("content") or item.get("text") or item.get("description", "")
|
|
197
|
+
priority = item.get("priority", "medium")
|
|
198
|
+
status = item.get("status", "pending")
|
|
199
|
+
|
|
200
|
+
# Normalize values
|
|
201
|
+
if priority not in ("high", "medium", "low"):
|
|
202
|
+
priority = "medium"
|
|
203
|
+
if status not in ("pending", "in_progress", "completed"):
|
|
204
|
+
status = "pending"
|
|
205
|
+
|
|
206
|
+
if entry_content:
|
|
207
|
+
entry = PlanEntry(content=str(entry_content), priority=priority, status=status)
|
|
208
|
+
entries.append(entry)
|
|
209
|
+
elif isinstance(item, str):
|
|
210
|
+
entries.append(PlanEntry(content=item, priority="medium", status="pending"))
|
|
211
|
+
return entries
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def to_agui_input_content(
|
|
215
|
+
parts: UserContent | Sequence[UserContent] | None,
|
|
216
|
+
) -> list[InputContent]:
|
|
217
|
+
"""Convert pydantic-ai UserContent parts to AG-UI InputContent format.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
parts: UserContent part(s) to convert (str, ImageUrl, BinaryContent, etc.)
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
List of AG-UI InputContent items
|
|
224
|
+
"""
|
|
225
|
+
from ag_ui.core import BinaryInputContent, TextInputContent
|
|
226
|
+
|
|
227
|
+
if parts is None:
|
|
228
|
+
return []
|
|
229
|
+
|
|
230
|
+
# Normalize to list
|
|
231
|
+
part_list = (
|
|
232
|
+
[parts] if isinstance(parts, str | FileUrl | BinaryContent | CachePoint) else list(parts)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
result: list[InputContent] = []
|
|
236
|
+
for part in part_list:
|
|
237
|
+
match part:
|
|
238
|
+
case str() as text:
|
|
239
|
+
result.append(TextInputContent(text=text))
|
|
240
|
+
|
|
241
|
+
case ImageUrl(url=url, media_type=media_type):
|
|
242
|
+
result.append(BinaryInputContent(url=str(url), mime_type=media_type))
|
|
243
|
+
|
|
244
|
+
case AudioUrl(url=url, media_type=media_type):
|
|
245
|
+
result.append(BinaryInputContent(url=str(url), mime_type=media_type))
|
|
246
|
+
|
|
247
|
+
case DocumentUrl(url=url, media_type=media_type):
|
|
248
|
+
result.append(BinaryInputContent(url=str(url), mime_type=media_type))
|
|
249
|
+
|
|
250
|
+
case VideoUrl(url=url, media_type=media_type):
|
|
251
|
+
result.append(BinaryInputContent(url=str(url), mime_type=media_type))
|
|
252
|
+
|
|
253
|
+
case FileUrl(url=url, media_type=media_type):
|
|
254
|
+
# Generic FileUrl fallback
|
|
255
|
+
result.append(BinaryInputContent(url=str(url), mime_type=media_type))
|
|
256
|
+
|
|
257
|
+
case BinaryImage(data=data, media_type=media_type):
|
|
258
|
+
encoded = base64.b64encode(data).decode("utf-8")
|
|
259
|
+
result.append(BinaryInputContent(data=encoded, mime_type=media_type))
|
|
260
|
+
|
|
261
|
+
case BinaryContent(data=data, media_type=media_type):
|
|
262
|
+
encoded = base64.b64encode(data).decode("utf-8")
|
|
263
|
+
result.append(BinaryInputContent(data=encoded, mime_type=media_type))
|
|
264
|
+
|
|
265
|
+
case CachePoint():
|
|
266
|
+
# Cache points are markers, not actual content - skip
|
|
267
|
+
pass
|
|
268
|
+
|
|
269
|
+
case _:
|
|
270
|
+
# Fallback: convert to string
|
|
271
|
+
result.append(TextInputContent(text=str(part)))
|
|
272
|
+
|
|
273
|
+
return result
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def to_agui_tool(tool: Tool) -> AGUITool:
|
|
277
|
+
"""Convert native Tool to AG-UI Tool format.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
tool: native Tool instance
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
AG-UI Tool with JSON Schema parameters
|
|
284
|
+
"""
|
|
285
|
+
from ag_ui.core import Tool as AGUITool
|
|
286
|
+
|
|
287
|
+
schema = tool.schema
|
|
288
|
+
func_schema = schema["function"]
|
|
289
|
+
return AGUITool(
|
|
290
|
+
name=func_schema["name"],
|
|
291
|
+
description=func_schema.get("description", ""),
|
|
292
|
+
parameters=func_schema.get("parameters", {"type": "object", "properties": {}}),
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _repair_partial_json(buffer: str) -> str:
|
|
297
|
+
"""Attempt to repair truncated JSON for preview purposes.
|
|
298
|
+
|
|
299
|
+
Handles common truncation cases:
|
|
300
|
+
- Unclosed strings
|
|
301
|
+
- Missing closing braces/brackets
|
|
302
|
+
- Trailing commas
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
buffer: Potentially incomplete JSON string
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
Repaired JSON string (may still be invalid in edge cases)
|
|
309
|
+
"""
|
|
310
|
+
if not buffer:
|
|
311
|
+
return "{}"
|
|
312
|
+
|
|
313
|
+
result = buffer.rstrip()
|
|
314
|
+
|
|
315
|
+
# Check if we're in the middle of a string by counting unescaped quotes
|
|
316
|
+
in_string = False
|
|
317
|
+
i = 0
|
|
318
|
+
while i < len(result):
|
|
319
|
+
char = result[i]
|
|
320
|
+
if char == "\\" and i + 1 < len(result):
|
|
321
|
+
i += 2 # Skip escaped character
|
|
322
|
+
continue
|
|
323
|
+
if char == '"':
|
|
324
|
+
in_string = not in_string
|
|
325
|
+
i += 1
|
|
326
|
+
|
|
327
|
+
# Close unclosed string
|
|
328
|
+
if in_string:
|
|
329
|
+
result += '"'
|
|
330
|
+
|
|
331
|
+
# Remove trailing comma (invalid JSON)
|
|
332
|
+
result = result.rstrip()
|
|
333
|
+
if result.endswith(","):
|
|
334
|
+
result = result[:-1]
|
|
335
|
+
|
|
336
|
+
# Balance braces and brackets
|
|
337
|
+
open_braces = result.count("{") - result.count("}")
|
|
338
|
+
open_brackets = result.count("[") - result.count("]")
|
|
339
|
+
|
|
340
|
+
result += "]" * max(0, open_brackets)
|
|
341
|
+
result += "}" * max(0, open_braces)
|
|
342
|
+
|
|
343
|
+
return result
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class ToolCallAccumulator:
|
|
347
|
+
"""Accumulates streamed tool call arguments.
|
|
348
|
+
|
|
349
|
+
AG-UI streams tool call arguments as deltas, this class accumulates them
|
|
350
|
+
and provides the complete arguments when the tool call ends.
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
def __init__(self) -> None:
|
|
354
|
+
self._calls: dict[str, dict[str, Any]] = {}
|
|
355
|
+
|
|
356
|
+
def start(self, tool_call_id: str, tool_name: str) -> None:
|
|
357
|
+
"""Start tracking a new tool call."""
|
|
358
|
+
self._calls[tool_call_id] = {"name": tool_name, "args_buffer": ""}
|
|
359
|
+
|
|
360
|
+
def add_args(self, tool_call_id: str, delta: str) -> None:
|
|
361
|
+
"""Add argument delta to a tool call."""
|
|
362
|
+
if tool_call_id in self._calls:
|
|
363
|
+
self._calls[tool_call_id]["args_buffer"] += delta
|
|
364
|
+
|
|
365
|
+
def complete(self, tool_call_id: str) -> tuple[str, dict[str, Any]] | None:
|
|
366
|
+
"""Complete a tool call and return (tool_name, parsed_args).
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
Tuple of (tool_name, args_dict) or None if call not found
|
|
370
|
+
"""
|
|
371
|
+
if tool_call_id not in self._calls:
|
|
372
|
+
return None
|
|
373
|
+
|
|
374
|
+
call_data = self._calls.pop(tool_call_id)
|
|
375
|
+
args_str = call_data["args_buffer"]
|
|
376
|
+
try:
|
|
377
|
+
args = anyenv.load_json(args_str) if args_str else {}
|
|
378
|
+
except anyenv.JsonLoadError:
|
|
379
|
+
args = {"raw": args_str}
|
|
380
|
+
return call_data["name"], args
|
|
381
|
+
|
|
382
|
+
def get_pending(self, tool_call_id: str) -> tuple[str, str] | None:
|
|
383
|
+
"""Get pending call data (tool_name, args_buffer) without completing."""
|
|
384
|
+
if tool_call_id not in self._calls:
|
|
385
|
+
return None
|
|
386
|
+
data = self._calls[tool_call_id]
|
|
387
|
+
return data["name"], data["args_buffer"]
|
|
388
|
+
|
|
389
|
+
def get_partial_args(self, tool_call_id: str) -> dict[str, Any]:
|
|
390
|
+
"""Get best-effort parsed args from incomplete JSON stream.
|
|
391
|
+
|
|
392
|
+
Uses heuristics to complete truncated JSON for preview purposes.
|
|
393
|
+
Handles unclosed strings, missing braces/brackets, and trailing commas.
|
|
394
|
+
|
|
395
|
+
Args:
|
|
396
|
+
tool_call_id: Tool call ID
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
Partially parsed arguments or empty dict
|
|
400
|
+
"""
|
|
401
|
+
if tool_call_id not in self._calls:
|
|
402
|
+
return {}
|
|
403
|
+
|
|
404
|
+
buffer = self._calls[tool_call_id]["args_buffer"]
|
|
405
|
+
if not buffer:
|
|
406
|
+
return {}
|
|
407
|
+
|
|
408
|
+
# Try direct parse first
|
|
409
|
+
try:
|
|
410
|
+
return anyenv.load_json(buffer)
|
|
411
|
+
except anyenv.JsonLoadError:
|
|
412
|
+
pass
|
|
413
|
+
|
|
414
|
+
# Try to repair truncated JSON
|
|
415
|
+
try:
|
|
416
|
+
repaired = _repair_partial_json(buffer)
|
|
417
|
+
return anyenv.load_json(repaired)
|
|
418
|
+
except anyenv.JsonLoadError:
|
|
419
|
+
return {}
|
|
420
|
+
|
|
421
|
+
def clear(self) -> None:
|
|
422
|
+
"""Clear all pending tool calls."""
|
|
423
|
+
self._calls.clear()
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Chunk transformer for AG-UI events.
|
|
2
|
+
|
|
3
|
+
Transforms TEXT_MESSAGE_CHUNK and TOOL_CALL_CHUNK events into proper
|
|
4
|
+
START/CONTENT/END sequences for easier downstream processing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from agentpool.log import get_logger
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from ag_ui.core import BaseEvent, TextMessageChunkEvent, ToolCallChunkEvent
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ChunkTransformer:
|
|
22
|
+
"""Transforms CHUNK events into proper START/CONTENT/END sequences.
|
|
23
|
+
|
|
24
|
+
AG-UI supports two streaming modes:
|
|
25
|
+
1. Explicit: TEXT_MESSAGE_START -> TEXT_MESSAGE_CONTENT* -> TEXT_MESSAGE_END
|
|
26
|
+
2. Chunk: TEXT_MESSAGE_CHUNK* (implicit start/end based on message_id changes)
|
|
27
|
+
|
|
28
|
+
This transformer normalizes chunk mode into explicit mode for consistent handling.
|
|
29
|
+
Same applies for TOOL_CALL_CHUNK events.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self) -> None:
|
|
33
|
+
"""Initialize transformer."""
|
|
34
|
+
# Track active text message: message_id -> role
|
|
35
|
+
self._active_text: dict[str, str] | None = None
|
|
36
|
+
# Track active tool call: tool_call_id -> (name, parent_message_id)
|
|
37
|
+
self._active_tool: dict[str, tuple[str, str | None]] | None = None
|
|
38
|
+
|
|
39
|
+
def transform(self, event: BaseEvent) -> list[BaseEvent]:
|
|
40
|
+
"""Transform a single event, potentially expanding chunks.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
event: Input event
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
List of output events (may be empty, single, or multiple)
|
|
47
|
+
"""
|
|
48
|
+
from ag_ui.core import EventType
|
|
49
|
+
|
|
50
|
+
match event.type:
|
|
51
|
+
case EventType.TEXT_MESSAGE_CHUNK:
|
|
52
|
+
return self._handle_text_chunk(event) # type: ignore[arg-type]
|
|
53
|
+
|
|
54
|
+
case EventType.TOOL_CALL_CHUNK:
|
|
55
|
+
return self._handle_tool_chunk(event) # type: ignore[arg-type]
|
|
56
|
+
|
|
57
|
+
# These events close any pending chunks
|
|
58
|
+
case (
|
|
59
|
+
EventType.TEXT_MESSAGE_START
|
|
60
|
+
| EventType.TEXT_MESSAGE_END
|
|
61
|
+
| EventType.TOOL_CALL_START
|
|
62
|
+
| EventType.TOOL_CALL_END
|
|
63
|
+
| EventType.RUN_FINISHED
|
|
64
|
+
| EventType.RUN_ERROR
|
|
65
|
+
):
|
|
66
|
+
close_events = self._close_all_pending()
|
|
67
|
+
return [*close_events, event]
|
|
68
|
+
|
|
69
|
+
case _:
|
|
70
|
+
# Pass through other events unchanged
|
|
71
|
+
return [event]
|
|
72
|
+
|
|
73
|
+
def _handle_text_chunk(self, event: TextMessageChunkEvent) -> list[BaseEvent]:
|
|
74
|
+
"""Handle TEXT_MESSAGE_CHUNK event."""
|
|
75
|
+
from ag_ui.core import EventType, TextMessageContentEvent, TextMessageStartEvent
|
|
76
|
+
|
|
77
|
+
result: list[BaseEvent] = []
|
|
78
|
+
message_id = event.message_id
|
|
79
|
+
role = event.role or "assistant"
|
|
80
|
+
delta = event.delta
|
|
81
|
+
|
|
82
|
+
# Check if we need to close current text message (different ID)
|
|
83
|
+
if self._active_text is not None:
|
|
84
|
+
current_id = next(iter(self._active_text.keys()))
|
|
85
|
+
if message_id and message_id != current_id:
|
|
86
|
+
result.extend(self._close_text_message())
|
|
87
|
+
|
|
88
|
+
# Start new message if needed
|
|
89
|
+
if self._active_text is None and message_id:
|
|
90
|
+
self._active_text = {message_id: role}
|
|
91
|
+
start_event = TextMessageStartEvent(
|
|
92
|
+
type=EventType.TEXT_MESSAGE_START,
|
|
93
|
+
message_id=message_id,
|
|
94
|
+
role=role,
|
|
95
|
+
)
|
|
96
|
+
result.append(start_event)
|
|
97
|
+
|
|
98
|
+
# Emit content if we have delta and active message
|
|
99
|
+
if delta and self._active_text:
|
|
100
|
+
current_id = next(iter(self._active_text.keys()))
|
|
101
|
+
content_event = TextMessageContentEvent(
|
|
102
|
+
type=EventType.TEXT_MESSAGE_CONTENT,
|
|
103
|
+
message_id=current_id,
|
|
104
|
+
delta=delta,
|
|
105
|
+
)
|
|
106
|
+
result.append(content_event)
|
|
107
|
+
|
|
108
|
+
return result
|
|
109
|
+
|
|
110
|
+
def _handle_tool_chunk(self, event: ToolCallChunkEvent) -> list[BaseEvent]:
|
|
111
|
+
"""Handle TOOL_CALL_CHUNK event."""
|
|
112
|
+
from ag_ui.core import EventType, ToolCallArgsEvent, ToolCallStartEvent
|
|
113
|
+
|
|
114
|
+
result: list[BaseEvent] = []
|
|
115
|
+
tool_call_id = event.tool_call_id
|
|
116
|
+
tool_name = event.tool_call_name
|
|
117
|
+
parent_id = event.parent_message_id
|
|
118
|
+
delta = event.delta
|
|
119
|
+
|
|
120
|
+
# Check if we need to close current tool call (different ID)
|
|
121
|
+
if self._active_tool is not None:
|
|
122
|
+
current_id = next(iter(self._active_tool.keys()))
|
|
123
|
+
if tool_call_id and tool_call_id != current_id:
|
|
124
|
+
result.extend(self._close_tool_call())
|
|
125
|
+
|
|
126
|
+
# Start new tool call if needed
|
|
127
|
+
if self._active_tool is None and tool_call_id and tool_name:
|
|
128
|
+
self._active_tool = {tool_call_id: (tool_name, parent_id)}
|
|
129
|
+
start_event = ToolCallStartEvent(
|
|
130
|
+
type=EventType.TOOL_CALL_START,
|
|
131
|
+
tool_call_id=tool_call_id,
|
|
132
|
+
tool_call_name=tool_name,
|
|
133
|
+
parent_message_id=parent_id,
|
|
134
|
+
)
|
|
135
|
+
result.append(start_event)
|
|
136
|
+
|
|
137
|
+
# Emit args if we have delta and active tool call
|
|
138
|
+
if delta and self._active_tool:
|
|
139
|
+
current_id = next(iter(self._active_tool.keys()))
|
|
140
|
+
args_event = ToolCallArgsEvent(
|
|
141
|
+
type=EventType.TOOL_CALL_ARGS,
|
|
142
|
+
tool_call_id=current_id,
|
|
143
|
+
delta=delta,
|
|
144
|
+
)
|
|
145
|
+
result.append(args_event)
|
|
146
|
+
|
|
147
|
+
return result
|
|
148
|
+
|
|
149
|
+
def _close_text_message(self) -> list[BaseEvent]:
|
|
150
|
+
"""Close active text message."""
|
|
151
|
+
from ag_ui.core import EventType, TextMessageEndEvent
|
|
152
|
+
|
|
153
|
+
if self._active_text is None:
|
|
154
|
+
return []
|
|
155
|
+
|
|
156
|
+
message_id = next(iter(self._active_text.keys()))
|
|
157
|
+
self._active_text = None
|
|
158
|
+
|
|
159
|
+
end_event = TextMessageEndEvent(
|
|
160
|
+
type=EventType.TEXT_MESSAGE_END,
|
|
161
|
+
message_id=message_id,
|
|
162
|
+
)
|
|
163
|
+
logger.debug("Chunk transformer: TEXT_MESSAGE_END", message_id=message_id)
|
|
164
|
+
return [end_event]
|
|
165
|
+
|
|
166
|
+
def _close_tool_call(self) -> list[BaseEvent]:
|
|
167
|
+
"""Close active tool call."""
|
|
168
|
+
from ag_ui.core import EventType, ToolCallEndEvent
|
|
169
|
+
|
|
170
|
+
if self._active_tool is None:
|
|
171
|
+
return []
|
|
172
|
+
|
|
173
|
+
tool_call_id = next(iter(self._active_tool.keys()))
|
|
174
|
+
self._active_tool = None
|
|
175
|
+
|
|
176
|
+
end_event = ToolCallEndEvent(
|
|
177
|
+
type=EventType.TOOL_CALL_END,
|
|
178
|
+
tool_call_id=tool_call_id,
|
|
179
|
+
)
|
|
180
|
+
logger.debug("Chunk transformer: TOOL_CALL_END", tool_call_id=tool_call_id)
|
|
181
|
+
return [end_event]
|
|
182
|
+
|
|
183
|
+
def _close_all_pending(self) -> list[BaseEvent]:
|
|
184
|
+
"""Close all pending chunks (text and tool)."""
|
|
185
|
+
result: list[BaseEvent] = []
|
|
186
|
+
result.extend(self._close_text_message())
|
|
187
|
+
result.extend(self._close_tool_call())
|
|
188
|
+
return result
|
|
189
|
+
|
|
190
|
+
def flush(self) -> list[BaseEvent]:
|
|
191
|
+
"""Flush any pending events at end of stream.
|
|
192
|
+
|
|
193
|
+
Call this when the stream ends to ensure all pending
|
|
194
|
+
messages/tool calls are properly closed.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
List of closing events
|
|
198
|
+
"""
|
|
199
|
+
return self._close_all_pending()
|
|
200
|
+
|
|
201
|
+
def reset(self) -> None:
|
|
202
|
+
"""Reset transformer state."""
|
|
203
|
+
self._active_text = None
|
|
204
|
+
self._active_tool = None
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Extended AG-UI event types.
|
|
2
|
+
|
|
3
|
+
The upstream ag_ui.core.Event union is missing thinking events.
|
|
4
|
+
This module provides a complete Event type until the SDK is fixed.
|
|
5
|
+
|
|
6
|
+
TODO: Remove this workaround once upstream SDK is fixed.
|
|
7
|
+
See: https://github.com/ag-ui-protocol/ag-ui/pull/753
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Annotated
|
|
13
|
+
|
|
14
|
+
from ag_ui.core import (
|
|
15
|
+
ActivityDeltaEvent,
|
|
16
|
+
ActivitySnapshotEvent,
|
|
17
|
+
CustomEvent,
|
|
18
|
+
MessagesSnapshotEvent,
|
|
19
|
+
RawEvent,
|
|
20
|
+
RunErrorEvent,
|
|
21
|
+
RunFinishedEvent,
|
|
22
|
+
RunStartedEvent,
|
|
23
|
+
StateDeltaEvent,
|
|
24
|
+
StateSnapshotEvent,
|
|
25
|
+
StepFinishedEvent,
|
|
26
|
+
StepStartedEvent,
|
|
27
|
+
TextMessageChunkEvent,
|
|
28
|
+
TextMessageContentEvent,
|
|
29
|
+
TextMessageEndEvent,
|
|
30
|
+
TextMessageStartEvent,
|
|
31
|
+
ThinkingEndEvent,
|
|
32
|
+
ThinkingStartEvent,
|
|
33
|
+
ThinkingTextMessageContentEvent,
|
|
34
|
+
ThinkingTextMessageEndEvent,
|
|
35
|
+
ThinkingTextMessageStartEvent,
|
|
36
|
+
ToolCallArgsEvent,
|
|
37
|
+
ToolCallChunkEvent,
|
|
38
|
+
ToolCallEndEvent,
|
|
39
|
+
ToolCallResultEvent,
|
|
40
|
+
ToolCallStartEvent,
|
|
41
|
+
)
|
|
42
|
+
from pydantic import Field
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Complete Event union including thinking events (missing from upstream SDK)
|
|
46
|
+
Event = Annotated[
|
|
47
|
+
# Text message events
|
|
48
|
+
TextMessageStartEvent
|
|
49
|
+
| TextMessageContentEvent
|
|
50
|
+
| TextMessageEndEvent
|
|
51
|
+
| TextMessageChunkEvent
|
|
52
|
+
# Thinking events (missing from upstream Event union)
|
|
53
|
+
| ThinkingStartEvent
|
|
54
|
+
| ThinkingEndEvent
|
|
55
|
+
| ThinkingTextMessageStartEvent
|
|
56
|
+
| ThinkingTextMessageContentEvent
|
|
57
|
+
| ThinkingTextMessageEndEvent
|
|
58
|
+
# Tool call events
|
|
59
|
+
| ToolCallStartEvent
|
|
60
|
+
| ToolCallArgsEvent
|
|
61
|
+
| ToolCallEndEvent
|
|
62
|
+
| ToolCallChunkEvent
|
|
63
|
+
| ToolCallResultEvent
|
|
64
|
+
# State events
|
|
65
|
+
| StateSnapshotEvent
|
|
66
|
+
| StateDeltaEvent
|
|
67
|
+
| MessagesSnapshotEvent
|
|
68
|
+
# Activity events
|
|
69
|
+
| ActivitySnapshotEvent
|
|
70
|
+
| ActivityDeltaEvent
|
|
71
|
+
# Lifecycle events
|
|
72
|
+
| RunStartedEvent
|
|
73
|
+
| RunFinishedEvent
|
|
74
|
+
| RunErrorEvent
|
|
75
|
+
| StepStartedEvent
|
|
76
|
+
| StepFinishedEvent
|
|
77
|
+
# Special events
|
|
78
|
+
| RawEvent
|
|
79
|
+
| CustomEvent,
|
|
80
|
+
Field(discriminator="type"),
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
__all__ = ["Event"]
|