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.
- acp/__init__.py +13 -0
- acp/bridge/README.md +15 -2
- acp/bridge/__init__.py +3 -2
- acp/bridge/__main__.py +60 -19
- acp/bridge/ws_server.py +173 -0
- acp/bridge/ws_server_cli.py +89 -0
- acp/notifications.py +2 -1
- acp/stdio.py +39 -9
- acp/transports.py +362 -2
- acp/utils.py +15 -2
- agentpool/__init__.py +4 -1
- agentpool/agents/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +203 -88
- agentpool/agents/acp_agent/acp_converters.py +46 -21
- agentpool/agents/acp_agent/client_handler.py +157 -3
- agentpool/agents/acp_agent/session_state.py +4 -1
- agentpool/agents/agent.py +314 -107
- agentpool/agents/agui_agent/__init__.py +0 -2
- agentpool/agents/agui_agent/agui_agent.py +90 -21
- agentpool/agents/agui_agent/agui_converters.py +0 -131
- agentpool/agents/base_agent.py +163 -1
- agentpool/agents/claude_code_agent/claude_code_agent.py +626 -179
- agentpool/agents/claude_code_agent/converters.py +71 -3
- agentpool/agents/claude_code_agent/history.py +474 -0
- agentpool/agents/context.py +40 -0
- agentpool/agents/events/__init__.py +2 -0
- agentpool/agents/events/builtin_handlers.py +2 -1
- agentpool/agents/events/event_emitter.py +29 -2
- agentpool/agents/events/events.py +20 -0
- agentpool/agents/modes.py +54 -0
- agentpool/agents/tool_call_accumulator.py +213 -0
- agentpool/common_types.py +21 -0
- agentpool/config_resources/__init__.py +38 -1
- agentpool/config_resources/claude_code_agent.yml +3 -0
- agentpool/delegation/pool.py +37 -29
- agentpool/delegation/team.py +1 -0
- agentpool/delegation/teamrun.py +1 -0
- agentpool/diagnostics/__init__.py +53 -0
- agentpool/diagnostics/lsp_manager.py +1593 -0
- agentpool/diagnostics/lsp_proxy.py +41 -0
- agentpool/diagnostics/lsp_proxy_script.py +229 -0
- agentpool/diagnostics/models.py +398 -0
- agentpool/mcp_server/__init__.py +0 -2
- agentpool/mcp_server/client.py +12 -3
- agentpool/mcp_server/manager.py +25 -31
- agentpool/mcp_server/registries/official_registry_client.py +25 -0
- agentpool/mcp_server/tool_bridge.py +78 -66
- agentpool/messaging/__init__.py +0 -2
- agentpool/messaging/compaction.py +72 -197
- agentpool/messaging/message_history.py +12 -0
- agentpool/messaging/messages.py +52 -9
- agentpool/messaging/processing.py +3 -1
- agentpool/models/acp_agents/base.py +0 -22
- agentpool/models/acp_agents/mcp_capable.py +8 -148
- agentpool/models/acp_agents/non_mcp.py +129 -72
- agentpool/models/agents.py +35 -13
- agentpool/models/claude_code_agents.py +33 -2
- agentpool/models/manifest.py +43 -0
- agentpool/repomap.py +1 -1
- agentpool/resource_providers/__init__.py +9 -1
- agentpool/resource_providers/aggregating.py +52 -3
- agentpool/resource_providers/base.py +57 -1
- agentpool/resource_providers/mcp_provider.py +23 -0
- agentpool/resource_providers/plan_provider.py +130 -41
- agentpool/resource_providers/pool.py +2 -0
- agentpool/resource_providers/static.py +2 -0
- agentpool/sessions/__init__.py +2 -1
- agentpool/sessions/manager.py +31 -2
- agentpool/sessions/models.py +50 -0
- agentpool/skills/registry.py +13 -8
- agentpool/storage/manager.py +217 -1
- agentpool/testing.py +537 -19
- agentpool/utils/file_watcher.py +269 -0
- agentpool/utils/identifiers.py +121 -0
- agentpool/utils/pydantic_ai_helpers.py +46 -0
- agentpool/utils/streams.py +690 -1
- agentpool/utils/subprocess_utils.py +155 -0
- agentpool/utils/token_breakdown.py +461 -0
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/METADATA +27 -7
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/RECORD +170 -112
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +4 -0
- agentpool_cli/serve_acp.py +41 -20
- agentpool_cli/serve_agui.py +87 -0
- agentpool_cli/serve_opencode.py +119 -0
- agentpool_commands/__init__.py +30 -0
- agentpool_commands/agents.py +74 -1
- agentpool_commands/history.py +62 -0
- agentpool_commands/mcp.py +176 -0
- agentpool_commands/models.py +56 -3
- agentpool_commands/tools.py +57 -0
- agentpool_commands/utils.py +51 -0
- agentpool_config/builtin_tools.py +77 -22
- agentpool_config/commands.py +24 -1
- agentpool_config/compaction.py +258 -0
- agentpool_config/mcp_server.py +131 -1
- agentpool_config/storage.py +46 -1
- agentpool_config/tools.py +7 -1
- agentpool_config/toolsets.py +92 -148
- agentpool_server/acp_server/acp_agent.py +134 -150
- agentpool_server/acp_server/commands/acp_commands.py +216 -51
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +10 -10
- agentpool_server/acp_server/server.py +23 -79
- agentpool_server/acp_server/session.py +181 -19
- agentpool_server/opencode_server/.rules +95 -0
- agentpool_server/opencode_server/ENDPOINTS.md +362 -0
- agentpool_server/opencode_server/__init__.py +27 -0
- agentpool_server/opencode_server/command_validation.py +172 -0
- agentpool_server/opencode_server/converters.py +869 -0
- agentpool_server/opencode_server/dependencies.py +24 -0
- agentpool_server/opencode_server/input_provider.py +269 -0
- agentpool_server/opencode_server/models/__init__.py +228 -0
- agentpool_server/opencode_server/models/agent.py +53 -0
- agentpool_server/opencode_server/models/app.py +60 -0
- agentpool_server/opencode_server/models/base.py +26 -0
- agentpool_server/opencode_server/models/common.py +23 -0
- agentpool_server/opencode_server/models/config.py +37 -0
- agentpool_server/opencode_server/models/events.py +647 -0
- agentpool_server/opencode_server/models/file.py +88 -0
- agentpool_server/opencode_server/models/mcp.py +25 -0
- agentpool_server/opencode_server/models/message.py +162 -0
- agentpool_server/opencode_server/models/parts.py +190 -0
- agentpool_server/opencode_server/models/provider.py +81 -0
- agentpool_server/opencode_server/models/pty.py +43 -0
- agentpool_server/opencode_server/models/session.py +99 -0
- agentpool_server/opencode_server/routes/__init__.py +25 -0
- agentpool_server/opencode_server/routes/agent_routes.py +442 -0
- agentpool_server/opencode_server/routes/app_routes.py +139 -0
- agentpool_server/opencode_server/routes/config_routes.py +241 -0
- agentpool_server/opencode_server/routes/file_routes.py +392 -0
- agentpool_server/opencode_server/routes/global_routes.py +94 -0
- agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
- agentpool_server/opencode_server/routes/message_routes.py +705 -0
- agentpool_server/opencode_server/routes/pty_routes.py +299 -0
- agentpool_server/opencode_server/routes/session_routes.py +1205 -0
- agentpool_server/opencode_server/routes/tui_routes.py +139 -0
- agentpool_server/opencode_server/server.py +430 -0
- agentpool_server/opencode_server/state.py +121 -0
- agentpool_server/opencode_server/time_utils.py +8 -0
- agentpool_storage/__init__.py +16 -0
- agentpool_storage/base.py +103 -0
- agentpool_storage/claude_provider.py +907 -0
- agentpool_storage/file_provider.py +129 -0
- agentpool_storage/memory_provider.py +61 -0
- agentpool_storage/models.py +3 -0
- agentpool_storage/opencode_provider.py +730 -0
- agentpool_storage/project_store.py +325 -0
- agentpool_storage/session_store.py +6 -0
- agentpool_storage/sql_provider/__init__.py +4 -2
- agentpool_storage/sql_provider/models.py +48 -0
- agentpool_storage/sql_provider/sql_provider.py +134 -1
- agentpool_storage/sql_provider/utils.py +10 -1
- agentpool_storage/text_log_provider.py +1 -0
- agentpool_toolsets/builtin/__init__.py +0 -8
- agentpool_toolsets/builtin/code.py +95 -56
- agentpool_toolsets/builtin/debug.py +16 -21
- agentpool_toolsets/builtin/execution_environment.py +99 -103
- agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
- agentpool_toolsets/builtin/skills.py +86 -4
- agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
- agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
- agentpool_toolsets/fsspec_toolset/grep.py +74 -2
- agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
- agentpool_toolsets/fsspec_toolset/toolset.py +159 -38
- agentpool_toolsets/mcp_discovery/__init__.py +5 -0
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +454 -0
- agentpool_toolsets/mcp_run_toolset.py +84 -6
- agentpool_toolsets/builtin/agent_management.py +0 -239
- agentpool_toolsets/builtin/history.py +0 -36
- agentpool_toolsets/builtin/integration.py +0 -85
- agentpool_toolsets/builtin/tool_management.py +0 -90
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/entry_points.txt +0 -0
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/licenses/LICENSE +0 -0
agentpool_cli/serve_acp.py
CHANGED
|
@@ -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
|
-
|
|
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)
|
agentpool_commands/__init__.py
CHANGED
|
@@ -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,
|
agentpool_commands/agents.py
CHANGED
|
@@ -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
|