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,233 @@
|
|
|
1
|
+
"""Command for serving agents via Vercel AI protocol."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from typing import TYPE_CHECKING, Annotated, Any
|
|
8
|
+
|
|
9
|
+
import typer as t
|
|
10
|
+
|
|
11
|
+
from agentpool_cli import log, resolve_agent_config
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import AsyncIterator
|
|
16
|
+
|
|
17
|
+
from agentpool import ChatMessage
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
logger = log.get_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def vercel_command( # noqa: PLR0915
|
|
24
|
+
ctx: t.Context,
|
|
25
|
+
config: Annotated[str | None, t.Argument(help="Path to agent configuration")] = None,
|
|
26
|
+
agent_name: Annotated[
|
|
27
|
+
str | None, t.Option("--agent", "-a", help="Specific agent to serve")
|
|
28
|
+
] = None,
|
|
29
|
+
host: Annotated[str, t.Option(help="Host to bind server to")] = "localhost",
|
|
30
|
+
port: Annotated[int, t.Option(help="Port to listen on")] = 8000,
|
|
31
|
+
cors: Annotated[bool, t.Option(help="Enable CORS")] = True,
|
|
32
|
+
show_messages: Annotated[
|
|
33
|
+
bool, t.Option("--show-messages", help="Show message activity")
|
|
34
|
+
] = False,
|
|
35
|
+
) -> None:
|
|
36
|
+
"""Serve agents via Vercel AI Data Stream Protocol.
|
|
37
|
+
|
|
38
|
+
This creates a server compatible with Vercel AI SDK frontends,
|
|
39
|
+
allowing you to use your agents with Vercel AI UI components.
|
|
40
|
+
|
|
41
|
+
The server exposes a POST /chat endpoint that accepts Vercel AI
|
|
42
|
+
protocol requests and streams responses back.
|
|
43
|
+
|
|
44
|
+
If --agent is specified, only that agent is served. Otherwise,
|
|
45
|
+
the endpoint accepts an 'agent' field in the request to select
|
|
46
|
+
which agent to use.
|
|
47
|
+
"""
|
|
48
|
+
from fastapi import FastAPI
|
|
49
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
50
|
+
from pydantic_ai import PartDeltaEvent, PartStartEvent, TextPart, TextPartDelta
|
|
51
|
+
from starlette.requests import Request
|
|
52
|
+
from starlette.responses import JSONResponse, Response, StreamingResponse
|
|
53
|
+
import uvicorn
|
|
54
|
+
|
|
55
|
+
from agentpool import AgentPool, AgentsManifest
|
|
56
|
+
from agentpool.agents.events import StreamCompleteEvent
|
|
57
|
+
|
|
58
|
+
logger.info("Server PID", pid=os.getpid())
|
|
59
|
+
|
|
60
|
+
def on_message(message: ChatMessage[Any]) -> None:
|
|
61
|
+
print(message.format(style="simple"))
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
config_path = resolve_agent_config(config)
|
|
65
|
+
except ValueError as e:
|
|
66
|
+
msg = str(e)
|
|
67
|
+
raise t.BadParameter(msg) from e
|
|
68
|
+
|
|
69
|
+
manifest = AgentsManifest.from_file(config_path)
|
|
70
|
+
pool = AgentPool(manifest)
|
|
71
|
+
|
|
72
|
+
if show_messages:
|
|
73
|
+
for agent in pool.agents.values():
|
|
74
|
+
agent.message_sent.connect(on_message)
|
|
75
|
+
|
|
76
|
+
# Create FastAPI app
|
|
77
|
+
app = FastAPI(
|
|
78
|
+
title="AgentPool - Vercel AI Server",
|
|
79
|
+
description="Vercel AI Data Stream Protocol server for AgentPool",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if cors:
|
|
83
|
+
app.add_middleware(
|
|
84
|
+
CORSMiddleware,
|
|
85
|
+
allow_origins=["*"],
|
|
86
|
+
allow_credentials=True,
|
|
87
|
+
allow_methods=["*"],
|
|
88
|
+
allow_headers=["*"],
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@app.on_event("startup")
|
|
92
|
+
async def startup() -> None:
|
|
93
|
+
await pool.__aenter__()
|
|
94
|
+
logger.info("Agent pool initialized")
|
|
95
|
+
|
|
96
|
+
@app.on_event("shutdown")
|
|
97
|
+
async def shutdown() -> None:
|
|
98
|
+
await pool.__aexit__(None, None, None)
|
|
99
|
+
logger.info("Agent pool shut down")
|
|
100
|
+
|
|
101
|
+
@app.post("/chat")
|
|
102
|
+
async def chat(request: Request) -> Response:
|
|
103
|
+
"""Handle Vercel AI protocol chat requests.
|
|
104
|
+
|
|
105
|
+
Implements the Vercel AI Data Stream Protocol:
|
|
106
|
+
https://sdk.vercel.ai/docs/ai-sdk-ui/stream-protocol#data-stream-protocol
|
|
107
|
+
"""
|
|
108
|
+
body = await request.body()
|
|
109
|
+
try:
|
|
110
|
+
data = json.loads(body)
|
|
111
|
+
except json.JSONDecodeError as e:
|
|
112
|
+
return JSONResponse({"error": f"Invalid JSON: {e}"}, status_code=400)
|
|
113
|
+
|
|
114
|
+
# Extract messages from the request
|
|
115
|
+
messages = data.get("messages", [])
|
|
116
|
+
if not messages:
|
|
117
|
+
return JSONResponse({"error": "No messages provided"}, status_code=400)
|
|
118
|
+
|
|
119
|
+
# Get the last user message
|
|
120
|
+
last_message = messages[-1]
|
|
121
|
+
user_text = ""
|
|
122
|
+
if last_message.get("role") == "user":
|
|
123
|
+
parts = last_message.get("parts", [])
|
|
124
|
+
for part in parts:
|
|
125
|
+
if part.get("type") == "text":
|
|
126
|
+
user_text = part.get("text", "")
|
|
127
|
+
break
|
|
128
|
+
|
|
129
|
+
if not user_text:
|
|
130
|
+
return JSONResponse({"error": "No user text found"}, status_code=400)
|
|
131
|
+
|
|
132
|
+
# Determine which agent to use
|
|
133
|
+
if agent_name:
|
|
134
|
+
selected_agent = pool.get_agent(agent_name)
|
|
135
|
+
else:
|
|
136
|
+
if not pool.agents:
|
|
137
|
+
return JSONResponse({"error": "No agents available"}, status_code=500)
|
|
138
|
+
first_name = next(iter(pool.agents.keys()))
|
|
139
|
+
selected_agent = pool.get_agent(first_name)
|
|
140
|
+
|
|
141
|
+
async def generate_stream() -> AsyncIterator[str]:
|
|
142
|
+
"""Generate Vercel AI Data Stream Protocol events.
|
|
143
|
+
|
|
144
|
+
Protocol format:
|
|
145
|
+
- Text: 0:"text content"
|
|
146
|
+
- Finish: e:{"finishReason":"stop",...}
|
|
147
|
+
- Done: d:{"finishReason":"stop"}
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
async for event in selected_agent.run_stream(user_text):
|
|
151
|
+
# Handle pydantic-ai streaming events
|
|
152
|
+
if isinstance(event, PartStartEvent):
|
|
153
|
+
# New part started - if it's text, emit it
|
|
154
|
+
if isinstance(event.part, TextPart) and event.part.content:
|
|
155
|
+
text = event.part.content
|
|
156
|
+
escaped = json.dumps(text)
|
|
157
|
+
yield f"0:{escaped}\n"
|
|
158
|
+
|
|
159
|
+
elif isinstance(event, PartDeltaEvent):
|
|
160
|
+
# Delta update - emit text deltas
|
|
161
|
+
if isinstance(event.delta, TextPartDelta):
|
|
162
|
+
text = event.delta.content_delta
|
|
163
|
+
if text:
|
|
164
|
+
escaped = json.dumps(text)
|
|
165
|
+
yield f"0:{escaped}\n"
|
|
166
|
+
|
|
167
|
+
elif isinstance(event, StreamCompleteEvent):
|
|
168
|
+
# Stream complete - we've received the final message
|
|
169
|
+
# The content has already been streamed via deltas
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
# Send finish event
|
|
173
|
+
finish_data = {
|
|
174
|
+
"finishReason": "stop",
|
|
175
|
+
"usage": {"promptTokens": 0, "completionTokens": 0},
|
|
176
|
+
}
|
|
177
|
+
yield f"e:{json.dumps(finish_data)}\n"
|
|
178
|
+
|
|
179
|
+
# Send done marker
|
|
180
|
+
done_data = {"finishReason": "stop"}
|
|
181
|
+
yield f"d:{json.dumps(done_data)}\n"
|
|
182
|
+
|
|
183
|
+
except Exception as e:
|
|
184
|
+
logger.exception("Error during streaming")
|
|
185
|
+
# Send error as text
|
|
186
|
+
error_msg = f"Error: {e}"
|
|
187
|
+
escaped = json.dumps(error_msg)
|
|
188
|
+
yield f"0:{escaped}\n"
|
|
189
|
+
# Still send finish
|
|
190
|
+
finish_data = {"finishReason": "error"}
|
|
191
|
+
yield f"e:{json.dumps(finish_data)}\n"
|
|
192
|
+
done_data = {"finishReason": "error"}
|
|
193
|
+
yield f"d:{json.dumps(done_data)}\n"
|
|
194
|
+
|
|
195
|
+
return StreamingResponse(
|
|
196
|
+
generate_stream(),
|
|
197
|
+
media_type="text/plain; charset=utf-8",
|
|
198
|
+
headers={
|
|
199
|
+
"X-Vercel-AI-Data-Stream": "v1",
|
|
200
|
+
"Cache-Control": "no-cache",
|
|
201
|
+
"Connection": "keep-alive",
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
@app.get("/agents")
|
|
206
|
+
async def list_agents() -> dict[str, Any]:
|
|
207
|
+
"""List available agents."""
|
|
208
|
+
return {
|
|
209
|
+
"agents": [
|
|
210
|
+
{"name": name, "description": agent.description}
|
|
211
|
+
for name, agent in pool.agents.items()
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@app.get("/health")
|
|
216
|
+
async def health() -> dict[str, str]:
|
|
217
|
+
"""Health check endpoint."""
|
|
218
|
+
return {"status": "ok"}
|
|
219
|
+
|
|
220
|
+
# Get log level from the global context
|
|
221
|
+
log_level = ctx.obj.get("log_level", "info") if ctx.obj else "info"
|
|
222
|
+
|
|
223
|
+
print(f"Starting Vercel AI server on http://{host}:{port}")
|
|
224
|
+
print(f"Chat endpoint: POST http://{host}:{port}/chat")
|
|
225
|
+
print(f"Available agents: {list(pool.agents.keys())}")
|
|
226
|
+
|
|
227
|
+
uvicorn.run(app, host=host, port=port, log_level=log_level.lower())
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
if __name__ == "__main__":
|
|
231
|
+
import typer
|
|
232
|
+
|
|
233
|
+
typer.run(vercel_command)
|
agentpool_cli/store.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""Manages stored config mappings."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import TYPE_CHECKING, TypedDict
|
|
7
|
+
|
|
8
|
+
from agentpool_cli.log import get_logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from upath import UPath
|
|
13
|
+
from upathtools import JoinablePathLike
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
logger = get_logger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class ConfigFile:
|
|
21
|
+
"""Represents an active configuration."""
|
|
22
|
+
|
|
23
|
+
name: str
|
|
24
|
+
path: str
|
|
25
|
+
|
|
26
|
+
def __str__(self) -> str:
|
|
27
|
+
"""Format for display."""
|
|
28
|
+
return f"{self.name} ({self.path})"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ConfigMapping(TypedDict):
|
|
32
|
+
"""Type for config storage format."""
|
|
33
|
+
|
|
34
|
+
configs: dict[str, str] # name -> uri mapping
|
|
35
|
+
active: str | None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ConfigStore:
|
|
39
|
+
"""Manages stored config mappings."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, filename: str | None = None) -> None:
|
|
42
|
+
"""Initialize store with default paths."""
|
|
43
|
+
self._filename = filename or "configs.json"
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def config_dir(self) -> UPath:
|
|
47
|
+
"""Get config directory."""
|
|
48
|
+
import platformdirs
|
|
49
|
+
from upathtools import to_upath
|
|
50
|
+
|
|
51
|
+
return to_upath(platformdirs.user_config_dir("agentpool"))
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def config_file(self) -> UPath:
|
|
55
|
+
"""Get config file path."""
|
|
56
|
+
return self.config_dir / self._filename
|
|
57
|
+
|
|
58
|
+
def _ensure_config_dir(self) -> None:
|
|
59
|
+
"""Create config directory if needed."""
|
|
60
|
+
self.config_dir.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
if not self.config_file.exists():
|
|
62
|
+
mapping = ConfigMapping(configs={}, active=None)
|
|
63
|
+
self.save_mapping(mapping)
|
|
64
|
+
|
|
65
|
+
def load_mapping(self) -> ConfigMapping:
|
|
66
|
+
"""Load config mapping from disk."""
|
|
67
|
+
import anyenv
|
|
68
|
+
|
|
69
|
+
if not self.config_file.exists():
|
|
70
|
+
return ConfigMapping(configs={}, active=None)
|
|
71
|
+
try:
|
|
72
|
+
text = self.config_file.read_text("utf-8")
|
|
73
|
+
data = anyenv.load_json(text, return_type=dict)
|
|
74
|
+
active = data.get("active")
|
|
75
|
+
configs = data.get("configs", {})
|
|
76
|
+
return ConfigMapping(configs=configs, active=active)
|
|
77
|
+
except Exception:
|
|
78
|
+
logger.exception("Failed to load config mapping")
|
|
79
|
+
return ConfigMapping(configs={}, active=None)
|
|
80
|
+
|
|
81
|
+
def save_mapping(self, mapping: ConfigMapping) -> None:
|
|
82
|
+
"""Save config mapping to disk."""
|
|
83
|
+
import anyenv
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
self.config_file.write_text(anyenv.dump_json(mapping, indent=True))
|
|
87
|
+
except Exception:
|
|
88
|
+
logger.exception("Failed to save config mapping")
|
|
89
|
+
|
|
90
|
+
def add_config(self, name: str, path: JoinablePathLike) -> None:
|
|
91
|
+
"""Add a new named config.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
name: Name to register the config under
|
|
95
|
+
path: Path to the config file
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
ValueError: If name is invalid
|
|
99
|
+
FileNotFoundError: If config file doesn't exist
|
|
100
|
+
PermissionError: If config file can't be read
|
|
101
|
+
IsADirectoryError: If path points to a directory
|
|
102
|
+
"""
|
|
103
|
+
# Basic validation
|
|
104
|
+
from upathtools import to_upath
|
|
105
|
+
|
|
106
|
+
if not name.isidentifier():
|
|
107
|
+
msg = f"Invalid config name: {name} (must be a valid Python identifier)"
|
|
108
|
+
raise ValueError(msg)
|
|
109
|
+
|
|
110
|
+
path_obj = to_upath(path).resolve()
|
|
111
|
+
if not path_obj.exists():
|
|
112
|
+
msg = f"Config file not found: {path}"
|
|
113
|
+
raise FileNotFoundError(msg)
|
|
114
|
+
|
|
115
|
+
if not path_obj.is_file():
|
|
116
|
+
msg = f"Path is not a file: {path}"
|
|
117
|
+
raise IsADirectoryError(msg)
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
# Try to read file to verify access
|
|
121
|
+
path_obj.read_bytes()
|
|
122
|
+
except PermissionError as exc:
|
|
123
|
+
msg = f"Cannot read config file: {path}"
|
|
124
|
+
raise PermissionError(msg) from exc
|
|
125
|
+
# All good, save the config
|
|
126
|
+
mapping = self.load_mapping()
|
|
127
|
+
mapping["configs"][name] = str(path_obj)
|
|
128
|
+
logger.debug("Adding config %r -> %s", name, path_obj)
|
|
129
|
+
self.save_mapping(mapping)
|
|
130
|
+
|
|
131
|
+
def remove_config(self, name: str) -> None:
|
|
132
|
+
"""Remove a named config."""
|
|
133
|
+
mapping = self.load_mapping()
|
|
134
|
+
if name == mapping["active"]:
|
|
135
|
+
mapping["active"] = None
|
|
136
|
+
mapping["configs"].pop(name, None)
|
|
137
|
+
self.save_mapping(mapping)
|
|
138
|
+
|
|
139
|
+
def set_active(self, name: str) -> None:
|
|
140
|
+
"""Set the active config."""
|
|
141
|
+
mapping = self.load_mapping()
|
|
142
|
+
if name not in mapping["configs"]:
|
|
143
|
+
msg = f"Config {name} not found"
|
|
144
|
+
raise KeyError(msg)
|
|
145
|
+
mapping["active"] = name
|
|
146
|
+
self.save_mapping(mapping)
|
|
147
|
+
|
|
148
|
+
def get_active(self) -> ConfigFile | None:
|
|
149
|
+
"""Get active config if one is set.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
ConfigFile if an active config is set, None otherwise
|
|
153
|
+
"""
|
|
154
|
+
mapping = self.load_mapping()
|
|
155
|
+
if not mapping["active"]:
|
|
156
|
+
return None
|
|
157
|
+
name = mapping["active"]
|
|
158
|
+
return ConfigFile(name=name, path=mapping["configs"][name])
|
|
159
|
+
|
|
160
|
+
def list_configs(self) -> list[tuple[str, str]]:
|
|
161
|
+
"""List all configs with their paths."""
|
|
162
|
+
mapping = self.load_mapping()
|
|
163
|
+
return list(mapping["configs"].items())
|
|
164
|
+
|
|
165
|
+
def get_config(self, name: str) -> str:
|
|
166
|
+
"""Get path for a named config."""
|
|
167
|
+
mapping = self.load_mapping()
|
|
168
|
+
if name not in mapping["configs"]:
|
|
169
|
+
msg = f"Config {name} not found"
|
|
170
|
+
raise KeyError(msg)
|
|
171
|
+
return mapping["configs"][name]
|
agentpool_cli/task.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Task execution command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from typing import TYPE_CHECKING, Annotated
|
|
7
|
+
|
|
8
|
+
import typer as t
|
|
9
|
+
|
|
10
|
+
from agentpool_cli import log, resolve_agent_config
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from agentpool import AgentsManifest
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
TASK_HELP = """
|
|
18
|
+
Execute a defined task with the specified agent.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
agentpool task docs write_api_docs --prompt "Include code examples"
|
|
22
|
+
agentpool task docs write_api_docs --log-level DEBUG
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def execute_job(
|
|
27
|
+
agent_name: str,
|
|
28
|
+
task_name: str,
|
|
29
|
+
config: AgentsManifest,
|
|
30
|
+
*,
|
|
31
|
+
prompt: str | None = None,
|
|
32
|
+
) -> str:
|
|
33
|
+
"""Execute task with agent."""
|
|
34
|
+
from agentpool import AgentPool
|
|
35
|
+
|
|
36
|
+
async with AgentPool(config) as pool:
|
|
37
|
+
# Get both agent and task
|
|
38
|
+
agent = pool.get_agent(agent_name)
|
|
39
|
+
task = pool.get_job(task_name)
|
|
40
|
+
|
|
41
|
+
# Create final prompt from task and additional input
|
|
42
|
+
task_prompt = task.prompt
|
|
43
|
+
if prompt:
|
|
44
|
+
task_prompt = f"{task_prompt}\n\nAdditional instructions:\n{prompt}"
|
|
45
|
+
|
|
46
|
+
result = await agent.run(task_prompt)
|
|
47
|
+
return result.data
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def task_command(
|
|
51
|
+
agent_name: Annotated[str, t.Argument(help="Name of agent to run task with")],
|
|
52
|
+
task_name: Annotated[str, t.Argument(help="Name of task to execute")],
|
|
53
|
+
config: Annotated[
|
|
54
|
+
str | None, t.Option("--config", "-c", help="Agent configuration file")
|
|
55
|
+
] = None,
|
|
56
|
+
prompt: Annotated[str | None, t.Option("--prompt", "-p", help="Additional prompt")] = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""Execute a task with the specified agent."""
|
|
59
|
+
logger = log.get_logger(__name__)
|
|
60
|
+
try:
|
|
61
|
+
logger.debug("Starting task execution", name=task_name)
|
|
62
|
+
|
|
63
|
+
# Resolve configuration path
|
|
64
|
+
try:
|
|
65
|
+
config_path = resolve_agent_config(config)
|
|
66
|
+
logger.debug("Using config", source=config_path)
|
|
67
|
+
except ValueError as e:
|
|
68
|
+
msg = str(e)
|
|
69
|
+
raise t.BadParameter(msg) from e
|
|
70
|
+
|
|
71
|
+
from agentpool import AgentsManifest
|
|
72
|
+
|
|
73
|
+
manifest = AgentsManifest.from_file(config_path)
|
|
74
|
+
result = asyncio.run(execute_job(agent_name, task_name, manifest, prompt=prompt))
|
|
75
|
+
print(result)
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
t.echo(f"Error: {e}", err=True)
|
|
79
|
+
logger.debug("Exception details", exc_info=True)
|
|
80
|
+
raise t.Exit(1) from e
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__":
|
|
84
|
+
t.run(task_command)
|
agentpool_cli/utils.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Utilities for creating Typer commands from Pydantic models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
import types as pytypes
|
|
7
|
+
from typing import TYPE_CHECKING, Annotated, Any, Union, get_args, get_origin
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Callable
|
|
14
|
+
from inspect import Parameter
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def resolve_type(field_type: Any) -> Any:
|
|
20
|
+
"""Resolve actual type from Union/Optional types."""
|
|
21
|
+
origin = get_origin(field_type)
|
|
22
|
+
|
|
23
|
+
# Handle Any
|
|
24
|
+
if field_type is Any:
|
|
25
|
+
return str
|
|
26
|
+
|
|
27
|
+
# Handle both Union and | syntax
|
|
28
|
+
if origin is Union or origin is pytypes.UnionType:
|
|
29
|
+
types_ = [t for t in get_args(field_type) if t is not type(None)]
|
|
30
|
+
return resolve_type(types_[0]) if len(types_) == 1 else str
|
|
31
|
+
|
|
32
|
+
# Handle lists/sets
|
|
33
|
+
if origin in {list, set}:
|
|
34
|
+
item_type = get_args(field_type)[0]
|
|
35
|
+
return list[resolve_type(item_type)] # type: ignore[misc]
|
|
36
|
+
|
|
37
|
+
return field_type
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def create_typer_command[T: BaseModel](
|
|
41
|
+
config_cls: type[T],
|
|
42
|
+
callback: Callable[[T], Any] | None = None,
|
|
43
|
+
*,
|
|
44
|
+
name: str | None = None,
|
|
45
|
+
) -> typer.models.CommandInfo:
|
|
46
|
+
"""Create a Typer CommandInfo from a Pydantic model."""
|
|
47
|
+
|
|
48
|
+
def make_command(**kwargs: Any) -> Any:
|
|
49
|
+
"""Command created from model."""
|
|
50
|
+
config = config_cls(**kwargs)
|
|
51
|
+
if callback:
|
|
52
|
+
return callback(config)
|
|
53
|
+
return config
|
|
54
|
+
|
|
55
|
+
# Create parameters from model fields
|
|
56
|
+
params: dict[str, Parameter] = {}
|
|
57
|
+
for field_name, field in config_cls.model_fields.items():
|
|
58
|
+
if field_name == "type": # Skip discriminator
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
field_type = resolve_type(field.annotation)
|
|
62
|
+
default = field.default if field.default != ... else None
|
|
63
|
+
|
|
64
|
+
# First field becomes argument
|
|
65
|
+
if not params:
|
|
66
|
+
# For arguments, the param name should be the field name
|
|
67
|
+
params[field_name] = inspect.Parameter(
|
|
68
|
+
field_name,
|
|
69
|
+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
70
|
+
annotation=Annotated[field_type, typer.Argument(help=field.description)],
|
|
71
|
+
default=default,
|
|
72
|
+
)
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
# For options, we need proper param_decls
|
|
76
|
+
option_name = field_name.replace("_", "-")
|
|
77
|
+
params[field_name] = inspect.Parameter(
|
|
78
|
+
field_name,
|
|
79
|
+
inspect.Parameter.KEYWORD_ONLY,
|
|
80
|
+
annotation=Annotated[
|
|
81
|
+
field_type,
|
|
82
|
+
typer.Option(
|
|
83
|
+
"--" + option_name, # Explicit param_decls
|
|
84
|
+
help=field.description,
|
|
85
|
+
),
|
|
86
|
+
],
|
|
87
|
+
default=default,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Create function with signature
|
|
91
|
+
make_command.__signature__ = inspect.Signature( # type: ignore
|
|
92
|
+
list(params.values()), return_annotation=config_cls
|
|
93
|
+
)
|
|
94
|
+
make_command.__annotations__ = {k: v.annotation for k, v in params.items()}
|
|
95
|
+
|
|
96
|
+
# Create command
|
|
97
|
+
if name is None:
|
|
98
|
+
name = config_cls.__name__.lower().replace("command", "")
|
|
99
|
+
|
|
100
|
+
return typer.models.CommandInfo(
|
|
101
|
+
name=name,
|
|
102
|
+
callback=make_command,
|
|
103
|
+
help=config_cls.__doc__,
|
|
104
|
+
)
|
agentpool_cli/watch.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Command for watching agents and displaying messages."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from typing import TYPE_CHECKING, Annotated, Any
|
|
7
|
+
|
|
8
|
+
import typer as t
|
|
9
|
+
|
|
10
|
+
from agentpool_cli import log
|
|
11
|
+
from agentpool_cli.cli_types import DetailLevel # noqa: TC001
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from agentpool import ChatMessage
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logger = log.get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def watch_command(
|
|
22
|
+
config: Annotated[str, t.Argument(help="Path to agent configuration")],
|
|
23
|
+
show_messages: Annotated[
|
|
24
|
+
bool, t.Option("--show-messages", help="Show all messages (not just final responses)")
|
|
25
|
+
] = True,
|
|
26
|
+
detail_level: Annotated[
|
|
27
|
+
DetailLevel, t.Option("-d", "--detail", help="Output detail level")
|
|
28
|
+
] = "simple",
|
|
29
|
+
show_metadata: Annotated[bool, t.Option("--metadata", help="Show message metadata")] = False,
|
|
30
|
+
show_costs: Annotated[bool, t.Option("--costs", help="Show token usage and costs")] = False,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Run agents in event-watching mode."""
|
|
33
|
+
|
|
34
|
+
def on_message(chat_message: ChatMessage[Any]) -> None:
|
|
35
|
+
text = chat_message.format(
|
|
36
|
+
style=detail_level,
|
|
37
|
+
show_metadata=show_metadata,
|
|
38
|
+
show_costs=show_costs,
|
|
39
|
+
)
|
|
40
|
+
print(text)
|
|
41
|
+
|
|
42
|
+
async def run_watch() -> None:
|
|
43
|
+
from agentpool import AgentPool, AgentsManifest
|
|
44
|
+
|
|
45
|
+
manifest = AgentsManifest.from_file(config)
|
|
46
|
+
async with AgentPool(manifest) as pool:
|
|
47
|
+
# Connect message handlers if showing all messages
|
|
48
|
+
if show_messages:
|
|
49
|
+
for agent in pool.agents.values():
|
|
50
|
+
agent.message_sent.connect(on_message)
|
|
51
|
+
|
|
52
|
+
await pool.run_event_loop()
|
|
53
|
+
|
|
54
|
+
asyncio.run(run_watch())
|