agentpool 2.2.3__py3-none-any.whl → 2.5.0__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.
- acp/__init__.py +0 -4
- acp/acp_requests.py +20 -77
- acp/agent/connection.py +8 -0
- acp/agent/implementations/debug_server/debug_server.py +6 -2
- acp/agent/protocol.py +6 -0
- acp/client/connection.py +38 -29
- acp/client/implementations/default_client.py +3 -2
- acp/client/implementations/headless_client.py +2 -2
- acp/connection.py +2 -2
- acp/notifications.py +18 -49
- acp/schema/__init__.py +2 -0
- acp/schema/agent_responses.py +21 -0
- acp/schema/client_requests.py +3 -3
- acp/schema/session_state.py +63 -29
- acp/task/supervisor.py +2 -2
- acp/utils.py +2 -2
- agentpool/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +278 -263
- agentpool/agents/acp_agent/acp_converters.py +150 -17
- agentpool/agents/acp_agent/client_handler.py +35 -24
- agentpool/agents/acp_agent/session_state.py +14 -6
- agentpool/agents/agent.py +471 -643
- agentpool/agents/agui_agent/agui_agent.py +104 -107
- agentpool/agents/agui_agent/helpers.py +3 -4
- agentpool/agents/base_agent.py +485 -32
- agentpool/agents/claude_code_agent/FORKING.md +191 -0
- agentpool/agents/claude_code_agent/__init__.py +13 -1
- agentpool/agents/claude_code_agent/claude_code_agent.py +654 -334
- agentpool/agents/claude_code_agent/converters.py +4 -141
- agentpool/agents/claude_code_agent/models.py +77 -0
- agentpool/agents/claude_code_agent/static_info.py +100 -0
- agentpool/agents/claude_code_agent/usage.py +242 -0
- agentpool/agents/events/__init__.py +22 -0
- agentpool/agents/events/builtin_handlers.py +65 -0
- agentpool/agents/events/event_emitter.py +3 -0
- agentpool/agents/events/events.py +84 -3
- agentpool/agents/events/infer_info.py +145 -0
- agentpool/agents/events/processors.py +254 -0
- agentpool/agents/interactions.py +41 -6
- agentpool/agents/modes.py +13 -0
- agentpool/agents/slashed_agent.py +5 -4
- agentpool/agents/tool_wrapping.py +18 -6
- agentpool/common_types.py +35 -21
- agentpool/config_resources/acp_assistant.yml +2 -2
- agentpool/config_resources/agents.yml +3 -0
- agentpool/config_resources/agents_template.yml +1 -0
- agentpool/config_resources/claude_code_agent.yml +9 -8
- agentpool/config_resources/external_acp_agents.yml +2 -1
- agentpool/delegation/base_team.py +4 -30
- agentpool/delegation/pool.py +104 -265
- agentpool/delegation/team.py +57 -57
- agentpool/delegation/teamrun.py +50 -55
- agentpool/functional/run.py +10 -4
- agentpool/mcp_server/client.py +73 -38
- agentpool/mcp_server/conversions.py +54 -13
- agentpool/mcp_server/manager.py +9 -23
- agentpool/mcp_server/registries/official_registry_client.py +10 -1
- agentpool/mcp_server/tool_bridge.py +114 -79
- agentpool/messaging/connection_manager.py +11 -10
- agentpool/messaging/event_manager.py +5 -5
- agentpool/messaging/message_container.py +6 -30
- agentpool/messaging/message_history.py +87 -8
- agentpool/messaging/messagenode.py +52 -14
- agentpool/messaging/messages.py +2 -26
- agentpool/messaging/processing.py +10 -22
- agentpool/models/__init__.py +1 -1
- agentpool/models/acp_agents/base.py +6 -2
- agentpool/models/acp_agents/mcp_capable.py +124 -15
- agentpool/models/acp_agents/non_mcp.py +0 -23
- agentpool/models/agents.py +66 -66
- agentpool/models/agui_agents.py +1 -1
- agentpool/models/claude_code_agents.py +111 -17
- agentpool/models/file_parsing.py +0 -1
- agentpool/models/manifest.py +70 -50
- agentpool/prompts/conversion_manager.py +1 -1
- agentpool/prompts/prompts.py +5 -2
- agentpool/resource_providers/__init__.py +2 -0
- agentpool/resource_providers/aggregating.py +4 -2
- agentpool/resource_providers/base.py +13 -3
- agentpool/resource_providers/codemode/code_executor.py +72 -5
- agentpool/resource_providers/codemode/helpers.py +2 -2
- agentpool/resource_providers/codemode/provider.py +64 -12
- agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
- agentpool/resource_providers/codemode/remote_provider.py +9 -12
- agentpool/resource_providers/filtering.py +3 -1
- agentpool/resource_providers/mcp_provider.py +66 -12
- agentpool/resource_providers/plan_provider.py +111 -18
- agentpool/resource_providers/pool.py +5 -3
- agentpool/resource_providers/resource_info.py +111 -0
- agentpool/resource_providers/static.py +2 -2
- agentpool/sessions/__init__.py +2 -0
- agentpool/sessions/manager.py +2 -3
- agentpool/sessions/models.py +9 -6
- agentpool/sessions/protocol.py +28 -0
- agentpool/sessions/session.py +11 -55
- agentpool/storage/manager.py +361 -54
- agentpool/talk/registry.py +4 -4
- agentpool/talk/talk.py +9 -10
- agentpool/testing.py +1 -1
- agentpool/tool_impls/__init__.py +6 -0
- agentpool/tool_impls/agent_cli/__init__.py +42 -0
- agentpool/tool_impls/agent_cli/tool.py +95 -0
- agentpool/tool_impls/bash/__init__.py +64 -0
- agentpool/tool_impls/bash/helpers.py +35 -0
- agentpool/tool_impls/bash/tool.py +171 -0
- agentpool/tool_impls/delete_path/__init__.py +70 -0
- agentpool/tool_impls/delete_path/tool.py +142 -0
- agentpool/tool_impls/download_file/__init__.py +80 -0
- agentpool/tool_impls/download_file/tool.py +183 -0
- agentpool/tool_impls/execute_code/__init__.py +55 -0
- agentpool/tool_impls/execute_code/tool.py +163 -0
- agentpool/tool_impls/grep/__init__.py +80 -0
- agentpool/tool_impls/grep/tool.py +200 -0
- agentpool/tool_impls/list_directory/__init__.py +73 -0
- agentpool/tool_impls/list_directory/tool.py +197 -0
- agentpool/tool_impls/question/__init__.py +42 -0
- agentpool/tool_impls/question/tool.py +127 -0
- agentpool/tool_impls/read/__init__.py +104 -0
- agentpool/tool_impls/read/tool.py +305 -0
- agentpool/tools/__init__.py +2 -1
- agentpool/tools/base.py +114 -34
- agentpool/tools/manager.py +57 -1
- agentpool/ui/base.py +2 -2
- agentpool/ui/mock_provider.py +2 -2
- agentpool/ui/stdlib_provider.py +2 -2
- agentpool/utils/streams.py +21 -96
- agentpool/vfs_registry.py +7 -2
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/METADATA +16 -22
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/RECORD +242 -195
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +20 -0
- agentpool_cli/create.py +1 -1
- agentpool_cli/serve_acp.py +59 -1
- agentpool_cli/serve_opencode.py +1 -1
- agentpool_cli/ui.py +557 -0
- agentpool_commands/__init__.py +12 -5
- agentpool_commands/agents.py +1 -1
- agentpool_commands/pool.py +260 -0
- agentpool_commands/session.py +1 -1
- agentpool_commands/text_sharing/__init__.py +119 -0
- agentpool_commands/text_sharing/base.py +123 -0
- agentpool_commands/text_sharing/github_gist.py +80 -0
- agentpool_commands/text_sharing/opencode.py +462 -0
- agentpool_commands/text_sharing/paste_rs.py +59 -0
- agentpool_commands/text_sharing/pastebin.py +116 -0
- agentpool_commands/text_sharing/shittycodingagent.py +112 -0
- agentpool_commands/utils.py +31 -32
- agentpool_config/__init__.py +30 -2
- agentpool_config/agentpool_tools.py +498 -0
- agentpool_config/converters.py +1 -1
- agentpool_config/event_handlers.py +42 -0
- agentpool_config/events.py +1 -1
- agentpool_config/forward_targets.py +1 -4
- agentpool_config/jinja.py +3 -3
- agentpool_config/mcp_server.py +1 -5
- agentpool_config/nodes.py +1 -1
- agentpool_config/observability.py +44 -0
- agentpool_config/session.py +0 -3
- agentpool_config/storage.py +38 -39
- agentpool_config/task.py +3 -3
- agentpool_config/tools.py +11 -28
- agentpool_config/toolsets.py +22 -90
- agentpool_server/a2a_server/agent_worker.py +307 -0
- agentpool_server/a2a_server/server.py +23 -18
- agentpool_server/acp_server/acp_agent.py +125 -56
- agentpool_server/acp_server/commands/acp_commands.py +46 -216
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +8 -7
- agentpool_server/acp_server/event_converter.py +651 -0
- agentpool_server/acp_server/input_provider.py +53 -10
- agentpool_server/acp_server/server.py +1 -11
- agentpool_server/acp_server/session.py +90 -410
- agentpool_server/acp_server/session_manager.py +8 -34
- agentpool_server/agui_server/server.py +3 -1
- agentpool_server/mcp_server/server.py +5 -2
- agentpool_server/opencode_server/ENDPOINTS.md +53 -14
- agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
- agentpool_server/opencode_server/__init__.py +0 -8
- agentpool_server/opencode_server/converters.py +132 -26
- agentpool_server/opencode_server/input_provider.py +160 -8
- agentpool_server/opencode_server/models/__init__.py +42 -20
- agentpool_server/opencode_server/models/app.py +12 -0
- agentpool_server/opencode_server/models/events.py +203 -29
- agentpool_server/opencode_server/models/mcp.py +19 -0
- agentpool_server/opencode_server/models/message.py +18 -1
- agentpool_server/opencode_server/models/parts.py +134 -1
- agentpool_server/opencode_server/models/question.py +56 -0
- agentpool_server/opencode_server/models/session.py +13 -1
- agentpool_server/opencode_server/routes/__init__.py +4 -0
- agentpool_server/opencode_server/routes/agent_routes.py +33 -2
- agentpool_server/opencode_server/routes/app_routes.py +66 -3
- agentpool_server/opencode_server/routes/config_routes.py +66 -5
- agentpool_server/opencode_server/routes/file_routes.py +184 -5
- agentpool_server/opencode_server/routes/global_routes.py +1 -1
- agentpool_server/opencode_server/routes/lsp_routes.py +1 -1
- agentpool_server/opencode_server/routes/message_routes.py +122 -66
- agentpool_server/opencode_server/routes/permission_routes.py +63 -0
- agentpool_server/opencode_server/routes/pty_routes.py +23 -22
- agentpool_server/opencode_server/routes/question_routes.py +128 -0
- agentpool_server/opencode_server/routes/session_routes.py +139 -68
- agentpool_server/opencode_server/routes/tui_routes.py +1 -1
- agentpool_server/opencode_server/server.py +47 -2
- agentpool_server/opencode_server/state.py +30 -0
- agentpool_storage/__init__.py +0 -4
- agentpool_storage/base.py +81 -2
- agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
- agentpool_storage/claude_provider/__init__.py +42 -0
- agentpool_storage/{claude_provider.py → claude_provider/provider.py} +190 -8
- agentpool_storage/file_provider.py +149 -15
- agentpool_storage/memory_provider.py +132 -12
- agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
- agentpool_storage/opencode_provider/__init__.py +16 -0
- agentpool_storage/opencode_provider/helpers.py +414 -0
- agentpool_storage/opencode_provider/provider.py +895 -0
- agentpool_storage/session_store.py +20 -6
- agentpool_storage/sql_provider/sql_provider.py +135 -2
- agentpool_storage/sql_provider/utils.py +2 -12
- agentpool_storage/zed_provider/__init__.py +16 -0
- agentpool_storage/zed_provider/helpers.py +281 -0
- agentpool_storage/zed_provider/models.py +130 -0
- agentpool_storage/zed_provider/provider.py +442 -0
- agentpool_storage/zed_provider.py +803 -0
- agentpool_toolsets/__init__.py +0 -2
- agentpool_toolsets/builtin/__init__.py +2 -4
- agentpool_toolsets/builtin/code.py +4 -4
- agentpool_toolsets/builtin/debug.py +115 -40
- agentpool_toolsets/builtin/execution_environment.py +54 -165
- agentpool_toolsets/builtin/skills.py +0 -77
- agentpool_toolsets/builtin/subagent_tools.py +64 -51
- agentpool_toolsets/builtin/workers.py +4 -2
- agentpool_toolsets/composio_toolset.py +2 -2
- agentpool_toolsets/entry_points.py +3 -1
- agentpool_toolsets/fsspec_toolset/grep.py +25 -5
- agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
- agentpool_toolsets/fsspec_toolset/toolset.py +350 -66
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +74 -17
- agentpool_toolsets/mcp_run_toolset.py +8 -11
- agentpool_toolsets/notifications.py +33 -33
- agentpool_toolsets/openapi.py +3 -1
- agentpool_toolsets/search_toolset.py +3 -1
- agentpool_config/resources.py +0 -33
- agentpool_server/acp_server/acp_tools.py +0 -43
- agentpool_server/acp_server/commands/spawn.py +0 -210
- agentpool_storage/opencode_provider.py +0 -730
- agentpool_storage/text_log_provider.py +0 -276
- agentpool_toolsets/builtin/chain.py +0 -288
- agentpool_toolsets/builtin/user_interaction.py +0 -52
- agentpool_toolsets/semantic_memory_toolset.py +0 -536
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -9,7 +9,7 @@ This is the reverse of the conversion done in acp_server/session.py handle_event
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import base64
|
|
12
|
-
from typing import TYPE_CHECKING, Any, overload
|
|
12
|
+
from typing import TYPE_CHECKING, Any, assert_never, overload
|
|
13
13
|
|
|
14
14
|
from pydantic_ai import (
|
|
15
15
|
AudioUrl,
|
|
@@ -53,12 +53,24 @@ from agentpool.agents.events import (
|
|
|
53
53
|
if TYPE_CHECKING:
|
|
54
54
|
from collections.abc import Sequence
|
|
55
55
|
|
|
56
|
-
from pydantic_ai import UserContent
|
|
57
|
-
|
|
58
|
-
from acp.schema import
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
from pydantic_ai import FinishReason, UserContent
|
|
57
|
+
|
|
58
|
+
from acp.schema import (
|
|
59
|
+
ContentBlock,
|
|
60
|
+
HttpMcpServer,
|
|
61
|
+
McpServer,
|
|
62
|
+
SessionConfigOption,
|
|
63
|
+
SessionModelState,
|
|
64
|
+
SessionModeState,
|
|
65
|
+
SessionUpdate,
|
|
66
|
+
SseMcpServer,
|
|
67
|
+
StdioMcpServer,
|
|
68
|
+
StopReason,
|
|
69
|
+
ToolCallContent,
|
|
70
|
+
ToolCallLocation,
|
|
71
|
+
)
|
|
61
72
|
from agentpool.agents.events import RichAgentStreamEvent, ToolCallContentItem
|
|
73
|
+
from agentpool.agents.modes import ModeCategory, ModeInfo
|
|
62
74
|
from agentpool_config.mcp_server import (
|
|
63
75
|
MCPServerConfig,
|
|
64
76
|
SSEMCPServerConfig,
|
|
@@ -66,15 +78,122 @@ if TYPE_CHECKING:
|
|
|
66
78
|
StreamableHTTPMCPServerConfig,
|
|
67
79
|
)
|
|
68
80
|
|
|
81
|
+
STOP_REASON_MAP: dict[StopReason, FinishReason] = {
|
|
82
|
+
"end_turn": "stop",
|
|
83
|
+
"max_tokens": "length",
|
|
84
|
+
"max_turn_requests": "length",
|
|
85
|
+
"refusal": "content_filter",
|
|
86
|
+
"cancelled": "error",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_modes(
|
|
91
|
+
config_options: list[SessionConfigOption],
|
|
92
|
+
available_modes: SessionModeState | None,
|
|
93
|
+
available_models: SessionModelState | None,
|
|
94
|
+
) -> list[ModeCategory]:
|
|
95
|
+
from acp.schema import SessionConfigSelectGroup
|
|
96
|
+
from agentpool.agents.modes import ModeCategory, ModeInfo
|
|
97
|
+
|
|
98
|
+
categories: list[ModeCategory] = []
|
|
99
|
+
|
|
100
|
+
if config_options:
|
|
101
|
+
for config_opt in config_options:
|
|
102
|
+
# Extract options from the config (ungrouped or grouped)
|
|
103
|
+
mode_infos: list[ModeInfo] = []
|
|
104
|
+
if isinstance(config_opt.options, list):
|
|
105
|
+
for opt_item in config_opt.options:
|
|
106
|
+
if isinstance(opt_item, SessionConfigSelectGroup):
|
|
107
|
+
mode_infos.extend(
|
|
108
|
+
ModeInfo(
|
|
109
|
+
id=sub_opt.value,
|
|
110
|
+
name=sub_opt.name,
|
|
111
|
+
description=sub_opt.description or "",
|
|
112
|
+
category_id=config_opt.id,
|
|
113
|
+
)
|
|
114
|
+
for sub_opt in opt_item.options
|
|
115
|
+
)
|
|
116
|
+
else:
|
|
117
|
+
# Ungrouped options
|
|
118
|
+
mode_infos.append(
|
|
119
|
+
ModeInfo(
|
|
120
|
+
id=opt_item.value,
|
|
121
|
+
name=opt_item.name,
|
|
122
|
+
description=opt_item.description or "",
|
|
123
|
+
category_id=config_opt.id,
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
categories.append(
|
|
128
|
+
ModeCategory(
|
|
129
|
+
id=config_opt.id,
|
|
130
|
+
name=config_opt.name,
|
|
131
|
+
available_modes=mode_infos,
|
|
132
|
+
current_mode_id=config_opt.current_value,
|
|
133
|
+
category=config_opt.category or "other",
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
return categories
|
|
137
|
+
|
|
138
|
+
# Legacy: Convert ACP SessionModeState to ModeCategory
|
|
139
|
+
if available_modes:
|
|
140
|
+
acp_modes = available_modes
|
|
141
|
+
modes = [
|
|
142
|
+
ModeInfo(
|
|
143
|
+
id=m.id,
|
|
144
|
+
name=m.name,
|
|
145
|
+
description=m.description or "",
|
|
146
|
+
category_id="permissions",
|
|
147
|
+
)
|
|
148
|
+
for m in acp_modes.available_modes
|
|
149
|
+
]
|
|
150
|
+
categories.append(
|
|
151
|
+
ModeCategory(
|
|
152
|
+
id="permissions",
|
|
153
|
+
name="Mode",
|
|
154
|
+
available_modes=modes,
|
|
155
|
+
current_mode_id=acp_modes.current_mode_id,
|
|
156
|
+
category="mode",
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Legacy: Convert ACP SessionModelState to ModeCategory
|
|
161
|
+
if available_models:
|
|
162
|
+
acp_models = available_models
|
|
163
|
+
models = [
|
|
164
|
+
ModeInfo(
|
|
165
|
+
id=m.model_id,
|
|
166
|
+
name=m.name,
|
|
167
|
+
description=m.description or "",
|
|
168
|
+
category_id="model",
|
|
169
|
+
)
|
|
170
|
+
for m in acp_models.available_models
|
|
171
|
+
]
|
|
172
|
+
categories.append(
|
|
173
|
+
ModeCategory(
|
|
174
|
+
id="model",
|
|
175
|
+
name="Model",
|
|
176
|
+
available_modes=models,
|
|
177
|
+
current_mode_id=acp_models.current_model_id,
|
|
178
|
+
category="model",
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return categories
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def to_finish_reason(stop_reason: StopReason) -> FinishReason:
|
|
186
|
+
return STOP_REASON_MAP.get(stop_reason, "stop")
|
|
187
|
+
|
|
69
188
|
|
|
70
189
|
def convert_acp_locations(
|
|
71
|
-
locations:
|
|
190
|
+
locations: Sequence[ToolCallLocation] | None,
|
|
72
191
|
) -> list[LocationContentItem]:
|
|
73
192
|
"""Convert ACP ToolCallLocation list to native LocationContentItem list."""
|
|
74
193
|
return [LocationContentItem(path=loc.path, line=loc.line) for loc in locations or []]
|
|
75
194
|
|
|
76
195
|
|
|
77
|
-
def convert_acp_content(content:
|
|
196
|
+
def convert_acp_content(content: Sequence[ToolCallContent] | None) -> list[ToolCallContentItem]:
|
|
78
197
|
"""Convert ACP ToolCallContent list to native ToolCallContentItem list."""
|
|
79
198
|
if not content:
|
|
80
199
|
return []
|
|
@@ -217,7 +336,7 @@ def acp_to_native_event(update: SessionUpdate) -> RichAgentStreamEvent[Any] | No
|
|
|
217
336
|
raw_input=raw_input or {},
|
|
218
337
|
)
|
|
219
338
|
|
|
220
|
-
# Tool call progress -> ToolCallProgressEvent
|
|
339
|
+
# Tool call progress -> ToolCallProgressEvent or ToolCallCompleteEvent
|
|
221
340
|
case ToolCallProgress(
|
|
222
341
|
tool_call_id=tool_call_id,
|
|
223
342
|
status=status,
|
|
@@ -225,6 +344,20 @@ def acp_to_native_event(update: SessionUpdate) -> RichAgentStreamEvent[Any] | No
|
|
|
225
344
|
content=content,
|
|
226
345
|
raw_output=raw_output,
|
|
227
346
|
):
|
|
347
|
+
# If completed, return ToolCallCompleteEvent for metadata injection
|
|
348
|
+
if status == "completed":
|
|
349
|
+
from agentpool.agents.events import ToolCallCompleteEvent
|
|
350
|
+
|
|
351
|
+
return ToolCallCompleteEvent(
|
|
352
|
+
tool_call_id=tool_call_id,
|
|
353
|
+
tool_name=title or "unknown",
|
|
354
|
+
tool_input={}, # ACP doesn't provide input in progress updates
|
|
355
|
+
tool_result=str(raw_output) if raw_output else "",
|
|
356
|
+
agent_name="", # Will be set by agent
|
|
357
|
+
message_id="",
|
|
358
|
+
metadata=None, # Will be injected by agent from metadata accumulator
|
|
359
|
+
)
|
|
360
|
+
# Otherwise return progress event
|
|
228
361
|
return ToolCallProgressEvent(
|
|
229
362
|
tool_call_id=tool_call_id,
|
|
230
363
|
status=status or "in_progress",
|
|
@@ -247,22 +380,22 @@ def acp_to_native_event(update: SessionUpdate) -> RichAgentStreamEvent[Any] | No
|
|
|
247
380
|
|
|
248
381
|
|
|
249
382
|
@overload
|
|
250
|
-
def mcp_config_to_acp(config: StdioMCPServerConfig) -> StdioMcpServer
|
|
383
|
+
def mcp_config_to_acp(config: StdioMCPServerConfig) -> StdioMcpServer: ...
|
|
251
384
|
|
|
252
385
|
|
|
253
386
|
@overload
|
|
254
|
-
def mcp_config_to_acp(config: SSEMCPServerConfig) -> SseMcpServer
|
|
387
|
+
def mcp_config_to_acp(config: SSEMCPServerConfig) -> SseMcpServer: ...
|
|
255
388
|
|
|
256
389
|
|
|
257
390
|
@overload
|
|
258
|
-
def mcp_config_to_acp(config: StreamableHTTPMCPServerConfig) -> HttpMcpServer
|
|
391
|
+
def mcp_config_to_acp(config: StreamableHTTPMCPServerConfig) -> HttpMcpServer: ...
|
|
259
392
|
|
|
260
393
|
|
|
261
394
|
@overload
|
|
262
|
-
def mcp_config_to_acp(config: MCPServerConfig) -> McpServer
|
|
395
|
+
def mcp_config_to_acp(config: MCPServerConfig) -> McpServer: ...
|
|
263
396
|
|
|
264
397
|
|
|
265
|
-
def mcp_config_to_acp(config: MCPServerConfig) -> McpServer
|
|
398
|
+
def mcp_config_to_acp(config: MCPServerConfig) -> McpServer:
|
|
266
399
|
"""Convert native MCPServerConfig to ACP McpServer format.
|
|
267
400
|
|
|
268
401
|
If the config has tool filtering (enabled_tools or disabled_tools),
|
|
@@ -303,8 +436,8 @@ def mcp_config_to_acp(config: MCPServerConfig) -> McpServer | None:
|
|
|
303
436
|
case StreamableHTTPMCPServerConfig(url=url):
|
|
304
437
|
return HttpMcpServer(name=config.name or str(url), url=url, headers=[])
|
|
305
438
|
|
|
306
|
-
case _:
|
|
307
|
-
|
|
439
|
+
case _ as unreachable:
|
|
440
|
+
assert_never(unreachable)
|
|
308
441
|
|
|
309
442
|
|
|
310
443
|
def mcp_configs_to_acp(configs: Sequence[MCPServerConfig]) -> list[McpServer]:
|
|
@@ -316,4 +449,4 @@ def mcp_configs_to_acp(configs: Sequence[MCPServerConfig]) -> list[McpServer]:
|
|
|
316
449
|
Returns:
|
|
317
450
|
List of ACP-compatible McpServer instances (skips unconvertible configs)
|
|
318
451
|
"""
|
|
319
|
-
return [
|
|
452
|
+
return [mcp_config_to_acp(config) for config in configs]
|
|
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import TYPE_CHECKING, Any
|
|
8
|
-
import uuid
|
|
9
8
|
|
|
10
9
|
import anyio
|
|
11
10
|
|
|
@@ -21,7 +20,6 @@ from acp.schema import (
|
|
|
21
20
|
WriteTextFileResponse,
|
|
22
21
|
)
|
|
23
22
|
from agentpool.log import get_logger
|
|
24
|
-
from agentpool.tools.base import Tool
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
if TYPE_CHECKING:
|
|
@@ -79,7 +77,7 @@ class ACPClientHandler(Client):
|
|
|
79
77
|
self.state = state
|
|
80
78
|
self._input_provider = input_provider
|
|
81
79
|
self._update_event = asyncio.Event()
|
|
82
|
-
# Map ACP terminal IDs to process manager IDs
|
|
80
|
+
# Map ACP terminal IDs to process manager IDs (for local execution only)
|
|
83
81
|
self._terminal_to_process: dict[str, str] = {}
|
|
84
82
|
# Copy tool confirmation mode from agent (can be updated via set_tool_confirmation_mode)
|
|
85
83
|
self.tool_confirmation_mode: ToolConfirmationMode = agent.tool_confirmation_mode
|
|
@@ -224,13 +222,21 @@ class ACPClientHandler(Client):
|
|
|
224
222
|
|
|
225
223
|
if self._input_provider:
|
|
226
224
|
ctx = self._agent.get_context() # Use the agent's NodeContext
|
|
227
|
-
# Attach
|
|
225
|
+
# Attach tool call metadata for permission event matching
|
|
228
226
|
ctx.tool_call_id = params.tool_call.tool_call_id
|
|
227
|
+
ctx.tool_name = params.tool_call.title
|
|
228
|
+
args = (
|
|
229
|
+
params.tool_call.raw_input if isinstance(params.tool_call.raw_input, dict) else {}
|
|
230
|
+
)
|
|
231
|
+
ctx.tool_input = args
|
|
229
232
|
# Create a dummy tool representation from ACP params
|
|
230
|
-
|
|
231
|
-
|
|
233
|
+
from agentpool.tools import FunctionTool
|
|
234
|
+
|
|
235
|
+
tool = FunctionTool(
|
|
236
|
+
callable=lambda: None, name=params.tool_call.tool_call_id, description=name
|
|
237
|
+
)
|
|
232
238
|
try:
|
|
233
|
-
result = await self._input_provider.get_tool_confirmation(ctx, tool=tool, args=
|
|
239
|
+
result = await self._input_provider.get_tool_confirmation(ctx, tool=tool, args=args)
|
|
234
240
|
# Map confirmation result to ACP response
|
|
235
241
|
if result == "allow":
|
|
236
242
|
option_id = params.options[0].option_id if params.options else "allow"
|
|
@@ -265,9 +271,10 @@ class ACPClientHandler(Client):
|
|
|
265
271
|
logger.debug("Read file", path=params.path, num_chars=len(content))
|
|
266
272
|
return ReadTextFileResponse(content=content)
|
|
267
273
|
|
|
268
|
-
except FileNotFoundError:
|
|
269
|
-
|
|
270
|
-
|
|
274
|
+
except (FileNotFoundError, KeyError):
|
|
275
|
+
# Match Zed behavior: return empty string for non-existent files
|
|
276
|
+
logger.debug("File not found, returning empty string", path=params.path)
|
|
277
|
+
return ReadTextFileResponse(content="")
|
|
271
278
|
except Exception:
|
|
272
279
|
logger.exception("Failed to read file", path=params.path)
|
|
273
280
|
raise
|
|
@@ -290,11 +297,18 @@ class ACPClientHandler(Client):
|
|
|
290
297
|
raise
|
|
291
298
|
|
|
292
299
|
async def create_terminal(self, params: CreateTerminalRequest) -> CreateTerminalResponse:
|
|
293
|
-
"""Create a new terminal session via
|
|
300
|
+
"""Create a new terminal session via the configured ExecutionEnvironment.
|
|
301
|
+
|
|
302
|
+
The ProcessManager implementation determines where the terminal runs
|
|
303
|
+
(local, Docker, E2B, SSH, or forwarded to parent ACP client like Zed).
|
|
304
|
+
|
|
305
|
+
The terminal_id returned by process_manager.start_process() is used directly.
|
|
306
|
+
"""
|
|
294
307
|
if not self.allow_terminal:
|
|
295
308
|
raise RuntimeError("Terminal operations not allowed")
|
|
309
|
+
|
|
296
310
|
try:
|
|
297
|
-
|
|
311
|
+
terminal_id = await self.env.process_manager.start_process(
|
|
298
312
|
command=params.command,
|
|
299
313
|
args=list(params.args) if params.args else None,
|
|
300
314
|
cwd=params.cwd,
|
|
@@ -304,10 +318,10 @@ class ACPClientHandler(Client):
|
|
|
304
318
|
logger.exception("Failed to create terminal", command=params.command)
|
|
305
319
|
raise
|
|
306
320
|
else:
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
logger.info(
|
|
321
|
+
# Use the ID from process_manager directly - for ACPProcessManager this
|
|
322
|
+
# is already the parent's terminal ID (e.g., Zed's)
|
|
323
|
+
self._terminal_to_process[terminal_id] = terminal_id
|
|
324
|
+
logger.info("Created terminal", terminal_id=terminal_id, command=params.command)
|
|
311
325
|
return CreateTerminalResponse(terminal_id=terminal_id)
|
|
312
326
|
|
|
313
327
|
async def terminal_output(self, params: TerminalOutputRequest) -> TerminalOutputResponse:
|
|
@@ -319,8 +333,7 @@ class ACPClientHandler(Client):
|
|
|
319
333
|
if terminal_id not in self._terminal_to_process:
|
|
320
334
|
raise ValueError(f"Terminal {terminal_id} not found")
|
|
321
335
|
|
|
322
|
-
|
|
323
|
-
proc_output = await self.env.process_manager.get_output(process_id)
|
|
336
|
+
proc_output = await self.env.process_manager.get_output(terminal_id)
|
|
324
337
|
output = proc_output.combined or proc_output.stdout or ""
|
|
325
338
|
return TerminalOutputResponse(output=output, truncated=proc_output.truncated)
|
|
326
339
|
|
|
@@ -335,8 +348,7 @@ class ACPClientHandler(Client):
|
|
|
335
348
|
if terminal_id not in self._terminal_to_process:
|
|
336
349
|
raise ValueError(f"Terminal {terminal_id} not found")
|
|
337
350
|
|
|
338
|
-
|
|
339
|
-
exit_code = await self.env.process_manager.wait_for_exit(process_id)
|
|
351
|
+
exit_code = await self.env.process_manager.wait_for_exit(terminal_id)
|
|
340
352
|
logger.debug("Terminal exited", terminal_id=terminal_id, exit_code=exit_code)
|
|
341
353
|
return WaitForTerminalExitResponse(exit_code=exit_code)
|
|
342
354
|
|
|
@@ -351,8 +363,7 @@ class ACPClientHandler(Client):
|
|
|
351
363
|
if terminal_id not in self._terminal_to_process:
|
|
352
364
|
raise ValueError(f"Terminal {terminal_id} not found")
|
|
353
365
|
|
|
354
|
-
|
|
355
|
-
await self.env.process_manager.kill_process(process_id)
|
|
366
|
+
await self.env.process_manager.kill_process(terminal_id)
|
|
356
367
|
logger.info("Killed terminal", terminal_id=terminal_id)
|
|
357
368
|
return KillTerminalCommandResponse()
|
|
358
369
|
|
|
@@ -364,8 +375,8 @@ class ACPClientHandler(Client):
|
|
|
364
375
|
terminal_id = params.terminal_id
|
|
365
376
|
if terminal_id not in self._terminal_to_process:
|
|
366
377
|
raise ValueError(f"Terminal {terminal_id} not found")
|
|
367
|
-
|
|
368
|
-
await self.env.process_manager.release_process(
|
|
378
|
+
|
|
379
|
+
await self.env.process_manager.release_process(terminal_id)
|
|
369
380
|
del self._terminal_to_process[terminal_id]
|
|
370
381
|
logger.info("Released terminal", terminal_id=terminal_id)
|
|
371
382
|
return ReleaseTerminalResponse()
|
|
@@ -9,7 +9,12 @@ from agentpool.log import get_logger
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
-
from acp.schema import
|
|
12
|
+
from acp.schema import (
|
|
13
|
+
AvailableCommandsUpdate,
|
|
14
|
+
SessionConfigOption,
|
|
15
|
+
SessionModelState,
|
|
16
|
+
SessionModeState,
|
|
17
|
+
)
|
|
13
18
|
from agentpool.agents.events import RichAgentStreamEvent
|
|
14
19
|
|
|
15
20
|
logger = get_logger(__name__)
|
|
@@ -28,20 +33,23 @@ class ACPSessionState:
|
|
|
28
33
|
"""Queue of native events converted from ACP updates."""
|
|
29
34
|
|
|
30
35
|
current_model_id: str | None = None
|
|
31
|
-
"""Current model ID from session state."""
|
|
36
|
+
"""Current model ID from session state (legacy)."""
|
|
32
37
|
|
|
33
38
|
models: SessionModelState | None = None
|
|
34
|
-
"""Full model state including available models
|
|
39
|
+
"""Full model state including available models (legacy)."""
|
|
35
40
|
|
|
36
41
|
modes: SessionModeState | None = None
|
|
37
|
-
"""Full mode state including available modes
|
|
42
|
+
"""Full mode state including available modes (legacy)."""
|
|
38
43
|
|
|
39
44
|
current_mode_id: str | None = None
|
|
40
|
-
"""Current mode ID."""
|
|
45
|
+
"""Current mode ID (legacy)."""
|
|
46
|
+
|
|
47
|
+
config_options: list[SessionConfigOption] = dataclass_field(default_factory=list)
|
|
48
|
+
"""Unified session config options (replaces modes/models in newer ACP versions)."""
|
|
41
49
|
|
|
42
50
|
available_commands: AvailableCommandsUpdate | None = None
|
|
43
51
|
"""Available commands from the agent."""
|
|
44
52
|
|
|
45
53
|
def clear(self) -> None:
|
|
46
54
|
self.events.clear()
|
|
47
|
-
# Note: Don't clear current_model_id
|
|
55
|
+
# Note: Don't clear current_model_id, models, config_options - those persist
|