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,419 @@
|
|
|
1
|
+
"""Storage manager for handling multiple providers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
7
|
+
|
|
8
|
+
from anyenv import method_spawner
|
|
9
|
+
from pydantic_ai import Agent
|
|
10
|
+
|
|
11
|
+
from agentpool.log import get_logger
|
|
12
|
+
from agentpool.storage.serialization import serialize_messages
|
|
13
|
+
from agentpool.utils.tasks import TaskManager
|
|
14
|
+
from agentpool_config.storage import (
|
|
15
|
+
FileStorageConfig,
|
|
16
|
+
MemoryStorageConfig,
|
|
17
|
+
SQLStorageConfig,
|
|
18
|
+
TextLogConfig,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from collections.abc import Sequence
|
|
24
|
+
from datetime import datetime
|
|
25
|
+
from types import TracebackType
|
|
26
|
+
|
|
27
|
+
from agentpool.common_types import JsonValue
|
|
28
|
+
from agentpool.messaging import ChatMessage
|
|
29
|
+
from agentpool_config.session import SessionQuery
|
|
30
|
+
from agentpool_config.storage import BaseStorageProviderConfig, StorageConfig
|
|
31
|
+
from agentpool_storage.base import StorageProvider
|
|
32
|
+
|
|
33
|
+
logger = get_logger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class StorageManager:
|
|
37
|
+
"""Manages multiple storage providers.
|
|
38
|
+
|
|
39
|
+
Handles:
|
|
40
|
+
- Provider initialization and cleanup
|
|
41
|
+
- Message distribution to providers
|
|
42
|
+
- History loading from capable providers
|
|
43
|
+
- Global logging filters
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, config: StorageConfig) -> None:
|
|
47
|
+
"""Initialize storage manager.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
config: Storage configuration including providers and filters
|
|
51
|
+
"""
|
|
52
|
+
self.config = config
|
|
53
|
+
self.task_manager = TaskManager()
|
|
54
|
+
self.providers = [self._create_provider(cfg) for cfg in self.config.effective_providers]
|
|
55
|
+
|
|
56
|
+
async def __aenter__(self) -> Self:
|
|
57
|
+
"""Initialize all providers."""
|
|
58
|
+
for provider in self.providers:
|
|
59
|
+
await provider.__aenter__()
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
async def __aexit__(
|
|
63
|
+
self,
|
|
64
|
+
exc_type: type[BaseException] | None,
|
|
65
|
+
exc_val: BaseException | None,
|
|
66
|
+
exc_tb: TracebackType | None,
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Clean up all providers."""
|
|
69
|
+
errors = []
|
|
70
|
+
for provider in self.providers:
|
|
71
|
+
try:
|
|
72
|
+
await provider.__aexit__(exc_type, exc_val, exc_tb)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
errors.append(e)
|
|
75
|
+
logger.exception("Error cleaning up provider", provider=provider)
|
|
76
|
+
|
|
77
|
+
await self.task_manager.cleanup_tasks()
|
|
78
|
+
|
|
79
|
+
if errors:
|
|
80
|
+
msg = "Provider cleanup errors"
|
|
81
|
+
raise ExceptionGroup(msg, errors)
|
|
82
|
+
|
|
83
|
+
def cleanup(self) -> None:
|
|
84
|
+
"""Clean up all providers."""
|
|
85
|
+
for provider in self.providers:
|
|
86
|
+
try:
|
|
87
|
+
provider.cleanup()
|
|
88
|
+
except Exception:
|
|
89
|
+
logger.exception("Error cleaning up provider", provider=provider)
|
|
90
|
+
self.providers.clear()
|
|
91
|
+
|
|
92
|
+
def _create_provider(self, config: BaseStorageProviderConfig) -> StorageProvider:
|
|
93
|
+
"""Create provider instance from configuration."""
|
|
94
|
+
# Extract common settings from BaseStorageProviderConfig
|
|
95
|
+
match self.config.filter_mode:
|
|
96
|
+
case "and" if self.config.agents and config.agents:
|
|
97
|
+
logged_agents: set[str] | None = self.config.agents & config.agents
|
|
98
|
+
case "and":
|
|
99
|
+
# If either is None, use the other; if both None, use None (log all)
|
|
100
|
+
if self.config.agents is None and config.agents is None:
|
|
101
|
+
logged_agents = None
|
|
102
|
+
else:
|
|
103
|
+
logged_agents = self.config.agents or config.agents or set()
|
|
104
|
+
case "override":
|
|
105
|
+
logged_agents = config.agents if config.agents is not None else self.config.agents
|
|
106
|
+
|
|
107
|
+
provider_config = config.model_copy(
|
|
108
|
+
update={
|
|
109
|
+
"log_messages": config.log_messages and self.config.log_messages,
|
|
110
|
+
"log_conversations": config.log_conversations and self.config.log_conversations,
|
|
111
|
+
"log_commands": config.log_commands and self.config.log_commands,
|
|
112
|
+
"log_context": config.log_context and self.config.log_context,
|
|
113
|
+
"agents": logged_agents,
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
match provider_config:
|
|
118
|
+
case SQLStorageConfig() as config:
|
|
119
|
+
from agentpool_storage.sql_provider import SQLModelProvider
|
|
120
|
+
|
|
121
|
+
return SQLModelProvider(provider_config)
|
|
122
|
+
case FileStorageConfig():
|
|
123
|
+
from agentpool_storage.file_provider import FileProvider
|
|
124
|
+
|
|
125
|
+
return FileProvider(provider_config)
|
|
126
|
+
case TextLogConfig():
|
|
127
|
+
from agentpool_storage.text_log_provider import TextLogProvider
|
|
128
|
+
|
|
129
|
+
return TextLogProvider(provider_config)
|
|
130
|
+
|
|
131
|
+
case MemoryStorageConfig():
|
|
132
|
+
from agentpool_storage.memory_provider import MemoryStorageProvider
|
|
133
|
+
|
|
134
|
+
return MemoryStorageProvider(provider_config)
|
|
135
|
+
case _:
|
|
136
|
+
msg = f"Unknown provider type: {provider_config}"
|
|
137
|
+
raise ValueError(msg)
|
|
138
|
+
|
|
139
|
+
def get_history_provider(self, preferred: str | None = None) -> StorageProvider:
|
|
140
|
+
"""Get provider for loading history.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
preferred: Optional preferred provider name
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
First capable provider based on priority:
|
|
147
|
+
1. Preferred provider if specified and capable
|
|
148
|
+
2. Default provider if specified and capable
|
|
149
|
+
3. First capable provider
|
|
150
|
+
4. Raises error if no capable provider found
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
# Function to find capable provider by name
|
|
154
|
+
def find_provider(name: str) -> StorageProvider | None:
|
|
155
|
+
for p in self.providers:
|
|
156
|
+
if (
|
|
157
|
+
not getattr(p, "write_only", False)
|
|
158
|
+
and p.can_load_history
|
|
159
|
+
and p.__class__.__name__.lower() == name.lower()
|
|
160
|
+
):
|
|
161
|
+
return p
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
# Try preferred provider
|
|
165
|
+
if preferred and (provider := find_provider(preferred)):
|
|
166
|
+
return provider
|
|
167
|
+
|
|
168
|
+
# Try default provider
|
|
169
|
+
if self.config.default_provider:
|
|
170
|
+
if provider := find_provider(self.config.default_provider):
|
|
171
|
+
return provider
|
|
172
|
+
msg = "Default provider not found or not capable of loading history"
|
|
173
|
+
logger.warning(msg, provider=self.config.default_provider)
|
|
174
|
+
|
|
175
|
+
# Find first capable provider
|
|
176
|
+
for provider in self.providers:
|
|
177
|
+
if not getattr(provider, "write_only", False) and provider.can_load_history:
|
|
178
|
+
return provider
|
|
179
|
+
|
|
180
|
+
msg = "No capable provider found for loading history"
|
|
181
|
+
raise RuntimeError(msg)
|
|
182
|
+
|
|
183
|
+
@method_spawner
|
|
184
|
+
async def filter_messages(
|
|
185
|
+
self,
|
|
186
|
+
query: SessionQuery,
|
|
187
|
+
preferred_provider: str | None = None,
|
|
188
|
+
) -> list[ChatMessage[str]]:
|
|
189
|
+
"""Get messages matching query.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
query: Filter criteria
|
|
193
|
+
preferred_provider: Optional preferred provider to use
|
|
194
|
+
"""
|
|
195
|
+
provider = self.get_history_provider(preferred_provider)
|
|
196
|
+
return await provider.filter_messages(query)
|
|
197
|
+
|
|
198
|
+
@method_spawner
|
|
199
|
+
async def log_message(self, message: ChatMessage[Any]) -> None:
|
|
200
|
+
"""Log message to all providers."""
|
|
201
|
+
if not self.config.log_messages:
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
for provider in self.providers:
|
|
205
|
+
if provider.should_log_agent(message.name or "no name"):
|
|
206
|
+
await provider.log_message(
|
|
207
|
+
conversation_id=message.conversation_id or "",
|
|
208
|
+
message_id=message.message_id,
|
|
209
|
+
content=str(message.content),
|
|
210
|
+
role=message.role,
|
|
211
|
+
name=message.name,
|
|
212
|
+
cost_info=message.cost_info,
|
|
213
|
+
model=message.model_name,
|
|
214
|
+
response_time=message.response_time,
|
|
215
|
+
forwarded_from=message.forwarded_from,
|
|
216
|
+
provider_name=message.provider_name,
|
|
217
|
+
provider_response_id=message.provider_response_id,
|
|
218
|
+
messages=serialize_messages(message.messages),
|
|
219
|
+
finish_reason=message.finish_reason,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
@method_spawner
|
|
223
|
+
async def log_conversation(
|
|
224
|
+
self,
|
|
225
|
+
*,
|
|
226
|
+
conversation_id: str,
|
|
227
|
+
node_name: str,
|
|
228
|
+
start_time: datetime | None = None,
|
|
229
|
+
) -> None:
|
|
230
|
+
"""Log conversation to all providers."""
|
|
231
|
+
if not self.config.log_conversations:
|
|
232
|
+
return
|
|
233
|
+
|
|
234
|
+
for provider in self.providers:
|
|
235
|
+
await provider.log_conversation(
|
|
236
|
+
conversation_id=conversation_id,
|
|
237
|
+
node_name=node_name,
|
|
238
|
+
start_time=start_time,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
@method_spawner
|
|
242
|
+
async def log_command(
|
|
243
|
+
self,
|
|
244
|
+
*,
|
|
245
|
+
agent_name: str,
|
|
246
|
+
session_id: str,
|
|
247
|
+
command: str,
|
|
248
|
+
context_type: type | None = None,
|
|
249
|
+
metadata: dict[str, JsonValue] | None = None,
|
|
250
|
+
) -> None:
|
|
251
|
+
"""Log command to all providers."""
|
|
252
|
+
if not self.config.log_commands:
|
|
253
|
+
return
|
|
254
|
+
|
|
255
|
+
for provider in self.providers:
|
|
256
|
+
await provider.log_command(
|
|
257
|
+
agent_name=agent_name,
|
|
258
|
+
session_id=session_id,
|
|
259
|
+
command=command,
|
|
260
|
+
context_type=context_type,
|
|
261
|
+
metadata=metadata,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
@method_spawner
|
|
265
|
+
async def log_context_message(
|
|
266
|
+
self,
|
|
267
|
+
*,
|
|
268
|
+
conversation_id: str,
|
|
269
|
+
content: str,
|
|
270
|
+
role: str,
|
|
271
|
+
name: str | None = None,
|
|
272
|
+
model: str | None = None,
|
|
273
|
+
) -> None:
|
|
274
|
+
"""Log context message to all providers."""
|
|
275
|
+
for provider in self.providers:
|
|
276
|
+
await provider.log_context_message(
|
|
277
|
+
conversation_id=conversation_id,
|
|
278
|
+
content=content,
|
|
279
|
+
role=role,
|
|
280
|
+
name=name,
|
|
281
|
+
model=model,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
@method_spawner
|
|
285
|
+
async def reset(
|
|
286
|
+
self,
|
|
287
|
+
*,
|
|
288
|
+
agent_name: str | None = None,
|
|
289
|
+
hard: bool = False,
|
|
290
|
+
) -> tuple[int, int]:
|
|
291
|
+
"""Reset storage in all providers concurrently."""
|
|
292
|
+
|
|
293
|
+
async def reset_provider(provider: StorageProvider) -> tuple[int, int]:
|
|
294
|
+
try:
|
|
295
|
+
return await provider.reset(agent_name=agent_name, hard=hard)
|
|
296
|
+
except Exception:
|
|
297
|
+
cls_name = provider.__class__.__name__
|
|
298
|
+
logger.exception("Error resetting provider", provider=cls_name)
|
|
299
|
+
return (0, 0)
|
|
300
|
+
|
|
301
|
+
results = await asyncio.gather(*(reset_provider(provider) for provider in self.providers))
|
|
302
|
+
# Return the counts from the last provider (maintaining existing behavior)
|
|
303
|
+
return results[-1] if results else (0, 0)
|
|
304
|
+
|
|
305
|
+
@method_spawner
|
|
306
|
+
async def get_conversation_counts(
|
|
307
|
+
self,
|
|
308
|
+
*,
|
|
309
|
+
agent_name: str | None = None,
|
|
310
|
+
) -> tuple[int, int]:
|
|
311
|
+
"""Get counts from primary provider."""
|
|
312
|
+
provider = self.get_history_provider()
|
|
313
|
+
return await provider.get_conversation_counts(agent_name=agent_name)
|
|
314
|
+
|
|
315
|
+
@method_spawner
|
|
316
|
+
async def get_commands(
|
|
317
|
+
self,
|
|
318
|
+
agent_name: str,
|
|
319
|
+
session_id: str,
|
|
320
|
+
*,
|
|
321
|
+
limit: int | None = None,
|
|
322
|
+
current_session_only: bool = False,
|
|
323
|
+
preferred_provider: str | None = None,
|
|
324
|
+
) -> list[str]:
|
|
325
|
+
"""Get command history."""
|
|
326
|
+
if not self.config.log_commands:
|
|
327
|
+
return []
|
|
328
|
+
|
|
329
|
+
provider = self.get_history_provider(preferred_provider)
|
|
330
|
+
return await provider.get_commands(
|
|
331
|
+
agent_name=agent_name,
|
|
332
|
+
session_id=session_id,
|
|
333
|
+
limit=limit,
|
|
334
|
+
current_session_only=current_session_only,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
async def update_conversation_title(
|
|
338
|
+
self,
|
|
339
|
+
conversation_id: str,
|
|
340
|
+
title: str,
|
|
341
|
+
) -> None:
|
|
342
|
+
"""Update conversation title in all providers.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
conversation_id: ID of the conversation to update
|
|
346
|
+
title: New title for the conversation
|
|
347
|
+
"""
|
|
348
|
+
for provider in self.providers:
|
|
349
|
+
await provider.update_conversation_title(conversation_id, title)
|
|
350
|
+
|
|
351
|
+
async def get_conversation_title(
|
|
352
|
+
self,
|
|
353
|
+
conversation_id: str,
|
|
354
|
+
) -> str | None:
|
|
355
|
+
"""Get the title of a conversation.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
conversation_id: ID of the conversation
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
The conversation title, or None if not set.
|
|
362
|
+
"""
|
|
363
|
+
provider = self.get_history_provider()
|
|
364
|
+
return await provider.get_conversation_title(conversation_id)
|
|
365
|
+
|
|
366
|
+
async def generate_conversation_title(
|
|
367
|
+
self,
|
|
368
|
+
conversation_id: str,
|
|
369
|
+
messages: Sequence[ChatMessage[Any]],
|
|
370
|
+
) -> str | None:
|
|
371
|
+
"""Generate and store a title for a conversation.
|
|
372
|
+
|
|
373
|
+
Uses the configured title generation model to create a short,
|
|
374
|
+
descriptive title based on the conversation content.
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
conversation_id: ID of the conversation to title
|
|
378
|
+
messages: Messages to use for title generation
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
The generated title, or None if title generation is disabled.
|
|
382
|
+
"""
|
|
383
|
+
if not self.config.title_generation_model:
|
|
384
|
+
return None
|
|
385
|
+
|
|
386
|
+
# Check if title already exists
|
|
387
|
+
existing = await self.get_conversation_title(conversation_id)
|
|
388
|
+
if existing:
|
|
389
|
+
return existing
|
|
390
|
+
|
|
391
|
+
# Format messages for the prompt
|
|
392
|
+
formatted = "\n".join(
|
|
393
|
+
f"{msg.role}: {msg.content[:500]}"
|
|
394
|
+
for msg in messages[:4] # Limit context
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
try:
|
|
398
|
+
agent: Agent[None, str] = Agent(
|
|
399
|
+
model=self.config.title_generation_model,
|
|
400
|
+
instructions=self.config.title_generation_prompt,
|
|
401
|
+
)
|
|
402
|
+
result = await agent.run(formatted)
|
|
403
|
+
title = result.output.strip().strip("\"'") # Remove quotes if present
|
|
404
|
+
|
|
405
|
+
# Store the title
|
|
406
|
+
await self.update_conversation_title(conversation_id, title)
|
|
407
|
+
logger.debug(
|
|
408
|
+
"Generated conversation title",
|
|
409
|
+
conversation_id=conversation_id,
|
|
410
|
+
title=title,
|
|
411
|
+
)
|
|
412
|
+
except Exception:
|
|
413
|
+
logger.exception(
|
|
414
|
+
"Failed to generate conversation title",
|
|
415
|
+
conversation_id=conversation_id,
|
|
416
|
+
)
|
|
417
|
+
return None
|
|
418
|
+
else:
|
|
419
|
+
return title
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Serialization utilities."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from pydantic import ConfigDict, TypeAdapter
|
|
8
|
+
|
|
9
|
+
from agentpool.log import get_logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Sequence
|
|
14
|
+
|
|
15
|
+
from pydantic_ai import ModelMessage, ModelRequestPart, ModelResponsePart
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
# Type adapter for serializing ModelResponsePart sequences
|
|
21
|
+
parts_adapter = TypeAdapter(
|
|
22
|
+
list,
|
|
23
|
+
config=ConfigDict(ser_json_bytes="base64", val_json_bytes="base64"),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Type adapter for serializing ModelMessage sequences
|
|
27
|
+
messages_adapter = TypeAdapter(
|
|
28
|
+
list,
|
|
29
|
+
config=ConfigDict(ser_json_bytes="base64", val_json_bytes="base64"),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def deserialize_parts(parts_json: str | None) -> Sequence[ModelResponsePart]:
|
|
34
|
+
"""Deserialize pydantic-ai message parts from JSON string.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
parts_json: JSON string representation of parts or None if empty
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Sequence of ModelResponsePart objects, empty if deserialization fails
|
|
41
|
+
"""
|
|
42
|
+
if not parts_json:
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
# Deserialize using pydantic's JSON deserialization
|
|
47
|
+
return parts_adapter.validate_json(parts_json.encode())
|
|
48
|
+
except Exception as e: # noqa: BLE001
|
|
49
|
+
logger.warning("Failed to deserialize message parts", error=e)
|
|
50
|
+
return [] # Return empty list on failure
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def serialize_parts(parts: Sequence[ModelResponsePart | ModelRequestPart]) -> str | None:
|
|
54
|
+
"""Serialize pydantic-ai message parts from ChatMessage.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
parts: Sequence of ModelResponsePart from ChatMessage.parts
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
JSON string representation of parts or None if empty
|
|
61
|
+
"""
|
|
62
|
+
if not parts:
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
# Convert parts to serializable format
|
|
67
|
+
serializable_parts = []
|
|
68
|
+
for part in parts:
|
|
69
|
+
# Handle RetryPromptPart context serialization issues
|
|
70
|
+
from pydantic_ai import RetryPromptPart
|
|
71
|
+
|
|
72
|
+
if isinstance(part, RetryPromptPart) and isinstance(part.content, list):
|
|
73
|
+
for content in part.content:
|
|
74
|
+
if isinstance(content, dict) and "ctx" in content:
|
|
75
|
+
content["ctx"] = {k: str(v) for k, v in content["ctx"].items()}
|
|
76
|
+
serializable_parts.append(part)
|
|
77
|
+
|
|
78
|
+
# Serialize using pydantic's JSON serialization
|
|
79
|
+
return parts_adapter.dump_json(serializable_parts).decode()
|
|
80
|
+
except Exception as e: # noqa: BLE001
|
|
81
|
+
logger.warning("Failed to serialize message parts", error=e)
|
|
82
|
+
return str(parts) # Fallback to string representation
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def deserialize_messages(messages_json: str | None) -> list[ModelMessage]:
|
|
86
|
+
"""Deserialize pydantic-ai ModelMessage list from JSON string.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
messages_json: JSON string representation of messages or None if empty
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
List of ModelMessage objects, empty if deserialization fails
|
|
93
|
+
"""
|
|
94
|
+
if not messages_json:
|
|
95
|
+
return []
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
# Deserialize using pydantic's JSON deserialization
|
|
99
|
+
return messages_adapter.validate_json(messages_json.encode())
|
|
100
|
+
except Exception as e: # noqa: BLE001
|
|
101
|
+
logger.warning("Failed to deserialize model messages", error=e)
|
|
102
|
+
return [] # Return empty list on failure
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def serialize_messages(messages: Sequence[ModelMessage]) -> str | None:
|
|
106
|
+
"""Serialize pydantic-ai ModelMessage list to JSON string.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
messages: Sequence of ModelMessage objects from ChatMessage.messages
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
JSON string representation of messages or None if empty
|
|
113
|
+
"""
|
|
114
|
+
if not messages:
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
# Convert messages to serializable format
|
|
119
|
+
serializable_messages = []
|
|
120
|
+
for message in messages:
|
|
121
|
+
# Handle RetryPromptPart context serialization issues
|
|
122
|
+
from pydantic_ai import ModelRequest, RetryPromptPart
|
|
123
|
+
|
|
124
|
+
if isinstance(message, ModelRequest):
|
|
125
|
+
for part in message.parts:
|
|
126
|
+
if isinstance(part, RetryPromptPart) and isinstance(part.content, list):
|
|
127
|
+
for content in part.content:
|
|
128
|
+
if isinstance(content, dict) and "ctx" in content:
|
|
129
|
+
content["ctx"] = {k: str(v) for k, v in content["ctx"].items()}
|
|
130
|
+
serializable_messages.append(message)
|
|
131
|
+
|
|
132
|
+
# Serialize using pydantic's JSON serialization
|
|
133
|
+
return messages_adapter.dump_json(serializable_messages).decode()
|
|
134
|
+
except Exception as e: # noqa: BLE001
|
|
135
|
+
logger.warning("Failed to serialize model messages", error=e)
|
|
136
|
+
return str(messages) # Fallback to string representation
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Talk classes."""
|
|
2
|
+
|
|
3
|
+
from agentpool.talk.stats import TalkStats, AggregatedTalkStats
|
|
4
|
+
from agentpool.talk.talk import Talk, TeamTalk
|
|
5
|
+
from agentpool.talk.registry import ConnectionRegistry
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"AggregatedTalkStats",
|
|
9
|
+
"ConnectionRegistry",
|
|
10
|
+
"Talk",
|
|
11
|
+
"TalkStats",
|
|
12
|
+
"TeamTalk",
|
|
13
|
+
]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Manages message flow between agents/groups."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
7
|
+
|
|
8
|
+
from psygnal import Signal
|
|
9
|
+
|
|
10
|
+
from agentpool.log import get_logger
|
|
11
|
+
from agentpool.talk.talk import Talk
|
|
12
|
+
from agentpool.utils.baseregistry import AgentPoolError, BaseRegistry
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from agentpool import MessageNode
|
|
17
|
+
from agentpool.messaging import ChatMessage
|
|
18
|
+
from agentpool.talk.stats import TalkStats
|
|
19
|
+
from agentpool_config.conditions import ConnectionCondition
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ConnectionRegistryError(AgentPoolError):
|
|
26
|
+
"""Errors related to connection registration."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class EventContext[TMessageContent]:
|
|
31
|
+
"""Base context for all condition/event operations."""
|
|
32
|
+
|
|
33
|
+
message: ChatMessage[TMessageContent]
|
|
34
|
+
"""The message being processed."""
|
|
35
|
+
|
|
36
|
+
target: MessageNode[Any, Any]
|
|
37
|
+
"""The target node this message is being sent to."""
|
|
38
|
+
|
|
39
|
+
stats: TalkStats
|
|
40
|
+
"""Statistics for the current connection."""
|
|
41
|
+
|
|
42
|
+
registry: ConnectionRegistry | None
|
|
43
|
+
"""Registry of all named connections."""
|
|
44
|
+
|
|
45
|
+
talk: Talk
|
|
46
|
+
"""The Talk instance handling this message flow."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
class TriggerContext[TMessageContent](EventContext[TMessageContent]):
|
|
51
|
+
"""Context for trigger events, extending base context with event information."""
|
|
52
|
+
|
|
53
|
+
event_type: Literal["condition_met", "message_processed", "disconnected"]
|
|
54
|
+
"""Type of event that triggered this call."""
|
|
55
|
+
|
|
56
|
+
condition: ConnectionCondition
|
|
57
|
+
"""The condition that was triggered (if event_type is condition_met)."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ConnectionRegistry(BaseRegistry[str, Talk]):
|
|
61
|
+
"""Registry for managing named connections.
|
|
62
|
+
|
|
63
|
+
Allows looking up Talk instances by their name. Only named
|
|
64
|
+
connections get registered.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
message_flow = Signal(Talk.ConnectionProcessed)
|
|
68
|
+
|
|
69
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
70
|
+
"""Initialize registry and connect event handlers."""
|
|
71
|
+
super().__init__(*args, **kwargs)
|
|
72
|
+
# Connect handlers to EventedDict events
|
|
73
|
+
self._items.events.added.connect(self._on_talk_added)
|
|
74
|
+
self._items.events.removed.connect(self._on_talk_removed)
|
|
75
|
+
self._items.events.changed.connect(self._on_talk_changed)
|
|
76
|
+
|
|
77
|
+
def _on_talk_added(self, name: str, talk: Talk) -> None:
|
|
78
|
+
"""Handle new talk being added to registry."""
|
|
79
|
+
talk.connection_processed.connect(self._handle_message_flow)
|
|
80
|
+
logger.debug("Connected signal for talk", name=name)
|
|
81
|
+
|
|
82
|
+
def _on_talk_removed(self, name: str, talk: Talk) -> None:
|
|
83
|
+
"""Handle talk being removed from registry."""
|
|
84
|
+
talk.connection_processed.disconnect(self._handle_message_flow)
|
|
85
|
+
logger.debug("Disconnected signal for talk", name=name)
|
|
86
|
+
|
|
87
|
+
def _on_talk_changed(self, name: str, old_talk: Talk, new_talk: Talk) -> None:
|
|
88
|
+
"""Handle talk being replaced in registry."""
|
|
89
|
+
old_talk.connection_processed.disconnect(self._handle_message_flow)
|
|
90
|
+
new_talk.connection_processed.connect(self._handle_message_flow)
|
|
91
|
+
logger.debug("Reconnected signal for talk", name=name)
|
|
92
|
+
|
|
93
|
+
def _handle_message_flow(self, event: Talk.ConnectionProcessed) -> None:
|
|
94
|
+
"""Forward message flow to global stream."""
|
|
95
|
+
self.message_flow.emit(event)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def _error_class(self) -> type[ConnectionRegistryError]:
|
|
99
|
+
return ConnectionRegistryError
|
|
100
|
+
|
|
101
|
+
def _validate_item(self, item: Any) -> Talk:
|
|
102
|
+
"""Ensure only Talk instances can be registered."""
|
|
103
|
+
if not isinstance(item, Talk):
|
|
104
|
+
msg = f"Expected Talk instance, got {type(item)}"
|
|
105
|
+
raise self._error_class(msg)
|
|
106
|
+
|
|
107
|
+
return item
|
|
108
|
+
|
|
109
|
+
def register_auto(self, talk: Talk[Any], base_name: str | None = None) -> str:
|
|
110
|
+
"""Register talk with auto-generated unique name.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
talk: Talk instance to register
|
|
114
|
+
base_name: Optional base name to use (defaults to talk.name)
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
The actual name used for registration
|
|
118
|
+
"""
|
|
119
|
+
base = base_name or talk.name
|
|
120
|
+
counter = 1
|
|
121
|
+
name = base
|
|
122
|
+
|
|
123
|
+
while name in self:
|
|
124
|
+
name = f"{base}_{counter}"
|
|
125
|
+
counter += 1
|
|
126
|
+
talk.name = name
|
|
127
|
+
self.register(name, talk)
|
|
128
|
+
return name
|