agentpool 2.2.3__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.
- acp/__init__.py +0 -4
- acp/acp_requests.py +20 -77
- acp/agent/connection.py +8 -0
- acp/agent/implementations/debug_server/debug_server.py +6 -2
- acp/agent/protocol.py +6 -0
- acp/client/connection.py +38 -29
- acp/client/implementations/default_client.py +3 -2
- acp/client/implementations/headless_client.py +2 -2
- acp/connection.py +2 -2
- acp/notifications.py +18 -49
- acp/schema/__init__.py +2 -0
- acp/schema/agent_responses.py +21 -0
- acp/schema/client_requests.py +3 -3
- acp/schema/session_state.py +63 -29
- acp/task/supervisor.py +2 -2
- acp/utils.py +2 -2
- agentpool/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +278 -263
- agentpool/agents/acp_agent/acp_converters.py +150 -17
- agentpool/agents/acp_agent/client_handler.py +35 -24
- agentpool/agents/acp_agent/session_state.py +14 -6
- agentpool/agents/agent.py +471 -643
- agentpool/agents/agui_agent/agui_agent.py +104 -107
- agentpool/agents/agui_agent/helpers.py +3 -4
- agentpool/agents/base_agent.py +485 -32
- agentpool/agents/claude_code_agent/FORKING.md +191 -0
- agentpool/agents/claude_code_agent/__init__.py +13 -1
- agentpool/agents/claude_code_agent/claude_code_agent.py +654 -334
- agentpool/agents/claude_code_agent/converters.py +4 -141
- agentpool/agents/claude_code_agent/models.py +77 -0
- agentpool/agents/claude_code_agent/static_info.py +100 -0
- agentpool/agents/claude_code_agent/usage.py +242 -0
- agentpool/agents/events/__init__.py +22 -0
- agentpool/agents/events/builtin_handlers.py +65 -0
- agentpool/agents/events/event_emitter.py +3 -0
- agentpool/agents/events/events.py +84 -3
- agentpool/agents/events/infer_info.py +145 -0
- agentpool/agents/events/processors.py +254 -0
- agentpool/agents/interactions.py +41 -6
- agentpool/agents/modes.py +13 -0
- agentpool/agents/slashed_agent.py +5 -4
- agentpool/agents/tool_wrapping.py +18 -6
- agentpool/common_types.py +35 -21
- agentpool/config_resources/acp_assistant.yml +2 -2
- agentpool/config_resources/agents.yml +3 -0
- agentpool/config_resources/agents_template.yml +1 -0
- agentpool/config_resources/claude_code_agent.yml +9 -8
- agentpool/config_resources/external_acp_agents.yml +2 -1
- agentpool/delegation/base_team.py +4 -30
- agentpool/delegation/pool.py +104 -265
- agentpool/delegation/team.py +57 -57
- agentpool/delegation/teamrun.py +50 -55
- agentpool/functional/run.py +10 -4
- agentpool/mcp_server/client.py +73 -38
- agentpool/mcp_server/conversions.py +54 -13
- agentpool/mcp_server/manager.py +9 -23
- agentpool/mcp_server/registries/official_registry_client.py +10 -1
- agentpool/mcp_server/tool_bridge.py +114 -79
- agentpool/messaging/connection_manager.py +11 -10
- agentpool/messaging/event_manager.py +5 -5
- agentpool/messaging/message_container.py +6 -30
- agentpool/messaging/message_history.py +87 -8
- agentpool/messaging/messagenode.py +52 -14
- agentpool/messaging/messages.py +2 -26
- agentpool/messaging/processing.py +10 -22
- agentpool/models/__init__.py +1 -1
- agentpool/models/acp_agents/base.py +6 -2
- agentpool/models/acp_agents/mcp_capable.py +124 -15
- agentpool/models/acp_agents/non_mcp.py +0 -23
- agentpool/models/agents.py +66 -66
- agentpool/models/agui_agents.py +1 -1
- agentpool/models/claude_code_agents.py +111 -17
- agentpool/models/file_parsing.py +0 -1
- agentpool/models/manifest.py +70 -50
- agentpool/prompts/conversion_manager.py +1 -1
- agentpool/prompts/prompts.py +5 -2
- agentpool/resource_providers/__init__.py +2 -0
- agentpool/resource_providers/aggregating.py +4 -2
- agentpool/resource_providers/base.py +13 -3
- agentpool/resource_providers/codemode/code_executor.py +72 -5
- agentpool/resource_providers/codemode/helpers.py +2 -2
- agentpool/resource_providers/codemode/provider.py +64 -12
- agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
- agentpool/resource_providers/codemode/remote_provider.py +9 -12
- agentpool/resource_providers/filtering.py +3 -1
- agentpool/resource_providers/mcp_provider.py +66 -12
- agentpool/resource_providers/plan_provider.py +111 -18
- agentpool/resource_providers/pool.py +5 -3
- agentpool/resource_providers/resource_info.py +111 -0
- agentpool/resource_providers/static.py +2 -2
- agentpool/sessions/__init__.py +2 -0
- agentpool/sessions/manager.py +2 -3
- agentpool/sessions/models.py +9 -6
- agentpool/sessions/protocol.py +28 -0
- agentpool/sessions/session.py +11 -55
- agentpool/storage/manager.py +361 -54
- agentpool/talk/registry.py +4 -4
- agentpool/talk/talk.py +9 -10
- agentpool/testing.py +1 -1
- agentpool/tool_impls/__init__.py +6 -0
- agentpool/tool_impls/agent_cli/__init__.py +42 -0
- agentpool/tool_impls/agent_cli/tool.py +95 -0
- agentpool/tool_impls/bash/__init__.py +64 -0
- agentpool/tool_impls/bash/helpers.py +35 -0
- agentpool/tool_impls/bash/tool.py +171 -0
- agentpool/tool_impls/delete_path/__init__.py +70 -0
- agentpool/tool_impls/delete_path/tool.py +142 -0
- agentpool/tool_impls/download_file/__init__.py +80 -0
- agentpool/tool_impls/download_file/tool.py +183 -0
- agentpool/tool_impls/execute_code/__init__.py +55 -0
- agentpool/tool_impls/execute_code/tool.py +163 -0
- agentpool/tool_impls/grep/__init__.py +80 -0
- agentpool/tool_impls/grep/tool.py +200 -0
- agentpool/tool_impls/list_directory/__init__.py +73 -0
- agentpool/tool_impls/list_directory/tool.py +197 -0
- agentpool/tool_impls/question/__init__.py +42 -0
- agentpool/tool_impls/question/tool.py +127 -0
- agentpool/tool_impls/read/__init__.py +104 -0
- agentpool/tool_impls/read/tool.py +305 -0
- agentpool/tools/__init__.py +2 -1
- agentpool/tools/base.py +114 -34
- agentpool/tools/manager.py +57 -1
- agentpool/ui/base.py +2 -2
- agentpool/ui/mock_provider.py +2 -2
- agentpool/ui/stdlib_provider.py +2 -2
- agentpool/utils/streams.py +21 -96
- agentpool/vfs_registry.py +7 -2
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/METADATA +16 -22
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/RECORD +242 -195
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +20 -0
- agentpool_cli/create.py +1 -1
- agentpool_cli/serve_acp.py +59 -1
- agentpool_cli/serve_opencode.py +1 -1
- agentpool_cli/ui.py +557 -0
- agentpool_commands/__init__.py +12 -5
- agentpool_commands/agents.py +1 -1
- agentpool_commands/pool.py +260 -0
- agentpool_commands/session.py +1 -1
- agentpool_commands/text_sharing/__init__.py +119 -0
- agentpool_commands/text_sharing/base.py +123 -0
- agentpool_commands/text_sharing/github_gist.py +80 -0
- agentpool_commands/text_sharing/opencode.py +462 -0
- agentpool_commands/text_sharing/paste_rs.py +59 -0
- agentpool_commands/text_sharing/pastebin.py +116 -0
- agentpool_commands/text_sharing/shittycodingagent.py +112 -0
- agentpool_commands/utils.py +31 -32
- agentpool_config/__init__.py +30 -2
- agentpool_config/agentpool_tools.py +498 -0
- agentpool_config/converters.py +1 -1
- agentpool_config/event_handlers.py +42 -0
- agentpool_config/events.py +1 -1
- agentpool_config/forward_targets.py +1 -4
- agentpool_config/jinja.py +3 -3
- agentpool_config/mcp_server.py +1 -5
- agentpool_config/nodes.py +1 -1
- agentpool_config/observability.py +44 -0
- agentpool_config/session.py +0 -3
- agentpool_config/storage.py +38 -39
- agentpool_config/task.py +3 -3
- agentpool_config/tools.py +11 -28
- agentpool_config/toolsets.py +22 -90
- agentpool_server/a2a_server/agent_worker.py +307 -0
- agentpool_server/a2a_server/server.py +23 -18
- agentpool_server/acp_server/acp_agent.py +125 -56
- agentpool_server/acp_server/commands/acp_commands.py +46 -216
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +8 -7
- agentpool_server/acp_server/event_converter.py +651 -0
- agentpool_server/acp_server/input_provider.py +53 -10
- agentpool_server/acp_server/server.py +1 -11
- agentpool_server/acp_server/session.py +90 -410
- agentpool_server/acp_server/session_manager.py +8 -34
- agentpool_server/agui_server/server.py +3 -1
- agentpool_server/mcp_server/server.py +5 -2
- agentpool_server/opencode_server/ENDPOINTS.md +53 -14
- agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
- agentpool_server/opencode_server/__init__.py +0 -8
- agentpool_server/opencode_server/converters.py +132 -26
- agentpool_server/opencode_server/input_provider.py +160 -8
- agentpool_server/opencode_server/models/__init__.py +42 -20
- agentpool_server/opencode_server/models/app.py +12 -0
- agentpool_server/opencode_server/models/events.py +203 -29
- agentpool_server/opencode_server/models/mcp.py +19 -0
- agentpool_server/opencode_server/models/message.py +18 -1
- agentpool_server/opencode_server/models/parts.py +134 -1
- agentpool_server/opencode_server/models/question.py +56 -0
- agentpool_server/opencode_server/models/session.py +13 -1
- agentpool_server/opencode_server/routes/__init__.py +4 -0
- agentpool_server/opencode_server/routes/agent_routes.py +33 -2
- agentpool_server/opencode_server/routes/app_routes.py +66 -3
- agentpool_server/opencode_server/routes/config_routes.py +66 -5
- agentpool_server/opencode_server/routes/file_routes.py +184 -5
- agentpool_server/opencode_server/routes/global_routes.py +1 -1
- agentpool_server/opencode_server/routes/lsp_routes.py +1 -1
- agentpool_server/opencode_server/routes/message_routes.py +122 -66
- agentpool_server/opencode_server/routes/permission_routes.py +63 -0
- agentpool_server/opencode_server/routes/pty_routes.py +23 -22
- agentpool_server/opencode_server/routes/question_routes.py +128 -0
- agentpool_server/opencode_server/routes/session_routes.py +139 -68
- agentpool_server/opencode_server/routes/tui_routes.py +1 -1
- agentpool_server/opencode_server/server.py +47 -2
- agentpool_server/opencode_server/state.py +30 -0
- agentpool_storage/__init__.py +0 -4
- agentpool_storage/base.py +81 -2
- agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
- agentpool_storage/claude_provider/__init__.py +42 -0
- agentpool_storage/{claude_provider.py → claude_provider/provider.py} +190 -8
- agentpool_storage/file_provider.py +149 -15
- agentpool_storage/memory_provider.py +132 -12
- agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
- agentpool_storage/opencode_provider/__init__.py +16 -0
- agentpool_storage/opencode_provider/helpers.py +414 -0
- agentpool_storage/opencode_provider/provider.py +895 -0
- agentpool_storage/session_store.py +20 -6
- agentpool_storage/sql_provider/sql_provider.py +135 -2
- agentpool_storage/sql_provider/utils.py +2 -12
- agentpool_storage/zed_provider/__init__.py +16 -0
- agentpool_storage/zed_provider/helpers.py +281 -0
- agentpool_storage/zed_provider/models.py +130 -0
- agentpool_storage/zed_provider/provider.py +442 -0
- agentpool_storage/zed_provider.py +803 -0
- agentpool_toolsets/__init__.py +0 -2
- agentpool_toolsets/builtin/__init__.py +2 -4
- agentpool_toolsets/builtin/code.py +4 -4
- agentpool_toolsets/builtin/debug.py +115 -40
- agentpool_toolsets/builtin/execution_environment.py +54 -165
- agentpool_toolsets/builtin/skills.py +0 -77
- agentpool_toolsets/builtin/subagent_tools.py +64 -51
- agentpool_toolsets/builtin/workers.py +4 -2
- agentpool_toolsets/composio_toolset.py +2 -2
- agentpool_toolsets/entry_points.py +3 -1
- agentpool_toolsets/fsspec_toolset/grep.py +25 -5
- agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
- agentpool_toolsets/fsspec_toolset/toolset.py +350 -66
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +74 -17
- agentpool_toolsets/mcp_run_toolset.py +8 -11
- agentpool_toolsets/notifications.py +33 -33
- agentpool_toolsets/openapi.py +3 -1
- agentpool_toolsets/search_toolset.py +3 -1
- agentpool_config/resources.py +0 -33
- agentpool_server/acp_server/acp_tools.py +0 -43
- agentpool_server/acp_server/commands/spawn.py +0 -210
- agentpool_storage/opencode_provider.py +0 -730
- agentpool_storage/text_log_provider.py +0 -276
- agentpool_toolsets/builtin/chain.py +0 -288
- agentpool_toolsets/builtin/user_interaction.py +0 -52
- agentpool_toolsets/semantic_memory_toolset.py +0 -536
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -17,7 +17,9 @@ from pathlib import Path
|
|
|
17
17
|
from typing import TYPE_CHECKING, Any
|
|
18
18
|
|
|
19
19
|
from pydantic import HttpUrl
|
|
20
|
+
from pydantic_ai import RunContext # noqa: TC002
|
|
20
21
|
|
|
22
|
+
from agentpool.agents.context import AgentContext # noqa: TC001
|
|
21
23
|
from agentpool.log import get_logger
|
|
22
24
|
from agentpool.mcp_server.client import MCPClient
|
|
23
25
|
from agentpool.mcp_server.registries.official_registry_client import (
|
|
@@ -28,7 +30,10 @@ from agentpool.resource_providers import ResourceProvider
|
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
if TYPE_CHECKING:
|
|
31
|
-
from
|
|
33
|
+
from collections.abc import Sequence
|
|
34
|
+
|
|
35
|
+
from fastmcp.client.sampling import SamplingHandler
|
|
36
|
+
|
|
32
37
|
from agentpool.mcp_server.registries.official_registry_client import RegistryServer
|
|
33
38
|
from agentpool.tools.base import Tool
|
|
34
39
|
from agentpool_config.mcp_server import MCPServerConfig
|
|
@@ -58,6 +63,7 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
58
63
|
registry_url: str = "https://registry.modelcontextprotocol.io",
|
|
59
64
|
allowed_servers: list[str] | None = None,
|
|
60
65
|
blocked_servers: list[str] | None = None,
|
|
66
|
+
sampling_callback: SamplingHandler[Any, Any] | None = None,
|
|
61
67
|
) -> None:
|
|
62
68
|
"""Initialize the MCP Discovery toolset.
|
|
63
69
|
|
|
@@ -66,6 +72,7 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
66
72
|
registry_url: Base URL for the MCP registry API
|
|
67
73
|
allowed_servers: If set, only these server names can be used
|
|
68
74
|
blocked_servers: Server names that cannot be used
|
|
75
|
+
sampling_callback: Callback for MCP sampling requests
|
|
69
76
|
"""
|
|
70
77
|
super().__init__(name=name)
|
|
71
78
|
self._registry_url = registry_url
|
|
@@ -75,6 +82,7 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
75
82
|
self._tools_cache: dict[str, list[dict[str, Any]]] = {}
|
|
76
83
|
self._allowed_servers = set(allowed_servers) if allowed_servers else None
|
|
77
84
|
self._blocked_servers = set(blocked_servers) if blocked_servers else set()
|
|
85
|
+
self._sampling_callback = sampling_callback
|
|
78
86
|
self._tools: list[Tool] | None = None
|
|
79
87
|
# Lazy-loaded semantic search components
|
|
80
88
|
self._db: Any = None
|
|
@@ -191,7 +199,7 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
191
199
|
del self._connections[server_name]
|
|
192
200
|
|
|
193
201
|
config = await self._get_server_config(server_name)
|
|
194
|
-
client = MCPClient(config=config)
|
|
202
|
+
client = MCPClient(config=config, sampling_callback=self._sampling_callback)
|
|
195
203
|
await client.__aenter__()
|
|
196
204
|
self._connections[server_name] = client
|
|
197
205
|
logger.info("Connected to MCP server", server=server_name)
|
|
@@ -207,7 +215,7 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
207
215
|
logger.warning("Error closing connection", server=name, error=e)
|
|
208
216
|
self._connections.clear()
|
|
209
217
|
|
|
210
|
-
async def get_tools(self) ->
|
|
218
|
+
async def get_tools(self) -> Sequence[Tool]:
|
|
211
219
|
"""Get the discovery tools."""
|
|
212
220
|
if self._tools is not None:
|
|
213
221
|
return self._tools
|
|
@@ -387,6 +395,7 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
387
395
|
|
|
388
396
|
async def call_mcp_tool( # noqa: D417
|
|
389
397
|
self,
|
|
398
|
+
ctx: RunContext,
|
|
390
399
|
agent_ctx: AgentContext,
|
|
391
400
|
server_name: str,
|
|
392
401
|
tool_name: str,
|
|
@@ -397,6 +406,9 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
397
406
|
Use this to execute a specific tool on an MCP server. The server
|
|
398
407
|
connection is reused if already established.
|
|
399
408
|
|
|
409
|
+
This properly supports progress reporting, elicitation, and sampling
|
|
410
|
+
through the AgentContext integration.
|
|
411
|
+
|
|
400
412
|
Args:
|
|
401
413
|
server_name: Name of the MCP server (e.g., "com.github/github")
|
|
402
414
|
tool_name: Name of the tool to call
|
|
@@ -416,21 +428,15 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
416
428
|
try:
|
|
417
429
|
client = await self._get_connection(server_name)
|
|
418
430
|
|
|
419
|
-
#
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
content.text for content in result.content if isinstance(content, TextContent)
|
|
427
|
-
]
|
|
428
|
-
|
|
429
|
-
if text_parts:
|
|
430
|
-
return "\n".join(text_parts)
|
|
431
|
+
# Use MCPClient.call_tool which handles progress, elicitation, and sampling
|
|
432
|
+
return await client.call_tool(
|
|
433
|
+
name=tool_name,
|
|
434
|
+
run_context=ctx,
|
|
435
|
+
arguments=arguments or {},
|
|
436
|
+
agent_ctx=agent_ctx,
|
|
437
|
+
)
|
|
431
438
|
|
|
432
|
-
#
|
|
433
|
-
return str(result)
|
|
439
|
+
# Result is already processed by MCPClient (ToolReturn, str, or structured data)
|
|
434
440
|
|
|
435
441
|
except MCPRegistryError as e:
|
|
436
442
|
return f"Error: {e}"
|
|
@@ -452,3 +458,54 @@ class MCPDiscoveryToolset(ResourceProvider):
|
|
|
452
458
|
self._tmpdir = None
|
|
453
459
|
self._db = None
|
|
454
460
|
self._table = None
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
if __name__ == "__main__":
|
|
464
|
+
import asyncio
|
|
465
|
+
|
|
466
|
+
from agentpool.agents.agent import Agent
|
|
467
|
+
|
|
468
|
+
async def main() -> None:
|
|
469
|
+
"""End-to-end example: Add MCP discovery toolset to an agent and call a tool."""
|
|
470
|
+
# Create the discovery toolset
|
|
471
|
+
toolset = MCPDiscoveryToolset(
|
|
472
|
+
name="mcp_discovery",
|
|
473
|
+
# Optionally restrict to specific servers for safety
|
|
474
|
+
# allowed_servers=["@modelcontextprotocol/server-everything"],
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
# Create an AgentPool agent with the toolset
|
|
478
|
+
agent = Agent(
|
|
479
|
+
model="openai:gpt-4o",
|
|
480
|
+
system_prompt="""
|
|
481
|
+
You are a helpful assistant with access to MCP servers.
|
|
482
|
+
Use the MCP discovery tools to search for and use tools from the MCP ecosystem.
|
|
483
|
+
""",
|
|
484
|
+
toolsets=[toolset],
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
async with agent:
|
|
488
|
+
# Example 1: Search for servers
|
|
489
|
+
print("\n=== Example 1: Search for file system servers ===")
|
|
490
|
+
result = await agent.run(
|
|
491
|
+
"Search for MCP servers related to file systems and show me the top 3 results"
|
|
492
|
+
)
|
|
493
|
+
print(result.data)
|
|
494
|
+
|
|
495
|
+
# Example 2: List tools from a specific server
|
|
496
|
+
print("\n=== Example 2: List tools from a server ===")
|
|
497
|
+
result = await agent.run(
|
|
498
|
+
"List the tools available on the '@modelcontextprotocol/server-everything' server"
|
|
499
|
+
)
|
|
500
|
+
print(result.data)
|
|
501
|
+
|
|
502
|
+
# Example 3: Call a tool (using a safe, read-only tool for demo)
|
|
503
|
+
print("\n=== Example 3: Call a tool ===")
|
|
504
|
+
result = await agent.run(
|
|
505
|
+
"""Use the MCP discovery to call the 'echo' tool from
|
|
506
|
+
'@modelcontextprotocol/server-everything' with the argument
|
|
507
|
+
message='Hello from MCP Discovery!'"""
|
|
508
|
+
)
|
|
509
|
+
print(result.data)
|
|
510
|
+
|
|
511
|
+
asyncio.run(main())
|
|
@@ -12,6 +12,8 @@ from agentpool.resource_providers import ResourceProvider
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import Sequence
|
|
16
|
+
from contextlib import AbstractAsyncContextManager
|
|
15
17
|
from types import TracebackType
|
|
16
18
|
|
|
17
19
|
from mcp import ClientSession
|
|
@@ -44,15 +46,14 @@ class McpRunTools(ResourceProvider):
|
|
|
44
46
|
self.client = Client(session_id=id_, config=config)
|
|
45
47
|
self._tools: list[Tool] | None = None
|
|
46
48
|
self._session: ClientSession | None = None
|
|
47
|
-
|
|
49
|
+
# Context manager for persistent connection
|
|
50
|
+
self._mcp_client_ctx: AbstractAsyncContextManager[ClientSession] | None = None
|
|
48
51
|
|
|
49
52
|
async def __aenter__(self) -> Self:
|
|
50
53
|
"""Start persistent SSE connection."""
|
|
51
|
-
# Create MCPClient from mcp_run
|
|
52
54
|
mcp_client = self.client.mcp_sse()
|
|
53
55
|
self._mcp_client_ctx = mcp_client.connect()
|
|
54
56
|
self._session = await self._mcp_client_ctx.__aenter__()
|
|
55
|
-
|
|
56
57
|
# Set up notification handler for tool changes
|
|
57
58
|
# The MCP ClientSession dispatches notifications via _received_notification
|
|
58
59
|
# We monkey-patch it to intercept ToolListChangedNotification
|
|
@@ -64,7 +65,6 @@ class McpRunTools(ResourceProvider):
|
|
|
64
65
|
if isinstance(notification.root, ToolListChangedNotification):
|
|
65
66
|
logger.info("MCP.run tool list changed notification received")
|
|
66
67
|
await self._on_tools_changed()
|
|
67
|
-
# Call original handler
|
|
68
68
|
await original_handler(notification)
|
|
69
69
|
|
|
70
70
|
self._session._received_notification = notification_handler # type: ignore[method-assign]
|
|
@@ -89,7 +89,7 @@ class McpRunTools(ResourceProvider):
|
|
|
89
89
|
self._tools = None
|
|
90
90
|
await self.tools_changed.emit(self.create_change_event("tools"))
|
|
91
91
|
|
|
92
|
-
async def get_tools(self) ->
|
|
92
|
+
async def get_tools(self) -> Sequence[Tool]:
|
|
93
93
|
"""Get tools from MCP.run."""
|
|
94
94
|
# Return cached tools if available
|
|
95
95
|
if self._tools is not None:
|
|
@@ -97,8 +97,7 @@ class McpRunTools(ResourceProvider):
|
|
|
97
97
|
|
|
98
98
|
self._tools = []
|
|
99
99
|
for name, tool in self.client.tools.items():
|
|
100
|
-
# Capture session for use in tool calls
|
|
101
|
-
session = self._session
|
|
100
|
+
session = self._session # Capture session for use in tool calls
|
|
102
101
|
|
|
103
102
|
async def run(
|
|
104
103
|
tool_name: str = name,
|
|
@@ -113,11 +112,9 @@ class McpRunTools(ResourceProvider):
|
|
|
113
112
|
return await new_session.call_tool(tool_name, arguments=input_dict) # type: ignore[no-any-return]
|
|
114
113
|
|
|
115
114
|
run.__name__ = name
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
)
|
|
115
|
+
schema = cast(OpenAIFunctionDefinition, tool.input_schema)
|
|
116
|
+
wrapped_tool = self.create_tool(run, schema_override=schema)
|
|
119
117
|
self._tools.append(wrapped_tool)
|
|
120
|
-
|
|
121
118
|
return self._tools
|
|
122
119
|
|
|
123
120
|
async def refresh_tools(self) -> None:
|
|
@@ -11,7 +11,7 @@ from agentpool.resource_providers import ResourceProvider
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
-
from collections.abc import Mapping
|
|
14
|
+
from collections.abc import Mapping, Sequence
|
|
15
15
|
|
|
16
16
|
from agentpool.tools.base import Tool
|
|
17
17
|
|
|
@@ -19,6 +19,35 @@ if TYPE_CHECKING:
|
|
|
19
19
|
logger = get_logger(__name__)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
def get_schema(channel_names: list[str] | None) -> OpenAIFunctionDefinition:
|
|
23
|
+
properties: dict[str, Any] = {
|
|
24
|
+
"message": {"type": "string", "description": "The notification message body"},
|
|
25
|
+
"title": {"type": "string", "description": "Optional notification title"},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if channel_names:
|
|
29
|
+
properties["channel"] = {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"enum": channel_names,
|
|
32
|
+
"description": "Send to a specific channel. If not specified, sends to all channels.",
|
|
33
|
+
}
|
|
34
|
+
else:
|
|
35
|
+
properties["channel"] = {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "Send to a specific channel. If not specified, sends to all channels.",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return OpenAIFunctionDefinition(
|
|
41
|
+
name="send_notification",
|
|
42
|
+
description=(
|
|
43
|
+
"Send a notification via configured channels. "
|
|
44
|
+
"Specify a channel name to send to that channel only, "
|
|
45
|
+
"or omit to broadcast to all channels."
|
|
46
|
+
),
|
|
47
|
+
parameters={"type": "object", "properties": properties, "required": ["message"]},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
22
51
|
class NotificationsTools(ResourceProvider):
|
|
23
52
|
"""Provider for Apprise-based notification tools.
|
|
24
53
|
|
|
@@ -53,44 +82,15 @@ class NotificationsTools(ResourceProvider):
|
|
|
53
82
|
self._apprise.add(url, tag=channel_name)
|
|
54
83
|
logger.debug("Added notification URL", channel=channel_name, url=url[:30] + "...")
|
|
55
84
|
|
|
56
|
-
async def get_tools(self) ->
|
|
85
|
+
async def get_tools(self) -> Sequence[Tool]:
|
|
57
86
|
"""Get notification tools with dynamic schema based on configured channels."""
|
|
58
87
|
if self._tools is not None:
|
|
59
88
|
return self._tools
|
|
60
89
|
|
|
61
90
|
channel_names = sorted(self.channels.keys())
|
|
62
|
-
|
|
63
|
-
properties: dict[str, Any] = {
|
|
64
|
-
"message": {"type": "string", "description": "The notification message body"},
|
|
65
|
-
"title": {"type": "string", "description": "Optional notification title"},
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if channel_names:
|
|
69
|
-
properties["channel"] = {
|
|
70
|
-
"type": "string",
|
|
71
|
-
"enum": channel_names,
|
|
72
|
-
"description": "Send to a specific channel. If not specified, sends to all channels.", # noqa: E501
|
|
73
|
-
}
|
|
74
|
-
else:
|
|
75
|
-
properties["channel"] = {
|
|
76
|
-
"type": "string",
|
|
77
|
-
"description": "Send to a specific channel. If not specified, sends to all channels.", # noqa: E501
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
schema_override = OpenAIFunctionDefinition(
|
|
81
|
-
name="send_notification",
|
|
82
|
-
description=(
|
|
83
|
-
"Send a notification via configured channels. "
|
|
84
|
-
"Specify a channel name to send to that channel only, "
|
|
85
|
-
"or omit to broadcast to all channels."
|
|
86
|
-
),
|
|
87
|
-
parameters={"type": "object", "properties": properties, "required": ["message"]},
|
|
88
|
-
)
|
|
89
|
-
|
|
91
|
+
schema = get_schema(channel_names)
|
|
90
92
|
self._tools = [
|
|
91
|
-
self.create_tool(
|
|
92
|
-
self.send_notification, schema_override=schema_override, open_world=True
|
|
93
|
-
)
|
|
93
|
+
self.create_tool(self.send_notification, schema_override=schema, open_world=True)
|
|
94
94
|
]
|
|
95
95
|
return self._tools
|
|
96
96
|
|
agentpool_toolsets/openapi.py
CHANGED
|
@@ -13,6 +13,8 @@ from agentpool.resource_providers import ResourceProvider
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
|
+
from collections.abc import Sequence
|
|
17
|
+
|
|
16
18
|
import httpx
|
|
17
19
|
from upathtools import JoinablePathLike
|
|
18
20
|
|
|
@@ -41,7 +43,7 @@ class OpenAPITools(ResourceProvider):
|
|
|
41
43
|
self._operations: dict[str, Any] = {}
|
|
42
44
|
self._factory: OpenAPICallableFactory | None = None
|
|
43
45
|
|
|
44
|
-
async def get_tools(self) ->
|
|
46
|
+
async def get_tools(self) -> Sequence[Tool]:
|
|
45
47
|
"""Get all API operations as tools."""
|
|
46
48
|
if not self._spec:
|
|
47
49
|
await self._load_spec()
|
|
@@ -9,6 +9,8 @@ from agentpool.resource_providers import ResourceProvider
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
12
14
|
from searchly.base import (
|
|
13
15
|
CountryCode,
|
|
14
16
|
LanguageCode,
|
|
@@ -178,7 +180,7 @@ class SearchTools(ResourceProvider):
|
|
|
178
180
|
|
|
179
181
|
return formatted
|
|
180
182
|
|
|
181
|
-
async def get_tools(self) ->
|
|
183
|
+
async def get_tools(self) -> Sequence[Tool]:
|
|
182
184
|
"""Get search tools from configured providers."""
|
|
183
185
|
tools: list[Tool] = []
|
|
184
186
|
if self._web_provider:
|
agentpool_config/resources.py
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"""Models for resource information."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
from typing import TYPE_CHECKING, Self
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from mcp.types import Resource as MCPResource
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@dataclass
|
|
14
|
-
class ResourceInfo:
|
|
15
|
-
"""Information about an available resource.
|
|
16
|
-
|
|
17
|
-
This class provides essential information about a resource that can be loaded.
|
|
18
|
-
Use the resource name with load_resource() to access the actual content.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
name: str
|
|
22
|
-
"""Name of the resource, use this with load_resource()"""
|
|
23
|
-
|
|
24
|
-
uri: str
|
|
25
|
-
"""URI identifying the resource location"""
|
|
26
|
-
|
|
27
|
-
description: str | None = None
|
|
28
|
-
"""Optional description of the resource's content or purpose"""
|
|
29
|
-
|
|
30
|
-
@classmethod
|
|
31
|
-
async def from_mcp_resource(cls, resource: MCPResource) -> Self:
|
|
32
|
-
"""Create ResourceInfo from MCP resource."""
|
|
33
|
-
return cls(name=resource.name, uri=str(resource.uri), description=resource.description)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"""ACP resource providers."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
|
-
|
|
7
|
-
from exxec.acp_provider import ACPExecutionEnvironment
|
|
8
|
-
|
|
9
|
-
from agentpool.resource_providers import PlanProvider
|
|
10
|
-
from agentpool_toolsets.builtin import CodeTools, ExecutionEnvironmentTools
|
|
11
|
-
from agentpool_toolsets.fsspec_toolset import FSSpecTools
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from agentpool.resource_providers.aggregating import AggregatingResourceProvider
|
|
16
|
-
from agentpool_server.acp_server.session import ACPSession
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_acp_provider(session: ACPSession) -> AggregatingResourceProvider:
|
|
20
|
-
"""Create aggregated resource provider with ACP-specific toolsets.
|
|
21
|
-
|
|
22
|
-
Args:
|
|
23
|
-
session: The ACP session to create providers for
|
|
24
|
-
|
|
25
|
-
Returns:
|
|
26
|
-
AggregatingResourceProvider with execution, filesystem, and code tools
|
|
27
|
-
"""
|
|
28
|
-
from agentpool.resource_providers.aggregating import AggregatingResourceProvider
|
|
29
|
-
|
|
30
|
-
execution_env = ACPExecutionEnvironment(
|
|
31
|
-
fs=session.fs, requests=session.requests, cwd=session.cwd
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
providers = [
|
|
35
|
-
PlanProvider(),
|
|
36
|
-
ExecutionEnvironmentTools(env=execution_env, name=f"acp_execution_{session.session_id}"),
|
|
37
|
-
FSSpecTools(execution_env, name=f"acp_fs_{session.session_id}", cwd=session.cwd),
|
|
38
|
-
CodeTools(execution_env, name=f"acp_code_{session.session_id}", cwd=session.cwd),
|
|
39
|
-
]
|
|
40
|
-
return AggregatingResourceProvider(providers=providers, name=f"acp_{session.session_id}")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
__all__ = ["get_acp_provider"]
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
"""Spawn subagent slash command."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
-
import uuid
|
|
7
|
-
|
|
8
|
-
from pydantic_ai import (
|
|
9
|
-
FinalResultEvent,
|
|
10
|
-
FunctionToolCallEvent,
|
|
11
|
-
FunctionToolResultEvent,
|
|
12
|
-
PartDeltaEvent,
|
|
13
|
-
PartStartEvent,
|
|
14
|
-
RetryPromptPart,
|
|
15
|
-
TextPart,
|
|
16
|
-
TextPartDelta,
|
|
17
|
-
ThinkingPart,
|
|
18
|
-
ThinkingPartDelta,
|
|
19
|
-
ToolCallPartDelta,
|
|
20
|
-
ToolReturnPart,
|
|
21
|
-
)
|
|
22
|
-
from slashed import CommandContext, CommandError # noqa: TC002
|
|
23
|
-
|
|
24
|
-
from agentpool.agents.events import StreamCompleteEvent, ToolCallProgressEvent
|
|
25
|
-
from agentpool.log import get_logger
|
|
26
|
-
from agentpool.messaging.context import NodeContext # noqa: TC001
|
|
27
|
-
from agentpool_commands.base import NodeCommand
|
|
28
|
-
from agentpool_server.acp_server.session import ACPSession # noqa: TC001
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if TYPE_CHECKING:
|
|
32
|
-
from agentpool.agents.events import RichAgentStreamEvent
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
logger = get_logger(__name__)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class SpawnSubagentCommand(NodeCommand):
|
|
39
|
-
"""Spawn a subagent to execute a specific task.
|
|
40
|
-
|
|
41
|
-
The subagent runs concurrently and reports progress in a dedicated tool call box.
|
|
42
|
-
|
|
43
|
-
Usage:
|
|
44
|
-
/spawn "agent-name" "prompt for the subagent"
|
|
45
|
-
/spawn "code-reviewer" "Review the main.py file for potential bugs"
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
name = "spawn"
|
|
49
|
-
category = "agents"
|
|
50
|
-
|
|
51
|
-
async def execute_command(
|
|
52
|
-
self,
|
|
53
|
-
ctx: CommandContext[NodeContext[ACPSession]],
|
|
54
|
-
agent_name: str,
|
|
55
|
-
task_prompt: str,
|
|
56
|
-
) -> None:
|
|
57
|
-
"""Spawn a subagent to execute a task.
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
ctx: Command context with ACP session
|
|
61
|
-
agent_name: Name of the agent to spawn
|
|
62
|
-
task_prompt: Task prompt for the subagent
|
|
63
|
-
"""
|
|
64
|
-
session = ctx.context.data
|
|
65
|
-
assert session, "ACP session required for spawn command"
|
|
66
|
-
# Generate unique tool call ID
|
|
67
|
-
tool_call_id = f"spawn-{agent_name}-{uuid.uuid4().hex[:8]}"
|
|
68
|
-
try:
|
|
69
|
-
# Check if agent exists in pool
|
|
70
|
-
if not session.agent_pool or agent_name not in session.agent_pool.agents:
|
|
71
|
-
available = list(session.agent_pool.agents.keys())
|
|
72
|
-
error_msg = f"Agent {agent_name!r} not found. Available agents: {available}"
|
|
73
|
-
await ctx.print(f"❌ {error_msg}")
|
|
74
|
-
return
|
|
75
|
-
|
|
76
|
-
target_agent = session.agent_pool.get_agent(agent_name)
|
|
77
|
-
await session.notifications.tool_call_start(
|
|
78
|
-
tool_call_id=tool_call_id,
|
|
79
|
-
title=f"Spawning agent: {agent_name}",
|
|
80
|
-
kind="execute",
|
|
81
|
-
raw_input={
|
|
82
|
-
"agent_name": agent_name,
|
|
83
|
-
"task_prompt": task_prompt,
|
|
84
|
-
},
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
aggregated_content: list[str] = [] # Aggregate output as we stream
|
|
88
|
-
try:
|
|
89
|
-
# Run the subagent and handle events
|
|
90
|
-
async for event in target_agent.run_stream(task_prompt):
|
|
91
|
-
await _handle_subagent_event(event, tool_call_id, aggregated_content, session)
|
|
92
|
-
|
|
93
|
-
final_content = "".join(aggregated_content).strip()
|
|
94
|
-
await session.notifications.tool_call_progress(
|
|
95
|
-
tool_call_id=tool_call_id,
|
|
96
|
-
status="completed",
|
|
97
|
-
content=[final_content] if final_content else None,
|
|
98
|
-
)
|
|
99
|
-
except Exception as e:
|
|
100
|
-
error_msg = f"Subagent execution failed: {e}"
|
|
101
|
-
logger.exception("Subagent execution error", error=str(e))
|
|
102
|
-
await session.notifications.tool_call_progress(
|
|
103
|
-
tool_call_id=tool_call_id,
|
|
104
|
-
status="failed",
|
|
105
|
-
raw_output=error_msg,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
except Exception as e:
|
|
109
|
-
error_msg = f"Failed to spawn agent '{agent_name}': {e}"
|
|
110
|
-
logger.exception("Spawn command error", error=str(e))
|
|
111
|
-
raise CommandError(error_msg) from e
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
async def _handle_subagent_event(
|
|
115
|
-
event: RichAgentStreamEvent[Any],
|
|
116
|
-
tool_call_id: str,
|
|
117
|
-
aggregated_content: list[str],
|
|
118
|
-
session: ACPSession,
|
|
119
|
-
) -> None:
|
|
120
|
-
"""Handle events from spawned subagent and convert to tool_call_progress.
|
|
121
|
-
|
|
122
|
-
Args:
|
|
123
|
-
event: Event from the subagent stream
|
|
124
|
-
tool_call_id: ID of the tool call box
|
|
125
|
-
aggregated_content: List to accumulate content for final display
|
|
126
|
-
session: ACP session for notifications
|
|
127
|
-
"""
|
|
128
|
-
match event:
|
|
129
|
-
case (
|
|
130
|
-
PartStartEvent(part=TextPart(content=delta))
|
|
131
|
-
| PartDeltaEvent(delta=TextPartDelta(content_delta=delta))
|
|
132
|
-
):
|
|
133
|
-
# Subagent text output → accumulate and update progress
|
|
134
|
-
aggregated_content.append(delta)
|
|
135
|
-
await session.notifications.tool_call_progress(
|
|
136
|
-
tool_call_id=tool_call_id,
|
|
137
|
-
status="in_progress",
|
|
138
|
-
content=["".join(aggregated_content)],
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
case (
|
|
142
|
-
PartStartEvent(part=ThinkingPart(content=delta))
|
|
143
|
-
| PartDeltaEvent(delta=ThinkingPartDelta(content_delta=delta))
|
|
144
|
-
):
|
|
145
|
-
# Subagent thinking → show thinking indicator
|
|
146
|
-
if delta:
|
|
147
|
-
thinking_text = f"💭 {delta}"
|
|
148
|
-
aggregated_content.append(thinking_text)
|
|
149
|
-
await session.notifications.tool_call_progress(
|
|
150
|
-
tool_call_id=tool_call_id,
|
|
151
|
-
status="in_progress",
|
|
152
|
-
content=["".join(aggregated_content)],
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
case FunctionToolCallEvent(part=part):
|
|
156
|
-
# Subagent calls a tool → show nested tool call
|
|
157
|
-
tool_text = f"\n🔧 Using tool: {part.tool_name}\n"
|
|
158
|
-
aggregated_content.append(tool_text)
|
|
159
|
-
await session.notifications.tool_call_progress(
|
|
160
|
-
tool_call_id=tool_call_id,
|
|
161
|
-
status="in_progress",
|
|
162
|
-
content=["".join(aggregated_content)],
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
case FunctionToolResultEvent(
|
|
166
|
-
result=ToolReturnPart(content=content, tool_name=tool_name),
|
|
167
|
-
):
|
|
168
|
-
# Subagent tool completes → show tool result
|
|
169
|
-
result_text = f"✅ {tool_name}: {content}\n"
|
|
170
|
-
aggregated_content.append(result_text)
|
|
171
|
-
await session.notifications.tool_call_progress(
|
|
172
|
-
tool_call_id=tool_call_id,
|
|
173
|
-
status="in_progress",
|
|
174
|
-
content=["".join(aggregated_content)],
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
case FunctionToolResultEvent(
|
|
178
|
-
result=RetryPromptPart(tool_name=tool_name) as result,
|
|
179
|
-
):
|
|
180
|
-
# Tool call failed and needs retry
|
|
181
|
-
error_message = result.model_response()
|
|
182
|
-
error_text = f"❌ {tool_name or 'unknown'}: Error: {error_message}\n"
|
|
183
|
-
aggregated_content.append(error_text)
|
|
184
|
-
await session.notifications.tool_call_progress(
|
|
185
|
-
tool_call_id=tool_call_id,
|
|
186
|
-
status="in_progress",
|
|
187
|
-
content=["".join(aggregated_content)],
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
case ToolCallProgressEvent(message=message, tool_name=tool_name):
|
|
191
|
-
# Progress event from tools
|
|
192
|
-
if message:
|
|
193
|
-
progress_text = f"🔄 {tool_name}: {message}\n"
|
|
194
|
-
aggregated_content.append(progress_text)
|
|
195
|
-
await session.notifications.tool_call_progress(
|
|
196
|
-
tool_call_id=tool_call_id,
|
|
197
|
-
status="in_progress",
|
|
198
|
-
content=["".join(aggregated_content)],
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
case (
|
|
202
|
-
PartStartEvent()
|
|
203
|
-
| PartDeltaEvent(delta=ToolCallPartDelta())
|
|
204
|
-
| FinalResultEvent()
|
|
205
|
-
| StreamCompleteEvent()
|
|
206
|
-
):
|
|
207
|
-
pass # These events don't need special handling
|
|
208
|
-
|
|
209
|
-
case _:
|
|
210
|
-
logger.debug("Unhandled subagent event", event_type=type(event).__name__)
|