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
@@ -15,9 +15,9 @@ from agentpool.ui.base import InputProvider
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from acp import RequestPermissionResponse
18
+ from agentpool import AgentContext
18
19
  from agentpool.agents.context import ConfirmationResult
19
20
  from agentpool.messaging import ChatMessage
20
- from agentpool.messaging.context import NodeContext
21
21
  from agentpool.tools.base import Tool
22
22
  from agentpool_server.acp_server.session import ACPSession
23
23
 
@@ -100,7 +100,7 @@ class ACPInputProvider(InputProvider):
100
100
 
101
101
  async def get_tool_confirmation(
102
102
  self,
103
- context: NodeContext[Any],
103
+ context: AgentContext[Any],
104
104
  tool: Tool,
105
105
  args: dict[str, Any],
106
106
  message_history: list[ChatMessage[Any]] | None = None,
@@ -131,18 +131,53 @@ class ACPInputProvider(InputProvider):
131
131
  return "skip"
132
132
 
133
133
  # Create a descriptive title for the permission request
134
- args_str = ", ".join(f"{k}={v}" for k, v in args.items())
134
+ # args_str = ", ".join(f"{k}={v}" for k, v in args.items())
135
+ # Use the tool_call_id from context - this must match the UI tool call
136
+ actual_tool_call_id = getattr(context, "tool_call_id", None)
137
+ if not actual_tool_call_id:
138
+ msg = (
139
+ f"No tool_call_id in context for tool {tool.name!r}. "
140
+ "This indicates a bug in tool call tracking."
141
+ )
142
+ logger.error(msg)
143
+ raise RuntimeError(msg) # noqa: TRY301
144
+ logger.debug(
145
+ "Requesting permission",
146
+ tool_name=tool.name,
147
+ tool_call_id=actual_tool_call_id,
148
+ )
149
+ # Note: We no longer send tool_call_start/progress notifications here.
150
+ # The streaming loop (via ACPEventConverter) already sends ToolCallStart
151
+ # before the permission callback is invoked, so Zed already knows about
152
+ # the tool call. Sending duplicates was causing sync issues.
153
+
154
+ from acp.utils import generate_tool_title
155
+
156
+ title = generate_tool_title(tool.name, args)
135
157
  response = await self.session.requests.request_permission(
136
- tool_call_id=f"{tool.name}_{hash(frozenset(args.items()))}",
137
- title=f"Execute tool {tool.name!r} with args: {args_str}",
158
+ tool_call_id=actual_tool_call_id,
159
+ title=title,
160
+ raw_input=args,
138
161
  options=DEFAULT_PERMISSION_OPTIONS,
139
162
  )
163
+ logger.info(
164
+ "Permission response received",
165
+ tool_name=tool.name,
166
+ outcome=response.outcome,
167
+ outcome_type=type(response.outcome).__name__,
168
+ )
140
169
  # Map ACP permission response to our confirmation result
141
170
  if isinstance(response.outcome, AllowedOutcome):
171
+ logger.info(
172
+ "AllowedOutcome detected",
173
+ option_id=response.outcome.option_id,
174
+ tool_name=tool.name,
175
+ )
142
176
  return self._handle_permission_response(response.outcome.option_id, tool.name)
143
177
  if response.outcome.outcome == "cancelled":
178
+ logger.debug("Permission cancelled", tool_name=tool.name)
144
179
  return "skip"
145
- # Handle other outcomes
180
+ # Handle other unexpected outcomes
146
181
  logger.warning("Unexpected permission outcome", outcome=response.outcome.outcome)
147
182
 
148
183
  except Exception:
@@ -150,20 +185,28 @@ class ACPInputProvider(InputProvider):
150
185
  # Default to abort on error to be safe
151
186
  return "abort_run"
152
187
  else:
153
- return "abort_run"
188
+ return "skip" # Default to skip for unknown outcomes
154
189
 
155
190
  def _handle_permission_response(self, option_id: str, tool_name: str) -> ConfirmationResult:
156
191
  """Handle permission response and update tool approval state."""
157
- match option_id:
192
+ # Normalize to hyphen format for matching
193
+ normalized = option_id.replace("_", "-")
194
+ logger.info(
195
+ "Handling permission response",
196
+ option_id=option_id,
197
+ normalized=normalized,
198
+ tool_name=tool_name,
199
+ )
200
+ match normalized:
158
201
  case "allow-once":
159
202
  return "allow"
160
203
  case "allow-always":
161
204
  self._tool_approvals[tool_name] = "allow_always"
162
205
  logger.info("Tool approval set", tool_name=tool_name, approval="allow_always")
163
206
  return "allow"
164
- case "reject-once":
207
+ case "reject-once" | "deny-once":
165
208
  return "skip"
166
- case "reject-always":
209
+ case "reject-always" | "deny-always":
167
210
  self._tool_approvals[tool_name] = "reject_always"
168
211
  logger.info("Tool approval set", tool_name=tool_name, approval="reject_always")
169
212
  return "skip"
@@ -7,14 +7,10 @@ the Agent Client Protocol.
7
7
  from __future__ import annotations
8
8
 
9
9
  import asyncio
10
- from datetime import timedelta
11
10
  import functools
12
11
  from typing import TYPE_CHECKING, Any, Self
13
12
 
14
- import logfire
15
-
16
- from acp import AgentSideConnection
17
- from acp.stdio import stdio_streams
13
+ from acp import serve
18
14
  from agentpool import AgentPool
19
15
  from agentpool.log import get_logger
20
16
  from agentpool.models.manifest import AgentsManifest
@@ -23,41 +19,14 @@ from agentpool_server.acp_server.acp_agent import AgentPoolACPAgent
23
19
 
24
20
 
25
21
  if TYPE_CHECKING:
26
- from collections.abc import Sequence
27
-
28
- from tokonomics.model_discovery import ProviderType
29
- from tokonomics.model_discovery.model_info import ModelInfo
30
22
  from upathtools import JoinablePathLike
31
23
 
32
- from acp.schema import ModelInfo as ACPModelInfo
24
+ from acp import Transport
33
25
 
34
26
 
35
27
  logger = get_logger(__name__)
36
28
 
37
29
 
38
- def _convert_to_acp_model_info(
39
- toko_models: Sequence[ModelInfo],
40
- ) -> list[ACPModelInfo]:
41
- """Convert tokonomics ModelInfo list to ACP ModelInfo list.
42
-
43
- Args:
44
- toko_models: List of tokonomics ModelInfo objects
45
-
46
- Returns:
47
- List of ACP ModelInfo objects with pydantic_ai_id as model_id
48
- """
49
- from acp.schema import ModelInfo as ACPModelInfo
50
-
51
- return [
52
- ACPModelInfo(
53
- model_id=model.pydantic_ai_id,
54
- name=f"{model.provider}: {model.name}" if model.provider else model.name,
55
- description=model.format(),
56
- )
57
- for model in toko_models
58
- ]
59
-
60
-
61
30
  class ACPServer(BaseServer):
62
31
  """ACP (Agent Client Protocol) server for agentpool using external library.
63
32
 
@@ -75,13 +44,13 @@ class ACPServer(BaseServer):
75
44
  name: str | None = None,
76
45
  file_access: bool = True,
77
46
  terminal_access: bool = True,
78
- providers: list[ProviderType] | None = None,
79
47
  debug_messages: bool = False,
80
48
  debug_file: str | None = None,
81
49
  debug_commands: bool = False,
82
50
  agent: str | None = None,
83
51
  load_skills: bool = True,
84
52
  config_path: str | None = None,
53
+ transport: Transport = "stdio",
85
54
  ) -> None:
86
55
  """Initialize ACP server with configuration.
87
56
 
@@ -90,27 +59,24 @@ class ACPServer(BaseServer):
90
59
  name: Optional Server name (auto-generated if None)
91
60
  file_access: Whether to support file access operations
92
61
  terminal_access: Whether to support terminal access operations
93
- providers: List of providers to use for model discovery (None = openrouter)
94
62
  debug_messages: Whether to enable debug message logging
95
63
  debug_file: File path for debug message logging
96
64
  debug_commands: Whether to enable debug slash commands for testing
97
65
  agent: Optional specific agent name to use (defaults to first agent)
98
66
  load_skills: Whether to load client-side skills from .claude/skills
99
67
  config_path: Path to the configuration file (for tracking/hot-switching)
68
+ transport: Transport configuration ("stdio", "websocket", or transport object)
100
69
  """
101
70
  super().__init__(pool, name=name, raise_exceptions=True)
102
71
  self.file_access = file_access
103
72
  self.terminal_access = terminal_access
104
- self.providers = providers or ["openai", "anthropic", "gemini"]
105
73
  self.debug_messages = debug_messages
106
74
  self.debug_file = debug_file
107
75
  self.debug_commands = debug_commands
108
76
  self.agent = agent
109
77
  self.load_skills = load_skills
110
78
  self.config_path = config_path
111
-
112
- self._available_models: list[ACPModelInfo] = []
113
- self._models_initialized = False
79
+ self.transport: Transport = transport
114
80
 
115
81
  @classmethod
116
82
  def from_config(
@@ -119,12 +85,12 @@ class ACPServer(BaseServer):
119
85
  *,
120
86
  file_access: bool = True,
121
87
  terminal_access: bool = True,
122
- providers: list[ProviderType] | None = None,
123
88
  debug_messages: bool = False,
124
89
  debug_file: str | None = None,
125
90
  debug_commands: bool = False,
126
91
  agent: str | None = None,
127
92
  load_skills: bool = True,
93
+ transport: Transport = "stdio",
128
94
  ) -> Self:
129
95
  """Create ACP server from existing agentpool configuration.
130
96
 
@@ -132,12 +98,12 @@ class ACPServer(BaseServer):
132
98
  config_path: Path to agentpool YAML config file
133
99
  file_access: Enable file system access
134
100
  terminal_access: Enable terminal access
135
- providers: List of provider types to use for model discovery
136
101
  debug_messages: Enable saving JSON messages to file
137
102
  debug_file: Path to debug file
138
103
  debug_commands: Enable debug slash commands for testing
139
104
  agent: Optional specific agent name to use (defaults to first agent)
140
105
  load_skills: Whether to load client-side skills from .claude/skills
106
+ transport: Transport configuration ("stdio", "websocket", or transport object)
141
107
 
142
108
  Returns:
143
109
  Configured ACP server instance with agent pool from config
@@ -148,13 +114,13 @@ class ACPServer(BaseServer):
148
114
  pool,
149
115
  file_access=file_access,
150
116
  terminal_access=terminal_access,
151
- providers=providers,
152
117
  debug_messages=debug_messages,
153
118
  debug_file=debug_file or "acp-debug.jsonl" if debug_messages else None,
154
119
  debug_commands=debug_commands,
155
120
  agent=agent,
156
121
  load_skills=load_skills,
157
122
  config_path=str(config_path),
123
+ transport=transport,
158
124
  )
