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,212 @@
|
|
|
1
|
+
"""Statement-by-statement execution with automatic progress tracking."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ast
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
import inspect
|
|
8
|
+
import time
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
import anyio
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import AsyncIterator, Awaitable, Callable
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ProgressInfo:
|
|
20
|
+
"""Information about code execution progress."""
|
|
21
|
+
|
|
22
|
+
current: float
|
|
23
|
+
"""Current progress value."""
|
|
24
|
+
|
|
25
|
+
total: float
|
|
26
|
+
"""Total progress value."""
|
|
27
|
+
|
|
28
|
+
message: str
|
|
29
|
+
"""Progress message describing current operation."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def count_statements(code: str) -> int:
|
|
33
|
+
"""Count total statements in the code."""
|
|
34
|
+
try:
|
|
35
|
+
tree = ast.parse(code)
|
|
36
|
+
return len(tree.body)
|
|
37
|
+
except SyntaxError:
|
|
38
|
+
return 0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ProgressTrackingExecutor:
|
|
42
|
+
"""Execute Python code statement-by-statement with automatic progress reporting."""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
progress_callback: Callable[[ProgressInfo], Awaitable[Any]] | None = None,
|
|
47
|
+
step_delay: float = 0.01,
|
|
48
|
+
) -> None:
|
|
49
|
+
"""Initialize executor.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
progress_callback: Optional callback for progress reporting
|
|
53
|
+
step_delay: Delay between statement executions (for async behavior)
|
|
54
|
+
"""
|
|
55
|
+
self.globals: dict[str, Any] = {"__builtins__": __builtins__}
|
|
56
|
+
self.locals: dict[str, Any] = {}
|
|
57
|
+
self.progress_callback = progress_callback
|
|
58
|
+
self.step_delay = step_delay
|
|
59
|
+
self.total_statements = 0
|
|
60
|
+
self.current_statement = 0
|
|
61
|
+
self.start_time: float | None = None
|
|
62
|
+
|
|
63
|
+
def update_namespace(self, namespace: dict[str, Any]) -> None:
|
|
64
|
+
"""Update the execution namespace with additional globals."""
|
|
65
|
+
self.globals.update(namespace)
|
|
66
|
+
|
|
67
|
+
async def execute_with_progress(self, code: str) -> Any:
|
|
68
|
+
"""Execute code with automatic progress reporting.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
code: Python source code to execute
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Result of code execution
|
|
75
|
+
"""
|
|
76
|
+
self.total_statements = count_statements(code)
|
|
77
|
+
self.current_statement = 0
|
|
78
|
+
self.start_time = time.time()
|
|
79
|
+
|
|
80
|
+
if self.total_statements == 0:
|
|
81
|
+
return "No statements to execute"
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
tree = ast.parse(code)
|
|
85
|
+
|
|
86
|
+
for i, node in enumerate(tree.body):
|
|
87
|
+
self.current_statement = i + 1
|
|
88
|
+
|
|
89
|
+
# Report progress if callback available
|
|
90
|
+
if self.progress_callback:
|
|
91
|
+
node_type = type(node).__name__
|
|
92
|
+
message = f"Executing {node_type.lower()} statement"
|
|
93
|
+
|
|
94
|
+
progress_info = ProgressInfo(
|
|
95
|
+
current=float(self.current_statement),
|
|
96
|
+
total=float(self.total_statements),
|
|
97
|
+
message=message,
|
|
98
|
+
)
|
|
99
|
+
await self.progress_callback(progress_info)
|
|
100
|
+
|
|
101
|
+
# Execute the statement
|
|
102
|
+
compiled = compile(
|
|
103
|
+
ast.Module(body=[node], type_ignores=[]), f"<statement_{i}>", "exec"
|
|
104
|
+
)
|
|
105
|
+
exec(compiled, self.globals, self.locals)
|
|
106
|
+
|
|
107
|
+
# Small delay for async behavior
|
|
108
|
+
if self.step_delay > 0:
|
|
109
|
+
await anyio.sleep(self.step_delay)
|
|
110
|
+
|
|
111
|
+
# Try to get result from main() function or return success
|
|
112
|
+
if "main" in self.locals and callable(self.locals["main"]):
|
|
113
|
+
result = self.locals["main"]()
|
|
114
|
+
if inspect.iscoroutine(result):
|
|
115
|
+
result = await result
|
|
116
|
+
return result
|
|
117
|
+
except Exception as e:
|
|
118
|
+
# Report error with current progress
|
|
119
|
+
if self.progress_callback:
|
|
120
|
+
progress_info = ProgressInfo(
|
|
121
|
+
current=float(self.current_statement),
|
|
122
|
+
total=float(self.total_statements),
|
|
123
|
+
message=f"Error: {str(e)[:50]}...",
|
|
124
|
+
)
|
|
125
|
+
await self.progress_callback(progress_info)
|
|
126
|
+
raise
|
|
127
|
+
else:
|
|
128
|
+
return "Code executed successfully"
|
|
129
|
+
|
|
130
|
+
async def execute_statements(self, code: str) -> AsyncIterator[tuple[str, dict[str, Any]]]:
|
|
131
|
+
"""Execute code statement by statement, yielding each executed statement.
|
|
132
|
+
|
|
133
|
+
This method is useful for external progress tracking or debugging.
|
|
134
|
+
|
|
135
|
+
Yields:
|
|
136
|
+
(statement_source, metadata) tuples
|
|
137
|
+
"""
|
|
138
|
+
self.total_statements = count_statements(code)
|
|
139
|
+
self.current_statement = 0
|
|
140
|
+
self.start_time = time.time()
|
|
141
|
+
|
|
142
|
+
if self.total_statements == 0:
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
tree = ast.parse(code)
|
|
146
|
+
for i, node in enumerate(tree.body):
|
|
147
|
+
self.current_statement = i + 1
|
|
148
|
+
statement_code = ast.unparse(node)
|
|
149
|
+
# Create metadata
|
|
150
|
+
elapsed_time = time.time() - (self.start_time or time.time())
|
|
151
|
+
metadata = {
|
|
152
|
+
"statement_index": i,
|
|
153
|
+
"total_statements": self.total_statements,
|
|
154
|
+
"node_type": type(node).__name__,
|
|
155
|
+
"elapsed_seconds": elapsed_time,
|
|
156
|
+
"locals_before": dict(self.locals),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Execute the statement
|
|
160
|
+
try:
|
|
161
|
+
compiled = compile(
|
|
162
|
+
ast.Module(body=[node], type_ignores=[]), f"<statement_{i}>", "exec"
|
|
163
|
+
)
|
|
164
|
+
exec(compiled, self.globals, self.locals)
|
|
165
|
+
metadata["status"] = "success"
|
|
166
|
+
except Exception as e: # noqa: BLE001
|
|
167
|
+
metadata["status"] = "error"
|
|
168
|
+
metadata["error"] = str(e)
|
|
169
|
+
|
|
170
|
+
metadata["locals_after"] = dict(self.locals)
|
|
171
|
+
yield statement_code, metadata
|
|
172
|
+
|
|
173
|
+
if self.step_delay > 0:
|
|
174
|
+
await anyio.sleep(self.step_delay)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
if __name__ == "__main__":
|
|
178
|
+
from pydantic_ai import RunContext # noqa: TC002
|
|
179
|
+
|
|
180
|
+
from agentpool import log
|
|
181
|
+
from agentpool.agents import AgentContext # noqa: TC001
|
|
182
|
+
|
|
183
|
+
log.configure_logging()
|
|
184
|
+
code = """
|
|
185
|
+
x = 10
|
|
186
|
+
y = 20
|
|
187
|
+
z = x + y
|
|
188
|
+
print(f"Result: {z}")
|
|
189
|
+
for i in range(3):
|
|
190
|
+
print(f"Loop: {i}")
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
async def run_me(run_context: RunContext, ctx: AgentContext) -> str:
|
|
194
|
+
"""Test function using the unified progress system."""
|
|
195
|
+
executor = ProgressTrackingExecutor(step_delay=0.5)
|
|
196
|
+
results = []
|
|
197
|
+
async for x in executor.execute_statements(code):
|
|
198
|
+
await ctx.events.custom(x)
|
|
199
|
+
results.append(x[0])
|
|
200
|
+
|
|
201
|
+
return f"Code executed successfully. Executed {len(results)} statements."
|
|
202
|
+
|
|
203
|
+
async def main() -> None:
|
|
204
|
+
from agentpool.delegation import AgentPool
|
|
205
|
+
|
|
206
|
+
async with AgentPool() as pool:
|
|
207
|
+
agent = await pool.add_agent("test-agent", model="openai:gpt-5-nano", tools=[run_me])
|
|
208
|
+
print("🚀 Testing unified progress system...")
|
|
209
|
+
async for event in agent.run_stream("Run run_me and show progress."):
|
|
210
|
+
print(f"Event: {event}")
|
|
211
|
+
|
|
212
|
+
anyio.run(main)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Meta-resource provider that exposes tools through Python execution."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from functools import partial
|
|
6
|
+
import inspect
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
from agentpool.agents.context import AgentContext # noqa: TC001
|
|
10
|
+
from agentpool.resource_providers import AggregatingResourceProvider
|
|
11
|
+
from agentpool.resource_providers.codemode.default_prompt import USAGE
|
|
12
|
+
from agentpool.resource_providers.codemode.helpers import (
|
|
13
|
+
tools_to_codegen,
|
|
14
|
+
validate_code,
|
|
15
|
+
)
|
|
16
|
+
from agentpool_toolsets.fsspec_toolset.toolset import FSSpecTools
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from schemez import ToolsetCodeGenerator
|
|
21
|
+
|
|
22
|
+
from agentpool.resource_providers import ResourceProvider
|
|
23
|
+
from agentpool.tools.base import Tool
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CodeModeResourceProvider(AggregatingResourceProvider):
|
|
27
|
+
"""Provider that wraps tools into a single Python execution environment."""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
providers: list[ResourceProvider],
|
|
32
|
+
name: str = "meta_tools",
|
|
33
|
+
include_docstrings: bool = True,
|
|
34
|
+
usage_notes: str = USAGE,
|
|
35
|
+
) -> None:
|
|
36
|
+
"""Initialize meta provider.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
providers: Providers whose tools to wrap
|
|
40
|
+
name: Provider name
|
|
41
|
+
include_docstrings: Include function docstrings in documentation
|
|
42
|
+
usage_notes: Usage notes for the codemode tool
|
|
43
|
+
"""
|
|
44
|
+
super().__init__(providers=providers, name=name)
|
|
45
|
+
self.include_docstrings = include_docstrings
|
|
46
|
+
self._cached_tool: Tool | None = None
|
|
47
|
+
self.usage_notes = usage_notes
|
|
48
|
+
|
|
49
|
+
async def get_tools(self) -> list[Tool]:
|
|
50
|
+
"""Return single meta-tool for Python execution with available tools."""
|
|
51
|
+
# Always generate fresh toolset to reflect current tools
|
|
52
|
+
toolset_generator = await self._get_code_generator()
|
|
53
|
+
desc = toolset_generator.generate_tool_description()
|
|
54
|
+
desc += self.usage_notes
|
|
55
|
+
|
|
56
|
+
if self._cached_tool is None:
|
|
57
|
+
# Create a closure that captures self but isn't a bound method
|
|
58
|
+
async def execute_tool(ctx: AgentContext, python_code: str) -> Any:
|
|
59
|
+
"""These docstings are overriden by description_override."""
|
|
60
|
+
return await self.execute(ctx, python_code)
|
|
61
|
+
|
|
62
|
+
self._cached_tool = self.create_tool(execute_tool, description_override=desc)
|
|
63
|
+
else:
|
|
64
|
+
# Update the description on existing cached tool
|
|
65
|
+
self._cached_tool.description = desc
|
|
66
|
+
|
|
67
|
+
return [self._cached_tool]
|
|
68
|
+
|
|
69
|
+
async def execute(self, ctx: AgentContext, python_code: str) -> Any: # noqa: D417
|
|
70
|
+
"""Execute Python code with all wrapped tools available as functions.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
python_code: Python code to execute
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Result of the last expression or explicit return value
|
|
77
|
+
"""
|
|
78
|
+
toolset_generator = await self._get_code_generator()
|
|
79
|
+
namespace = toolset_generator.generate_execution_namespace()
|
|
80
|
+
|
|
81
|
+
# Wrap namespace callables to inject AgentContext
|
|
82
|
+
for value in namespace.values():
|
|
83
|
+
if callable(value) and hasattr(value, "callable"):
|
|
84
|
+
# It's a NamespaceCallable - wrap its underlying callable with ctx
|
|
85
|
+
original_callable = value.callable
|
|
86
|
+
if "agent_ctx" in inspect.signature(original_callable).parameters:
|
|
87
|
+
value.callable = partial(original_callable, agent_ctx=ctx)
|
|
88
|
+
|
|
89
|
+
# async def report_progress(current: int, total: int, message: str = ""):
|
|
90
|
+
# """Report progress during code execution."""
|
|
91
|
+
# await ctx.report_progress(current, total, message)
|
|
92
|
+
|
|
93
|
+
# namespace["report_progress"] = NamespaceCallable(report_progress)
|
|
94
|
+
|
|
95
|
+
validate_code(python_code)
|
|
96
|
+
try:
|
|
97
|
+
exec(python_code, namespace)
|
|
98
|
+
result = await namespace["main"]()
|
|
99
|
+
# Handle edge cases with coroutines and return values
|
|
100
|
+
if inspect.iscoroutine(result):
|
|
101
|
+
result = await result
|
|
102
|
+
if not result: # in order to not confuse the model, return a success message.
|
|
103
|
+
return "Code executed successfully"
|
|
104
|
+
except Exception as e: # noqa: BLE001
|
|
105
|
+
return f"Error executing code: {e!s}"
|
|
106
|
+
else:
|
|
107
|
+
return result
|
|
108
|
+
|
|
109
|
+
def invalidate_cache(self) -> None:
|
|
110
|
+
"""Invalidate cached tool when providers change."""
|
|
111
|
+
self._cached_tool = None
|
|
112
|
+
# Note: We no longer cache the toolset generator, so no need to clear it
|
|
113
|
+
|
|
114
|
+
async def _get_code_generator(self) -> ToolsetCodeGenerator:
|
|
115
|
+
"""Get fresh toolset generator with current tools."""
|
|
116
|
+
tools = await super().get_tools()
|
|
117
|
+
return tools_to_codegen(tools=tools, include_docstrings=self.include_docstrings)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
import anyio
|
|
122
|
+
|
|
123
|
+
from agentpool import Agent
|
|
124
|
+
from agentpool.delegation.pool import AgentPool
|
|
125
|
+
|
|
126
|
+
static_provider = FSSpecTools()
|
|
127
|
+
provider = CodeModeResourceProvider([static_provider])
|
|
128
|
+
|
|
129
|
+
async def main() -> None:
|
|
130
|
+
print("Available tools:")
|
|
131
|
+
for tool in await provider.get_tools():
|
|
132
|
+
print(f"- {tool.name}: {tool.description[:100]}...")
|
|
133
|
+
|
|
134
|
+
async with AgentPool() as pool:
|
|
135
|
+
agent: Agent[None, str] = Agent(
|
|
136
|
+
model="openai:gpt-5-nano", event_handlers=["simple"], retries=1
|
|
137
|
+
)
|
|
138
|
+
pool.register("test_agent", agent)
|
|
139
|
+
async with agent:
|
|
140
|
+
agent.tools.add_provider(provider)
|
|
141
|
+
prompt = (
|
|
142
|
+
"Call list_directory with path='.'. "
|
|
143
|
+
"Write: async def main(): "
|
|
144
|
+
"result = await list_directory(path='.'); "
|
|
145
|
+
"return result"
|
|
146
|
+
)
|
|
147
|
+
result = await agent.run(prompt)
|
|
148
|
+
print(f"Result: {result}")
|
|
149
|
+
|
|
150
|
+
anyio.run(main)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Code execution provider with secure tool isolation via FastAPI server."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
7
|
+
|
|
8
|
+
from agentpool.log import get_logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
from types import TracebackType
|
|
14
|
+
|
|
15
|
+
from exxec.base import ExecutionEnvironment
|
|
16
|
+
from exxec.configs import ExecutionEnvironmentConfig
|
|
17
|
+
from schemez import ToolsetCodeGenerator
|
|
18
|
+
|
|
19
|
+
from agentpool.tools.base import Tool
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class RemoteMCPExecutor:
|
|
27
|
+
"""Provides secure code execution with tool access.
|
|
28
|
+
|
|
29
|
+
Code Generation mode (ctx-zip style):
|
|
30
|
+
- Tool functions are generated as Python files inside sandbox
|
|
31
|
+
- User code imports tools directly, no HTTP server needed
|
|
32
|
+
- Better for cloud sandboxes (E2B, etc.) that can't reach localhost
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
toolset_generator: ToolsetCodeGenerator
|
|
36
|
+
"""Code generator for tools."""
|
|
37
|
+
|
|
38
|
+
execution_env: ExecutionEnvironment
|
|
39
|
+
"""Execution environment for running code."""
|
|
40
|
+
|
|
41
|
+
use_code_generation: bool = False
|
|
42
|
+
"""If True, use code generation approach instead of HTTP server."""
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def from_tools(
|
|
46
|
+
cls,
|
|
47
|
+
tools: Sequence[Tool],
|
|
48
|
+
env_config: ExecutionEnvironmentConfig,
|
|
49
|
+
include_docstrings: bool = True,
|
|
50
|
+
) -> RemoteMCPExecutor:
|
|
51
|
+
"""Create provider from tools and environment configuration.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
tools: Tools to make available for code execution
|
|
55
|
+
env_config: Execution environment configuration
|
|
56
|
+
include_docstrings: Include function docstrings in documentation
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
RemoteMCPExecutor instance
|
|
60
|
+
"""
|
|
61
|
+
from agentpool.resource_providers.codemode.helpers import tools_to_codegen
|
|
62
|
+
|
|
63
|
+
toolset_gen = tools_to_codegen(tools, include_docstrings)
|
|
64
|
+
execution_env = env_config.get_provider()
|
|
65
|
+
return cls(toolset_gen, execution_env)
|
|
66
|
+
|
|
67
|
+
def get_tool_description(self) -> str:
|
|
68
|
+
"""Get comprehensive description of available tools."""
|
|
69
|
+
# For code generation mode, provide import-based usage instructions
|
|
70
|
+
tool_names = [gen.name for gen in self.toolset_generator.generators]
|
|
71
|
+
desc = self.toolset_generator.generate_tool_description()
|
|
72
|
+
desc += "Usage:\n"
|
|
73
|
+
for name in tool_names:
|
|
74
|
+
desc += f" from tools.{name} import {name}\n"
|
|
75
|
+
desc += f" result = await {name}(...)\n"
|
|
76
|
+
return desc
|
|
77
|
+
|
|
78
|
+
async def execute_code(self, code: str) -> Any:
|
|
79
|
+
"""Execute code with tools available.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
code: Python code to execute
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Execution result from the environment
|
|
86
|
+
"""
|
|
87
|
+
return await self.execution_env.execute(code)
|
|
88
|
+
|
|
89
|
+
async def __aenter__(self) -> Self:
|
|
90
|
+
"""Async context manager entry."""
|
|
91
|
+
await self.execution_env.__aenter__()
|
|
92
|
+
return self
|
|
93
|
+
|
|
94
|
+
async def __aexit__(
|
|
95
|
+
self,
|
|
96
|
+
exc_type: type[BaseException] | None,
|
|
97
|
+
exc_val: BaseException | None,
|
|
98
|
+
exc_tb: TracebackType | None,
|
|
99
|
+
) -> None:
|
|
100
|
+
"""Async context manager exit."""
|
|
101
|
+
return await self.execution_env.__aexit__(exc_type, exc_val, exc_tb)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
if __name__ == "__main__":
|
|
105
|
+
import anyio
|
|
106
|
+
from exxec.configs import LocalExecutionEnvironmentConfig
|
|
107
|
+
|
|
108
|
+
from agentpool.tools.base import Tool
|
|
109
|
+
|
|
110
|
+
def add_numbers(x: int, y: int) -> int:
|
|
111
|
+
"""Add two numbers."""
|
|
112
|
+
return x + y
|
|
113
|
+
|
|
114
|
+
def multiply_numbers(x: int, y: int) -> int:
|
|
115
|
+
"""Multiply two numbers."""
|
|
116
|
+
return x * y
|
|
117
|
+
|
|
118
|
+
async def main() -> None:
|
|
119
|
+
print("\n=== Code Generation Approach (ctx-zip style) ===")
|
|
120
|
+
tools = [Tool.from_callable(add_numbers), Tool.from_callable(multiply_numbers)]
|
|
121
|
+
config = LocalExecutionEnvironmentConfig() # Could be E2B, etc.
|
|
122
|
+
provider = RemoteMCPExecutor.from_tools(tools, config)
|
|
123
|
+
async with provider:
|
|
124
|
+
print("Tool description:")
|
|
125
|
+
print(provider.get_tool_description())
|
|
126
|
+
print("\nExecuting code with direct imports...")
|
|
127
|
+
|
|
128
|
+
# Code that imports tools directly (no HTTP calls)
|
|
129
|
+
code = """
|
|
130
|
+
from tools.add_numbers import add_numbers
|
|
131
|
+
from tools.multiply_numbers import multiply_numbers
|
|
132
|
+
|
|
133
|
+
# Direct function calls - no HTTP server needed!
|
|
134
|
+
result1 = add_numbers(5, 3)
|
|
135
|
+
result2 = multiply_numbers(4, 7)
|
|
136
|
+
|
|
137
|
+
_result = {"addition": result1, "multiplication": result2}
|
|
138
|
+
print(f"Addition: {result1}, Multiplication: {result2}")
|
|
139
|
+
"""
|
|
140
|
+
result = await provider.execute_code(code)
|
|
141
|
+
print(f"Result: {result.result}")
|
|
142
|
+
|
|
143
|
+
anyio.run(main)
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""Secure code execution provider using isolated execution environments."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import contextlib
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
8
|
+
|
|
9
|
+
from exxec.configs import LocalExecutionEnvironmentConfig
|
|
10
|
+
|
|
11
|
+
from agentpool.agents.context import AgentContext # noqa: TC001
|
|
12
|
+
from agentpool.log import get_logger
|
|
13
|
+
from agentpool.resource_providers.codemode.code_executor import (
|
|
14
|
+
RemoteCodeExecutor,
|
|
15
|
+
)
|
|
16
|
+
from agentpool.resource_providers.codemode.default_prompt import USAGE
|
|
17
|
+
from agentpool.resource_providers.codemode.helpers import validate_code
|
|
18
|
+
from agentpool.resource_providers.codemode.provider import (
|
|
19
|
+
CodeModeResourceProvider,
|
|
20
|
+
)
|
|
21
|
+
from agentpool.tools.base import Tool
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
logger = get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from types import TracebackType
|
|
28
|
+
|
|
29
|
+
from exxec.configs import ExecutionEnvironmentConfig
|
|
30
|
+
|
|
31
|
+
from agentpool.resource_providers import ResourceProvider
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
PROGRESS_HELPER = """
|
|
35
|
+
async def report_progress(current: int, total: int, message: str = "") -> None:
|
|
36
|
+
'''Report progress during execution'''
|
|
37
|
+
percentage = (current / total) * 100 if total > 0 else 0
|
|
38
|
+
print(f"Progress: {percentage:.1f}% ({current}/{total}) {message}")
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class RemoteCodeModeResourceProvider(CodeModeResourceProvider):
|
|
43
|
+
"""Provider that executes code in secure isolation with tool access via server."""
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
providers: list[ResourceProvider],
|
|
48
|
+
execution_config: ExecutionEnvironmentConfig | None = None,
|
|
49
|
+
name: str = "secure_code_executor",
|
|
50
|
+
include_docstrings: bool = True,
|
|
51
|
+
usage_notes: str = USAGE,
|
|
52
|
+
server_host: str = "localhost",
|
|
53
|
+
server_port: int = 8000,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Initialize secure code execution provider.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
providers: Providers whose tools to expose
|
|
59
|
+
execution_config: Execution environment configuration
|
|
60
|
+
name: Provider name
|
|
61
|
+
include_docstrings: Include function docstrings in documentation
|
|
62
|
+
usage_notes: Usage notes for the provider
|
|
63
|
+
server_host: Host for tool server
|
|
64
|
+
server_port: Port for tool server
|
|
65
|
+
"""
|
|
66
|
+
super().__init__(
|
|
67
|
+
providers=providers,
|
|
68
|
+
name=name,
|
|
69
|
+
include_docstrings=include_docstrings,
|
|
70
|
+
usage_notes=usage_notes,
|
|
71
|
+
)
|
|
72
|
+
self.execution_config = execution_config or LocalExecutionEnvironmentConfig()
|
|
73
|
+
self.server_host = server_host
|
|
74
|
+
self.server_port = server_port
|
|
75
|
+
self._code_executor: RemoteCodeExecutor | None = None
|
|
76
|
+
self._provider_lock = asyncio.Lock()
|
|
77
|
+
|
|
78
|
+
async def execute(self, ctx: AgentContext, python_code: str) -> Any: # noqa: D417
|
|
79
|
+
"""Execute Python code in secure environment with tools available via HTTP.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
python_code: Python code to execute
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Result of the code execution
|
|
86
|
+
"""
|
|
87
|
+
code_provider = await self._get_code_executor()
|
|
88
|
+
logger.info("Validating code", code=python_code)
|
|
89
|
+
validate_code(python_code)
|
|
90
|
+
full_code = f"{PROGRESS_HELPER}\n\n{python_code}"
|
|
91
|
+
logger.info("Complete code", code=full_code)
|
|
92
|
+
try:
|
|
93
|
+
result = await code_provider.execution_env.execute(full_code)
|
|
94
|
+
if result.success:
|
|
95
|
+
logger.info("Code executed successfully")
|
|
96
|
+
if result.result is None:
|
|
97
|
+
return "Code executed successfully"
|
|
98
|
+
return result.result
|
|
99
|
+
except Exception as e: # noqa: BLE001
|
|
100
|
+
return f"Error in secure execution: {e!s}"
|
|
101
|
+
else:
|
|
102
|
+
return f"Error executing code: {result.error}"
|
|
103
|
+
|
|
104
|
+
async def _get_code_executor(self) -> RemoteCodeExecutor:
|
|
105
|
+
"""Get cached code execution provider with thread-safe initialization."""
|
|
106
|
+
async with self._provider_lock:
|
|
107
|
+
if self._code_executor is None:
|
|
108
|
+
all_tools = await super().get_tools()
|
|
109
|
+
self._code_executor = RemoteCodeExecutor.from_tools(
|
|
110
|
+
all_tools,
|
|
111
|
+
self.execution_config,
|
|
112
|
+
server_host=self.server_host,
|
|
113
|
+
server_port=self.server_port,
|
|
114
|
+
include_docstrings=self.include_docstrings,
|
|
115
|
+
)
|
|
116
|
+
# Initialize the provider and start server
|
|
117
|
+
await self._code_executor.__aenter__()
|
|
118
|
+
|
|
119
|
+
return self._code_executor
|
|
120
|
+
|
|
121
|
+
async def __aenter__(self) -> Self:
|
|
122
|
+
"""Async context manager entry."""
|
|
123
|
+
return self
|
|
124
|
+
|
|
125
|
+
async def __aexit__(
|
|
126
|
+
self,
|
|
127
|
+
exc_type: type[BaseException] | None,
|
|
128
|
+
exc_val: BaseException | None,
|
|
129
|
+
exc_tb: TracebackType | None,
|
|
130
|
+
) -> None:
|
|
131
|
+
"""Async context manager exit."""
|
|
132
|
+
if self._code_executor is not None:
|
|
133
|
+
with contextlib.suppress(Exception):
|
|
134
|
+
await self._code_executor.__aexit__(exc_type, exc_val, exc_tb)
|
|
135
|
+
self._code_executor = None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
import webbrowser
|
|
140
|
+
|
|
141
|
+
import anyio
|
|
142
|
+
from exxec.configs import LocalExecutionEnvironmentConfig
|
|
143
|
+
|
|
144
|
+
from agentpool import Agent, log
|
|
145
|
+
from agentpool.resource_providers import StaticResourceProvider
|
|
146
|
+
|
|
147
|
+
log.configure_logging()
|
|
148
|
+
|
|
149
|
+
def open_browser(url: str) -> bool:
|
|
150
|
+
"""Use this to open url in the default browser."""
|
|
151
|
+
return webbrowser.open(url)
|
|
152
|
+
|
|
153
|
+
async def main() -> None:
|
|
154
|
+
tools = [Tool.from_callable(open_browser)]
|
|
155
|
+
static_provider = StaticResourceProvider(tools=tools)
|
|
156
|
+
config = LocalExecutionEnvironmentConfig(timeout=30.0)
|
|
157
|
+
provider = RemoteCodeModeResourceProvider(
|
|
158
|
+
providers=[static_provider],
|
|
159
|
+
execution_config=config,
|
|
160
|
+
server_port=9999,
|
|
161
|
+
)
|
|
162
|
+
print("Available tools:")
|
|
163
|
+
for tool in await provider.get_tools():
|
|
164
|
+
print(f"- {tool.name}: {tool.description}")
|
|
165
|
+
|
|
166
|
+
async with Agent(model="anthropic:claude-haiku-4-5") as agent:
|
|
167
|
+
agent.tools.add_provider(provider)
|
|
168
|
+
result = await agent.run("open google.com in the browser.")
|
|
169
|
+
print(f"Result: {result}")
|
|
170
|
+
|
|
171
|
+
anyio.run(main)
|