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.
Files changed (311) hide show
  1. acp/__init__.py +13 -4
  2. acp/acp_requests.py +20 -77
  3. acp/agent/connection.py +8 -0
  4. acp/agent/implementations/debug_server/debug_server.py +6 -2
  5. acp/agent/protocol.py +6 -0
  6. acp/bridge/README.md +15 -2
  7. acp/bridge/__init__.py +3 -2
  8. acp/bridge/__main__.py +60 -19
  9. acp/bridge/ws_server.py +173 -0
  10. acp/bridge/ws_server_cli.py +89 -0
  11. acp/client/connection.py +38 -29
  12. acp/client/implementations/default_client.py +3 -2
  13. acp/client/implementations/headless_client.py +2 -2
  14. acp/connection.py +2 -2
  15. acp/notifications.py +20 -50
  16. acp/schema/__init__.py +2 -0
  17. acp/schema/agent_responses.py +21 -0
  18. acp/schema/client_requests.py +3 -3
  19. acp/schema/session_state.py +63 -29
  20. acp/stdio.py +39 -9
  21. acp/task/supervisor.py +2 -2
  22. acp/transports.py +362 -2
  23. acp/utils.py +17 -4
  24. agentpool/__init__.py +6 -1
  25. agentpool/agents/__init__.py +2 -0
  26. agentpool/agents/acp_agent/acp_agent.py +407 -277
  27. agentpool/agents/acp_agent/acp_converters.py +196 -38
  28. agentpool/agents/acp_agent/client_handler.py +191 -26
  29. agentpool/agents/acp_agent/session_state.py +17 -6
  30. agentpool/agents/agent.py +607 -572
  31. agentpool/agents/agui_agent/__init__.py +0 -2
  32. agentpool/agents/agui_agent/agui_agent.py +176 -110
  33. agentpool/agents/agui_agent/agui_converters.py +0 -131
  34. agentpool/agents/agui_agent/helpers.py +3 -4
  35. agentpool/agents/base_agent.py +632 -17
  36. agentpool/agents/claude_code_agent/FORKING.md +191 -0
  37. agentpool/agents/claude_code_agent/__init__.py +13 -1
  38. agentpool/agents/claude_code_agent/claude_code_agent.py +1058 -291
  39. agentpool/agents/claude_code_agent/converters.py +74 -143
  40. agentpool/agents/claude_code_agent/history.py +474 -0
  41. agentpool/agents/claude_code_agent/models.py +77 -0
  42. agentpool/agents/claude_code_agent/static_info.py +100 -0
  43. agentpool/agents/claude_code_agent/usage.py +242 -0
  44. agentpool/agents/context.py +40 -0
  45. agentpool/agents/events/__init__.py +24 -0
  46. agentpool/agents/events/builtin_handlers.py +67 -1
  47. agentpool/agents/events/event_emitter.py +32 -2
  48. agentpool/agents/events/events.py +104 -3
  49. agentpool/agents/events/infer_info.py +145 -0
  50. agentpool/agents/events/processors.py +254 -0
  51. agentpool/agents/interactions.py +41 -6
  52. agentpool/agents/modes.py +67 -0
  53. agentpool/agents/slashed_agent.py +5 -4
  54. agentpool/agents/tool_call_accumulator.py +213 -0
  55. agentpool/agents/tool_wrapping.py +18 -6
  56. agentpool/common_types.py +56 -21
  57. agentpool/config_resources/__init__.py +38 -1
  58. agentpool/config_resources/acp_assistant.yml +2 -2
  59. agentpool/config_resources/agents.yml +3 -0
  60. agentpool/config_resources/agents_template.yml +1 -0
  61. agentpool/config_resources/claude_code_agent.yml +10 -6
  62. agentpool/config_resources/external_acp_agents.yml +2 -1
  63. agentpool/delegation/base_team.py +4 -30
  64. agentpool/delegation/pool.py +136 -289
  65. agentpool/delegation/team.py +58 -57
  66. agentpool/delegation/teamrun.py +51 -55
  67. agentpool/diagnostics/__init__.py +53 -0
  68. agentpool/diagnostics/lsp_manager.py +1593 -0
  69. agentpool/diagnostics/lsp_proxy.py +41 -0
  70. agentpool/diagnostics/lsp_proxy_script.py +229 -0
  71. agentpool/diagnostics/models.py +398 -0
  72. agentpool/functional/run.py +10 -4
  73. agentpool/mcp_server/__init__.py +0 -2
  74. agentpool/mcp_server/client.py +76 -32
  75. agentpool/mcp_server/conversions.py +54 -13
  76. agentpool/mcp_server/manager.py +34 -54
  77. agentpool/mcp_server/registries/official_registry_client.py +35 -1
  78. agentpool/mcp_server/tool_bridge.py +186 -139
  79. agentpool/messaging/__init__.py +0 -2
  80. agentpool/messaging/compaction.py +72 -197
  81. agentpool/messaging/connection_manager.py +11 -10
  82. agentpool/messaging/event_manager.py +5 -5
  83. agentpool/messaging/message_container.py +6 -30
  84. agentpool/messaging/message_history.py +99 -8
  85. agentpool/messaging/messagenode.py +52 -14
  86. agentpool/messaging/messages.py +54 -35
  87. agentpool/messaging/processing.py +12 -22
  88. agentpool/models/__init__.py +1 -1
  89. agentpool/models/acp_agents/base.py +6 -24
  90. agentpool/models/acp_agents/mcp_capable.py +126 -157
  91. agentpool/models/acp_agents/non_mcp.py +129 -95
  92. agentpool/models/agents.py +98 -76
  93. agentpool/models/agui_agents.py +1 -1
  94. agentpool/models/claude_code_agents.py +144 -19
  95. agentpool/models/file_parsing.py +0 -1
  96. agentpool/models/manifest.py +113 -50
  97. agentpool/prompts/conversion_manager.py +1 -1
  98. agentpool/prompts/prompts.py +5 -2
  99. agentpool/repomap.py +1 -1
  100. agentpool/resource_providers/__init__.py +11 -1
  101. agentpool/resource_providers/aggregating.py +56 -5
  102. agentpool/resource_providers/base.py +70 -4
  103. agentpool/resource_providers/codemode/code_executor.py +72 -5
  104. agentpool/resource_providers/codemode/helpers.py +2 -2
  105. agentpool/resource_providers/codemode/provider.py +64 -12
  106. agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
  107. agentpool/resource_providers/codemode/remote_provider.py +9 -12
  108. agentpool/resource_providers/filtering.py +3 -1
  109. agentpool/resource_providers/mcp_provider.py +89 -12
  110. agentpool/resource_providers/plan_provider.py +228 -46
  111. agentpool/resource_providers/pool.py +7 -3
  112. agentpool/resource_providers/resource_info.py +111 -0
  113. agentpool/resource_providers/static.py +4 -2
  114. agentpool/sessions/__init__.py +4 -1
  115. agentpool/sessions/manager.py +33 -5
  116. agentpool/sessions/models.py +59 -6
  117. agentpool/sessions/protocol.py +28 -0
  118. agentpool/sessions/session.py +11 -55
  119. agentpool/skills/registry.py +13 -8
  120. agentpool/storage/manager.py +572 -49
  121. agentpool/talk/registry.py +4 -4
  122. agentpool/talk/talk.py +9 -10
  123. agentpool/testing.py +538 -20
  124. agentpool/tool_impls/__init__.py +6 -0
  125. agentpool/tool_impls/agent_cli/__init__.py +42 -0
  126. agentpool/tool_impls/agent_cli/tool.py +95 -0
  127. agentpool/tool_impls/bash/__init__.py +64 -0
  128. agentpool/tool_impls/bash/helpers.py +35 -0
  129. agentpool/tool_impls/bash/tool.py +171 -0
  130. agentpool/tool_impls/delete_path/__init__.py +70 -0
  131. agentpool/tool_impls/delete_path/tool.py +142 -0
  132. agentpool/tool_impls/download_file/__init__.py +80 -0
  133. agentpool/tool_impls/download_file/tool.py +183 -0
  134. agentpool/tool_impls/execute_code/__init__.py +55 -0
  135. agentpool/tool_impls/execute_code/tool.py +163 -0
  136. agentpool/tool_impls/grep/__init__.py +80 -0
  137. agentpool/tool_impls/grep/tool.py +200 -0
  138. agentpool/tool_impls/list_directory/__init__.py +73 -0
  139. agentpool/tool_impls/list_directory/tool.py +197 -0
  140. agentpool/tool_impls/question/__init__.py +42 -0
  141. agentpool/tool_impls/question/tool.py +127 -0
  142. agentpool/tool_impls/read/__init__.py +104 -0
  143. agentpool/tool_impls/read/tool.py +305 -0
  144. agentpool/tools/__init__.py +2 -1
  145. agentpool/tools/base.py +114 -34
  146. agentpool/tools/manager.py +57 -1
  147. agentpool/ui/base.py +2 -2
  148. agentpool/ui/mock_provider.py +2 -2
  149. agentpool/ui/stdlib_provider.py +2 -2
  150. agentpool/utils/file_watcher.py +269 -0
  151. agentpool/utils/identifiers.py +121 -0
  152. agentpool/utils/pydantic_ai_helpers.py +46 -0
  153. agentpool/utils/streams.py +616 -2
  154. agentpool/utils/subprocess_utils.py +155 -0
  155. agentpool/utils/token_breakdown.py +461 -0
  156. agentpool/vfs_registry.py +7 -2
  157. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/METADATA +41 -27
  158. agentpool-2.5.0.dist-info/RECORD +579 -0
  159. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
  160. agentpool_cli/__main__.py +24 -0
  161. agentpool_cli/create.py +1 -1
  162. agentpool_cli/serve_acp.py +100 -21
  163. agentpool_cli/serve_agui.py +87 -0
  164. agentpool_cli/serve_opencode.py +119 -0
  165. agentpool_cli/ui.py +557 -0
  166. agentpool_commands/__init__.py +42 -5
  167. agentpool_commands/agents.py +75 -2
  168. agentpool_commands/history.py +62 -0
  169. agentpool_commands/mcp.py +176 -0
  170. agentpool_commands/models.py +56 -3
  171. agentpool_commands/pool.py +260 -0
  172. agentpool_commands/session.py +1 -1
  173. agentpool_commands/text_sharing/__init__.py +119 -0
  174. agentpool_commands/text_sharing/base.py +123 -0
  175. agentpool_commands/text_sharing/github_gist.py +80 -0
  176. agentpool_commands/text_sharing/opencode.py +462 -0
  177. agentpool_commands/text_sharing/paste_rs.py +59 -0
  178. agentpool_commands/text_sharing/pastebin.py +116 -0
  179. agentpool_commands/text_sharing/shittycodingagent.py +112 -0
  180. agentpool_commands/tools.py +57 -0
  181. agentpool_commands/utils.py +80 -30
  182. agentpool_config/__init__.py +30 -2
  183. agentpool_config/agentpool_tools.py +498 -0
  184. agentpool_config/builtin_tools.py +77 -22
  185. agentpool_config/commands.py +24 -1
  186. agentpool_config/compaction.py +258 -0
  187. agentpool_config/converters.py +1 -1
  188. agentpool_config/event_handlers.py +42 -0
  189. agentpool_config/events.py +1 -1
  190. agentpool_config/forward_targets.py +1 -4
  191. agentpool_config/jinja.py +3 -3
  192. agentpool_config/mcp_server.py +132 -6
  193. agentpool_config/nodes.py +1 -1
  194. agentpool_config/observability.py +44 -0
  195. agentpool_config/session.py +0 -3
  196. agentpool_config/storage.py +82 -38
  197. agentpool_config/task.py +3 -3
  198. agentpool_config/tools.py +11 -22
  199. agentpool_config/toolsets.py +109 -233
  200. agentpool_server/a2a_server/agent_worker.py +307 -0
  201. agentpool_server/a2a_server/server.py +23 -18
  202. agentpool_server/acp_server/acp_agent.py +234 -181
  203. agentpool_server/acp_server/commands/acp_commands.py +151 -156
  204. agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +18 -17
  205. agentpool_server/acp_server/event_converter.py +651 -0
  206. agentpool_server/acp_server/input_provider.py +53 -10
  207. agentpool_server/acp_server/server.py +24 -90
  208. agentpool_server/acp_server/session.py +173 -331
  209. agentpool_server/acp_server/session_manager.py +8 -34
  210. agentpool_server/agui_server/server.py +3 -1
  211. agentpool_server/mcp_server/server.py +5 -2
  212. agentpool_server/opencode_server/.rules +95 -0
  213. agentpool_server/opencode_server/ENDPOINTS.md +401 -0
  214. agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
  215. agentpool_server/opencode_server/__init__.py +19 -0
  216. agentpool_server/opencode_server/command_validation.py +172 -0
  217. agentpool_server/opencode_server/converters.py +975 -0
  218. agentpool_server/opencode_server/dependencies.py +24 -0
  219. agentpool_server/opencode_server/input_provider.py +421 -0
  220. agentpool_server/opencode_server/models/__init__.py +250 -0
  221. agentpool_server/opencode_server/models/agent.py +53 -0
  222. agentpool_server/opencode_server/models/app.py +72 -0
  223. agentpool_server/opencode_server/models/base.py +26 -0
  224. agentpool_server/opencode_server/models/common.py +23 -0
  225. agentpool_server/opencode_server/models/config.py +37 -0
  226. agentpool_server/opencode_server/models/events.py +821 -0
  227. agentpool_server/opencode_server/models/file.py +88 -0
  228. agentpool_server/opencode_server/models/mcp.py +44 -0
  229. agentpool_server/opencode_server/models/message.py +179 -0
  230. agentpool_server/opencode_server/models/parts.py +323 -0
  231. agentpool_server/opencode_server/models/provider.py +81 -0
  232. agentpool_server/opencode_server/models/pty.py +43 -0
  233. agentpool_server/opencode_server/models/question.py +56 -0
  234. agentpool_server/opencode_server/models/session.py +111 -0
  235. agentpool_server/opencode_server/routes/__init__.py +29 -0
  236. agentpool_server/opencode_server/routes/agent_routes.py +473 -0
  237. agentpool_server/opencode_server/routes/app_routes.py +202 -0
  238. agentpool_server/opencode_server/routes/config_routes.py +302 -0
  239. agentpool_server/opencode_server/routes/file_routes.py +571 -0
  240. agentpool_server/opencode_server/routes/global_routes.py +94 -0
  241. agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
  242. agentpool_server/opencode_server/routes/message_routes.py +761 -0
  243. agentpool_server/opencode_server/routes/permission_routes.py +63 -0
  244. agentpool_server/opencode_server/routes/pty_routes.py +300 -0
  245. agentpool_server/opencode_server/routes/question_routes.py +128 -0
  246. agentpool_server/opencode_server/routes/session_routes.py +1276 -0
  247. agentpool_server/opencode_server/routes/tui_routes.py +139 -0
  248. agentpool_server/opencode_server/server.py +475 -0
  249. agentpool_server/opencode_server/state.py +151 -0
  250. agentpool_server/opencode_server/time_utils.py +8 -0
  251. agentpool_storage/__init__.py +12 -0
  252. agentpool_storage/base.py +184 -2
  253. agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
  254. agentpool_storage/claude_provider/__init__.py +42 -0
  255. agentpool_storage/claude_provider/provider.py +1089 -0
  256. agentpool_storage/file_provider.py +278 -15
  257. agentpool_storage/memory_provider.py +193 -12
  258. agentpool_storage/models.py +3 -0
  259. agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
  260. agentpool_storage/opencode_provider/__init__.py +16 -0
  261. agentpool_storage/opencode_provider/helpers.py +414 -0
  262. agentpool_storage/opencode_provider/provider.py +895 -0
  263. agentpool_storage/project_store.py +325 -0
  264. agentpool_storage/session_store.py +26 -6
  265. agentpool_storage/sql_provider/__init__.py +4 -2
  266. agentpool_storage/sql_provider/models.py +48 -0
  267. agentpool_storage/sql_provider/sql_provider.py +269 -3
  268. agentpool_storage/sql_provider/utils.py +12 -13
  269. agentpool_storage/zed_provider/__init__.py +16 -0
  270. agentpool_storage/zed_provider/helpers.py +281 -0
  271. agentpool_storage/zed_provider/models.py +130 -0
  272. agentpool_storage/zed_provider/provider.py +442 -0
  273. agentpool_storage/zed_provider.py +803 -0
  274. agentpool_toolsets/__init__.py +0 -2
  275. agentpool_toolsets/builtin/__init__.py +2 -12
  276. agentpool_toolsets/builtin/code.py +96 -57
  277. agentpool_toolsets/builtin/debug.py +118 -48
  278. agentpool_toolsets/builtin/execution_environment.py +115 -230
  279. agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
  280. agentpool_toolsets/builtin/skills.py +9 -4
  281. agentpool_toolsets/builtin/subagent_tools.py +64 -51
  282. agentpool_toolsets/builtin/workers.py +4 -2
  283. agentpool_toolsets/composio_toolset.py +2 -2
  284. agentpool_toolsets/entry_points.py +3 -1
  285. agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
  286. agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
  287. agentpool_toolsets/fsspec_toolset/grep.py +99 -7
  288. agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
  289. agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
  290. agentpool_toolsets/fsspec_toolset/toolset.py +500 -95
  291. agentpool_toolsets/mcp_discovery/__init__.py +5 -0
  292. agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
  293. agentpool_toolsets/mcp_discovery/toolset.py +511 -0
  294. agentpool_toolsets/mcp_run_toolset.py +87 -12
  295. agentpool_toolsets/notifications.py +33 -33
  296. agentpool_toolsets/openapi.py +3 -1
  297. agentpool_toolsets/search_toolset.py +3 -1
  298. agentpool-2.1.9.dist-info/RECORD +0 -474
  299. agentpool_config/resources.py +0 -33
  300. agentpool_server/acp_server/acp_tools.py +0 -43
  301. agentpool_server/acp_server/commands/spawn.py +0 -210
  302. agentpool_storage/text_log_provider.py +0 -275
  303. agentpool_toolsets/builtin/agent_management.py +0 -239
  304. agentpool_toolsets/builtin/chain.py +0 -288
  305. agentpool_toolsets/builtin/history.py +0 -36
  306. agentpool_toolsets/builtin/integration.py +0 -85
  307. agentpool_toolsets/builtin/tool_management.py +0 -90
  308. agentpool_toolsets/builtin/user_interaction.py +0 -52
  309. agentpool_toolsets/semantic_memory_toolset.py +0 -536
  310. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
  311. {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=f"conv_{session_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
- logger.warning(
174
- "Session agent no longer exists",
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
- session = self._active.get(session_id)
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
- "Error closing session during pool swap", session=session.session_id
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(None, pool_agent.model_name, str)
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
- self.fastmcp.tool(annotations=tool_annotations, task=True)(tool_handler)
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
+