159
125
  agent_names = list(server.pool.agents.keys())
160
126
 
@@ -170,13 +136,13 @@ class ACPServer(BaseServer):
170
136
 
171
137
  async def _start_async(self) -> None:
172
138
  """Start the ACP server (blocking async - runs until stopped)."""
173
- agent_names = list(self.pool.agents.keys())
174
- self.log.info("Starting ACP server on stdio", agent_names=agent_names)
175
- await self._initialize_models() # Initialize models on first run
139
+ transport_name = (
140
+ type(self.transport).__name__ if not isinstance(self.transport, str) else self.transport
141
+ )
142
+ self.log.info("Starting ACP server", transport=transport_name)
176
143
  create_acp_agent = functools.partial(
177
144
  AgentPoolACPAgent,
178
145
  agent_pool=self.pool,
179
- available_models=self._available_models,
180
146
  file_access=self.file_access,
181
147
  terminal_access=self.terminal_access,
182
148
  debug_commands=self.debug_commands,
@@ -184,27 +150,26 @@ class ACPServer(BaseServer):
184
150
  load_skills=self.load_skills,
185
151
  server=self,
186
152
  )
187
- reader, writer = await stdio_streams()
188
- file = self.debug_file if self.debug_messages else None
189
- conn = AgentSideConnection(create_acp_agent, writer, reader, debug_file=file)
153
+
154
+ debug_file = self.debug_file if self.debug_messages else None
190
155
  self.log.info("ACP server started", file=self.file_access, terminal=self.terminal_access)
