agentpool 2.1.9__py3-none-any.whl → 2.2.3__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 (174) hide show
  1. acp/__init__.py +13 -0
  2. acp/bridge/README.md +15 -2
  3. acp/bridge/__init__.py +3 -2
  4. acp/bridge/__main__.py +60 -19
  5. acp/bridge/ws_server.py +173 -0
  6. acp/bridge/ws_server_cli.py +89 -0
  7. acp/notifications.py +2 -1
  8. acp/stdio.py +39 -9
  9. acp/transports.py +362 -2
  10. acp/utils.py +15 -2
  11. agentpool/__init__.py +4 -1
  12. agentpool/agents/__init__.py +2 -0
  13. agentpool/agents/acp_agent/acp_agent.py +203 -88
  14. agentpool/agents/acp_agent/acp_converters.py +46 -21
  15. agentpool/agents/acp_agent/client_handler.py +157 -3
  16. agentpool/agents/acp_agent/session_state.py +4 -1
  17. agentpool/agents/agent.py +314 -107
  18. agentpool/agents/agui_agent/__init__.py +0 -2
  19. agentpool/agents/agui_agent/agui_agent.py +90 -21
  20. agentpool/agents/agui_agent/agui_converters.py +0 -131
  21. agentpool/agents/base_agent.py +163 -1
  22. agentpool/agents/claude_code_agent/claude_code_agent.py +626 -179
  23. agentpool/agents/claude_code_agent/converters.py +71 -3
  24. agentpool/agents/claude_code_agent/history.py +474 -0
  25. agentpool/agents/context.py +40 -0
  26. agentpool/agents/events/__init__.py +2 -0
  27. agentpool/agents/events/builtin_handlers.py +2 -1
  28. agentpool/agents/events/event_emitter.py +29 -2
  29. agentpool/agents/events/events.py +20 -0
  30. agentpool/agents/modes.py +54 -0
  31. agentpool/agents/tool_call_accumulator.py +213 -0
  32. agentpool/common_types.py +21 -0
  33. agentpool/config_resources/__init__.py +38 -1
  34. agentpool/config_resources/claude_code_agent.yml +3 -0
  35. agentpool/delegation/pool.py +37 -29
  36. agentpool/delegation/team.py +1 -0
  37. agentpool/delegation/teamrun.py +1 -0
  38. agentpool/diagnostics/__init__.py +53 -0
  39. agentpool/diagnostics/lsp_manager.py +1593 -0
  40. agentpool/diagnostics/lsp_proxy.py +41 -0
  41. agentpool/diagnostics/lsp_proxy_script.py +229 -0
  42. agentpool/diagnostics/models.py +398 -0
  43. agentpool/mcp_server/__init__.py +0 -2
  44. agentpool/mcp_server/client.py +12 -3
  45. agentpool/mcp_server/manager.py +25 -31
  46. agentpool/mcp_server/registries/official_registry_client.py +25 -0
  47. agentpool/mcp_server/tool_bridge.py +78 -66
  48. agentpool/messaging/__init__.py +0 -2
  49. agentpool/messaging/compaction.py +72 -197
  50. agentpool/messaging/message_history.py +12 -0
  51. agentpool/messaging/messages.py +52 -9
  52. agentpool/messaging/processing.py +3 -1
  53. agentpool/models/acp_agents/base.py +0 -22
  54. agentpool/models/acp_agents/mcp_capable.py +8 -148
  55. agentpool/models/acp_agents/non_mcp.py +129 -72
  56. agentpool/models/agents.py +35 -13
  57. agentpool/models/claude_code_agents.py +33 -2
  58. agentpool/models/manifest.py +43 -0
  59. agentpool/repomap.py +1 -1
  60. agentpool/resource_providers/__init__.py +9 -1
  61. agentpool/resource_providers/aggregating.py +52 -3
  62. agentpool/resource_providers/base.py +57 -1
  63. agentpool/resource_providers/mcp_provider.py +23 -0
  64. agentpool/resource_providers/plan_provider.py +130 -41
  65. agentpool/resource_providers/pool.py +2 -0
  66. agentpool/resource_providers/static.py +2 -0
  67. agentpool/sessions/__init__.py +2 -1
  68. agentpool/sessions/manager.py +31 -2
  69. agentpool/sessions/models.py +50 -0
  70. agentpool/skills/registry.py +13 -8
  71. agentpool/storage/manager.py +217 -1
  72. agentpool/testing.py +537 -19
  73. agentpool/utils/file_watcher.py +269 -0
  74. agentpool/utils/identifiers.py +121 -0
  75. agentpool/utils/pydantic_ai_helpers.py +46 -0
  76. agentpool/utils/streams.py +690 -1
  77. agentpool/utils/subprocess_utils.py +155 -0
  78. agentpool/utils/token_breakdown.py +461 -0
  79. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/METADATA +27 -7
  80. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/RECORD +170 -112
  81. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/WHEEL +1 -1
  82. agentpool_cli/__main__.py +4 -0
  83. agentpool_cli/serve_acp.py +41 -20
  84. agentpool_cli/serve_agui.py +87 -0
  85. agentpool_cli/serve_opencode.py +119 -0
  86. agentpool_commands/__init__.py +30 -0
  87. agentpool_commands/agents.py +74 -1
  88. agentpool_commands/history.py +62 -0
  89. agentpool_commands/mcp.py +176 -0
  90. agentpool_commands/models.py +56 -3
  91. agentpool_commands/tools.py +57 -0
  92. agentpool_commands/utils.py +51 -0
  93. agentpool_config/builtin_tools.py +77 -22
  94. agentpool_config/commands.py +24 -1
  95. agentpool_config/compaction.py +258 -0
  96. agentpool_config/mcp_server.py +131 -1
  97. agentpool_config/storage.py +46 -1
  98. agentpool_config/tools.py +7 -1
  99. agentpool_config/toolsets.py +92 -148
  100. agentpool_server/acp_server/acp_agent.py +134 -150
  101. agentpool_server/acp_server/commands/acp_commands.py +216 -51
  102. agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +10 -10
  103. agentpool_server/acp_server/server.py +23 -79
  104. agentpool_server/acp_server/session.py +181 -19
  105. agentpool_server/opencode_server/.rules +95 -0
  106. agentpool_server/opencode_server/ENDPOINTS.md +362 -0
  107. agentpool_server/opencode_server/__init__.py +27 -0
  108. agentpool_server/opencode_server/command_validation.py +172 -0
  109. agentpool_server/opencode_server/converters.py +869 -0
  110. agentpool_server/opencode_server/dependencies.py +24 -0
  111. agentpool_server/opencode_server/input_provider.py +269 -0
  112. agentpool_server/opencode_server/models/__init__.py +228 -0
  113. agentpool_server/opencode_server/models/agent.py +53 -0
  114. agentpool_server/opencode_server/models/app.py +60 -0
  115. agentpool_server/opencode_server/models/base.py +26 -0
  116. agentpool_server/opencode_server/models/common.py +23 -0
  117. agentpool_server/opencode_server/models/config.py +37 -0
  118. agentpool_server/opencode_server/models/events.py +647 -0
  119. agentpool_server/opencode_server/models/file.py +88 -0
  120. agentpool_server/opencode_server/models/mcp.py +25 -0
  121. agentpool_server/opencode_server/models/message.py +162 -0
  122. agentpool_server/opencode_server/models/parts.py +190 -0
  123. agentpool_server/opencode_server/models/provider.py +81 -0
  124. agentpool_server/opencode_server/models/pty.py +43 -0
  125. agentpool_server/opencode_server/models/session.py +99 -0
  126. agentpool_server/opencode_server/routes/__init__.py +25 -0
  127. agentpool_server/opencode_server/routes/agent_routes.py +442 -0
  128. agentpool_server/opencode_server/routes/app_routes.py +139 -0
  129. agentpool_server/opencode_server/routes/config_routes.py +241 -0
  130. agentpool_server/opencode_server/routes/file_routes.py +392 -0
  131. agentpool_server/opencode_server/routes/global_routes.py +94 -0
  132. agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
  133. agentpool_server/opencode_server/routes/message_routes.py +705 -0
  134. agentpool_server/opencode_server/routes/pty_routes.py +299 -0
  135. agentpool_server/opencode_server/routes/session_routes.py +1205 -0
  136. agentpool_server/opencode_server/routes/tui_routes.py +139 -0
  137. agentpool_server/opencode_server/server.py +430 -0
  138. agentpool_server/opencode_server/state.py +121 -0
  139. agentpool_server/opencode_server/time_utils.py +8 -0
  140. agentpool_storage/__init__.py +16 -0
  141. agentpool_storage/base.py +103 -0
  142. agentpool_storage/claude_provider.py +907 -0
  143. agentpool_storage/file_provider.py +129 -0
  144. agentpool_storage/memory_provider.py +61 -0
  145. agentpool_storage/models.py +3 -0
  146. agentpool_storage/opencode_provider.py +730 -0
  147. agentpool_storage/project_store.py +325 -0
  148. agentpool_storage/session_store.py +6 -0
  149. agentpool_storage/sql_provider/__init__.py +4 -2
  150. agentpool_storage/sql_provider/models.py +48 -0
  151. agentpool_storage/sql_provider/sql_provider.py +134 -1
  152. agentpool_storage/sql_provider/utils.py +10 -1
  153. agentpool_storage/text_log_provider.py +1 -0
  154. agentpool_toolsets/builtin/__init__.py +0 -8
  155. agentpool_toolsets/builtin/code.py +95 -56
  156. agentpool_toolsets/builtin/debug.py +16 -21
  157. agentpool_toolsets/builtin/execution_environment.py +99 -103
  158. agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
  159. agentpool_toolsets/builtin/skills.py +86 -4
  160. agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
  161. agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
  162. agentpool_toolsets/fsspec_toolset/grep.py +74 -2
  163. agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
  164. agentpool_toolsets/fsspec_toolset/toolset.py +159 -38
  165. agentpool_toolsets/mcp_discovery/__init__.py +5 -0
  166. agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
  167. agentpool_toolsets/mcp_discovery/toolset.py +454 -0
  168. agentpool_toolsets/mcp_run_toolset.py +84 -6
  169. agentpool_toolsets/builtin/agent_management.py +0 -239
  170. agentpool_toolsets/builtin/history.py +0 -36
  171. agentpool_toolsets/builtin/integration.py +0 -85
  172. agentpool_toolsets/builtin/tool_management.py +0 -90
  173. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/entry_points.txt +0 -0
  174. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -9,7 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  import asyncio
