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
@@ -2,15 +2,21 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from typing import TYPE_CHECKING, Any, Literal
6
+
5
7
  from slashed import CommandContext, CommandError # noqa: TC002
6
8
  from slashed.completers import CallbackCompleter
7
9
 
8
10
  from agentpool.messaging.context import NodeContext # noqa: TC001
9
11
  from agentpool_commands.base import NodeCommand
10
- from agentpool_commands.completers import get_available_agents
12
+ from agentpool_commands.completers import get_available_agents, get_available_nodes
11
13
  from agentpool_commands.markdown_utils import format_table
12
14
 
13
15
 
16
+ if TYPE_CHECKING:
17
+ from agentpool.delegation import BaseTeam
18
+
19
+
14
20
  class CreateAgentCommand(NodeCommand):
15
21
  """Create a new agent in the current session.
16
22
 
@@ -71,7 +77,7 @@ class CreateAgentCommand(NodeCommand):
71
77
  # Create and register the new agent
72
78
  await ctx.context.pool.add_agent(
73
79
  name=agent_name,
74
- model=model or current_agent.model_name,
80
+ model=model or current_agent.model_name or "openai:gpt-4o-mini",
75
81
  system_prompt=system_prompt or (),
76
82
  description=description,
77
83
  tools=tool_list,
@@ -197,3 +203,70 @@ class SwitchAgentCommand(NodeCommand):
197
203
  def get_completer(self) -> CallbackCompleter:
198
204
  """Get completer for agent names."""
199
205
  return CallbackCompleter(get_available_agents)
206
+
207
+
208
+ class CreateTeamCommand(NodeCommand):
209
+ """Create a team from existing agents/nodes.
210
+
211
+ Teams allow multiple agents to work together, either in parallel
212
+ or sequentially (pipeline).
213
+
214
+ Options:
215
+ --mode sequential|parallel How the team operates (default: sequential)
216
+
217
+ Examples:
218
+ # Create a team named "crew" with alice and bob
219
+ /create-team crew alice bob
220
+
221
+ # Create a parallel team
222
+ /create-team reviewers alice bob --mode parallel
223
+ """
224
+
225
+ name = "create-team"
226
+ category = "agents"
227
+
228
+ async def execute_command(
229
+ self,
230
+ ctx: CommandContext[NodeContext],
231
+ name: str,
232
+ *nodes: str,
233
+ mode: Literal["sequential", "parallel"] = "sequential",
234
+ ) -> None:
235
+ """Create a team from existing nodes.
236
+
237
+ Args:
238
+ ctx: Command context
239
+ name: Name for the team
240
+ nodes: Names of agents/teams to include
241
+ mode: How the team operates (sequential or parallel)
242
+ """
243
+ if not ctx.context.pool:
244
+ msg = "No agent pool available"
245
+ raise CommandError(msg)
246
+
247
+ if len(nodes) < 2: # noqa: PLR2004
248
+ msg = "At least 2 members are required to create a team"
249
+ raise CommandError(msg)
250
+
251
+ # Verify all nodes exist
252
+ node_list = list(nodes)
253
+ for node_name in node_list:
254
+ if node_name not in ctx.context.pool.nodes:
255
+ available = ", ".join(ctx.context.pool.nodes.keys())
256
+ msg = f"Node '{node_name}' not found. Available: {available}"
257
+ raise CommandError(msg)
258
+
259
+ # Create the team
260
+ if mode == "sequential":
261
+ team: BaseTeam[Any, Any] = ctx.context.pool.create_team_run(node_list, name=name)
262
+ else:
263
+ team = ctx.context.pool.create_team(node_list, name=name)
264
+
265
+ mode_str = "pipeline" if mode == "sequential" else "parallel"
266
+ await ctx.print(
267
+ f"**Created {mode_str} team** `{team.name}` with nodes: `{', '.join(node_list)}`"
268
+ )
269
+
270
+ def get_completer(self) -> CallbackCompleter:
271
+ """Get completer for node names."""
272
+ return CallbackCompleter(get_available_nodes)
@@ -0,0 +1,62 @@
1
+ """History management commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slashed import CommandContext, CommandError # noqa: TC002
6
+
7
+ from agentpool.messaging.context import NodeContext # noqa: TC001
8
+ from agentpool_commands.base import NodeCommand
9
+
10
+
11
+ class SearchHistoryCommand(NodeCommand):
12
+ """Search conversation history.
13
+
14
+ Search through past conversations with optional filtering.
15
+
16
+ Options:
17
+ --hours N Look back N hours (default: 24)
18
+ --limit N Maximum results to return (default: 5)
19
+
20
+ Examples:
21
+ /search-history # Recent conversations
22
+ /search-history "error handling" # Search for specific topic
23
+ /search-history --hours 48 --limit 10
24
+ """
25
+
26
+ name = "search-history"
27
+ category = "history"
28
+
29
+ async def execute_command(
30
+ self,
31
+ ctx: CommandContext[NodeContext],
32
+ query: str | None = None,
33
+ *,
34
+ hours: int = 24,
35
+ limit: int = 5,
36
+ ) -> None:
37
+ """Search conversation history.
38
+
39
+ Args:
40
+ ctx: Command context
41
+ query: Optional search query
42
+ hours: Look back period in hours
43
+ limit: Maximum results to return
44
+ """
45
+ if not ctx.context.pool:
46
+ msg = "No agent pool available for history search"
47
+ raise CommandError(msg)
48
+
49
+ try:
50
+ from agentpool_storage.formatters import format_output
51
+
52
+ provider = ctx.context.pool.storage.get_history_provider()
53
+ results = await provider.get_filtered_conversations(
54
+ query=query,
55
+ period=f"{hours}h",
56
+ limit=limit,
57
+ )
58
+ output = format_output(results)
59
+ await ctx.print(f"## Search Results\n\n{output}")
60
+ except Exception as e:
61
+ msg = f"Failed to search history: {e}"
62
+ raise CommandError(msg) from e
@@ -0,0 +1,176 @@
1
+ """MCP server management commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any, Literal
6
+
7
+ from pydantic import HttpUrl
8
+ from slashed import CommandContext, CommandError # noqa: TC002
9
+
10
+ from agentpool_commands.base import NodeCommand
11
+
12
+
13
+ if TYPE_CHECKING:
14
+ from agentpool.agents.context import AgentContext
15
+ from agentpool.messaging import MessageNode
16
+ from agentpool_config.mcp_server import MCPServerConfig
17
+
18
+
19
+ class AddMCPServerCommand(NodeCommand):
20
+ """Add a local MCP server via stdio transport.
21
+
22
+ Registers a new MCP server that runs as a subprocess.
23
+
24
+ Options:
25
+ --args "arg1|arg2" Pipe-separated command arguments
26
+ --env "KEY=val|KEY2=val" Pipe-separated environment variables
27
+
28
+ Examples:
29
+ /add-mcp-server myserver npx --args "mcp-server-filesystem|/tmp"
30
+ /add-mcp-server graphql npx --args "mcp-graphql" --env "ENDPOINT=https://api.example.com/graphql"
31
+ """
32
+
33
+ name = "add-mcp-server"
34
+ category = "integrations"
35
+
36
+ @classmethod
37
+ def supports_node(cls, node: MessageNode[Any, Any]) -> bool:
38
+ from agentpool import Agent
39
+
40
+ return isinstance(node, Agent)
41
+
42
+ async def execute_command(
43
+ self,
44
+ ctx: CommandContext[AgentContext],
45
+ name: str,
46
+ command: str,
47
+ *,
48
+ args: str | None = None,
49
+ env: str | None = None,
50
+ ) -> None:
51
+ """Add a local MCP server.
52
+
53
+ Args:
54
+ ctx: Command context
55
+ name: Unique name for the MCP server
56
+ command: Command to execute for the server
57
+ args: Pipe-separated command arguments
58
+ env: Pipe-separated environment variables (KEY=value format)
59
+ """
60
+ from agentpool_config.mcp_server import StdioMCPServerConfig
61
+
62
+ try:
63
+ # Parse arguments
64
+ arg_list = [a.strip() for a in args.split("|")] if args else []
65
+ # Parse environment variables
66
+ env_dict: dict[str, str] = {}
67
+ if env:
68
+ for pair in env.split("|"):
69
+ if "=" in pair:
70
+ key, value = pair.split("=", 1)
71
+ env_dict[key.strip()] = value.strip()
72
+
73
+ config = StdioMCPServerConfig(name=name, command=command, args=arg_list, env=env_dict)
74
+ await ctx.context.agent.mcp.setup_server(config, add_to_config=True)
75
+ await ctx.print(f"**Added MCP server** `{name}` with command: `{command}`")
76
+
77
+ except Exception as e:
78
+ msg = f"Failed to add MCP server: {e}"
79
+ raise CommandError(msg) from e
80
+
81
+
82
+ class AddRemoteMCPServerCommand(NodeCommand):
83
+ """Add a remote MCP server via HTTP transport.
84
+
85
+ Connects to an MCP server running on a remote URL.
86
+
87
+ Options:
88
+ --transport sse|streamable-http Transport type (default: streamable-http)
89
+
90
+ Examples:
91
+ /add-remote-mcp-server myapi https://api.example.com/mcp
92
+ /add-remote-mcp-server legacy https://old.api.com/mcp --transport sse
93
+ """
94
+
95
+ name = "add-remote-mcp-server"
96
+ category = "integrations"
97
+
98
+ @classmethod
99
+ def supports_node(cls, node: MessageNode[Any, Any]) -> bool:
100
+ from agentpool import Agent
101
+
102
+ return isinstance(node, Agent)
103
+
104
+ async def execute_command(
105
+ self,
106
+ ctx: CommandContext[AgentContext],
107
+ name: str,
108
+ url: str,
109
+ *,
110
+ transport: Literal["sse", "streamable-http"] = "streamable-http",
111
+ ) -> None:
112
+ """Add a remote MCP server.
113
+
114
+ Args:
115
+ ctx: Command context
116
+ name: Unique name for the MCP server
117
+ url: Server URL endpoint
118
+ transport: HTTP transport type (sse or streamable-http)
119
+ """
120
+ from agentpool_config.mcp_server import SSEMCPServerConfig, StreamableHTTPMCPServerConfig
121
+
122
+ try:
123
+ config: MCPServerConfig
124
+ if transport == "sse":
125
+ config = SSEMCPServerConfig(name=name, url=HttpUrl(url))
126
+ else:
127
+ config = StreamableHTTPMCPServerConfig(name=name, url=HttpUrl(url))
128
+
129
+ await ctx.context.agent.mcp.setup_server(config, add_to_config=True)
130
+ await ctx.print(f"**Added remote MCP server** `{name}` at `{url}` using {transport}")
131
+
132
+ except Exception as e:
133
+ msg = f"Failed to add remote MCP server: {e}"
134
+ raise CommandError(msg) from e
135
+
136
+
137
+ class ListMCPServersCommand(NodeCommand):
138
+ """List all configured MCP servers.
139
+
140
+ Shows server name, type, and connection status.
141
+ """
142
+
143
+ name = "list-mcp-servers"
144
+ category = "integrations"
145
+
146
+ @classmethod
147
+ def supports_node(cls, node: MessageNode[Any, Any]) -> bool:
148
+ from agentpool import Agent
149
+
150
+ return isinstance(node, Agent)
151
+
152
+ async def execute_command(self, ctx: CommandContext[AgentContext]) -> None:
153
+ """List all MCP servers.
154
+
155
+ Args:
156
+ ctx: Command context
157
+ """
158
+ from agentpool_commands.markdown_utils import format_table
159
+
160
+ servers = ctx.context.agent.mcp.providers
161
+ if not servers:
162
+ await ctx.print("No MCP servers configured.")
163
+ return
164
+
165
+ rows = []
166
+ for server in servers:
167
+ server_type = type(server.server).__name__.replace("MCPServerConfig", "")
168
+ rows.append({
169
+ "Name": server.name,
170
+ "Type": server_type,
171
+ "Status": "connected" if server.client.connected else "disconnected",
172
+ })
173
+
174
+ headers = ["Name", "Type", "Status"]
175
+ table = format_table(headers, rows)
176
+ await ctx.print(f"## MCP Servers\n\n{table}")
@@ -16,6 +16,59 @@ if TYPE_CHECKING:
16
16
  from agentpool.messaging import MessageNode
17
17
 
18
18
 
19
+ class ListModelsCommand(NodeCommand):
20
+ """List available models for the current agent.
21
+
22
+ Displays all models that can be used with the current agent,
23
+ formatted as a markdown table with model ID, name, and description.
24
+
25
+ Examples:
26
+ /list-models
27
+ """
28
+
29
+ name = "list-models"
30
+ category = "model"
31
+
32
+ async def execute_command(
33
+ self,
34
+ ctx: CommandContext[AgentContext],
35
+ ) -> None:
36
+ """List available models.
37
+
38
+ Args:
39
+ ctx: Command context
40
+ """
41
+ agent = ctx.context.agent
42
+ models = await agent.get_available_models()
43
+
44
+ if not models:
45
+ await ctx.print("No models available for this agent.")
46
+ return
47
+
48
+ # Build markdown table
49
+ lines = [
50
+ "| Model ID | Name | Description |",
51
+ "|----------|------|-------------|",
52
+ ]
53
+
54
+ for model in models:
55
+ model_id = model.id_override if model.id_override else model.id
56
+ name = model.name or ""
57
+ description = model.description or ""
58
+ # Escape pipe characters in fields
59
+ name = name.replace("|", "\\|")
60
+ description = description.replace("|", "\\|")
61
+ lines.append(f"| `{model_id}` | {name} | {description} |")
62
+
63
+ await ctx.print("\n".join(lines))
64
+
65
+ @classmethod
66
+ def supports_node(cls, node: MessageNode[Any, Any]) -> bool:
67
+ from agentpool import ACPAgent, Agent, ClaudeCodeAgent
68
+
69
+ return isinstance(node, Agent | ACPAgent | ClaudeCodeAgent)
70
+
71
+
19
72
  class SetModelCommand(NodeCommand):
20
73
  """Change the language model for the current conversation.