191
- try: # Keep the connection alive until shutdown
192
- await self._shutdown_event.wait()
156
+
157
+ try:
158
+ await serve(
159
+ create_acp_agent,
160
+ transport=self.transport,
161
+ shutdown_event=self._shutdown_event,
162
+ debug_file=debug_file,
163
+ )
193
164
  except asyncio.CancelledError:
194
165
  self.log.info("ACP server shutdown requested")
195
166
  raise
196
167
  except KeyboardInterrupt:
197
168
  self.log.info("ACP server shutdown requested")
198
169
  except Exception:
199
- self.log.exception("Connection receive task failed")
200
- finally:
201
- await conn.close()
170
+ self.log.exception("ACP server error")
202
171
 
203
- async def swap_pool(
204
- self,
205
- config_path: str,
206
- agent: str | None = None,
207
- ) -> list[str]:
172
+ async def swap_pool(self, config_path: str, agent: str | None = None) -> list[str]:
208
173
  """Swap the current pool with a new one from config.
209
174
 
210
175
  This method handles the full lifecycle of swapping pools:
@@ -228,17 +193,14 @@ class ACPServer(BaseServer):
228
193
  self.log.info("Loading new pool configuration", config_path=config_path)
229
194
  new_manifest = AgentsManifest.from_file(config_path)
230
195
  new_pool = AgentPool(manifest=new_manifest)
231
-
232
196
  # 2. Validate agent exists in new pool if specified
233
197
  agent_names = list(new_pool.all_agents.keys())
234
198
  if not agent_names:
235
199
  msg = "New configuration contains no agents"
236
200
  raise ValueError(msg)
237
-
238
201
  if agent and agent not in agent_names:
239
202
  msg = f"Agent {agent!r} not found in new config. Available: {agent_names}"
240
203
  raise ValueError(msg)
241
-
242
204
  # 3. Enter new pool context first (so we can roll back if it fails)
243
205
  try:
244
206
  await new_pool.__aenter__()
@@ -246,43 +208,15 @@ class ACPServer(BaseServer):
246
208
  self.log.exception("Failed to initialize new pool")
247
209
  msg = f"Failed to initialize new pool: {e}"
248
210
  raise ValueError(msg) from e
249
-
250
211
  # 4. Exit old pool context
251
212
  old_pool = self.pool
252
213
  try:
253
214
  await old_pool.__aexit__(None, None, None)
254
215
  except Exception:
255
216
  self.log.exception("Error closing old pool (continuing with swap)")
256
-
257
217
  # 5. Update references
258
218
  self.pool = new_pool
259
219
  self.agent = agent
260
220
  self.config_path = config_path
261
-
262
221
  self.log.info("Pool swapped successfully", agent_names=agent_names, default_agent=agent)
263
222
  return agent_names
264
-
265
- @logfire.instrument("ACP: Initializing models.")
266
- async def _initialize_models(self) -> None:
267
- """Initialize available models using tokonomics model discovery.
268
-
269
- Converts tokonomics ModelInfo to ACP ModelInfo format at startup
270
- so all downstream code works with ACP types consistently.
271
- """
272
- from tokonomics.model_discovery import get_all_models
273
-
274
- if self._models_initialized:
275
- return
276
- try:
277
- self.log.info("Discovering available models...")
278
- delta = timedelta(days=200)
279
- toko_models = await get_all_models(providers=self.providers, max_age=delta)
280
- # Convert to ACP format once at startup
281
- self._available_models = _convert_to_acp_model_info(toko_models)
282
- self._models_initialized = True
283
- self.log.info("Discovered models", count=len(self._available_models))
284
- except Exception:
285
- self.log.exception("Failed to discover models")
286
- self._available_models = []
287
- finally:
288
- self._models_initialized = True