11
11
  import os
12
- from typing import Annotated
12
+ from typing import TYPE_CHECKING, Annotated, Literal
13
13
 
14
14
  from platformdirs import user_log_path
15
15
  import typer as t
@@ -17,6 +17,10 @@ import typer as t
17
17
  from agentpool_cli import log, resolve_agent_config
18
18
 
19
19
 
20
+ if TYPE_CHECKING:
21
+ from acp import Transport
22
+
23
+
20
24
  logger = log.get_logger(__name__)
21
25
 
22
26
 
@@ -49,13 +53,6 @@ def acp_command(
49
53
  help="File to save JSON-RPC debug messages (default: acp-debug.jsonl)",
50
54
  ),
51
55
  ] = None,
52
- providers: Annotated[
53
- list[str] | None,
54
- t.Option(
55
- "--model-provider",
56
- help="Providers to search for models (can be specified multiple times)",
57
- ),
58
- ] = None,
59
56
  debug_commands: Annotated[
60
57
  bool,
61
58
  t.Option(
@@ -77,6 +74,28 @@ def acp_command(
77
74
  help="Load client-side skills from .claude/skills directory",
78
75
  ),
79
76
  ] = True,
77
+ transport: Annotated[
78
+ Literal["stdio", "websocket"],
79
+ t.Option(
80
+ "--transport",
81
+ "-t",
82
+ help="Transport type: stdio (default) or websocket",
83
+ ),
84
+ ] = "stdio",
85
+ ws_host: Annotated[
86
+ str,
87
+ t.Option(
88
+ "--ws-host",
89
+ help="WebSocket host (only used with --transport websocket)",
90
+ ),
91
+ ] = "localhost",
92
+ ws_port: Annotated[
93
+ int,
94
+ t.Option(
95
+ "--ws-port",
96
+ help="WebSocket port (only used with --transport websocket)",
97
+ ),
98
+ ] = 8765,
80
99
  ) -> None:
