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
|
@@ -25,9 +25,13 @@ from agentpool.tools.base import Tool
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
28
|
+
from collections.abc import Sequence
|
|
29
|
+
|
|
28
30
|
from exxec import ExecutionEnvironment
|
|
31
|
+
from slashed import Command
|
|
29
32
|
|
|
30
33
|
from acp.schema import (
|
|
34
|
+
AvailableCommand,
|
|
31
35
|
CreateTerminalRequest,
|
|
32
36
|
KillTerminalCommandRequest,
|
|
33
37
|
ReadTextFileRequest,
|
|
@@ -98,11 +102,93 @@ class ACPClientHandler(Client):
|
|
|
98
102
|
return self._agent.config.allow_terminal
|
|
99
103
|
|
|
100
104
|
async def session_update(self, params: SessionNotification[Any]) -> None:
|
|
101
|
-
"""Handle session update notifications from the agent.
|
|
105
|
+
"""Handle session update notifications from the agent.
|
|
106
|
+
|
|
107
|
+
Some updates are state changes (mode, model, config) that should update
|
|
108
|
+
session state. Others are stream events (text chunks, tool calls) that
|
|
109
|
+
should be queued for the run_stream consumer.
|
|
110
|
+
"""
|
|
111
|
+
from acp.schema import (
|
|
112
|
+
AvailableCommandsUpdate,
|
|
113
|
+
ConfigOptionUpdate,
|
|
114
|
+
CurrentModelUpdate,
|
|
115
|
+
CurrentModeUpdate,
|
|
116
|
+
)
|
|
102
117
|
from agentpool.agents.acp_agent.acp_converters import acp_to_native_event
|
|
103
118
|
|
|
104
119
|
update = params.update
|
|
105
|
-
|
|
120
|
+
|
|
121
|
+
# Handle state updates - these modify session state, not stream events
|
|
122
|
+
match update:
|
|
123
|
+
case CurrentModeUpdate(current_mode_id=mode_id):
|
|
124
|
+
if self.state.modes:
|
|
125
|
+
self.state.modes.current_mode_id = mode_id
|
|
126
|
+
# Find ModeInfo and emit signal
|
|
127
|
+
for acp_mode in self.state.modes.available_modes:
|
|
128
|
+
if acp_mode.id == mode_id:
|
|
129
|
+
from agentpool.agents.modes import ModeInfo
|
|
130
|
+
|
|
131
|
+
mode_info = ModeInfo(
|
|
132
|
+
id=acp_mode.id,
|
|
133
|
+
name=acp_mode.name,
|
|
134
|
+
description=acp_mode.description or "",
|
|
135
|
+
category_id="remote",
|
|
136
|
+
)
|
|
137
|
+
await self._agent.state_updated.emit(mode_info)
|
|
138
|
+
break
|
|
139
|
+
self.state.current_mode_id = mode_id
|
|
140
|
+
logger.debug("Mode updated", mode_id=mode_id)
|
|
141
|
+
self._update_event.set()
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
case CurrentModelUpdate(current_model_id=model_id):
|
|
145
|
+
self.state.current_model_id = model_id
|
|
146
|
+
if self.state.models:
|
|
147
|
+
self.state.models.current_model_id = model_id
|
|
148
|
+
# Find ModelInfo and emit signal
|
|
149
|
+
for acp_model in self.state.models.available_models:
|
|
150
|
+
if acp_model.model_id == model_id:
|
|
151
|
+
from tokonomics.model_discovery.model_info import (
|
|
152
|
+
ModelInfo as TokoModelInfo,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
model_info = TokoModelInfo(
|
|
156
|
+
id=acp_model.model_id,
|
|
157
|
+
name=acp_model.name,
|
|
158
|
+
description=acp_model.description,
|
|
159
|
+
)
|
|
160
|
+
await self._agent.state_updated.emit(model_info)
|
|
161
|
+
break
|
|
162
|
+
logger.debug("Model updated", model_id=model_id)
|
|
163
|
+
self._update_event.set()
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
case ConfigOptionUpdate():
|
|
167
|
+
await self._agent.state_updated.emit(update)
|
|
168
|
+
logger.debug("Config option updated", update=update)
|
|
169
|
+
self._update_event.set()
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
case AvailableCommandsUpdate():
|
|
173
|
+
self.state.available_commands = update
|
|
174
|
+
# Populate command store with remote commands
|
|
175
|
+
self._populate_command_store(update.available_commands)
|
|
176
|
+
# Emit to parent session - remote commands will be merged with local ones.
|
|
177
|
+
# The "way back" works because session.split_commands() only extracts
|
|
178
|
+
# LOCAL commands; remote commands pass through to the agent prompt.
|
|
179
|
+
await self._agent.state_updated.emit(update)
|
|
180
|
+
logger.debug("Available commands updated", count=len(update.available_commands))
|
|
181
|
+
self._update_event.set()
|
|
182
|
+
return
|
|
183
|
+
|
|
184
|
+
# TODO: AgentPlanUpdate handling is complex and needs design work.
|
|
185
|
+
# Options:
|
|
186
|
+
# 1. Update pool.todos - requires merging with existing todos
|
|
187
|
+
# 2. Pass through to UI - but then todos aren't centrally managed
|
|
188
|
+
# 3. Switch to agent-owned todos instead of pool-owned
|
|
189
|
+
# For now, AgentPlanUpdate falls through to stream events.
|
|
190
|
+
|
|
191
|
+
# All other updates are stream events - convert and queue
|
|
106
192
|
if native_event := acp_to_native_event(update):
|
|
107
193
|
self.state.events.append(native_event)
|
|
108
194
|
self._update_event.set()
|
|
@@ -138,6 +224,8 @@ class ACPClientHandler(Client):
|
|
|
138
224
|
|
|
139
225
|
if self._input_provider:
|
|
140
226
|
ctx = self._agent.get_context() # Use the agent's NodeContext
|
|
227
|
+
# Attach tool_call_id for permission event matching in TUI
|
|
228
|
+
ctx.tool_call_id = params.tool_call.tool_call_id
|
|
141
229
|
# Create a dummy tool representation from ACP params
|
|
142
230
|
tool = Tool(callable=lambda: None, name=params.tool_call.tool_call_id, description=name)
|
|
143
231
|
# Extract arguments - ACP doesn't expose them in ToolCall
|
|
@@ -301,13 +389,79 @@ class ACPClientHandler(Client):
|
|
|
301
389
|
"""Handle extension notifications."""
|
|
302
390
|
logger.debug("Extension notification", method=method)
|
|
303
391
|
|
|
392
|
+
def _populate_command_store(self, commands: Sequence[AvailableCommand]) -> None:
|
|
393
|
+
"""Populate the agent's command store with remote ACP commands.
|
|
394
|
+
|
|
395
|
+
Args:
|
|
396
|
+
commands: List of AvailableCommand objects from the remote agent
|
|
397
|
+
"""
|
|
398
|
+
store = self._agent.command_store
|
|
399
|
+
|
|
400
|
+
for cmd in commands:
|
|
401
|
+
command = self._create_acp_command(cmd)
|
|
402
|
+
# Unregister if already exists (in case of update)
|
|
403
|
+
if store.get_command(cmd.name):
|
|
404
|
+
store.unregister_command(cmd.name)
|
|
405
|
+
store.register_command(command)
|
|
406
|
+
|
|
407
|
+
logger.debug("Populated command store", command_count=len(store.list_commands()))
|
|
408
|
+
|
|
409
|
+
def _create_acp_command(self, cmd: AvailableCommand) -> Command:
|
|
410
|
+
"""Create a slashed Command from an ACP AvailableCommand.
|
|
411
|
+
|
|
412
|
+
The command, when executed, sends a prompt with the slash command
|
|
413
|
+
to the remote ACP agent.
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
cmd: AvailableCommand from remote agent
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
A slashed Command that sends the command to the remote agent
|
|
420
|
+
"""
|
|
421
|
+
from pydantic_ai import PartDeltaEvent, TextPartDelta
|
|
422
|
+
from slashed import Command
|
|
423
|
+
|
|
424
|
+
name = cmd.name
|
|
425
|
+
description = cmd.description
|
|
426
|
+
input_hint = cmd.input.root.hint if cmd.input else None
|
|
427
|
+
|
|
428
|
+
async def execute_command(
|
|
429
|
+
ctx: Any,
|
|
430
|
+
args: list[str],
|
|
431
|
+
kwargs: dict[str, str],
|
|
432
|
+
) -> None:
|
|
433
|
+
"""Execute the remote ACP slash command."""
|
|
434
|
+
# Build command string
|
|
435
|
+
args_str = " ".join(args) if args else ""
|
|
436
|
+
if kwargs:
|
|
437
|
+
kwargs_str = " ".join(f"{k}={v}" for k, v in kwargs.items())
|
|
438
|
+
args_str = f"{args_str} {kwargs_str}".strip()
|
|
439
|
+
|
|
440
|
+
full_command = f"/{name} {args_str}".strip()
|
|
441
|
+
|
|
442
|
+
# Execute via agent run_stream - the slash command goes as a prompt
|
|
443
|
+
async for event in self._agent.run_stream(full_command):
|
|
444
|
+
# Extract text from PartDeltaEvent with TextPartDelta
|
|
445
|
+
if isinstance(event, PartDeltaEvent):
|
|
446
|
+
delta = event.delta
|
|
447
|
+
if isinstance(delta, TextPartDelta):
|
|
448
|
+
await ctx.print(delta.content_delta)
|
|
449
|
+
|
|
450
|
+
return Command.from_raw(
|
|
451
|
+
execute_command,
|
|
452
|
+
name=name,
|
|
453
|
+
description=description,
|
|
454
|
+
category="remote",
|
|
455
|
+
usage=input_hint,
|
|
456
|
+
)
|
|
457
|
+
|
|
304
458
|
|
|
305
459
|
if __name__ == "__main__":
|
|
306
460
|
from agentpool.agents.acp_agent import ACPAgent
|
|
307
461
|
|
|
308
462
|
async def main() -> None:
|
|
309
463
|
"""Demo: Basic call to an ACP agent."""
|
|
310
|
-
args = ["run", "agentpool", "serve-acp"
|
|
464
|
+
args = ["run", "agentpool", "serve-acp"]
|
|
311
465
|
cwd = str(Path.cwd())
|
|
312
466
|
async with ACPAgent(command="uv", args=args, cwd=cwd, event_handlers=["detailed"]) as agent:
|
|
313
467
|
print("Response (streaming): ", end="", flush=True)
|
|
@@ -9,7 +9,7 @@ from agentpool.log import get_logger
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
-
from acp.schema import SessionModelState, SessionModeState
|
|
12
|
+
from acp.schema import AvailableCommandsUpdate, SessionModelState, SessionModeState
|
|
13
13
|
from agentpool.agents.events import RichAgentStreamEvent
|
|
14
14
|
|
|
15
15
|
logger = get_logger(__name__)
|
|
@@ -39,6 +39,9 @@ class ACPSessionState:
|
|
|
39
39
|
current_mode_id: str | None = None
|
|
40
40
|
"""Current mode ID."""
|
|
41
41
|
|
|
42
|
+
available_commands: AvailableCommandsUpdate | None = None
|
|
43
|
+
"""Available commands from the agent."""
|
|
44
|
+
|
|
42
45
|
def clear(self) -> None:
|
|
43
46
|
self.events.clear()
|
|
44
47
|
# Note: Don't clear current_model_id or models - those persist across prompts
|