agentpool 2.1.9__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 +13 -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/bridge/README.md +15 -2
- acp/bridge/__init__.py +3 -2
- acp/bridge/__main__.py +60 -19
- acp/bridge/ws_server.py +173 -0
- acp/bridge/ws_server_cli.py +89 -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 +20 -50
- 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/stdio.py +39 -9
- acp/task/supervisor.py +2 -2
- acp/transports.py +362 -2
- acp/utils.py +17 -4
- agentpool/__init__.py +6 -1
- agentpool/agents/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +407 -277
- agentpool/agents/acp_agent/acp_converters.py +196 -38
- agentpool/agents/acp_agent/client_handler.py +191 -26
- agentpool/agents/acp_agent/session_state.py +17 -6
- agentpool/agents/agent.py +607 -572
- agentpool/agents/agui_agent/__init__.py +0 -2
- agentpool/agents/agui_agent/agui_agent.py +176 -110
- agentpool/agents/agui_agent/agui_converters.py +0 -131
- agentpool/agents/agui_agent/helpers.py +3 -4
- agentpool/agents/base_agent.py +632 -17
- 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 +1058 -291
- agentpool/agents/claude_code_agent/converters.py +74 -143
- agentpool/agents/claude_code_agent/history.py +474 -0
- 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/context.py +40 -0
- agentpool/agents/events/__init__.py +24 -0
- agentpool/agents/events/builtin_handlers.py +67 -1
- agentpool/agents/events/event_emitter.py +32 -2
- agentpool/agents/events/events.py +104 -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 +67 -0
- agentpool/agents/slashed_agent.py +5 -4
- agentpool/agents/tool_call_accumulator.py +213 -0
- agentpool/agents/tool_wrapping.py +18 -6
- agentpool/common_types.py +56 -21
- agentpool/config_resources/__init__.py +38 -1
- 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 +10 -6
- agentpool/config_resources/external_acp_agents.yml +2 -1
- agentpool/delegation/base_team.py +4 -30
- agentpool/delegation/pool.py +136 -289
- agentpool/delegation/team.py +58 -57
- agentpool/delegation/teamrun.py +51 -55
- agentpool/diagnostics/__init__.py +53 -0
- agentpool/diagnostics/lsp_manager.py +1593 -0
- agentpool/diagnostics/lsp_proxy.py +41 -0
- agentpool/diagnostics/lsp_proxy_script.py +229 -0
- agentpool/diagnostics/models.py +398 -0
- agentpool/functional/run.py +10 -4
- agentpool/mcp_server/__init__.py +0 -2
- agentpool/mcp_server/client.py +76 -32
- agentpool/mcp_server/conversions.py +54 -13
- agentpool/mcp_server/manager.py +34 -54
- agentpool/mcp_server/registries/official_registry_client.py +35 -1
- agentpool/mcp_server/tool_bridge.py +186 -139
- agentpool/messaging/__init__.py +0 -2
- agentpool/messaging/compaction.py +72 -197
- 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 +99 -8
- agentpool/messaging/messagenode.py +52 -14
- agentpool/messaging/messages.py +54 -35
- agentpool/messaging/processing.py +12 -22
- agentpool/models/__init__.py +1 -1
- agentpool/models/acp_agents/base.py +6 -24
- agentpool/models/acp_agents/mcp_capable.py +126 -157
- agentpool/models/acp_agents/non_mcp.py +129 -95
- agentpool/models/agents.py +98 -76
- agentpool/models/agui_agents.py +1 -1
- agentpool/models/claude_code_agents.py +144 -19
- agentpool/models/file_parsing.py +0 -1
- agentpool/models/manifest.py +113 -50
- agentpool/prompts/conversion_manager.py +1 -1
- agentpool/prompts/prompts.py +5 -2
- agentpool/repomap.py +1 -1
- agentpool/resource_providers/__init__.py +11 -1
- agentpool/resource_providers/aggregating.py +56 -5
- agentpool/resource_providers/base.py +70 -4
- 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 +89 -12
- agentpool/resource_providers/plan_provider.py +228 -46
- agentpool/resource_providers/pool.py +7 -3
- agentpool/resource_providers/resource_info.py +111 -0
- agentpool/resource_providers/static.py +4 -2
- agentpool/sessions/__init__.py +4 -1
- agentpool/sessions/manager.py +33 -5
- agentpool/sessions/models.py +59 -6
- agentpool/sessions/protocol.py +28 -0
- agentpool/sessions/session.py +11 -55
- agentpool/skills/registry.py +13 -8
- agentpool/storage/manager.py +572 -49
- agentpool/talk/registry.py +4 -4
- agentpool/talk/talk.py +9 -10
- agentpool/testing.py +538 -20
- 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/file_watcher.py +269 -0
- agentpool/utils/identifiers.py +121 -0
- agentpool/utils/pydantic_ai_helpers.py +46 -0
- agentpool/utils/streams.py +616 -2
- agentpool/utils/subprocess_utils.py +155 -0
- agentpool/utils/token_breakdown.py +461 -0
- agentpool/vfs_registry.py +7 -2
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/METADATA +41 -27
- agentpool-2.5.0.dist-info/RECORD +579 -0
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +24 -0
- agentpool_cli/create.py +1 -1
- agentpool_cli/serve_acp.py +100 -21
- agentpool_cli/serve_agui.py +87 -0
- agentpool_cli/serve_opencode.py +119 -0
- agentpool_cli/ui.py +557 -0
- agentpool_commands/__init__.py +42 -5
- agentpool_commands/agents.py +75 -2
- agentpool_commands/history.py +62 -0
- agentpool_commands/mcp.py +176 -0
- agentpool_commands/models.py +56 -3
- 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/tools.py +57 -0
- agentpool_commands/utils.py +80 -30
- agentpool_config/__init__.py +30 -2
- agentpool_config/agentpool_tools.py +498 -0
- agentpool_config/builtin_tools.py +77 -22
- agentpool_config/commands.py +24 -1
- agentpool_config/compaction.py +258 -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 +132 -6
- agentpool_config/nodes.py +1 -1
- agentpool_config/observability.py +44 -0
- agentpool_config/session.py +0 -3
- agentpool_config/storage.py +82 -38
- agentpool_config/task.py +3 -3
- agentpool_config/tools.py +11 -22
- agentpool_config/toolsets.py +109 -233
- agentpool_server/a2a_server/agent_worker.py +307 -0
- agentpool_server/a2a_server/server.py +23 -18
- agentpool_server/acp_server/acp_agent.py +234 -181
- agentpool_server/acp_server/commands/acp_commands.py +151 -156
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +18 -17
- agentpool_server/acp_server/event_converter.py +651 -0
- agentpool_server/acp_server/input_provider.py +53 -10
- agentpool_server/acp_server/server.py +24 -90
- agentpool_server/acp_server/session.py +173 -331
- 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/.rules +95 -0
- agentpool_server/opencode_server/ENDPOINTS.md +401 -0
- agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
- agentpool_server/opencode_server/__init__.py +19 -0
- agentpool_server/opencode_server/command_validation.py +172 -0
- agentpool_server/opencode_server/converters.py +975 -0
- agentpool_server/opencode_server/dependencies.py +24 -0
- agentpool_server/opencode_server/input_provider.py +421 -0
- agentpool_server/opencode_server/models/__init__.py +250 -0
- agentpool_server/opencode_server/models/agent.py +53 -0
- agentpool_server/opencode_server/models/app.py +72 -0
- agentpool_server/opencode_server/models/base.py +26 -0
- agentpool_server/opencode_server/models/common.py +23 -0
- agentpool_server/opencode_server/models/config.py +37 -0
- agentpool_server/opencode_server/models/events.py +821 -0
- agentpool_server/opencode_server/models/file.py +88 -0
- agentpool_server/opencode_server/models/mcp.py +44 -0
- agentpool_server/opencode_server/models/message.py +179 -0
- agentpool_server/opencode_server/models/parts.py +323 -0
- agentpool_server/opencode_server/models/provider.py +81 -0
- agentpool_server/opencode_server/models/pty.py +43 -0
- agentpool_server/opencode_server/models/question.py +56 -0
- agentpool_server/opencode_server/models/session.py +111 -0
- agentpool_server/opencode_server/routes/__init__.py +29 -0
- agentpool_server/opencode_server/routes/agent_routes.py +473 -0
- agentpool_server/opencode_server/routes/app_routes.py +202 -0
- agentpool_server/opencode_server/routes/config_routes.py +302 -0
- agentpool_server/opencode_server/routes/file_routes.py +571 -0
- agentpool_server/opencode_server/routes/global_routes.py +94 -0
- agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
- agentpool_server/opencode_server/routes/message_routes.py +761 -0
- agentpool_server/opencode_server/routes/permission_routes.py +63 -0
- agentpool_server/opencode_server/routes/pty_routes.py +300 -0
- agentpool_server/opencode_server/routes/question_routes.py +128 -0
- agentpool_server/opencode_server/routes/session_routes.py +1276 -0
- agentpool_server/opencode_server/routes/tui_routes.py +139 -0
- agentpool_server/opencode_server/server.py +475 -0
- agentpool_server/opencode_server/state.py +151 -0
- agentpool_server/opencode_server/time_utils.py +8 -0
- agentpool_storage/__init__.py +12 -0
- agentpool_storage/base.py +184 -2
- agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
- agentpool_storage/claude_provider/__init__.py +42 -0
- agentpool_storage/claude_provider/provider.py +1089 -0
- agentpool_storage/file_provider.py +278 -15
- agentpool_storage/memory_provider.py +193 -12
- agentpool_storage/models.py +3 -0
- 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/project_store.py +325 -0
- agentpool_storage/session_store.py +26 -6
- agentpool_storage/sql_provider/__init__.py +4 -2
- agentpool_storage/sql_provider/models.py +48 -0
- agentpool_storage/sql_provider/sql_provider.py +269 -3
- agentpool_storage/sql_provider/utils.py +12 -13
- 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 -12
- agentpool_toolsets/builtin/code.py +96 -57
- agentpool_toolsets/builtin/debug.py +118 -48
- agentpool_toolsets/builtin/execution_environment.py +115 -230
- agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
- agentpool_toolsets/builtin/skills.py +9 -4
- 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/__init__.py +13 -1
- agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
- agentpool_toolsets/fsspec_toolset/grep.py +99 -7
- agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
- agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
- agentpool_toolsets/fsspec_toolset/toolset.py +500 -95
- agentpool_toolsets/mcp_discovery/__init__.py +5 -0
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +511 -0
- agentpool_toolsets/mcp_run_toolset.py +87 -12
- agentpool_toolsets/notifications.py +33 -33
- agentpool_toolsets/openapi.py +3 -1
- agentpool_toolsets/search_toolset.py +3 -1
- agentpool-2.1.9.dist-info/RECORD +0 -474
- 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/text_log_provider.py +0 -275
- agentpool_toolsets/builtin/agent_management.py +0 -239
- agentpool_toolsets/builtin/chain.py +0 -288
- agentpool_toolsets/builtin/history.py +0 -36
- agentpool_toolsets/builtin/integration.py +0 -85
- agentpool_toolsets/builtin/tool_management.py +0 -90
- agentpool_toolsets/builtin/user_interaction.py +0 -52
- agentpool_toolsets/semantic_memory_toolset.py +0 -536
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -87,20 +87,15 @@ class ACPSessionManager:
|
|
|
87
87
|
logger.warning("Session ID already exists", session_id=session_id)
|
|
88
88
|
msg = f"Session {session_id} already exists"
|
|
89
89
|
raise ValueError(msg)
|
|
90
|
-
|
|
91
90
|
# Create and persist session data via pool's SessionManager
|
|
92
91
|
data = SessionData(
|
|
93
92
|
session_id=session_id,
|
|
94
93
|
agent_name=default_agent_name,
|
|
95
|
-
conversation_id=
|
|
94
|
+
conversation_id=session_id,
|
|
96
95
|
cwd=cwd,
|
|
97
|
-
metadata={
|
|
98
|
-
"protocol": "acp",
|
|
99
|
-
"mcp_server_count": len(mcp_servers) if mcp_servers else 0,
|
|
100
|
-
},
|
|
96
|
+
metadata={"protocol": "acp", "mcp_server_count": len(mcp_servers or [])},
|
|
101
97
|
)
|
|
102
98
|
await self.session_manager.save(data)
|
|
103
|
-
|
|
104
99
|
# Create the ACP-specific runtime session
|
|
105
100
|
session = ACPSession(
|
|
106
101
|
session_id=session_id,
|
|
@@ -115,26 +110,16 @@ class ACPSessionManager:
|
|
|
115
110
|
manager=self,
|
|
116
111
|
)
|
|
117
112
|
session.register_update_callback(self._on_commands_updated)
|
|
118
|
-
|
|
119
113
|
# Initialize async resources
|
|
120
114
|
await session.initialize()
|
|
121
|
-
|
|
122
115
|
# Initialize MCP servers if any are provided
|
|
123
116
|
await session.initialize_mcp_servers()
|
|
124
|
-
|
|
125
117
|
self._active[session_id] = session
|
|
126
118
|
logger.info("Created ACP session", session_id=session_id, agent=default_agent_name)
|
|
127
119
|
return session_id
|
|
128
120
|
|
|
129
121
|
def get_session(self, session_id: str) -> ACPSession | None:
|
|
130
|
-
"""Get an active session by ID.
|
|
131
|
-
|
|
132
|
-
Args:
|
|
133
|
-
session_id: Session identifier
|
|
134
|
-
|
|
135
|
-
Returns:
|
|
136
|
-
ACPSession instance or None if not found
|
|
137
|
-
"""
|
|
122
|
+
"""Get an active session by ID."""
|
|
138
123
|
return self._active.get(session_id)
|
|
139
124
|
|
|
140
125
|
async def resume_session(
|
|
@@ -161,7 +146,6 @@ class ACPSessionManager:
|
|
|
161
146
|
# Check if already active
|
|
162
147
|
if session_id in self._active:
|
|
163
148
|
return self._active[session_id]
|
|
164
|
-
|
|
165
149
|
# Try to load from pool's session store
|
|
166
150
|
data = await self.session_manager.store.load(session_id)
|
|
167
151
|
if data is None:
|
|
@@ -170,11 +154,8 @@ class ACPSessionManager:
|
|
|
170
154
|
|
|
171
155
|
# Validate agent still exists
|
|
172
156
|
if data.agent_name not in self._pool.all_agents:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
session_id=session_id,
|
|
176
|
-
agent=data.agent_name,
|
|
177
|
-
)
|
|
157
|
+
msg = "Session agent no longer exists"
|
|
158
|
+
logger.warning(msg, session_id=session_id, agent=data.agent_name)
|
|
178
159
|
return None
|
|
179
160
|
|
|
180
161
|
# Reconstruct ACP session
|
|
@@ -191,10 +172,8 @@ class ACPSessionManager:
|
|
|
191
172
|
manager=self,
|
|
192
173
|
)
|
|
193
174
|
session.register_update_callback(self._on_commands_updated)
|
|
194
|
-
|
|
195
175
|
# Initialize async resources
|
|
196
176
|
await session.initialize()
|
|
197
|
-
|
|
198
177
|
self._active[session_id] = session
|
|
199
178
|
logger.info("Resumed ACP session", session_id=session_id)
|
|
200
179
|
return session
|
|
@@ -224,10 +203,8 @@ class ACPSessionManager:
|
|
|
224
203
|
session_id: Session identifier
|
|
225
204
|
agent_name: New agent name
|
|
226
205
|
"""
|
|
227
|
-
|
|
228
|
-
if not session:
|
|
206
|
+
if not self._active.get(session_id):
|
|
229
207
|
return
|
|
230
|
-
|
|
231
208
|
# Load, update, and save session data
|
|
232
209
|
data = await self.session_manager.store.load(session_id)
|
|
233
210
|
if data:
|
|
@@ -267,11 +244,8 @@ class ACPSessionManager:
|
|
|
267
244
|
await session.close()
|
|
268
245
|
closed_count += 1
|
|
269
246
|
except Exception:
|
|
270
|
-
logger.exception(
|
|
271
|
-
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
logger.info("Closed all sessions for pool swap", count=closed_count)
|
|
247
|
+
logger.exception("Error closing session", session=session.session_id)
|
|
248
|
+
logger.info("Closed all sessions.", count=closed_count)
|
|
275
249
|
return closed_count
|
|
276
250
|
|
|
277
251
|
async def __aenter__(self) -> Self:
|
|
@@ -88,7 +88,9 @@ class AGUIServer(HTTPServer):
|
|
|
88
88
|
if pool_agent is None:
|
|
89
89
|
msg = f"Agent {agent_name!r} not found"
|
|
90
90
|
return JSONResponse({"error": msg}, status_code=404)
|
|
91
|
-
agentlet = await pool_agent.get_agentlet(
|
|
91
|
+
agentlet = await pool_agent.get_agentlet(
|
|
92
|
+
model=pool_agent.model_name, output_type=str, input_provider=None
|
|
93
|
+
)
|
|
92
94
|
try:
|
|
93
95
|
# Use AGUIAdapter.dispatch_request() which handles the full
|
|
94
96
|
# AG-UI protocol: parsing request, running agent, streaming response
|
|
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
from collections import defaultdict
|
|
6
6
|
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
|
-
from fastmcp import FastMCP
|
|
9
8
|
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
|
|
10
9
|
from key_value.aio.stores.disk import DiskStore
|
|
11
10
|
import mcp
|
|
@@ -22,6 +21,7 @@ if TYPE_CHECKING:
|
|
|
22
21
|
from collections.abc import Awaitable, Callable
|
|
23
22
|
from contextlib import AbstractAsyncContextManager
|
|
24
23
|
|
|
24
|
+
from fastmcp import FastMCP
|
|
25
25
|
from mcp.server.lowlevel.server import LifespanResultT
|
|
26
26
|
from pydantic import AnyUrl
|
|
27
27
|
|
|
@@ -71,6 +71,8 @@ class MCPServer(BaseServer):
|
|
|
71
71
|
instructions: Instructions for server usage
|
|
72
72
|
raise_exceptions: Whether to raise exceptions during server start
|
|
73
73
|
"""
|
|
74
|
+
from fastmcp import FastMCP
|
|
75
|
+
|
|
74
76
|
from agentpool.resource_providers.pool import PoolResourceProvider
|
|
75
77
|
|
|
76
78
|
super().__init__(pool, name=name, raise_exceptions=raise_exceptions)
|
|
@@ -129,7 +131,8 @@ class MCPServer(BaseServer):
|
|
|
129
131
|
idempotentHint=tool.hints.idempotent,
|
|
130
132
|
openWorldHint=tool.hints.open_world,
|
|
131
133
|
)
|
|
132
|
-
|
|
134
|
+
# TODO: set task=True?
|
|
135
|
+
self.fastmcp.tool(annotations=tool_annotations)(tool_handler)
|
|
133
136
|
|
|
134
137
|
self._tools_registered = True
|
|
135
138
|
logger.info("Registered MCP tools", count=len(tools))
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# OpenCode-Compatible Server
|
|
2
|
+
|
|
3
|
+
This module implements an OpenCode-compatible API server, allowing OpenCode SDK clients
|
|
4
|
+
to interact with AgentPool agents.
|
|
5
|
+
|
|
6
|
+
## Reference Documentation
|
|
7
|
+
|
|
8
|
+
- **Python SDK**: https://github.com/sst/opencode-sdk-python
|
|
9
|
+
- **Server Docs**: https://raw.githubusercontent.com/sst/opencode/refs/heads/dev/packages/web/src/content/docs/server.mdx
|
|
10
|
+
- **OpenCode Main Repo**: https://github.com/sst/opencode
|
|
11
|
+
|
|
12
|
+
## SDK Clone (for reference during development)
|
|
13
|
+
|
|
14
|
+
To get the SDK locally for reference:
|
|
15
|
+
```bash
|
|
16
|
+
git clone --depth 1 https://github.com/sst/opencode-sdk-python.git /tmp/opencode-sdk-python
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Key SDK paths:
|
|
20
|
+
- Types: `src/opencode_ai/types/` - All Pydantic models
|
|
21
|
+
- Resources: `src/opencode_ai/resources/` - API client methods (shows endpoint signatures)
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
opencode_server/
|
|
27
|
+
├── __init__.py
|
|
28
|
+
├── server.py # FastAPI app factory and main server class
|
|
29
|
+
├── models/ # Pydantic models matching OpenCode API types
|
|
30
|
+
│ ├── __init__.py
|
|
31
|
+
│ ├── base.py # Shared base model with camelCase alias config
|
|
32
|
+
│ ├── session.py # Session, SessionStatus, etc.
|
|
33
|
+
│ ├── message.py # Message, Parts, etc.
|
|
34
|
+
│ ├── provider.py # Provider, Model, Config
|
|
35
|
+
│ ├── file.py # File operations models
|
|
36
|
+
│ └── events.py # SSE event models
|
|
37
|
+
├── routes/ # Route handlers grouped by domain
|
|
38
|
+
│ ├── __init__.py
|
|
39
|
+
│ ├── global_routes.py
|
|
40
|
+
│ ├── session_routes.py
|
|
41
|
+
│ ├── message_routes.py
|
|
42
|
+
│ ├── file_routes.py
|
|
43
|
+
│ ├── config_routes.py
|
|
44
|
+
│ └── agent_routes.py
|
|
45
|
+
├── state.py # Server state management
|
|
46
|
+
└── ENDPOINTS.md # Implementation status checklist
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Key Conventions
|
|
50
|
+
|
|
51
|
+
### Models
|
|
52
|
+
- All models inherit from `OpenCodeBaseModel` which sets `populate_by_name=True`
|
|
53
|
+
- Use `Field(alias="camelCase")` for fields that differ from snake_case
|
|
54
|
+
- OpenCode uses camelCase in JSON (e.g., `sessionID`, `messageID`, `providerID`)
|
|
55
|
+
|
|
56
|
+
### Routes
|
|
57
|
+
- Each route file defines a router with appropriate prefix/tags
|
|
58
|
+
- Routes are registered in `server.py`
|
|
59
|
+
- Use dependency injection for server state access
|
|
60
|
+
|
|
61
|
+
### Field Naming Examples
|
|
62
|
+
```python
|
|
63
|
+
session_id: str = Field(alias="sessionID")
|
|
64
|
+
message_id: str = Field(alias="messageID")
|
|
65
|
+
provider_id: str = Field(alias="providerID")
|
|
66
|
+
model_id: str = Field(alias="modelID")
|
|
67
|
+
parent_id: str | None = Field(default=None, alias="parentID")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Implementation Status
|
|
71
|
+
|
|
72
|
+
See `ENDPOINTS.md` for the full checklist of endpoints and their implementation status.
|
|
73
|
+
|
|
74
|
+
## Logging
|
|
75
|
+
|
|
76
|
+
Log file location: `~/.local/state/agentpool/log/opencode.log`
|
|
77
|
+
|
|
78
|
+
To tail the logs:
|
|
79
|
+
```bash
|
|
80
|
+
tail -f ~/.local/state/agentpool/log/opencode.log
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
To filter for SSE events:
|
|
84
|
+
```bash
|
|
85
|
+
tail -f ~/.local/state/agentpool/log/opencode.log | grep -i sse
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Testing with the SDK
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from opencode_ai import Opencode
|
|
92
|
+
|
|
93
|
+
client = Opencode(base_url="http://localhost:4096")
|
|
94
|
+
sessions = client.session.list()
|
|
95
|
+
```
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
# OpenCode API Compatibility Checklist
|
|
2
|
+
|
|
3
|
+
This document tracks the implementation status of OpenCode-compatible API endpoints.
|
|
4
|
+
|
|
5
|
+
## Status Legend
|
|
6
|
+
- [ ] Not implemented
|
|
7
|
+
- [x] Implemented
|
|
8
|
+
- [~] Partial / Stub
|
|
9
|
+
- [-] Skipped (not needed)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Global
|
|
14
|
+
|
|
15
|
+
| Status | Method | Path | Description |
|
|
16
|
+
|--------|--------|------|-------------|
|
|
17
|
+
| [x] | GET | `/global/health` | Get server health and version |
|
|
18
|
+
| [x] | GET | `/global/event` | Get global events (SSE stream) |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Project & Path
|
|
23
|
+
|
|
24
|
+
| Status | Method | Path | Description |
|
|
25
|
+
|--------|--------|------|-------------|
|
|
26
|
+
| [x] | GET | `/project` | List all projects |
|
|
27
|
+
| [x] | GET | `/project/current` | Get the current project |
|
|
28
|
+
| [x] | GET | `/path` | Get the current path |
|
|
29
|
+
| [x] | GET | `/vcs` | Get VCS info for current project |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Instance
|
|
34
|
+
|
|
35
|
+
| Status | Method | Path | Description |
|
|
36
|
+
|--------|--------|------|-------------|
|
|
37
|
+
| [ ] | POST | `/instance/dispose` | Dispose the current instance |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Config
|
|
42
|
+
|
|
43
|
+
| Status | Method | Path | Description |
|
|
44
|
+
|--------|--------|------|-------------|
|
|
45
|
+
| [x] | GET | `/config` | Get config info |
|
|
46
|
+
| [x] | PATCH | `/config` | Update config |
|
|
47
|
+
| [~] | GET | `/config/providers` | List providers and default models |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Provider
|
|
52
|
+
|
|
53
|
+
| Status | Method | Path | Description |
|
|
54
|
+
|--------|--------|------|-------------|
|
|
55
|
+
| [~] | GET | `/provider` | List all providers |
|
|
56
|
+
| [x] | GET | `/provider/auth` | Get provider authentication methods |
|
|
57
|
+
| [x] | POST | `/provider/{id}/oauth/authorize` | Authorize provider via OAuth |
|
|
58
|
+
| [x] | POST | `/provider/{id}/oauth/callback` | Handle OAuth callback |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Sessions
|
|
63
|
+
|
|
64
|
+
| Status | Method | Path | Description |
|
|
65
|
+
|--------|--------|------|-------------|
|
|
66
|
+
| [x] | GET | `/session` | List all sessions |
|
|
67
|
+
| [x] | POST | `/session` | Create a new session |
|
|
68
|
+
| [x] | GET | `/session/status` | Get session status for all sessions |
|
|
69
|
+
| [x] | GET | `/session/{id}` | Get session details |
|
|
70
|
+
| [x] | DELETE | `/session/{id}` | Delete a session |
|
|
71
|
+
| [x] | PATCH | `/session/{id}` | Update session properties |
|
|
72
|
+
| [ ] | GET | `/session/{id}/children` | Get child sessions |
|
|
73
|
+
| [x] | GET | `/session/{id}/todo` | Get todo list for session |
|
|
74
|
+
| [x] | POST | `/session/{id}/init` | Analyze app, create AGENTS.md |
|
|
75
|
+
| [x] | POST | `/session/{id}/fork` | Fork session at message |
|
|
76
|
+
| [x] | POST | `/session/{id}/abort` | Abort running session |
|
|
77
|
+
| [x] | POST | `/session/{id}/share` | Share a session |
|
|
78
|
+
| [x] | DELETE | `/session/{id}/share` | Unshare a session |
|
|
79
|
+
| [x] | GET | `/session/{id}/diff` | Get diff for session |
|
|
80
|
+
| [x] | POST | `/session/{id}/summarize` | Summarize the session |
|
|
81
|
+
| [x] | POST | `/session/{id}/revert` | Revert a message |
|
|
82
|
+
| [x] | POST | `/session/{id}/unrevert` | Restore reverted messages |
|
|
83
|
+
| [x] | GET | `/session/{id}/permissions` | Get pending permission requests |
|
|
84
|
+
| [x] | POST | `/session/{id}/permissions/{permissionID}` | Respond to permission request |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Messages
|
|
89
|
+
|
|
90
|
+
| Status | Method | Path | Description |
|
|
91
|
+
|--------|--------|------|-------------|
|
|
92
|
+
| [x] | GET | `/session/{id}/message` | List messages in session |
|
|
93
|
+
| [x] | POST | `/session/{id}/message` | Send message (wait for response) |
|
|
94
|
+
| [x] | GET | `/session/{id}/message/{messageID}` | Get message details |
|
|
95
|
+
| [x] | POST | `/session/{id}/prompt_async` | Send message async (no wait) |
|
|
96
|
+
| [x] | POST | `/session/{id}/command` | Execute slash command (MCP prompts) |
|
|
97
|
+
| [x] | POST | `/session/{id}/shell` | Run shell command |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Commands
|
|
102
|
+
|
|
103
|
+
| Status | Method | Path | Description |
|
|
104
|
+
|--------|--------|------|-------------|
|
|
105
|
+
| [x] | GET | `/command` | List all commands (MCP prompts) |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Files
|
|
110
|
+
|
|
111
|
+
| Status | Method | Path | Description |
|
|
112
|
+
|--------|--------|------|-------------|
|
|
113
|
+
| [x] | GET | `/find?pattern=` | Search for text in files |
|
|
114
|
+
| [x] | GET | `/find/file?query=` | Find files by name |
|
|
115
|
+
| [~] | GET | `/find/symbol?query=` | Find workspace symbols |
|
|
116
|
+
| [x] | GET | `/file?path=` | List files and directories |
|
|
117
|
+
| [x] | GET | `/file/content?path=` | Read a file |
|
|
118
|
+
| [~] | GET | `/file/status` | Get status for tracked files |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Tools (Experimental)
|
|
123
|
+
|
|
124
|
+
| Status | Method | Path | Description |
|
|
125
|
+
|--------|--------|------|-------------|
|
|
126
|
+
| [x] | GET | `/experimental/tool/ids` | List all tool IDs |
|
|
127
|
+
| [x] | GET | `/experimental/tool?provider=&model=` | List tools with schemas |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## LSP, Formatters & MCP
|
|
132
|
+
|
|
133
|
+
| Status | Method | Path | Description |
|
|
134
|
+
|--------|--------|------|-------------|
|
|
135
|
+
| [x] | GET | `/lsp` | Get LSP server status |
|
|
136
|
+
| [x] | POST | `/lsp/start` | Start an LSP server |
|
|
137
|
+
| [x] | POST | `/lsp/stop` | Stop an LSP server |
|
|
138
|
+
| [x] | GET | `/lsp/servers` | List available LSP servers |
|
|
139
|
+
| [x] | GET | `/lsp/diagnostics` | Get LSP diagnostics (CLI-based) |
|
|
140
|
+
| [x] | GET | `/formatter` | Get formatter status (stub) |
|
|
141
|
+
| [~] | GET | `/mcp` | Get MCP server status |
|
|
142
|
+
| [x] | POST | `/mcp` | Add MCP server dynamically |
|
|
143
|
+
| [x] | GET | `/experimental/resource` | List MCP resources from connected servers |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Agents
|
|
148
|
+
|
|
149
|
+
| Status | Method | Path | Description |
|
|
150
|
+
|--------|--------|------|-------------|
|
|
151
|
+
| [~] | GET | `/agent` | List all available agents |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Logging
|
|
156
|
+
|
|
157
|
+
| Status | Method | Path | Description |
|
|
158
|
+
|--------|--------|------|-------------|
|
|
159
|
+
| [x] | POST | `/log` | Write log entry |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Modes
|
|
164
|
+
|
|
165
|
+
| Status | Method | Path | Description |
|
|
166
|
+
|--------|--------|------|-------------|
|
|
167
|
+
| [~] | GET | `/mode` | List all modes |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## PTY (Pseudo-Terminal)
|
|
172
|
+
|
|
173
|
+
| Status | Method | Path | Description |
|
|
174
|
+
|--------|--------|------|-------------|
|
|
175
|
+
| [x] | GET | `/pty` | List all PTY sessions |
|
|
176
|
+
| [x] | POST | `/pty` | Create a new PTY session |
|
|
177
|
+
| [x] | GET | `/pty/{ptyID}` | Get PTY session details |
|
|
178
|
+
| [x] | PATCH | `/pty/{ptyID}` | Update PTY session (resize, etc.) |
|
|
179
|
+
| [x] | DELETE | `/pty/{ptyID}` | Remove/kill PTY session |
|
|
180
|
+
| [x] | WS | `/pty/{ptyID}/connect` | Connect to PTY (WebSocket) |
|
|
181
|
+
|
|
182
|
+
### PTY SSE Event Types
|
|
183
|
+
|
|
184
|
+
| Status | Event Type | Description |
|
|
185
|
+
|--------|------------|-------------|
|
|
186
|
+
| [x] | `pty.created` | PTY session created |
|
|
187
|
+
| [x] | `pty.updated` | PTY session updated |
|
|
188
|
+
| [x] | `pty.exited` | PTY process exited |
|
|
189
|
+
| [x] | `pty.deleted` | PTY session deleted |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## TUI (External Control)
|
|
194
|
+
|
|
195
|
+
These endpoints allow external integrations (e.g., VSCode extension) to control the TUI
|
|
196
|
+
by broadcasting events via SSE.
|
|
197
|
+
|
|
198
|
+
| Status | Method | Path | Description |
|
|
199
|
+
|--------|--------|------|-------------|
|
|
200
|
+
| [x] | POST | `/tui/append-prompt` | Append text to prompt |
|
|
201
|
+
| [x] | POST | `/tui/open-help` | Open help dialog |
|
|
202
|
+
| [x] | POST | `/tui/open-sessions` | Open session selector |
|
|
203
|
+
| [x] | POST | `/tui/open-themes` | Open theme selector |
|
|
204
|
+
| [x] | POST | `/tui/open-models` | Open model selector |
|
|
205
|
+
| [x] | POST | `/tui/submit-prompt` | Submit current prompt |
|
|
206
|
+
| [x] | POST | `/tui/clear-prompt` | Clear the prompt |
|
|
207
|
+
| [x] | POST | `/tui/execute-command` | Execute a command |
|
|
208
|
+
| [x] | POST | `/tui/show-toast` | Show toast notification |
|
|
209
|
+
| [-] | GET | `/tui/control/next` | Wait for next control request (not needed) |
|
|
210
|
+
| [-] | POST | `/tui/control/response` | Respond to control request (not needed) |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Auth
|
|
215
|
+
|
|
216
|
+
| Status | Method | Path | Description |
|
|
217
|
+
|--------|--------|------|-------------|
|
|
218
|
+
| [ ] | PUT | `/auth/{id}` | Set authentication credentials |
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Events
|
|
223
|
+
|
|
224
|
+
| Status | Method | Path | Description |
|
|
225
|
+
|--------|--------|------|-------------|
|
|
226
|
+
| [x] | GET | `/event` | SSE event stream |
|
|
227
|
+
|
|
228
|
+
### SSE Event Types
|
|
229
|
+
|
|
230
|
+
All event types supported by the OpenCode protocol:
|
|
231
|
+
|
|
232
|
+
| Status | Event Type | Description |
|
|
233
|
+
|--------|------------|-------------|
|
|
234
|
+
| [x] | `server.connected` | Server connected (sent on SSE connect) |
|
|
235
|
+
| [-] | `global.disposed` | Global instance disposed (multi-project, not needed) |
|
|
236
|
+
| [-] | `installation.updated` | Installation updated (auto-upgrade complete, not needed) |
|
|
237
|
+
| [x] | `installation.update-available` | Update available (via `tui.toast.show` workaround) |
|
|
238
|
+
| [x] | `project.updated` | Project metadata updated |
|
|
239
|
+
| [-] | `server.instance.disposed` | Server instance disposed (multi-project, not needed) |
|
|
240
|
+
| [x] | `lsp.updated` | LSP server status updated |
|
|
241
|
+
| [~] | `lsp.client.diagnostics` | LSP client diagnostics received |
|
|
242
|
+
| [x] | `session.created` | Session created |
|
|
243
|
+
| [x] | `session.updated` | Session updated |
|
|
244
|
+
| [x] | `session.deleted` | Session deleted |
|
|
245
|
+
| [x] | `session.status` | Session status changed (running/idle/error) |
|
|
246
|
+
| [x] | `session.idle` | Session became idle (deprecated but used by TUI) |
|
|
247
|
+
| [x] | `session.compacted` | Session context was compacted/summarized |
|
|
248
|
+
| [ ] | `session.diff` | Session file diff updated |
|
|
249
|
+
| [x] | `session.error` | Session encountered an error |
|
|
250
|
+
| [x] | `message.updated` | Message created or updated |
|
|
251
|
+
| [x] | `message.removed` | Message removed (during revert) |
|
|
252
|
+
| [x] | `message.part.updated` | Message part (text, tool, etc.) updated |
|
|
253
|
+
| [x] | `message.part.removed` | Message part removed (during revert) |
|
|
254
|
+
| [x] | `permission.asked` | Tool permission requested (awaiting user response) |
|
|
255
|
+
| [x] | `permission.replied` | Permission request resolved (user responded) |
|
|
256
|
+
| [x] | `todo.updated` | Todo list item updated |
|
|
257
|
+
| [ ] | `file.edited` | File was edited |
|
|
258
|
+
| [x] | `file.watcher.updated` | File watcher detects project file changes |
|
|
259
|
+
| [x] | `vcs.branch.updated` | VCS branch changed (polling-based) |
|
|
260
|
+
| [ ] | `mcp.tools.changed` | MCP server tools changed |
|
|
261
|
+
| [ ] | `command.executed` | Slash command executed |
|
|
262
|
+
| [x] | `tui.prompt.append` | Append text to TUI prompt input |
|
|
263
|
+
| [x] | `tui.command.execute` | Execute a TUI command |
|
|
264
|
+
| [x] | `tui.toast.show` | Show toast notification in TUI |
|
|
265
|
+
| [x] | `pty.created` | PTY session created |
|
|
266
|
+
| [x] | `pty.updated` | PTY session updated |
|
|
267
|
+
| [x] | `pty.exited` | PTY process exited |
|
|
268
|
+
| [x] | `pty.deleted` | PTY session deleted |
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Docs
|
|
273
|
+
|
|
274
|
+
| Status | Method | Path | Description |
|
|
275
|
+
|--------|--------|------|-------------|
|
|
276
|
+
| [x] | GET | `/doc` | OpenAPI 3.1 specification |
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Implementation Summary
|
|
281
|
+
|
|
282
|
+
### Completed (TUI can connect!)
|
|
283
|
+
- Health check and SSE events
|
|
284
|
+
- Session CRUD operations
|
|
285
|
+
- File listing and reading
|
|
286
|
+
- Path/Project/VCS info
|
|
287
|
+
- Config endpoint
|
|
288
|
+
- All stubs needed for TUI to render
|
|
289
|
+
|
|
290
|
+
### Next Steps
|
|
291
|
+
1. **Agent Integration** - Wire up actual LLM calls for `/session/{id}/message`
|
|
292
|
+
2. **Provider Discovery** - Populate `/config/providers` with real models
|
|
293
|
+
3. **File Search** - Implement `/find` endpoints
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Testing
|
|
298
|
+
|
|
299
|
+
**Terminal 1:** Start server
|
|
300
|
+
```bash
|
|
301
|
+
duty opencode-server
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Terminal 2:** Attach TUI
|
|
305
|
+
```bash
|
|
306
|
+
duty opencode-tui
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Or combined (less reliable for interactive use):
|
|
310
|
+
```bash
|
|
311
|
+
duty opencode
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Tool Metadata Support - Complete OpenCode UI Coverage
|
|
317
|
+
|
|
318
|
+
**These are ALL 11 tools registered in OpenCode's UI that use metadata for enhanced rendering:**
|
|
319
|
+
|
|
320
|
+
| # | Tool | AgentPool | Metadata | UI Feature |
|
|
321
|
+
|---|------|-----------|----------|------------|
|
|
322
|
+
| 1 | `read` | ✅ **DONE** | `preview`, `truncated` | File preview, truncation badge |
|
|
323
|
+
| 2 | `list` | ✅ **DONE** | `count`, `truncated` | File count, directory tree |
|
|
324
|
+
| 3 | `glob` | ❌ **MISSING** | `count`, `truncated` | File count, pattern display |
|
|
325
|
+
| 4 | `grep` | ✅ **DONE** | `matches`, `truncated` | Match count badge |
|
|
326
|
+
| 5 | `webfetch` | ❌ **MISSING** | `url`, `format` | URL display |
|
|
327
|
+
| 6 | `task` | ❌ **MISSING** | `summary`, `sessionId` | **Sub-agent tool list** |
|
|
328
|
+
| 7 | `bash` | ✅ **DONE** | `output`, `exit`, `description` | Live output, exit code |
|
|
329
|
+
| 8 | `edit` | ✅ **DONE** | `diff`, `filediff`, `diagnostics` | **Diff viewer**, LSP errors |
|
|
330
|
+
| 9 | `write` | ⚠️ **PARTIAL** | `filePath`, `content`, (TODO: `diagnostics`) | Code viewer, LSP errors |
|
|
331
|
+
| 10 | `todowrite` | ✅ **DONE** | `todos` | **Interactive checkboxes** |
|
|
332
|
+
| 11 | `question` | ✅ **DONE** | `answers` | **Q&A display** |
|
|
333
|
+
|
|
334
|
+
### Summary
|
|
335
|
+
- **Total:** 11 OpenCode UI tools
|
|
336
|
+
- **Implemented:** 6/11 (✅)
|
|
337
|
+
- **Partial:** 1/11 (⚠️)
|
|
338
|
+
- **Missing:** 4/11 (❌)
|
|
339
|
+
|
|
340
|
+
### Missing Tools for 100% Coverage
|
|
341
|
+
1. **`glob`** - File pattern matching (HIGH priority - complements grep)
|
|
342
|
+
2. **`task`** - Sub-agent execution tracking (HIGH priority - delegation)
|
|
343
|
+
3. **`webfetch`** - Web content fetching (LOW priority - external)
|
|
344
|
+
4. **`write` diagnostics** - LSP integration (MEDIUM priority)
|
|
345
|
+
|
|
346
|
+
### Other OpenCode Tools (Not UI-Rendered)
|
|
347
|
+
These exist in OpenCode but don't have special UI treatment:
|
|
348
|
+
- `plan`, `batch`, `multiedit`, `patch`, `lsp`, `skill`, `codesearch`, `websearch`
|
|
349
|
+
|
|
350
|
+
See [`OPENCODE_UI_TOOLS_COMPLETE.md`](file:///home/phil65/dev/oss/agentpool/OPENCODE_UI_TOOLS_COMPLETE.md) for detailed metadata specs.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Tool UI Rendering
|
|
355
|
+
|
|
356
|
+
The OpenCode TUI has special rendering for certain tool names. Tools must use these exact names
|
|
357
|
+
and parameter formats (after snake_case → camelCase conversion) to get custom UI treatment.
|
|
358
|
+
|
|
359
|
+
Parameter conversion is handled in `converters.py` via `_PARAM_NAME_MAP`.
|
|
360
|
+
|
|
361
|
+
| Tool Name | Expected Parameters (camelCase) | UI Treatment |
|
|
362
|
+
|-----------|--------------------------------|--------------|
|
|
363
|
+
| `read` | `filePath`, `offset`, `limit` | Glasses icon, shows filename |
|
|
364
|
+
| `list` | `path` | Bullet-list icon, shows directory |
|
|
365
|
+
| `glob` | `path`, `pattern` | Magnifying-glass icon, shows pattern |
|
|
366
|
+
| `grep` | `path`, `pattern`, `include` | Magnifying-glass icon, shows pattern |
|
|
367
|
+
| `webfetch` | `url`, `format` | Window icon, shows URL |
|
|
368
|
+
| `task` | `subagent_type`, `description` | Task icon, shows agent summary |
|
|
369
|
+
| `bash` | `command`, `description` | Console icon, shows command + output |
|
|
370
|
+
| `edit` | `filePath`, `oldString`, `newString` | Code icon, **diff view** |
|
|
371
|
+
| `write` | `filePath`, `content` | Code icon, **syntax-highlighted content** |
|
|
372
|
+
| `todowrite` | `todos` (array with `status`, `content`) | Checklist icon, checkbox list |
|
|
373
|
+
| `todoread` | - | Filtered out (not displayed) |
|
|
374
|
+
|
|
375
|
+
### Metadata
|
|
376
|
+
|
|
377
|
+
Some tools also use `props.metadata` for additional UI data:
|
|
378
|
+
|
|
379
|
+
| Tool | Metadata Fields | Description |
|
|
380
|
+
|------|-----------------|-------------|
|
|
381
|
+
| `edit` | `filediff`, `diagnostics` | Diff data and LSP diagnostics |
|
|
382
|
+
| `write` | `filePath`, `content` | File path and content for UI display (diagnostics TODO) |
|
|
383
|
+
| `bash` | `command` | Fallback if `input.command` missing |
|
|
384
|
+
| `task` | `summary`, `sessionId` | Child tool summary and session ID |
|
|
385
|
+
|
|
386
|
+
### Parameter Name Mapping
|
|
387
|
+
|
|
388
|
+
The `_PARAM_NAME_MAP` in `converters.py` converts our snake_case to TUI's camelCase:
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
_PARAM_NAME_MAP = {
|
|
392
|
+
"path": "filePath",
|
|
393
|
+
"file_path": "filePath",
|
|
394
|
+
"old_string": "oldString",
|
|
395
|
+
"new_string": "newString",
|
|
396
|
+
"replace_all": "replaceAll",
|
|
397
|
+
"line_hint": "lineHint",
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
|