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
agentpool/delegation/team.py
CHANGED
|
@@ -4,12 +4,11 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
from time import perf_counter
|
|
7
|
-
from typing import TYPE_CHECKING, Any
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
8
8
|
from uuid import uuid4
|
|
9
9
|
|
|
10
10
|
from anyenv.async_run import as_generated
|
|
11
11
|
import anyio
|
|
12
|
-
from toprompt import to_prompt
|
|
13
12
|
|
|
14
13
|
from agentpool.common_types import SupportsRunStream
|
|
15
14
|
from agentpool.delegation.base_team import BaseTeam
|
|
@@ -33,36 +32,6 @@ if TYPE_CHECKING:
|
|
|
33
32
|
from agentpool_config.task import Job
|
|
34
33
|
|
|
35
34
|
|
|
36
|
-
async def normalize_stream_for_teams(
|
|
37
|
-
node: MessageNode[Any, Any],
|
|
38
|
-
*args: Any,
|
|
39
|
-
**kwargs: Any,
|
|
40
|
-
) -> AsyncIterator[tuple[MessageNode[Any, Any], RichAgentStreamEvent[Any]]]:
|
|
41
|
-
"""Normalize any streaming node to yield (node, event) tuples for team composition.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
node: The streaming node (Agent, Team, etc.)
|
|
45
|
-
*args: Arguments to pass to run_stream
|
|
46
|
-
**kwargs: Keyword arguments to pass to run_stream
|
|
47
|
-
|
|
48
|
-
Yields:
|
|
49
|
-
Tuples of (node, event) where node is the MessageNode instance
|
|
50
|
-
and event is the streaming event from that node.
|
|
51
|
-
"""
|
|
52
|
-
if not isinstance(node, SupportsRunStream):
|
|
53
|
-
msg = f"Node {node.name} does not support streaming"
|
|
54
|
-
raise TypeError(msg)
|
|
55
|
-
|
|
56
|
-
stream = node.run_stream(*args, **kwargs)
|
|
57
|
-
async for item in stream:
|
|
58
|
-
if isinstance(item, tuple):
|
|
59
|
-
# Already normalized (from Team or other composite node)
|
|
60
|
-
yield item
|
|
61
|
-
else:
|
|
62
|
-
# Raw event (from Agent) - wrap it with the source node
|
|
63
|
-
yield (node, item)
|
|
64
|
-
|
|
65
|
-
|
|
66
35
|
class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
67
36
|
"""Group of agents that can execute together."""
|
|
68
37
|
|
|
@@ -77,8 +46,7 @@ class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
|
77
46
|
final_prompt = list(prompts)
|
|
78
47
|
if self.shared_prompt:
|
|
79
48
|
final_prompt.insert(0, self.shared_prompt)
|
|
80
|
-
|
|
81
|
-
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
49
|
+
all_nodes = list(self.nodes)
|
|
82
50
|
# Create Talk connections for monitoring this execution
|
|
83
51
|
execution_talks: list[Talk[Any]] = []
|
|
84
52
|
for node in all_nodes:
|
|
@@ -130,8 +98,7 @@ class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
|
130
98
|
await queue.put(None)
|
|
131
99
|
|
|
132
100
|
# Get nodes to run
|
|
133
|
-
|
|
134
|
-
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
101
|
+
all_nodes = list(self.nodes)
|
|
135
102
|
|
|
136
103
|
# Start all agents
|
|
137
104
|
tasks = [asyncio.create_task(_run(n), name=f"run_{n.name}") for n in all_nodes]
|
|
@@ -163,8 +130,8 @@ class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
|
163
130
|
) -> ChatMessage[list[Any]]:
|
|
164
131
|
"""Run all agents in parallel and return combined message."""
|
|
165
132
|
# Prepare prompts and create user message
|
|
166
|
-
user_msg, processed_prompts
|
|
167
|
-
self.message_received.emit(user_msg)
|
|
133
|
+
user_msg, processed_prompts = await prepare_prompts(*prompts)
|
|
134
|
+
await self.message_received.emit(user_msg)
|
|
168
135
|
|
|
169
136
|
# Execute team logic
|
|
170
137
|
result = await self.execute(*processed_prompts, **kwargs)
|
|
@@ -195,7 +162,6 @@ class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
|
195
162
|
user_msg,
|
|
196
163
|
self,
|
|
197
164
|
self.connections,
|
|
198
|
-
original_message,
|
|
199
165
|
wait_for_connections,
|
|
200
166
|
)
|
|
201
167
|
|
|
@@ -203,7 +169,7 @@ class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
|
203
169
|
self,
|
|
204
170
|
*prompts: PromptCompatible,
|
|
205
171
|
**kwargs: Any,
|
|
206
|
-
) -> AsyncIterator[
|
|
172
|
+
) -> AsyncIterator[RichAgentStreamEvent[Any]]:
|
|
207
173
|
"""Stream responses from all team members in parallel.
|
|
208
174
|
|
|
209
175
|
Args:
|
|
@@ -211,23 +177,53 @@ class Team[TDeps = None](BaseTeam[TDeps, Any]):
|
|
|
211
177
|
kwargs: Additional arguments passed to each agent
|
|
212
178
|
|
|
213
179
|
Yields:
|
|
214
|
-
|
|
215
|
-
and event is the streaming event from that agent.
|
|
180
|
+
RichAgentStreamEvent, with member events wrapped in SubAgentEvent
|
|
216
181
|
"""
|
|
217
|
-
|
|
218
|
-
combined_prompt = "\n".join([await to_prompt(p) for p in prompts])
|
|
219
|
-
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
182
|
+
from agentpool.agents.events import SubAgentEvent
|
|
220
183
|
|
|
221
|
-
#
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
184
|
+
# Get nodes to run
|
|
185
|
+
all_nodes = list(self.nodes)
|
|
186
|
+
|
|
187
|
+
# Create list of streams
|
|
188
|
+
async def wrap_stream(
|
|
189
|
+
node: MessageNode[Any, Any],
|
|
190
|
+
) -> AsyncIterator[RichAgentStreamEvent[Any]]:
|
|
191
|
+
"""Wrap a node's stream events in SubAgentEvent."""
|
|
192
|
+
if not isinstance(node, SupportsRunStream):
|
|
193
|
+
return
|
|
194
|
+
async for event in node.run_stream(*prompts, **kwargs):
|
|
195
|
+
# Handle already-wrapped SubAgentEvents (nested teams)
|
|
196
|
+
if isinstance(event, SubAgentEvent):
|
|
197
|
+
yield SubAgentEvent(
|
|
198
|
+
source_name=event.source_name,
|
|
199
|
+
source_type=event.source_type,
|
|
200
|
+
event=event.event,
|
|
201
|
+
depth=event.depth + 1,
|
|
202
|
+
)
|
|
203
|
+
else:
|
|
204
|
+
# Determine source type based on node type
|
|
205
|
+
from agentpool.delegation.teamrun import TeamRun
|
|
206
|
+
|
|
207
|
+
if isinstance(node, TeamRun):
|
|
208
|
+
source_type: Literal["team_parallel", "team_sequential", "agent"] = (
|
|
209
|
+
"team_sequential"
|
|
210
|
+
)
|
|
211
|
+
elif isinstance(node, BaseTeam):
|
|
212
|
+
source_type = "team_parallel"
|
|
213
|
+
else:
|
|
214
|
+
source_type = "agent"
|
|
215
|
+
|
|
216
|
+
yield SubAgentEvent(
|
|
217
|
+
source_name=node.name,
|
|
218
|
+
source_type=source_type,
|
|
219
|
+
event=event,
|
|
220
|
+
depth=1,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
streams = [wrap_stream(node) for node in all_nodes]
|
|
224
|
+
# Merge all streams
|
|
225
|
+
async for event in as_generated(streams):
|
|
226
|
+
yield event
|
|
231
227
|
|
|
232
228
|
async def run_job[TJobResult](
|
|
233
229
|
self,
|
|
@@ -311,6 +307,7 @@ if __name__ == "__main__":
|
|
|
311
307
|
|
|
312
308
|
async def main() -> None:
|
|
313
309
|
from agentpool import Agent, TeamRun
|
|
310
|
+
from agentpool.agents.events import SubAgentEvent
|
|
314
311
|
|
|
315
312
|
agent_a = Agent(name="A", model="test")
|
|
316
313
|
agent_b = Agent(name="B", model="test")
|
|
@@ -320,7 +317,10 @@ if __name__ == "__main__":
|
|
|
320
317
|
outer_team = Team([inner_run, agent_c], name="Parallel")
|
|
321
318
|
|
|
322
319
|
print("Testing Team containing TeamRun...")
|
|
323
|
-
async for
|
|
324
|
-
|
|
320
|
+
async for event in outer_team.run_stream("test"):
|
|
321
|
+
if isinstance(event, SubAgentEvent):
|
|
322
|
+
print(f"[depth={event.depth}] {event.source_name}: {type(event.event).__name__}")
|
|
323
|
+
else:
|
|
324
|
+
print(f"Event: {type(event).__name__}")
|
|
325
325
|
|
|
326
326
|
anyio.run(main)
|
agentpool/delegation/teamrun.py
CHANGED
|
@@ -9,11 +9,9 @@ from typing import TYPE_CHECKING, Any, Literal, overload
|
|
|
9
9
|
from uuid import uuid4
|
|
10
10
|
|
|
11
11
|
import anyio
|
|
12
|
-
from pydantic_ai import PartDeltaEvent, TextPartDelta
|
|
13
12
|
|
|
14
13
|
from agentpool.common_types import SupportsRunStream
|
|
15
14
|
from agentpool.delegation.base_team import BaseTeam
|
|
16
|
-
from agentpool.delegation.team import normalize_stream_for_teams
|
|
17
15
|
from agentpool.log import get_logger
|
|
18
16
|
from agentpool.messaging import AgentResponse, ChatMessage, TeamResponse
|
|
19
17
|
from agentpool.messaging.processing import finalize_message, prepare_prompts
|
|
@@ -27,7 +25,7 @@ if TYPE_CHECKING:
|
|
|
27
25
|
|
|
28
26
|
from agentpool import MessageNode
|
|
29
27
|
from agentpool.agents.events import RichAgentStreamEvent
|
|
30
|
-
from agentpool.common_types import PromptCompatible
|
|
28
|
+
from agentpool.common_types import PromptCompatible
|
|
31
29
|
from agentpool.delegation import AgentPool
|
|
32
30
|
|
|
33
31
|
|
|
@@ -65,9 +63,6 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
65
63
|
display_name: str | None = None,
|
|
66
64
|
shared_prompt: str | None = None,
|
|
67
65
|
validator: MessageNode[Any, TResult],
|
|
68
|
-
picker: SupportsStructuredOutput | None = None,
|
|
69
|
-
num_picks: int | None = None,
|
|
70
|
-
pick_prompt: str | None = None,
|
|
71
66
|
agent_pool: AgentPool | None = None,
|
|
72
67
|
) -> None: ...
|
|
73
68
|
|
|
@@ -81,9 +76,6 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
81
76
|
display_name: str | None = None,
|
|
82
77
|
shared_prompt: str | None = None,
|
|
83
78
|
validator: None = None,
|
|
84
|
-
picker: SupportsStructuredOutput | None = None,
|
|
85
|
-
num_picks: int | None = None,
|
|
86
|
-
pick_prompt: str | None = None,
|
|
87
79
|
agent_pool: AgentPool | None = None,
|
|
88
80
|
) -> None: ...
|
|
89
81
|
|
|
@@ -97,9 +89,6 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
97
89
|
display_name: str | None = None,
|
|
98
90
|
shared_prompt: str | None = None,
|
|
99
91
|
validator: MessageNode[Any, TResult] | None = None,
|
|
100
|
-
picker: SupportsStructuredOutput | None = None,
|
|
101
|
-
num_picks: int | None = None,
|
|
102
|
-
pick_prompt: str | None = None,
|
|
103
92
|
agent_pool: AgentPool | None = None,
|
|
104
93
|
) -> None: ...
|
|
105
94
|
|
|
@@ -112,9 +101,6 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
112
101
|
display_name: str | None = None,
|
|
113
102
|
shared_prompt: str | None = None,
|
|
114
103
|
validator: MessageNode[Any, TResult] | None = None,
|
|
115
|
-
picker: SupportsStructuredOutput | None = None,
|
|
116
|
-
num_picks: int | None = None,
|
|
117
|
-
pick_prompt: str | None = None,
|
|
118
104
|
agent_pool: AgentPool | None = None,
|
|
119
105
|
# result_mode: ResultMode = "last",
|
|
120
106
|
) -> None:
|
|
@@ -124,9 +110,6 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
124
110
|
description=description,
|
|
125
111
|
display_name=display_name,
|
|
126
112
|
shared_prompt=shared_prompt,
|
|
127
|
-
picker=picker,
|
|
128
|
-
num_picks=num_picks,
|
|
129
|
-
pick_prompt=pick_prompt,
|
|
130
113
|
agent_pool=agent_pool,
|
|
131
114
|
)
|
|
132
115
|
self.validator = validator
|
|
@@ -147,8 +130,8 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
147
130
|
) -> ChatMessage[TResult]:
|
|
148
131
|
"""Run agents sequentially and return combined message."""
|
|
149
132
|
# Prepare prompts and create user message
|
|
150
|
-
user_msg, processed_prompts
|
|
151
|
-
self.message_received.emit(user_msg)
|
|
133
|
+
user_msg, processed_prompts = await prepare_prompts(*prompts)
|
|
134
|
+
await self.message_received.emit(user_msg)
|
|
152
135
|
# Execute sequential logic
|
|
153
136
|
message_id = str(uuid4()) # Always generate unique response ID
|
|
154
137
|
result = await self.execute(*processed_prompts, **kwargs)
|
|
@@ -187,7 +170,6 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
187
170
|
user_msg,
|
|
188
171
|
self,
|
|
189
172
|
self.connections,
|
|
190
|
-
original_message,
|
|
191
173
|
wait_for_connections,
|
|
192
174
|
)
|
|
193
175
|
|
|
@@ -224,12 +206,9 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
224
206
|
*prompt: PromptCompatible,
|
|
225
207
|
**kwargs: Any,
|
|
226
208
|
) -> AsyncIterator[Talk[Any] | AgentResponse[Any]]:
|
|
227
|
-
from toprompt import to_prompt
|
|
228
|
-
|
|
229
209
|
connections: list[Talk[Any]] = []
|
|
230
210
|
try:
|
|
231
|
-
|
|
232
|
-
all_nodes = list(await self.pick_agents(combined_prompt))
|
|
211
|
+
all_nodes = list(self.nodes)
|
|
233
212
|
if self.validator:
|
|
234
213
|
all_nodes.append(self.validator)
|
|
235
214
|
first = all_nodes[0]
|
|
@@ -274,7 +253,7 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
274
253
|
*prompts: PromptCompatible,
|
|
275
254
|
require_all: bool = True,
|
|
276
255
|
**kwargs: Any,
|
|
277
|
-
) -> AsyncIterator[
|
|
256
|
+
) -> AsyncIterator[RichAgentStreamEvent[Any]]:
|
|
278
257
|
"""Stream responses through the chain of team members.
|
|
279
258
|
|
|
280
259
|
Args:
|
|
@@ -284,50 +263,61 @@ class TeamRun[TDeps, TResult](BaseTeam[TDeps, TResult]):
|
|
|
284
263
|
kwargs: Additional arguments passed to each agent
|
|
285
264
|
|
|
286
265
|
Yields:
|
|
287
|
-
|
|
288
|
-
and event is the streaming event.
|
|
266
|
+
RichAgentStreamEvent, with member events wrapped in SubAgentEvent
|
|
289
267
|
"""
|
|
290
|
-
from agentpool.agents.events import StreamCompleteEvent
|
|
268
|
+
from agentpool.agents.events import StreamCompleteEvent, SubAgentEvent
|
|
269
|
+
from agentpool.delegation.team import Team
|
|
291
270
|
|
|
292
271
|
current_message = prompts
|
|
293
|
-
|
|
294
|
-
for agent in self.nodes:
|
|
272
|
+
for node in self.nodes:
|
|
295
273
|
try:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
# Use wrapper to normalize all streaming nodes to (agent, event) tuples
|
|
299
|
-
if not isinstance(agent, SupportsRunStream):
|
|
300
|
-
msg = f"Agent {agent.name} does not support streaming"
|
|
274
|
+
if not isinstance(node, SupportsRunStream):
|
|
275
|
+
msg = f"Node {node.name} does not support streaming"
|
|
301
276
|
raise TypeError(msg) # noqa: TRY301
|
|
302
277
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
278
|
+
async for event in node.run_stream(*current_message, **kwargs):
|
|
279
|
+
# Handle already-wrapped SubAgentEvents (nested teams)
|
|
280
|
+
if isinstance(event, SubAgentEvent):
|
|
281
|
+
yield SubAgentEvent(
|
|
282
|
+
source_name=event.source_name,
|
|
283
|
+
source_type=event.source_type,
|
|
284
|
+
event=event.event,
|
|
285
|
+
depth=event.depth + 1,
|
|
286
|
+
)
|
|
287
|
+
else:
|
|
288
|
+
# Determine source type based on node type
|
|
289
|
+
if isinstance(node, Team):
|
|
290
|
+
source_type: Literal["team_parallel", "team_sequential", "agent"] = (
|
|
291
|
+
"team_parallel"
|
|
292
|
+
)
|
|
293
|
+
elif isinstance(node, BaseTeam):
|
|
294
|
+
source_type = "team_sequential"
|
|
295
|
+
else:
|
|
296
|
+
source_type = "agent"
|
|
297
|
+
|
|
298
|
+
yield SubAgentEvent(
|
|
299
|
+
source_name=node.name,
|
|
300
|
+
source_type=source_type,
|
|
301
|
+
event=event,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Extract content for next agent in chain
|
|
305
|
+
if isinstance(event, StreamCompleteEvent):
|
|
306
|
+
current_message = (event.message.content,)
|
|
318
307
|
|
|
319
308
|
except Exception as e:
|
|
320
309
|
if require_all:
|
|
321
|
-
msg = f"Chain broken at {
|
|
310
|
+
msg = f"Chain broken at {node.name}: {e}"
|
|
322
311
|
logger.exception(msg)
|
|
323
312
|
raise ValueError(msg) from e
|
|
324
|
-
logger.warning("Chain handler failed", name=
|
|
313
|
+
logger.warning("Chain handler failed", name=node.name, error=e)
|
|
325
314
|
|
|
326
315
|
|
|
327
316
|
if __name__ == "__main__":
|
|
328
317
|
|
|
329
318
|
async def main() -> None:
|
|
330
319
|
from agentpool import Agent, Team
|
|
320
|
+
from agentpool.agents.events import SubAgentEvent
|
|
331
321
|
|
|
332
322
|
agent1 = Agent(name="Agent1", model="test")
|
|
333
323
|
agent2 = Agent(name="Agent2", model="test")
|
|
@@ -336,8 +326,13 @@ if __name__ == "__main__":
|
|
|
336
326
|
outer_run = TeamRun([inner_team, agent3], name="Sequential")
|
|
337
327
|
print("Testing TeamRun containing Team...")
|
|
338
328
|
try:
|
|
339
|
-
async for
|
|
340
|
-
|
|
329
|
+
async for event in outer_run.run_stream("test"):
|
|
330
|
+
if isinstance(event, SubAgentEvent):
|
|
331
|
+
print(
|
|
332
|
+
f"[depth={event.depth}] {event.source_name}: {type(event.event).__name__}"
|
|
333
|
+
)
|
|
334
|
+
else:
|
|
335
|
+
print(f"Event: {type(event).__name__}")
|
|
341
336
|
except Exception as e: # noqa: BLE001
|
|
342
337
|
print(f"Error: {e}")
|
|
343
338
|
|
agentpool/functional/run.py
CHANGED
|
@@ -42,11 +42,14 @@ async def run_agent(
|
|
|
42
42
|
) -> Any:
|
|
43
43
|
"""Run prompt through agent and return result."""
|
|
44
44
|
async with Agent[Any, str](**kwargs) as agent:
|
|
45
|
+
# Convert to structured output agent if output_type specified
|
|
46
|
+
final = agent.to_structured(output_type) if output_type is not None else agent
|
|
47
|
+
|
|
45
48
|
if image_url:
|
|
46
49
|
image = ImageUrl(url=image_url)
|
|
47
|
-
result = await
|
|
50
|
+
result = await final.run(prompt, image)
|
|
48
51
|
else:
|
|
49
|
-
result = await
|
|
52
|
+
result = await final.run(prompt)
|
|
50
53
|
return result.content
|
|
51
54
|
|
|
52
55
|
|
|
@@ -76,5 +79,8 @@ def run_agent_sync(
|
|
|
76
79
|
**kwargs: Unpack[AgentKwargs],
|
|
77
80
|
) -> Any:
|
|
78
81
|
"""Sync wrapper for run_agent."""
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
|
|
83
|
+
async def _run() -> Any:
|
|
84
|
+
return await run_agent(prompt, image_url, output_type=output_type, **kwargs) # type: ignore
|
|
85
|
+
|
|
86
|
+
return run_sync(_run())
|
agentpool/mcp_server/client.py
CHANGED
|
@@ -28,7 +28,7 @@ from agentpool.log import get_logger
|
|
|
28
28
|
from agentpool.mcp_server.constants import MCP_TO_LOGGING
|
|
29
29
|
from agentpool.mcp_server.helpers import extract_text_content, mcp_tool_to_fn_schema
|
|
30
30
|
from agentpool.mcp_server.message_handler import MCPMessageHandler
|
|
31
|
-
from agentpool.tools.base import
|
|
31
|
+
from agentpool.tools.base import FunctionTool
|
|
32
32
|
from agentpool.utils.signatures import create_modified_signature
|
|
33
33
|
from agentpool_config.mcp_server import (
|
|
34
34
|
SSEMCPServerConfig,
|
|
@@ -56,6 +56,7 @@ if TYPE_CHECKING:
|
|
|
56
56
|
Implementation,
|
|
57
57
|
Prompt as MCPPrompt,
|
|
58
58
|
Resource as MCPResource,
|
|
59
|
+
ResourceTemplate,
|
|
59
60
|
TextResourceContents,
|
|
60
61
|
Tool as MCPTool,
|
|
61
62
|
)
|
|
@@ -106,12 +107,17 @@ class MCPClient:
|
|
|
106
107
|
"""Check if client is connected by examining session state."""
|
|
107
108
|
return self._client.is_connected()
|
|
108
109
|
|
|
110
|
+
def _ensure_connected(self) -> None:
|
|
111
|
+
"""Ensure client is connected, raise RuntimeError if not."""
|
|
112
|
+
if not self.connected:
|
|
113
|
+
msg = "Not connected to MCP server"
|
|
114
|
+
raise RuntimeError(msg)
|
|
115
|
+
|
|
109
116
|
async def __aenter__(self) -> Self:
|
|
110
117
|
"""Enter context manager."""
|
|
111
118
|
try:
|
|
112
119
|
# First attempt with configured auth
|
|
113
120
|
await self._client.__aenter__() # type: ignore[no-untyped-call]
|
|
114
|
-
|
|
115
121
|
except Exception as first_error:
|
|
116
122
|
# OAuth fallback for HTTP/SSE if not already using OAuth
|
|
117
123
|
if not isinstance(self.config, StdioMCPServerConfig) and not self.config.auth.oauth:
|
|
@@ -241,31 +247,20 @@ class MCPClient:
|
|
|
241
247
|
|
|
242
248
|
Tools are filtered based on the server config's enabled_tools/disabled_tools settings.
|
|
243
249
|
"""
|
|
244
|
-
|
|
245
|
-
msg = "Not connected to MCP server"
|
|
246
|
-
raise RuntimeError(msg)
|
|
247
|
-
|
|
250
|
+
self._ensure_connected()
|
|
248
251
|
try:
|
|
249
252
|
tools = await self._client.list_tools()
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
logger.debug(
|
|
253
|
-
"Listed tools from MCP server",
|
|
254
|
-
total_tools=len(tools),
|
|
255
|
-
filtered_tools=len(filtered_tools),
|
|
256
|
-
)
|
|
253
|
+
filtered = [t for t in tools if self.config.is_tool_allowed(t.name)]
|
|
254
|
+
logger.debug("Listed tools from MCP server", total=len(tools), filtered=len(filtered))
|
|
257
255
|
except Exception as e: # noqa: BLE001
|
|
258
256
|
logger.warning("Failed to list tools", error=e)
|
|
259
257
|
return []
|
|
260
258
|
else:
|
|
261
|
-
return
|
|
259
|
+
return filtered
|
|
262
260
|
|
|
263
261
|
async def list_prompts(self) -> list[MCPPrompt]:
|
|
264
262
|
"""Get available prompts from the server."""
|
|
265
|
-
|
|
266
|
-
msg = "Not connected to MCP server"
|
|
267
|
-
raise RuntimeError(msg)
|
|
268
|
-
|
|
263
|
+
self._ensure_connected()
|
|
269
264
|
try:
|
|
270
265
|
return await self._client.list_prompts()
|
|
271
266
|
except Exception as e: # noqa: BLE001
|
|
@@ -274,31 +269,69 @@ class MCPClient:
|
|
|
274
269
|
|
|
275
270
|
async def list_resources(self) -> list[MCPResource]:
|
|
276
271
|
"""Get available resources from the server."""
|
|
277
|
-
|
|
278
|
-
msg = "Not connected to MCP server"
|
|
279
|
-
raise RuntimeError(msg)
|
|
280
|
-
|
|
272
|
+
self._ensure_connected()
|
|
281
273
|
try:
|
|
282
274
|
return await self._client.list_resources()
|
|
283
275
|
except Exception as e:
|
|
284
276
|
msg = f"Failed to list resources: {e}"
|
|
285
277
|
raise RuntimeError(msg) from e
|
|
286
278
|
|
|
279
|
+
async def list_resource_templates(self) -> list[ResourceTemplate]:
|
|
280
|
+
"""Get available resource templates from the server.
|
|
281
|
+
|
|
282
|
+
Resource templates are URI patterns with placeholders that can be
|
|
283
|
+
expanded to create concrete resource URIs.
|
|
284
|
+
|
|
285
|
+
Example template: "file:///{path}" -> expand with path="config.json"
|
|
286
|
+
-> "file:///config.json" which can then be read.
|
|
287
|
+
|
|
288
|
+
TODO: Integrate resource templates into the ResourceInfo system.
|
|
289
|
+
Currently templates are separate from resources - we need to decide:
|
|
290
|
+
- Should templates appear in list_resources() with a flag?
|
|
291
|
+
- Should ResourceInfo.read() accept kwargs for template expansion?
|
|
292
|
+
- Should templates have their own ResourceTemplateInfo class?
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
List of resource templates from the server
|
|
296
|
+
"""
|
|
297
|
+
self._ensure_connected()
|
|
298
|
+
try:
|
|
299
|
+
return await self._client.list_resource_templates()
|
|
300
|
+
except Exception as e:
|
|
301
|
+
msg = f"Failed to list resource templates: {e}"
|
|
302
|
+
raise RuntimeError(msg) from e
|
|
303
|
+
|
|
304
|
+
async def read_resource(self, uri: str) -> list[TextResourceContents | BlobResourceContents]:
|
|
305
|
+
"""Read resource content by URI.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
uri: URI of the resource to read
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
List of resource contents (text or blob)
|
|
312
|
+
|
|
313
|
+
Raises:
|
|
314
|
+
RuntimeError: If not connected or read fails
|
|
315
|
+
"""
|
|
316
|
+
self._ensure_connected()
|
|
317
|
+
try:
|
|
318
|
+
return await self._client.read_resource(uri)
|
|
319
|
+
except Exception as e:
|
|
320
|
+
msg = f"Failed to read resource {uri!r}: {e}"
|
|
321
|
+
raise RuntimeError(msg) from e
|
|
322
|
+
|
|
287
323
|
async def get_prompt(
|
|
288
324
|
self, name: str, arguments: dict[str, str] | None = None
|
|
289
325
|
) -> GetPromptResult:
|
|
290
326
|
"""Get a specific prompt's content."""
|
|
291
|
-
|
|
292
|
-
msg = "Not connected to MCP server"
|
|
293
|
-
raise RuntimeError(msg)
|
|
294
|
-
|
|
327
|
+
self._ensure_connected()
|
|
295
328
|
try:
|
|
296
329
|
return await self._client.get_prompt_mcp(name, arguments)
|
|
297
330
|
except Exception as e:
|
|
298
331
|
msg = f"Failed to get prompt {name!r}: {e}"
|
|
299
332
|
raise RuntimeError(msg) from e
|
|
300
333
|
|
|
301
|
-
def convert_tool(self, tool: MCPTool) ->
|
|
334
|
+
def convert_tool(self, tool: MCPTool) -> FunctionTool:
|
|
302
335
|
"""Create a properly typed callable from MCP tool schema."""
|
|
303
336
|
|
|
304
337
|
async def tool_callable(
|
|
@@ -319,7 +352,6 @@ class MCPClient:
|
|
|
319
352
|
schema = mcp_tool_to_fn_schema(tool)
|
|
320
353
|
fn_schema = FunctionSchema.from_dict(schema)
|
|
321
354
|
sig = fn_schema.to_python_signature()
|
|
322
|
-
|
|
323
355
|
tool_callable.__signature__ = create_modified_signature( # type: ignore[attr-defined]
|
|
324
356
|
sig, inject={"ctx": RunContext, "agent_ctx": AgentContext}
|
|
325
357
|
)
|
|
@@ -331,7 +363,7 @@ class MCPClient:
|
|
|
331
363
|
tool_callable.__annotations__ = annotations
|
|
332
364
|
tool_callable.__name__ = tool.name
|
|
333
365
|
tool_callable.__doc__ = tool.description or "No description provided."
|
|
334
|
-
return
|
|
366
|
+
return FunctionTool.from_callable(tool_callable, source="mcp")
|
|
335
367
|
|
|
336
368
|
async def call_tool(
|
|
337
369
|
self,
|
|
@@ -341,10 +373,7 @@ class MCPClient:
|
|
|
341
373
|
agent_ctx: AgentContext[Any] | None = None,
|
|
342
374
|
) -> ToolReturn | str | Any:
|
|
343
375
|
"""Call an MCP tool with full PydanticAI return type support."""
|
|
344
|
-
|
|
345
|
-
msg = "Not connected to MCP server"
|
|
346
|
-
raise RuntimeError(msg)
|
|
347
|
-
|
|
376
|
+
self._ensure_connected()
|
|
348
377
|
# Create progress handler that bridges to AgentContext if available
|
|
349
378
|
progress_handler = None
|
|
350
379
|
if agent_ctx:
|
|
@@ -385,9 +414,18 @@ class MCPClient:
|
|
|
385
414
|
|
|
386
415
|
self._current_elicitation_handler = elicitation_handler
|
|
387
416
|
|
|
417
|
+
# Prepare metadata to pass tool_call_id to the MCP server
|
|
418
|
+
meta = None
|
|
419
|
+
if agent_ctx and agent_ctx.tool_call_id:
|
|
420
|
+
# Use the same key that tool_bridge expects: "claudecode/toolUseId"
|
|
421
|
+
# Ensure it's a string (handles both real values and mocks)
|
|
422
|
+
tool_call_id = str(agent_ctx.tool_call_id) if agent_ctx.tool_call_id else None
|
|
423
|
+
if tool_call_id:
|
|
424
|
+
meta = {"claudecode/toolUseId": tool_call_id}
|
|
425
|
+
|
|
388
426
|
try:
|
|
389
427
|
result = await self._client.call_tool(
|
|
390
|
-
name, arguments, progress_handler=progress_handler
|
|
428
|
+
name, arguments, progress_handler=progress_handler, meta=meta
|
|
391
429
|
)
|
|
392
430
|
content = await self._from_mcp_content(result.content)
|
|
393
431
|
# Decision logic for return type
|
|
@@ -424,10 +462,7 @@ class MCPClient:
|
|
|
424
462
|
if __name__ == "__main__":
|
|
425
463
|
path = "/home/phil65/dev/oss/agentpool/tests/mcp_server/server.py"
|
|
426
464
|
# path = Path(__file__).parent / "test_mcp_server.py"
|
|
427
|
-
config = StdioMCPServerConfig(
|
|
428
|
-
command="uv",
|
|
429
|
-
args=["run", str(path)],
|
|
430
|
-
)
|
|
465
|
+
config = StdioMCPServerConfig(command="uv", args=["run", str(path)])
|
|
431
466
|
|
|
432
467
|
async def main() -> None:
|
|
433
468
|
async with MCPClient(config=config) as mcp_client:
|