21
74
 
@@ -46,7 +99,7 @@ class SetModelCommand(NodeCommand):
46
99
  """
47
100
  try:
48
101
  # Create new session with model override
49
- ctx.context.native_agent.set_model(model)
102
+ await ctx.context.agent.set_model(model)
50
103
  await ctx.print(f"โœ… **Model changed to:** `{model}`")
51
104
  except Exception as e: # noqa: BLE001
52
105
  await ctx.print(f"โŒ **Failed to change model:** {e}")
@@ -57,6 +110,6 @@ class SetModelCommand(NodeCommand):
57
110
 
58
111
  @classmethod
59
112
  def supports_node(cls, node: MessageNode[Any, Any]) -> bool:
60
- from agentpool import Agent
113
+ from agentpool import ACPAgent, Agent, ClaudeCodeAgent
61
114
 
62
- return isinstance(node, Agent)
115
+ return isinstance(node, Agent | ACPAgent | ClaudeCodeAgent)
@@ -0,0 +1,260 @@
1
+ """Pool-level commands for managing agent pools and configurations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from agentpool.agents.base_agent import BaseAgent
8
+ from agentpool_commands.base import NodeCommand
9
+
10
+
11
+ if TYPE_CHECKING:
12
+ from slashed import CommandContext
13
+
14
+ from agentpool.messaging.context import NodeContext
15
+
16
+
17
+ class ListPoolsCommand(NodeCommand):
18
+ """List available agent pool configurations.
19
+
20
+ Examples:
21
+ /list-pools
22
+ """
23
+
24
+ name = "list-pools"
25
+ category = "pool"
26
+
27
+ async def execute_command(self, ctx: CommandContext[NodeContext[Any]]) -> None:
28
+ """List available pool configurations.
29
+
30
+ Args:
31
+ ctx: Command context with node context
32
+ """
33
+ from agentpool_cli import agent_store
34
+
35
+ try:
36
+ output_lines = ["## ๐ŸŠ Agent Pool Configurations\n"]
37
+
38
+ # Show current pool info
39
+ output_lines.append("### ๐Ÿ“ Current Pool")
40
+
41
+ # Get config path from context config (works for all agent types)
42
+ current_config = ctx.context.config.config_file_path if ctx.context.config else None
43
+ if current_config:
44
+ output_lines.append(f"**Config:** `{current_config}`")
45
+ else:
46
+ output_lines.append("**Config:** *(default/built-in)*")
47
+
48
+ # Show agents in current pool
49
+ pool = ctx.context.pool
50
+ if pool:
51
+ agent_names = list(pool.all_agents.keys())
52
+ output_lines.append(f"**Agents:** {', '.join(f'`{n}`' for n in agent_names)}")
53
+ output_lines.append(f"**Active agent:** `{ctx.context.node.name}`")
54
+ else:
55
+ output_lines.append("**No pool available**")
56
+ output_lines.append("")
57
+
58
+ # Show stored configurations
59
+ output_lines.append("### ๐Ÿ’พ Stored Configurations")
60
+ stored_configs = agent_store.list_configs()
61
+ active_config = agent_store.get_active()
62
+
63
+ if not stored_configs:
64
+ output_lines.append("*No stored configurations*")
65
+ output_lines.append("")
66
+ output_lines.append("Use `agentpool add <name> <path>` to add configurations.")
67
+ else:
68
+ # Build markdown table
69
+ output_lines.append("| Name | Path |")
70
+ output_lines.append("|------|------|")
71
+ for name, path in stored_configs:
72
+ is_active = active_config and active_config.name == name
73
+ is_current = current_config and path == current_config
74
+ markers = []
75
+ if is_active:
76
+ markers.append("default")
77
+ if is_current:
78
+ markers.append("current")
79
+ name_col = f"{name} ({', '.join(markers)})" if markers else name
80
+ output_lines.append(f"| {name_col} | `{path}` |")
81
+
82
+ output_lines.append("")
83
+ output_lines.append("*Use `/set-pool <name>` or `/set-pool <path>` to switch pools.*")
84
+
85
+ await ctx.output.print("\n".join(output_lines))
86
+
87
+ except Exception as e: # noqa: BLE001
88
+ await ctx.output.print(f"โŒ **Error listing pools:** {e}")
89
+
90
+
91
+ class CompactCommand(NodeCommand):
92
+ """Compact the conversation history to reduce context size.
93
+
94
+ Uses the configured compaction pipeline from the agent pool manifest,
95
+ or falls back to a default summarizing pipeline.
96
+
97
+ Options:
98
+ --preset <name> Use a specific preset (minimal, balanced, summarizing)
99
+
100
+ Examples:
101
+ /compact
102
+ /compact --preset=minimal
103
+ """
104
+
105
+ name = "compact"
106
+ category = "pool"
107
+
108
+ async def execute_command(
109
+ self,
110
+ ctx: CommandContext[NodeContext[Any]],
111
+ *,
112
+ preset: str | None = None,
113
+ ) -> None:
114
+ """Compact the conversation history.
115
+
116
+ Args:
117
+ ctx: Command context with node context
118
+ preset: Optional preset name (minimal, balanced, summarizing)
119
+ """
120
+ from agentpool.agents.base_agent import BaseAgent
121
+
122
+ # Get agent from context
123
+ agent = ctx.context.node
124
+ if not isinstance(agent, BaseAgent):
125
+ await ctx.output.print(
126
+ "โŒ **This command requires an agent with conversation history**"
127
+ )
128
+ return
129
+
130
+ # Check if there's any history to compact
131
+ if not agent.conversation.get_history():
132
+ await ctx.output.print("๐Ÿ“ญ **No message history to compact**")
133
+ return
134
+
135
+ try:
136
+ # Get compaction pipeline
137
+ from agentpool.messaging.compaction import (
138
+ balanced_context,
139
+ minimal_context,
140
+ summarizing_context,
141
+ )
142
+
143
+ pipeline = None
144
+
145
+ # Check for preset override
146
+ if preset:
147
+ match preset.lower():
148
+ case "minimal":
149
+ pipeline = minimal_context()
150
+ case "balanced":
151
+ pipeline = balanced_context()
152
+ case "summarizing":
153
+ pipeline = summarizing_context()
154
+ case _:
155
+ await ctx.output.print(
156
+ f"โš ๏ธ **Unknown preset:** `{preset}`\n"
157
+ "Available: minimal, balanced, summarizing"
158
+ )
159
+ return
160
+
161
+ # Fall back to pool's configured pipeline
162
+ if pipeline is None and ctx.context.pool:
163
+ pipeline = ctx.context.pool.compaction_pipeline
164
+
165
+ # Fall back to default summarizing pipeline
166
+ if pipeline is None:
167
+ pipeline = summarizing_context()
168
+
169
+ await ctx.output.print("๐Ÿ”„ **Compacting conversation history...**")
170
+
171
+ # Apply the pipeline using shared helper
172
+ from agentpool.messaging.compaction import compact_conversation
173
+
174
+ original_count, compacted_count = await compact_conversation(
175
+ pipeline, agent.conversation
176
+ )
177
+ reduction = original_count - compacted_count
178
+
179
+ await ctx.output.print(
180
+ f"โœ… **Compaction complete**\n"
181
+ f"- Messages: {original_count} โ†’ {compacted_count} ({reduction} removed)\n"
182
+ f"- Reduction: {reduction / original_count * 100:.1f}%"
183
+ if original_count > 0
184
+ else "โœ… **Compaction complete** (no messages)"
185
+ )
186
+
187
+ except Exception as e: # noqa: BLE001
188
+ await ctx.output.print(f"โŒ **Error compacting history:** {e}")
189
+
190
+
191
+ class SpawnCommand(NodeCommand):
192
+ """Spawn a subagent to execute a specific task.
193
+
194
+ The subagent runs and its progress is streamed back through the event system.
195
+ How the progress is displayed depends on the protocol (tool box in ACP, inline, etc.).
196
+
197
+ Examples:
198
+ /spawn agent-name "task description"
199
+ /spawn code-reviewer "Review main.py for bugs"
200
+ """
201
+
202
+ name = "spawn"
203
+ category = "pool"
204
+
205
+ @classmethod
206
+ def supports_node(cls, node: Any) -> bool:
207
+ """Only available when running from an agent (needs events)."""
208
+ return isinstance(node, BaseAgent)
209
+
210
+ async def execute_command(
211
+ self,
212
+ ctx: CommandContext[NodeContext[Any]],
213
+ agent_name: str,
214
+ task_prompt: str,
215
+ ) -> None:
216
+ """Spawn a subagent to execute a task.
217
+
218
+ Args:
219
+ ctx: Command context with node context
220
+ agent_name: Name of the agent to spawn
221
+ task_prompt: Task prompt for the subagent
222
+ """
223
+ from agentpool.agents.events import SubAgentEvent
224
+
225
+ pool = ctx.context.pool
226
+ if not pool:
227
+ await ctx.output.print("โŒ **No agent pool available**")
228
+ return
229
+
230
+ if agent_name not in pool.nodes:
231
+ available = list(pool.nodes.keys())
232
+ await ctx.output.print(
233
+ f"โŒ **Agent** `{agent_name}` **not found**\n\n"
234
+ f"Available agents: {', '.join(available)}"
235
+ )
236
+ return
237
+
238
+ from agentpool.common_types import SupportsRunStream
239
+
240
+ agent = pool.nodes[agent_name]
241
+
242
+ # Check if node supports streaming
243
+ if not isinstance(agent, SupportsRunStream):
244
+ await ctx.output.print(f"โŒ **Agent** `{agent_name}` **does not support streaming**")
245
+ return
246
+
247
+ # Stream subagent execution by wrapping events in SubAgentEvent
248
+ # The event handler system (ACP, OpenCode, CLI, etc.) handles rendering
249
+ # Get parent agent's context to access event emitter
250
+ parent_ctx = ctx.context.agent.get_context()
251
+
252
+ async for event in agent.run_stream(task_prompt):
253
+ wrapped = SubAgentEvent(
254
+ source_name=agent_name,
255
+ source_type="agent",
256
+ event=event,
257
+ depth=1,
258
+ )
259
+ # Emit to parent agent's event stream
260
+ await parent_ctx.events.emit_event(wrapped)
@@ -23,7 +23,7 @@ class ClearCommand(AgentCommand):
23
23
  Args:
24
24
  ctx: Command context
25
25
  """
26
- ctx.context.agent.conversation.clear()
26
+ await ctx.context.agent.conversation.clear()
27
27
  await ctx.print("๐Ÿงน **Chat history cleared**")
28
28
 
29
29