81
100
  r"""Run agents as an ACP (Agent Client Protocol) server.
82
101
 
@@ -99,9 +118,19 @@ def acp_command(
99
118
  allowing users to switch between agents mid-conversation. Each agent appears
100
119
  as a different "mode" with its own name and capabilities.
101
120
  """
121
+ from acp import StdioTransport, WebSocketTransport
102
122
  from agentpool import log
123
+ from agentpool.config_resources import ACP_ASSISTANT
103
124
  from agentpool_server.acp_server import ACPServer
104
125
 
126
+ # Build transport config
127
+ if transport == "websocket":
128
+ transport_config: Transport = WebSocketTransport(host=ws_host, port=ws_port)
129
+ elif transport == "stdio":
130
+ transport_config = StdioTransport()
131
+ else:
132
+ raise t.BadParameter(f"Unknown transport: {transport}. Use 'stdio' or 'websocket'.")
133
+
105
134
  # Always log to file with rollover
106
135
  log_dir = user_log_path("agentpool", appauthor=False)
107
136
  log_dir.mkdir(parents=True, exist_ok=True)
@@ -117,40 +146,32 @@ def acp_command(
117
146
  msg = str(e)
118
147
  raise t.BadParameter(msg) from e
119
148
 
120
- logger.info("Starting ACP server", config_path=config_path)
149
+ logger.info("Starting ACP server", config_path=config_path, transport=transport)
121
150
  acp_server = ACPServer.from_config(
122
151
  config_path,
123
152
  file_access=file_access,
124
153
  terminal_access=terminal_access,
125
- providers=providers, # type: ignore[arg-type]
126
154
  debug_messages=debug_messages,
127
155
  debug_file=debug_file or "acp-debug.jsonl" if debug_messages else None,
128
156
  debug_commands=debug_commands,
129
157
  agent=agent,
130
158
  load_skills=load_skills,
159
+ transport=transport_config,
131
160
  )
132
161
  else:
133
162
  # Use default ACP assistant config
134
- from agentpool.config_resources import ACP_ASSISTANT
135
-
136
- logger.info("Starting ACP server with default configuration")
163
+ logger.info("Starting ACP server with default configuration", transport=transport)
137
164
  acp_server = ACPServer.from_config(
138
165
  ACP_ASSISTANT,
139
166
  file_access=file_access,
140
167
  terminal_access=terminal_access,
141
- providers=providers, # type: ignore[arg-type]
142
168
  debug_messages=debug_messages,
143
169
  debug_file=debug_file or "acp-debug.jsonl" if debug_messages else None,
144
170
  debug_commands=debug_commands,
145
171
  agent=agent,
146
172
  load_skills=load_skills,
173
+ transport=transport_config,
147
174
  )
148
- # Configure agent capabilities
149
- agent_count = len(acp_server.pool.all_agents)
150
- if agent_count == 0:
151
- logger.error("No agents found in configuration")
152
- raise t.Exit(1)
153
- logger.info("Configured agents for ACP protocol", count=agent_count)
154
175
  if show_messages:
155
176
  logger.info("Message activity logging enabled")
156
177
  if debug_messages:
@@ -0,0 +1,87 @@
1
+ """Command for running agents as an AG-UI server."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from typing import TYPE_CHECKING, Annotated, Any
7
+
8
+ import typer as t
9
+
10
+ from agentpool_cli import resolve_agent_config
11
+ from agentpool_cli.log import get_logger
12
+
13
+
14
+ if TYPE_CHECKING:
15
+ from agentpool import ChatMessage
16
+
17
+
18
+ logger = get_logger(__name__)
19
+
20
+
21
+ def agui_command(
22
+ ctx: t.Context,
23
+ config: Annotated[str | None, t.Argument(help="Path to agent configuration")] = None,
24
+ host: Annotated[str, t.Option(help="Host to bind server to")] = "localhost",
25
+ port: Annotated[int, t.Option(help="Port to listen on")] = 8002,
26
+ show_messages: Annotated[
27
+ bool, t.Option("--show-messages", help="Show message activity")
28
+ ] = False,
29
+ ) -> None:
30
+ """Run agents as an AG-UI server.
31
+
32
+ This creates an AG-UI protocol server that makes your agents available
33
+ through the AG-UI interface, compatible with AG-UI clients like Toad.
34
+
35
+ Each agent is accessible at /{agent_name} route.
36
+ """
37
+ import anyio
38
+
39
+ from agentpool import AgentPool, AgentsManifest
40
+ from agentpool_server.agui_server import AGUIServer
41
+
42
+ logger.info("Server PID", pid=os.getpid())
43
+
44
+ def on_message(message: ChatMessage[Any]) -> None:
45
+ print(message.format(style="simple"))
46
+
47
+ try:
48
+ config_path = resolve_agent_config(config)
49
+ except ValueError as e:
50
+ msg = str(e)
51
+ raise t.BadParameter(msg) from e
52
+
53
+ manifest = AgentsManifest.from_file(config_path)
54
+
55
+ async def run_server() -> None:
56
+ async with AgentPool(manifest) as pool:
57
+ if show_messages:
58
+ for agent in pool.agents.values():
59
+ agent.message_sent.connect(on_message)
60
+
61
+ server = AGUIServer(pool, host=host, port=port)
62
+ async with server:
63
+ logger.info(
64
+ "AG-UI server started",
65
+ host=host,
66
+ port=port,
67
+ agents=list(pool.agents.keys()),
68
+ )
69
+ # List agent routes
70
+ for name, url in server.list_agent_routes().items():
71
+ logger.info("Agent route", agent=name, url=url)
72
+
73
+ async with server.run_context():
74
+ # Keep running until interrupted
75
+ try:
76
+ while True:
77
+ await anyio.sleep(1)
78
+ except KeyboardInterrupt:
79
+ logger.info("Shutting down AG-UI server")
80
+
81
+ anyio.run(run_server)
82
+
83
+
84
+ if __name__ == "__main__":
85
+ import typer
86
+
87
+ typer.run(agui_command)
@@ -0,0 +1,119 @@
1
+ """Command for running agents as an OpenCode-compatible server.
2
+
3
+ This creates an HTTP server that implements the OpenCode API protocol,
4
+ allowing OpenCode TUI and SDK clients to interact with AgentPool agents.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Annotated
10
+
11
+ from platformdirs import user_log_path
12
+ import typer as t
13
+
14
+ from agentpool_cli import log, resolve_agent_config
15
+
16
+
17
+ logger = log.get_logger(__name__)
18
+
19
+
20
+ def opencode_command(
21
+ config: Annotated[str | None, t.Argument(help="Path to agent configuration (optional)")] = None,
22
+ host: Annotated[
23
+ str,
24
+ t.Option("--host", "-h", help="Host to bind to"),
25
+ ] = "127.0.0.1",
26
+ port: Annotated[
27
+ int,
28
+ t.Option("--port", "-p", help="Port to listen on"),
29
+ ] = 4096,
30
+ agent: Annotated[
31
+ str | None,
32
+ t.Option(
33
+ "--agent",
34
+ help="Name of specific agent to use (defaults to first agent in config)",
35
+ ),
36
+ ] = None,
37
+ working_dir: Annotated[
38
+ str | None,
39
+ t.Option(
40
+ "--working-dir",
41
+ "-w",
42
+ help="Working directory for file operations (defaults to current directory)",
43
+ ),
44
+ ] = None,
45
+ ) -> None:
46
+ """Run agents as an OpenCode-compatible HTTP server.
47
+
48
+ This creates an HTTP server implementing the OpenCode API protocol,
49
+ enabling your AgentPool agents to work with OpenCode TUI and SDK clients.
50
+
51
+ Configuration:
52
+ Config file is optional. Without a config file, creates a general-purpose
53
+ agent with default settings similar to the ACP server.
54
+
55
+ Agent Selection:
56
+ Use --agent to specify which agent to use by name. Without this option,
57
+ the first agent in your config is used as the default (or "assistant"
58
+ if no config provided).
59
+
60
+ Examples:
61
+ # Start with default agent
62
+ agentpool serve-opencode
63
+
64
+ # Start with specific config
65
+ agentpool serve-opencode agents.yml
66
+
67
+ # Start on custom port with specific agent
68
+ agentpool serve-opencode --port 8080 --agent myagent agents.yml
69
+ """
70
+ from agentpool import AgentPool, log as ap_log
71
+ from agentpool.config_resources import CLAUDE_CODE_ASSISTANT
72
+ from agentpool_server.opencode_server import OpenCodeServer
73
+
74
+ # Always log to file with rollover
75
+ log_dir = user_log_path("agentpool", appauthor=False)
76
+ log_dir.mkdir(parents=True, exist_ok=True)
77
+ log_file = log_dir / "opencode.log"
78
+ ap_log.configure_logging(force=True, log_file=str(log_file))
79
+ logger.info("Configured file logging with rollover", log_file=str(log_file))
80
+
81
+ # Resolve config path (use default if not provided)
82
+ if config:
83
+ try:
84
+ config_path = resolve_agent_config(config)
85
+ except ValueError as e:
86
+ raise t.BadParameter(str(e)) from e
87
+ else:
88
+ config_path = CLAUDE_CODE_ASSISTANT
89
+
90
+ logger.info("Starting OpenCode server", config_path=config_path, host=host, port=port)
91
+
92
+ # Load agent from config
93
+ pool = AgentPool(config_path)
94
+
95
+ async def run_server() -> None:
96
+ async with pool:
97
+ server = OpenCodeServer(
98
+ pool,
99
+ host=host,
100
+ port=port,
101
+ working_dir=working_dir,
102
+ agent_name=agent,
103
+ )
104
+ logger.info("Server starting", url=f"http://{host}:{port}")
105
+ await server.run_async()
106
+
107
+ import asyncio
108
+
109
+ try:
110
+ asyncio.run(run_server())
111
+ except KeyboardInterrupt:
112
+ logger.info("OpenCode server shutdown requested")
113
+ except Exception as e:
114
+ logger.exception("OpenCode server error")
115
+ raise t.Exit(1) from e
116
+
117
+
118
+ if __name__ == "__main__":
119
+ t.run(opencode_command)
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  from agentpool_commands.base import NodeCommand
6
6
  from agentpool_commands.agents import (
7
7
  CreateAgentCommand,
8
+ CreateTeamCommand,
8
9
  ListAgentsCommand,
9
10
  ShowAgentCommand,
10
11
  # SwitchAgentCommand,
@@ -15,6 +16,12 @@ from agentpool_commands.connections import (
15
16
  ListConnectionsCommand,
16
17
  DisconnectAllCommand,
17
18
  )
19
+ from agentpool_commands.history import SearchHistoryCommand
20
+ from agentpool_commands.mcp import (
21
+ AddMCPServerCommand,
22
+ AddRemoteMCPServerCommand,
23
+ ListMCPServersCommand,
24
+ )
18
25
  from agentpool_commands.models import SetModelCommand
19
26
  from agentpool_commands.prompts import ListPromptsCommand, ShowPromptCommand
20
27
  from agentpool_commands.resources import (
@@ -28,6 +35,7 @@ from agentpool_commands.tools import (
28
35
  DisableToolCommand,
29
36
  EnableToolCommand,
30
37
  ListToolsCommand,
38
+ RegisterCodeToolCommand,
31
39
  RegisterToolCommand,
32
40
  ShowToolCommand,
33
41
  )
@@ -39,6 +47,7 @@ from agentpool_commands.workers import (
39
47
  from agentpool_commands.utils import (
40
48
  CopyClipboardCommand,
41
49
  EditAgentFileCommand,
50
+ GetLogsCommand,
42
51
  ShareHistoryCommand,
43
52
  )
44
53
  from typing import TYPE_CHECKING, Any
@@ -64,6 +73,7 @@ def get_agent_commands(**kwargs: Any) -> Sequence[BaseCommand | type[SlashedComm
64
73
  "enable_enable_tool": EnableToolCommand,
65
74
  "enable_disable_tool": DisableToolCommand,
66
75
  "enable_register_tool": RegisterToolCommand,
76
+ "enable_register_code_tool": RegisterCodeToolCommand,
67
77
  "enable_list_resources": ListResourcesCommand,
68
78
  "enable_show_resource": ShowResourceCommand,
69
79
  "enable_add_resource": AddResourceCommand,
@@ -77,6 +87,11 @@ def get_agent_commands(**kwargs: Any) -> Sequence[BaseCommand | type[SlashedComm
77
87
  "enable_list_connections": ListConnectionsCommand,
78
88
  "enable_disconnect_all": DisconnectAllCommand,
79
89
  "enable_read": ReadCommand,
90
+ "enable_add_mcp_server": AddMCPServerCommand,
91
+ "enable_add_remote_mcp_server": AddRemoteMCPServerCommand,
92
+ "enable_list_mcp_servers": ListMCPServersCommand,
93
+ "enable_search_history": SearchHistoryCommand,
94
+ "enable_get_logs": GetLogsCommand,
80
95
  }
81
96
  return [command for flag, command in command_map.items() if kwargs.get(flag, True)]
82
97
 
@@ -85,6 +100,7 @@ def get_pool_commands(**kwargs: Any) -> Sequence[BaseCommand | type[SlashedComma
85
100
  """Get commands that operate on multiple agents or the pool itself."""
86
101
  command_map = {
87
102
  "enable_create_agent": CreateAgentCommand,
103
+ "enable_create_team": CreateTeamCommand,
88
104
  "enable_list_agents": ListAgentsCommand,
89
105
  "enable_show_agent": ShowAgentCommand,
90
106
  "enable_edit_agent_file": EditAgentFileCommand,
@@ -123,6 +139,7 @@ def get_commands(
123
139
  enable_enable_tool: bool = True,
124
140
  enable_disable_tool: bool = True,
125
141
  enable_register_tool: bool = True,
142
+ enable_register_code_tool: bool = True,
126
143
  enable_list_resources: bool = True,
127
144
  enable_show_resource: bool = True,
128
145
  enable_add_resource: bool = True,
@@ -136,7 +153,13 @@ def get_commands(
136
153
  enable_list_connections: bool = True,
137
154
  enable_disconnect_all: bool = True,
138
155
  enable_read: bool = True,
156
+ enable_add_mcp_server: bool = True,
157
+ enable_add_remote_mcp_server: bool = True,
158
+ enable_list_mcp_servers: bool = True,
159
+ enable_search_history: bool = True,
160
+ enable_get_logs: bool = True,
139
161
  enable_create_agent: bool = True,
162
+ enable_create_team: bool = True,
140
163
  enable_list_agents: bool = True,
141
164
  enable_show_agent: bool = True,
142
165
  enable_edit_agent_file: bool = True,
@@ -153,6 +176,7 @@ def get_commands(
153
176
  "enable_enable_tool": enable_enable_tool,
154
177
  "enable_disable_tool": enable_disable_tool,
155
178
  "enable_register_tool": enable_register_tool,
179
+ "enable_register_code_tool": enable_register_code_tool,
156
180
  "enable_list_resources": enable_list_resources,
157
181
  "enable_show_resource": enable_show_resource,
158
182
  "enable_add_resource": enable_add_resource,
@@ -166,9 +190,15 @@ def get_commands(
166
190
  "enable_list_connections": enable_list_connections,
167
191
  "enable_disconnect_all": enable_disconnect_all,
168
192
  "enable_read": enable_read,
193
+ "enable_add_mcp_server": enable_add_mcp_server,
194
+ "enable_add_remote_mcp_server": enable_add_remote_mcp_server,
195
+ "enable_list_mcp_servers": enable_list_mcp_servers,
196
+ "enable_search_history": enable_search_history,
197
+ "enable_get_logs": enable_get_logs,
169
198
  }
170
199
  pool_kwargs = {
171
200
  "enable_create_agent": enable_create_agent,
201
+ "enable_create_team": enable_create_team,
172
202
  "enable_list_agents": enable_list_agents,
173
203
  "enable_show_agent": enable_show_agent,
174
204
  "enable_edit_agent_file": enable_edit_agent_file,
@@ -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
 
@@ -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