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
acp/filesystem.py
ADDED
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
"""Filesystem implementation for ACP (Agent Communication Protocol) sessions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Literal, Required, overload
|
|
8
|
+
|
|
9
|
+
from anyenv import get_os_command_provider
|
|
10
|
+
from fsspec.asyn import sync_wrapper
|
|
11
|
+
from fsspec.spec import AbstractBufferedFile
|
|
12
|
+
from upathtools.filesystems.base import BaseAsyncFileSystem, BaseUPath, FileInfo
|
|
13
|
+
|
|
14
|
+
from acp.acp_requests import ACPRequests
|
|
15
|
+
from acp.notifications import ACPNotifications
|
|
16
|
+
from agentpool.mime_utils import guess_type, is_text_mime
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AcpInfo(FileInfo, total=False):
|
|
20
|
+
"""Info dict for ACP filesystem paths."""
|
|
21
|
+
|
|
22
|
+
islink: bool
|
|
23
|
+
timestamp: str | None
|
|
24
|
+
permissions: str | None
|
|
25
|
+
size: Required[int]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from acp.client.protocol import Client
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ACPFile(AbstractBufferedFile): # type: ignore[misc]
|
|
36
|
+
"""File-like object for ACP filesystem operations."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, fs: ACPFileSystem, path: str, mode: str = "rb", **kwargs: Any) -> None:
|
|
39
|
+
"""Initialize ACP file handle."""
|
|
40
|
+
super().__init__(fs, path, mode, **kwargs)
|
|
41
|
+
self._content: bytes | None = None
|
|
42
|
+
self.forced = False
|
|
43
|
+
self.fs = fs # assign again here just for typing
|
|
44
|
+
|
|
45
|
+
def _fetch_range(self, start: int | None, end: int | None) -> bytes:
|
|
46
|
+
"""Fetch byte range from file (sync wrapper)."""
|
|
47
|
+
if self._content is None:
|
|
48
|
+
# Run the async operation in the event loop
|
|
49
|
+
self._content = self.fs.cat_file(self.path) # pyright: ignore[reportAttributeAccessIssue]
|
|
50
|
+
assert self._content
|
|
51
|
+
|
|
52
|
+
if start is None and end is None:
|
|
53
|
+
return self._content
|
|
54
|
+
return self._content[start:end]
|
|
55
|
+
|
|
56
|
+
def _upload_chunk(self, final: bool = False) -> bool:
|
|
57
|
+
"""Upload buffered data to file (sync wrapper)."""
|
|
58
|
+
if final and self.buffer:
|
|
59
|
+
content = self.buffer.getvalue()
|
|
60
|
+
if isinstance(content, bytes):
|
|
61
|
+
content = content.decode("utf-8")
|
|
62
|
+
# Run the async operation in the event loop
|
|
63
|
+
self.fs.put_file(self.path, content)
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ACPPath(BaseUPath[AcpInfo]):
|
|
68
|
+
"""Path for ACP filesystem."""
|
|
69
|
+
|
|
70
|
+
__slots__ = ()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ACPFileSystem(BaseAsyncFileSystem[ACPPath, AcpInfo]):
|
|
74
|
+
"""Async filesystem for ACP sessions."""
|
|
75
|
+
|
|
76
|
+
protocol = "acp"
|
|
77
|
+
sep = "/"
|
|
78
|
+
upath_cls = ACPPath
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
client: Client,
|
|
83
|
+
session_id: str,
|
|
84
|
+
*,
|
|
85
|
+
use_cli_find: bool = True,
|
|
86
|
+
**kwargs: Any,
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Initialize ACP filesystem.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
client: ACP client for operations
|
|
92
|
+
session_id: Session identifier
|
|
93
|
+
use_cli_find: Use CLI find command for _find/_glob operations.
|
|
94
|
+
When True (default), uses a single `find` command for recursive
|
|
95
|
+
file discovery, which is much more efficient over the protocol
|
|
96
|
+
barrier than walking the tree with multiple ls calls.
|
|
97
|
+
**kwargs: Additional filesystem options
|
|
98
|
+
"""
|
|
99
|
+
super().__init__(**kwargs)
|
|
100
|
+
self.client = client
|
|
101
|
+
self.session_id = session_id
|
|
102
|
+
self.requests = ACPRequests(client, session_id)
|
|
103
|
+
self.notifications = ACPNotifications(client, session_id)
|
|
104
|
+
self.command_provider = get_os_command_provider()
|
|
105
|
+
self.use_cli_find = use_cli_find
|
|
106
|
+
|
|
107
|
+
async def _cat_file(
|
|
108
|
+
self, path: str, start: int | None = None, end: int | None = None, **kwargs: Any
|
|
109
|
+
) -> bytes:
|
|
110
|
+
"""Read file content via ACP session.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
path: File path to read
|
|
114
|
+
start: Start byte position (not supported by ACP)
|
|
115
|
+
end: End byte position (not supported by ACP)
|
|
116
|
+
**kwargs: Additional options
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
File content as bytes
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
NotImplementedError: If byte range is requested (ACP doesn't support
|
|
123
|
+
partial reads)
|
|
124
|
+
"""
|
|
125
|
+
if start is not None or end is not None:
|
|
126
|
+
msg = "ACP filesystem does not support byte range reads"
|
|
127
|
+
raise NotImplementedError(msg)
|
|
128
|
+
|
|
129
|
+
mime_type = guess_type(path)
|
|
130
|
+
|
|
131
|
+
if is_text_mime(mime_type):
|
|
132
|
+
# Text file - use read_text_file directly
|
|
133
|
+
try:
|
|
134
|
+
content = await self.requests.read_text_file(path)
|
|
135
|
+
return content.encode("utf-8")
|
|
136
|
+
except Exception as e:
|
|
137
|
+
raise FileNotFoundError(f"Could not read file {path}: {e}") from e
|
|
138
|
+
|
|
139
|
+
# Binary file - use base64 encoding via terminal command
|
|
140
|
+
try:
|
|
141
|
+
b64_cmd = self.command_provider.get_command("base64_encode")
|
|
142
|
+
cmd_str = b64_cmd.create_command(path)
|
|
143
|
+
output, exit_code = await self.requests.run_command(cmd_str, timeout_seconds=30)
|
|
144
|
+
|
|
145
|
+
if exit_code != 0:
|
|
146
|
+
msg = f"Could not read binary file {path}: {output}"
|
|
147
|
+
raise FileNotFoundError(msg) # noqa: TRY301
|
|
148
|
+
|
|
149
|
+
return b64_cmd.parse_command(output)
|
|
150
|
+
except Exception as e:
|
|
151
|
+
msg = f"Could not read file {path}: {e}"
|
|
152
|
+
raise FileNotFoundError(msg) from e
|
|
153
|
+
|
|
154
|
+
cat_file = sync_wrapper(_cat_file) # pyright: ignore[reportAssignmentType]
|
|
155
|
+
|
|
156
|
+
async def _put_file(self, path: str, content: str | bytes, **kwargs: Any) -> None:
|
|
157
|
+
"""Write file content via ACP session.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
path: File path to write
|
|
161
|
+
content: Content to write (string or bytes)
|
|
162
|
+
**kwargs: Additional options
|
|
163
|
+
"""
|
|
164
|
+
if isinstance(content, bytes):
|
|
165
|
+
content = content.decode("utf-8")
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
await self.requests.write_text_file(path, content)
|
|
169
|
+
except Exception as e:
|
|
170
|
+
msg = f"Could not write file {path}: {e}"
|
|
171
|
+
raise OSError(msg) from e
|
|
172
|
+
|
|
173
|
+
put_file = sync_wrapper(_put_file)
|
|
174
|
+
|
|
175
|
+
async def _pipe_file(self, path: str, data: bytes, **kwargs: Any) -> None:
|
|
176
|
+
"""Write bytes directly to a file path.
|
|
177
|
+
|
|
178
|
+
This is the fsspec standard method for writing data to a file.
|
|
179
|
+
Wraps _put_file for compatibility.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
path: File path to write
|
|
183
|
+
data: Bytes to write
|
|
184
|
+
**kwargs: Additional options
|
|
185
|
+
"""
|
|
186
|
+
await self._put_file(path, data, **kwargs)
|
|
187
|
+
|
|
188
|
+
pipe_file = sync_wrapper(_pipe_file)
|
|
189
|
+
|
|
190
|
+
@overload
|
|
191
|
+
async def _ls(self, path: str, detail: Literal[True] = ..., **kwargs: Any) -> list[AcpInfo]: ...
|
|
192
|
+
|
|
193
|
+
@overload
|
|
194
|
+
async def _ls(self, path: str, detail: Literal[False], **kwargs: Any) -> list[str]: ...
|
|
195
|
+
|
|
196
|
+
async def _ls(self, path: str, detail: bool = True, **kwargs: Any) -> list[AcpInfo] | list[str]:
|
|
197
|
+
"""List directory contents via terminal command.
|
|
198
|
+
|
|
199
|
+
Uses 'ls -la' command through ACP terminal to get directory listings.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
path: Directory path to list
|
|
203
|
+
detail: Whether to return detailed file information
|
|
204
|
+
**kwargs: Additional options
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
List of file information dictionaries or file names
|
|
208
|
+
"""
|
|
209
|
+
# Use OS-specific command to list directory contents
|
|
210
|
+
list_cmd = self.command_provider.get_command("list_directory")
|
|
211
|
+
ls_cmd = list_cmd.create_command(path)
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
output, exit_code = await self.requests.run_command(ls_cmd, timeout_seconds=10)
|
|
215
|
+
|
|
216
|
+
if exit_code != 0:
|
|
217
|
+
msg = f"Error listing directory {path!r}: {output}"
|
|
218
|
+
raise FileNotFoundError(msg) # noqa: TRY301
|
|
219
|
+
|
|
220
|
+
result = list_cmd.parse_command(output, path)
|
|
221
|
+
if detail:
|
|
222
|
+
return [
|
|
223
|
+
AcpInfo(
|
|
224
|
+
name=item.path, # fsspec expects full path in 'name'
|
|
225
|
+
type="file" if item.type == "link" else item.type,
|
|
226
|
+
size=item.size,
|
|
227
|
+
islink=item.type == "link",
|
|
228
|
+
timestamp=item.timestamp,
|
|
229
|
+
permissions=item.permissions,
|
|
230
|
+
)
|
|
231
|
+
for item in result
|
|
232
|
+
]
|
|
233
|
+
return [item.path for item in result] # Return full paths for consistency
|
|
234
|
+
|
|
235
|
+
except Exception as e:
|
|
236
|
+
msg = f"Could not list directory {path}: {e}"
|
|
237
|
+
raise FileNotFoundError(msg) from e
|
|
238
|
+
|
|
239
|
+
ls = sync_wrapper(_ls)
|
|
240
|
+
|
|
241
|
+
async def _info(self, path: str, **kwargs: Any) -> AcpInfo:
|
|
242
|
+
"""Get file information via stat command.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
path: File path to get info for
|
|
246
|
+
**kwargs: Additional options
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
File information dictionary
|
|
250
|
+
"""
|
|
251
|
+
info_cmd = self.command_provider.get_command("file_info")
|
|
252
|
+
stat_cmd = info_cmd.create_command(path)
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
output, exit_code = await self.requests.run_command(stat_cmd, timeout_seconds=5)
|
|
256
|
+
|
|
257
|
+
if exit_code != 0:
|
|
258
|
+
raise FileNotFoundError(f"File not found: {path}")
|
|
259
|
+
file_info = info_cmd.parse_command(output.strip(), path)
|
|
260
|
+
return AcpInfo(
|
|
261
|
+
name=file_info.path,
|
|
262
|
+
type="file" if file_info.type == "link" else file_info.type,
|
|
263
|
+
size=file_info.size,
|
|
264
|
+
islink=file_info.type == "link",
|
|
265
|
+
timestamp=file_info.timestamp,
|
|
266
|
+
permissions=file_info.permissions,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
except (OSError, ValueError) as e:
|
|
270
|
+
# Fallback: try to get basic info from ls
|
|
271
|
+
try:
|
|
272
|
+
ls_result = await self._ls(str(Path(path).parent), detail=True)
|
|
273
|
+
filename = Path(path).name
|
|
274
|
+
|
|
275
|
+
for item in ls_result:
|
|
276
|
+
if Path(item["name"]).name == filename:
|
|
277
|
+
return AcpInfo(
|
|
278
|
+
name=path, # fsspec expects full path in 'name'
|
|
279
|
+
type=item["type"],
|
|
280
|
+
size=item["size"],
|
|
281
|
+
islink=item.get("islink", False),
|
|
282
|
+
timestamp=item.get("timestamp"),
|
|
283
|
+
permissions=item.get("permissions"),
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
raise FileNotFoundError(f"File not found: {path}")
|
|
287
|
+
except (OSError, ValueError):
|
|
288
|
+
msg = f"Could not get file info for {path}: {e}"
|
|
289
|
+
raise FileNotFoundError(msg) from e
|
|
290
|
+
|
|
291
|
+
info = sync_wrapper(_info)
|
|
292
|
+
|
|
293
|
+
async def _exists(self, path: str, **kwargs: Any) -> bool:
|
|
294
|
+
"""Check if file exists via test command.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
path: File path to check
|
|
298
|
+
**kwargs: Additional options
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
True if file exists, False otherwise
|
|
302
|
+
"""
|
|
303
|
+
exists_cmd = self.command_provider.get_command("exists")
|
|
304
|
+
test_cmd = exists_cmd.create_command(path)
|
|
305
|
+
|
|
306
|
+
try:
|
|
307
|
+
output, exit_code = await self.requests.run_command(test_cmd, timeout_seconds=5)
|
|
308
|
+
except (OSError, ValueError):
|
|
309
|
+
return False
|
|
310
|
+
else:
|
|
311
|
+
return exists_cmd.parse_command(output, exit_code if exit_code is not None else 1)
|
|
312
|
+
|
|
313
|
+
exists = sync_wrapper(_exists) # pyright: ignore[reportAssignmentType]
|
|
314
|
+
|
|
315
|
+
async def _isdir(self, path: str, **kwargs: Any) -> bool:
|
|
316
|
+
"""Check if path is a directory via test command.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
path: Path to check
|
|
320
|
+
**kwargs: Additional options
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
True if path is a directory, False otherwise
|
|
324
|
+
"""
|
|
325
|
+
isdir_cmd = self.command_provider.get_command("is_directory")
|
|
326
|
+
test_cmd = isdir_cmd.create_command(path)
|
|
327
|
+
|
|
328
|
+
try:
|
|
329
|
+
output, exit_code = await self.requests.run_command(test_cmd, timeout_seconds=5)
|
|
330
|
+
except (OSError, ValueError):
|
|
331
|
+
return False
|
|
332
|
+
else:
|
|
333
|
+
return isdir_cmd.parse_command(output, exit_code if exit_code is not None else 1)
|
|
334
|
+
|
|
335
|
+
isdir = sync_wrapper(_isdir)
|
|
336
|
+
|
|
337
|
+
async def _isfile(self, path: str, **kwargs: Any) -> bool:
|
|
338
|
+
"""Check if path is a file via test command.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
path: Path to check
|
|
342
|
+
**kwargs: Additional options
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
True if path is a file, False otherwise
|
|
346
|
+
"""
|
|
347
|
+
isfile_cmd = self.command_provider.get_command("is_file")
|
|
348
|
+
test_cmd = isfile_cmd.create_command(path)
|
|
349
|
+
|
|
350
|
+
try:
|
|
351
|
+
output, exit_code = await self.requests.run_command(test_cmd, timeout_seconds=5)
|
|
352
|
+
except (OSError, ValueError):
|
|
353
|
+
return False
|
|
354
|
+
else:
|
|
355
|
+
return isfile_cmd.parse_command(output, exit_code if exit_code is not None else 1)
|
|
356
|
+
|
|
357
|
+
isfile = sync_wrapper(_isfile)
|
|
358
|
+
|
|
359
|
+
async def _makedirs(self, path: str, exist_ok: bool = False, **kwargs: Any) -> None:
|
|
360
|
+
"""Create directories via mkdir command.
|
|
361
|
+
|
|
362
|
+
Args:
|
|
363
|
+
path: Directory path to create
|
|
364
|
+
exist_ok: Don't raise error if directory already exists
|
|
365
|
+
**kwargs: Additional options
|
|
366
|
+
"""
|
|
367
|
+
create_cmd = self.command_provider.get_command("create_directory")
|
|
368
|
+
mkdir_cmd = create_cmd.create_command(path, parents=exist_ok)
|
|
369
|
+
|
|
370
|
+
try:
|
|
371
|
+
output, exit_code = await self.requests.run_command(mkdir_cmd, timeout_seconds=5)
|
|
372
|
+
success = create_cmd.parse_command(output, exit_code if exit_code is not None else 1)
|
|
373
|
+
if not success:
|
|
374
|
+
msg = f"Error creating directory {path}: {output}"
|
|
375
|
+
raise OSError(msg) # noqa: TRY301
|
|
376
|
+
except Exception as e:
|
|
377
|
+
msg = f"Could not create directory {path}: {e}"
|
|
378
|
+
raise OSError(msg) from e
|
|
379
|
+
|
|
380
|
+
makedirs = sync_wrapper(_makedirs)
|
|
381
|
+
|
|
382
|
+
async def _cp_file(self, path1: str, path2: str, **kwargs: Any) -> None:
|
|
383
|
+
"""Copy a file from path1 to path2.
|
|
384
|
+
|
|
385
|
+
Uses CLI cp/copy command for efficiency - single round-trip and
|
|
386
|
+
native binary file support without base64 encoding overhead.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
path1: Source file path
|
|
390
|
+
path2: Destination file path
|
|
391
|
+
**kwargs: Additional options
|
|
392
|
+
"""
|
|
393
|
+
copy_cmd = self.command_provider.get_command("copy_path")
|
|
394
|
+
cmd_str = copy_cmd.create_command(path1, path2, recursive=False)
|
|
395
|
+
|
|
396
|
+
try:
|
|
397
|
+
output, exit_code = await self.requests.run_command(cmd_str, timeout_seconds=30)
|
|
398
|
+
success = copy_cmd.parse_command(output, exit_code if exit_code is not None else 1)
|
|
399
|
+
if not success:
|
|
400
|
+
msg = f"Error copying {path1} to {path2}: {output}"
|
|
401
|
+
raise OSError(msg) # noqa: TRY301
|
|
402
|
+
except Exception as e:
|
|
403
|
+
msg = f"Could not copy {path1} to {path2}: {e}"
|
|
404
|
+
raise OSError(msg) from e
|
|
405
|
+
|
|
406
|
+
cp_file = sync_wrapper(_cp_file)
|
|
407
|
+
|
|
408
|
+
async def _rm(self, path: str, recursive: bool = False, **kwargs: Any) -> None:
|
|
409
|
+
"""Remove file or directory via rm command.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
path: Path to remove
|
|
413
|
+
recursive: Remove directories recursively
|
|
414
|
+
**kwargs: Additional options
|
|
415
|
+
"""
|
|
416
|
+
remove_cmd = self.command_provider.get_command("remove_path")
|
|
417
|
+
rm_cmd = remove_cmd.create_command(path, recursive=recursive)
|
|
418
|
+
|
|
419
|
+
try:
|
|
420
|
+
output, exit_code = await self.requests.run_command(rm_cmd, timeout_seconds=10)
|
|
421
|
+
success = remove_cmd.parse_command(output, exit_code if exit_code is not None else 1)
|
|
422
|
+
if not success:
|
|
423
|
+
msg = f"Error removing {path}: {output}"
|
|
424
|
+
raise OSError(msg) # noqa: TRY301
|
|
425
|
+
except Exception as e:
|
|
426
|
+
msg = f"Could not remove {path}: {e}"
|
|
427
|
+
raise OSError(msg) from e
|
|
428
|
+
|
|
429
|
+
rm = sync_wrapper(_rm)
|
|
430
|
+
|
|
431
|
+
async def _find(
|
|
432
|
+
self,
|
|
433
|
+
path: str,
|
|
434
|
+
maxdepth: int | None = None,
|
|
435
|
+
withdirs: bool = False,
|
|
436
|
+
**kwargs: Any,
|
|
437
|
+
) -> list[str] | dict[str, AcpInfo]:
|
|
438
|
+
"""Find files recursively.
|
|
439
|
+
|
|
440
|
+
When use_cli_find is enabled, uses a single CLI find command instead of
|
|
441
|
+
walking the directory tree with multiple ls calls. This is much more
|
|
442
|
+
efficient over the protocol barrier.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
path: Root path to search from
|
|
446
|
+
maxdepth: Maximum depth to descend (None for unlimited)
|
|
447
|
+
withdirs: Include directories in results
|
|
448
|
+
**kwargs: Additional options (detail=True returns dict with info)
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
List of paths, or dict mapping paths to info if detail=True
|
|
452
|
+
"""
|
|
453
|
+
if not self.use_cli_find:
|
|
454
|
+
# Fall back to default fsspec implementation (walks tree with _ls)
|
|
455
|
+
return await super()._find(path, maxdepth=maxdepth, withdirs=withdirs, **kwargs) # type: ignore[no-any-return]
|
|
456
|
+
|
|
457
|
+
detail = kwargs.pop("detail", False)
|
|
458
|
+
stripped = self._strip_protocol(path)
|
|
459
|
+
search_path = stripped if isinstance(stripped, str) else stripped[0]
|
|
460
|
+
|
|
461
|
+
# Determine file_type filter
|
|
462
|
+
file_type: Literal["file", "directory", "all"] = "all" if withdirs else "file"
|
|
463
|
+
|
|
464
|
+
# Use anyenv find command
|
|
465
|
+
find_cmd = self.command_provider.get_command("find")
|
|
466
|
+
cmd_str = find_cmd.create_command(
|
|
467
|
+
search_path, maxdepth=maxdepth, file_type=file_type, with_stats=detail
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
try:
|
|
471
|
+
output, exit_code = await self.requests.run_command(cmd_str, timeout_seconds=60)
|
|
472
|
+
|
|
473
|
+
if exit_code != 0:
|
|
474
|
+
# If find fails, fall back to default implementation
|
|
475
|
+
logger.warning("CLI find failed, falling back to walk: %s", output)
|
|
476
|
+
return await super()._find(path, maxdepth=maxdepth, withdirs=withdirs, **kwargs) # type: ignore[no-any-return]
|
|
477
|
+
|
|
478
|
+
entries = find_cmd.parse_command(output, search_path)
|
|
479
|
+
|
|
480
|
+
if detail:
|
|
481
|
+
# Return dict with info from find output
|
|
482
|
+
return {
|
|
483
|
+
entry.path: AcpInfo(
|
|
484
|
+
name=entry.path,
|
|
485
|
+
type="file" if entry.type == "link" else entry.type,
|
|
486
|
+
size=entry.size,
|
|
487
|
+
islink=entry.type == "link",
|
|
488
|
+
timestamp=entry.timestamp,
|
|
489
|
+
permissions=entry.permissions,
|
|
490
|
+
)
|
|
491
|
+
for entry in entries
|
|
492
|
+
if entry.name not in (".", "..")
|
|
493
|
+
}
|
|
494
|
+
return [entry.path for entry in entries if entry.name not in (".", "..")]
|
|
495
|
+
|
|
496
|
+
except Exception as e: # noqa: BLE001
|
|
497
|
+
logger.warning("CLI find error, falling back to walk: %s", e)
|
|
498
|
+
return await super()._find(path, maxdepth=maxdepth, withdirs=withdirs, **kwargs) # type: ignore[no-any-return]
|
|
499
|
+
|
|
500
|
+
find = sync_wrapper(_find) # pyright: ignore[reportAssignmentType]
|
|
501
|
+
|
|
502
|
+
def open(self, path: str, mode: str = "rb", **kwargs: Any) -> ACPFile:
|
|
503
|
+
"""Open file for reading or writing.
|
|
504
|
+
|
|
505
|
+
Args:
|
|
506
|
+
path: File path to open
|
|
507
|
+
mode: File mode ('rb', 'wb', 'ab', 'xb')
|
|
508
|
+
**kwargs: Additional options
|
|
509
|
+
|
|
510
|
+
Returns:
|
|
511
|
+
File-like object
|
|
512
|
+
"""
|
|
513
|
+
# Convert text modes to binary modes for fsspec compatibility
|
|
514
|
+
match mode:
|
|
515
|
+
case "r":
|
|
516
|
+
mode = "rb"
|
|
517
|
+
case "w":
|
|
518
|
+
mode = "wb"
|
|
519
|
+
case "a":
|
|
520
|
+
mode = "ab"
|
|
521
|
+
case "x":
|
|
522
|
+
mode = "xb"
|
|
523
|
+
|
|
524
|
+
return ACPFile(self, path, mode, **kwargs)
|