agentpool 2.1.9__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 +13 -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/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/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 +20 -50
- 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/stdio.py +39 -9
- acp/task/supervisor.py +2 -2
- acp/transports.py +362 -2
- acp/utils.py +17 -4
- agentpool/__init__.py +6 -1
- agentpool/agents/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +407 -277
- agentpool/agents/acp_agent/acp_converters.py +196 -38
- agentpool/agents/acp_agent/client_handler.py +191 -26
- agentpool/agents/acp_agent/session_state.py +17 -6
- agentpool/agents/agent.py +607 -572
- agentpool/agents/agui_agent/__init__.py +0 -2
- agentpool/agents/agui_agent/agui_agent.py +176 -110
- agentpool/agents/agui_agent/agui_converters.py +0 -131
- agentpool/agents/agui_agent/helpers.py +3 -4
- agentpool/agents/base_agent.py +632 -17
- 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 +1058 -291
- agentpool/agents/claude_code_agent/converters.py +74 -143
- agentpool/agents/claude_code_agent/history.py +474 -0
- 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/context.py +40 -0
- agentpool/agents/events/__init__.py +24 -0
- agentpool/agents/events/builtin_handlers.py +67 -1
- agentpool/agents/events/event_emitter.py +32 -2
- agentpool/agents/events/events.py +104 -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 +67 -0
- agentpool/agents/slashed_agent.py +5 -4
- agentpool/agents/tool_call_accumulator.py +213 -0
- agentpool/agents/tool_wrapping.py +18 -6
- agentpool/common_types.py +56 -21
- agentpool/config_resources/__init__.py +38 -1
- 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 +10 -6
- agentpool/config_resources/external_acp_agents.yml +2 -1
- agentpool/delegation/base_team.py +4 -30
- agentpool/delegation/pool.py +136 -289
- agentpool/delegation/team.py +58 -57
- agentpool/delegation/teamrun.py +51 -55
- 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/functional/run.py +10 -4
- agentpool/mcp_server/__init__.py +0 -2
- agentpool/mcp_server/client.py +76 -32
- agentpool/mcp_server/conversions.py +54 -13
- agentpool/mcp_server/manager.py +34 -54
- agentpool/mcp_server/registries/official_registry_client.py +35 -1
- agentpool/mcp_server/tool_bridge.py +186 -139
- agentpool/messaging/__init__.py +0 -2
- agentpool/messaging/compaction.py +72 -197
- 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 +99 -8
- agentpool/messaging/messagenode.py +52 -14
- agentpool/messaging/messages.py +54 -35
- agentpool/messaging/processing.py +12 -22
- agentpool/models/__init__.py +1 -1
- agentpool/models/acp_agents/base.py +6 -24
- agentpool/models/acp_agents/mcp_capable.py +126 -157
- agentpool/models/acp_agents/non_mcp.py +129 -95
- agentpool/models/agents.py +98 -76
- agentpool/models/agui_agents.py +1 -1
- agentpool/models/claude_code_agents.py +144 -19
- agentpool/models/file_parsing.py +0 -1
- agentpool/models/manifest.py +113 -50
- agentpool/prompts/conversion_manager.py +1 -1
- agentpool/prompts/prompts.py +5 -2
- agentpool/repomap.py +1 -1
- agentpool/resource_providers/__init__.py +11 -1
- agentpool/resource_providers/aggregating.py +56 -5
- agentpool/resource_providers/base.py +70 -4
- 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 +89 -12
- agentpool/resource_providers/plan_provider.py +228 -46
- agentpool/resource_providers/pool.py +7 -3
- agentpool/resource_providers/resource_info.py +111 -0
- agentpool/resource_providers/static.py +4 -2
- agentpool/sessions/__init__.py +4 -1
- agentpool/sessions/manager.py +33 -5
- agentpool/sessions/models.py +59 -6
- agentpool/sessions/protocol.py +28 -0
- agentpool/sessions/session.py +11 -55
- agentpool/skills/registry.py +13 -8
- agentpool/storage/manager.py +572 -49
- agentpool/talk/registry.py +4 -4
- agentpool/talk/talk.py +9 -10
- agentpool/testing.py +538 -20
- 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/file_watcher.py +269 -0
- agentpool/utils/identifiers.py +121 -0
- agentpool/utils/pydantic_ai_helpers.py +46 -0
- agentpool/utils/streams.py +616 -2
- agentpool/utils/subprocess_utils.py +155 -0
- agentpool/utils/token_breakdown.py +461 -0
- agentpool/vfs_registry.py +7 -2
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/METADATA +41 -27
- agentpool-2.5.0.dist-info/RECORD +579 -0
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +24 -0
- agentpool_cli/create.py +1 -1
- agentpool_cli/serve_acp.py +100 -21
- agentpool_cli/serve_agui.py +87 -0
- agentpool_cli/serve_opencode.py +119 -0
- agentpool_cli/ui.py +557 -0
- agentpool_commands/__init__.py +42 -5
- agentpool_commands/agents.py +75 -2
- agentpool_commands/history.py +62 -0
- agentpool_commands/mcp.py +176 -0
- agentpool_commands/models.py +56 -3
- 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/tools.py +57 -0
- agentpool_commands/utils.py +80 -30
- agentpool_config/__init__.py +30 -2
- agentpool_config/agentpool_tools.py +498 -0
- agentpool_config/builtin_tools.py +77 -22
- agentpool_config/commands.py +24 -1
- agentpool_config/compaction.py +258 -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 +132 -6
- agentpool_config/nodes.py +1 -1
- agentpool_config/observability.py +44 -0
- agentpool_config/session.py +0 -3
- agentpool_config/storage.py +82 -38
- agentpool_config/task.py +3 -3
- agentpool_config/tools.py +11 -22
- agentpool_config/toolsets.py +109 -233
- agentpool_server/a2a_server/agent_worker.py +307 -0
- agentpool_server/a2a_server/server.py +23 -18
- agentpool_server/acp_server/acp_agent.py +234 -181
- agentpool_server/acp_server/commands/acp_commands.py +151 -156
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +18 -17
- agentpool_server/acp_server/event_converter.py +651 -0
- agentpool_server/acp_server/input_provider.py +53 -10
- agentpool_server/acp_server/server.py +24 -90
- agentpool_server/acp_server/session.py +173 -331
- 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/.rules +95 -0
- agentpool_server/opencode_server/ENDPOINTS.md +401 -0
- agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
- agentpool_server/opencode_server/__init__.py +19 -0
- agentpool_server/opencode_server/command_validation.py +172 -0
- agentpool_server/opencode_server/converters.py +975 -0
- agentpool_server/opencode_server/dependencies.py +24 -0
- agentpool_server/opencode_server/input_provider.py +421 -0
- agentpool_server/opencode_server/models/__init__.py +250 -0
- agentpool_server/opencode_server/models/agent.py +53 -0
- agentpool_server/opencode_server/models/app.py +72 -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 +821 -0
- agentpool_server/opencode_server/models/file.py +88 -0
- agentpool_server/opencode_server/models/mcp.py +44 -0
- agentpool_server/opencode_server/models/message.py +179 -0
- agentpool_server/opencode_server/models/parts.py +323 -0
- agentpool_server/opencode_server/models/provider.py +81 -0
- agentpool_server/opencode_server/models/pty.py +43 -0
- agentpool_server/opencode_server/models/question.py +56 -0
- agentpool_server/opencode_server/models/session.py +111 -0
- agentpool_server/opencode_server/routes/__init__.py +29 -0
- agentpool_server/opencode_server/routes/agent_routes.py +473 -0
- agentpool_server/opencode_server/routes/app_routes.py +202 -0
- agentpool_server/opencode_server/routes/config_routes.py +302 -0
- agentpool_server/opencode_server/routes/file_routes.py +571 -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 +761 -0
- agentpool_server/opencode_server/routes/permission_routes.py +63 -0
- agentpool_server/opencode_server/routes/pty_routes.py +300 -0
- agentpool_server/opencode_server/routes/question_routes.py +128 -0
- agentpool_server/opencode_server/routes/session_routes.py +1276 -0
- agentpool_server/opencode_server/routes/tui_routes.py +139 -0
- agentpool_server/opencode_server/server.py +475 -0
- agentpool_server/opencode_server/state.py +151 -0
- agentpool_server/opencode_server/time_utils.py +8 -0
- agentpool_storage/__init__.py +12 -0
- agentpool_storage/base.py +184 -2
- agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
- agentpool_storage/claude_provider/__init__.py +42 -0
- agentpool_storage/claude_provider/provider.py +1089 -0
- agentpool_storage/file_provider.py +278 -15
- agentpool_storage/memory_provider.py +193 -12
- agentpool_storage/models.py +3 -0
- 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/project_store.py +325 -0
- agentpool_storage/session_store.py +26 -6
- agentpool_storage/sql_provider/__init__.py +4 -2
- agentpool_storage/sql_provider/models.py +48 -0
- agentpool_storage/sql_provider/sql_provider.py +269 -3
- agentpool_storage/sql_provider/utils.py +12 -13
- 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 -12
- agentpool_toolsets/builtin/code.py +96 -57
- agentpool_toolsets/builtin/debug.py +118 -48
- agentpool_toolsets/builtin/execution_environment.py +115 -230
- agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
- agentpool_toolsets/builtin/skills.py +9 -4
- 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/__init__.py +13 -1
- agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
- agentpool_toolsets/fsspec_toolset/grep.py +99 -7
- agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
- agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
- agentpool_toolsets/fsspec_toolset/toolset.py +500 -95
- agentpool_toolsets/mcp_discovery/__init__.py +5 -0
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +511 -0
- agentpool_toolsets/mcp_run_toolset.py +87 -12
- agentpool_toolsets/notifications.py +33 -33
- agentpool_toolsets/openapi.py +3 -1
- agentpool_toolsets/search_toolset.py +3 -1
- agentpool-2.1.9.dist-info/RECORD +0 -474
- 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/text_log_provider.py +0 -275
- agentpool_toolsets/builtin/agent_management.py +0 -239
- agentpool_toolsets/builtin/chain.py +0 -288
- agentpool_toolsets/builtin/history.py +0 -36
- agentpool_toolsets/builtin/integration.py +0 -85
- agentpool_toolsets/builtin/tool_management.py +0 -90
- agentpool_toolsets/builtin/user_interaction.py +0 -52
- agentpool_toolsets/semantic_memory_toolset.py +0 -536
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from agentpool.agents.agui_agent.agui_agent import AGUIAgent
|
|
4
4
|
from agentpool.agents.agui_agent.agui_converters import (
|
|
5
|
-
ToolCallAccumulator,
|
|
6
5
|
agui_to_native_event,
|
|
7
6
|
to_agui_input_content,
|
|
8
7
|
to_agui_tool,
|
|
@@ -12,7 +11,6 @@ from agentpool.agents.agui_agent.chunk_transformer import ChunkTransformer
|
|
|
12
11
|
__all__ = [
|
|
13
12
|
"AGUIAgent",
|
|
14
13
|
"ChunkTransformer",
|
|
15
|
-
"ToolCallAccumulator",
|
|
16
14
|
"agui_to_native_event",
|
|
17
15
|
"to_agui_input_content",
|
|
18
16
|
"to_agui_tool",
|
|
@@ -31,11 +31,11 @@ from agentpool.agents.agui_agent.chunk_transformer import ChunkTransformer
|
|
|
31
31
|
from agentpool.agents.agui_agent.helpers import execute_tool_calls, parse_sse_stream
|
|
32
32
|
from agentpool.agents.base_agent import BaseAgent
|
|
33
33
|
from agentpool.agents.events import RunStartedEvent, StreamCompleteEvent
|
|
34
|
+
from agentpool.agents.events.processors import FileTracker
|
|
34
35
|
from agentpool.log import get_logger
|
|
35
36
|
from agentpool.messaging import ChatMessage
|
|
36
|
-
from agentpool.messaging.processing import prepare_prompts
|
|
37
|
-
from agentpool.talk.stats import MessageStats
|
|
38
37
|
from agentpool.tools import ToolManager
|
|
38
|
+
from agentpool.utils.token_breakdown import calculate_usage_from_parts
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
if TYPE_CHECKING:
|
|
@@ -44,22 +44,26 @@ if TYPE_CHECKING:
|
|
|
44
44
|
from types import TracebackType
|
|
45
45
|
|
|
46
46
|
from ag_ui.core import Message, ToolMessage
|
|
47
|
-
from
|
|
47
|
+
from evented_config import EventConfig
|
|
48
|
+
from pydantic_ai import UserContent
|
|
49
|
+
from slashed import BaseCommand
|
|
50
|
+
from tokonomics.model_discovery.model_info import ModelInfo
|
|
48
51
|
|
|
49
|
-
from agentpool.agents.base_agent import ToolConfirmationMode
|
|
50
52
|
from agentpool.agents.context import AgentContext
|
|
51
53
|
from agentpool.agents.events import RichAgentStreamEvent
|
|
54
|
+
from agentpool.agents.modes import ModeCategory, ModeInfo
|
|
52
55
|
from agentpool.common_types import (
|
|
53
56
|
BuiltinEventHandlerType,
|
|
54
57
|
IndividualEventHandler,
|
|
55
|
-
PromptCompatible,
|
|
56
58
|
ToolType,
|
|
57
59
|
)
|
|
58
60
|
from agentpool.delegation import AgentPool
|
|
59
61
|
from agentpool.messaging import MessageHistory
|
|
62
|
+
from agentpool.models.agui_agents import AGUIAgentConfig
|
|
60
63
|
from agentpool.tools import Tool
|
|
61
64
|
from agentpool.ui.base import InputProvider
|
|
62
65
|
from agentpool_config.mcp_server import MCPServerConfig
|
|
66
|
+
from agentpool_config.nodes import ToolConfirmationMode
|
|
63
67
|
|
|
64
68
|
|
|
65
69
|
logger = get_logger(__name__)
|
|
@@ -132,6 +136,7 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
132
136
|
event_configs: Sequence[EventConfig] | None = None,
|
|
133
137
|
event_handlers: Sequence[IndividualEventHandler | BuiltinEventHandlerType] | None = None,
|
|
134
138
|
tool_confirmation_mode: ToolConfirmationMode = "per_tool",
|
|
139
|
+
commands: Sequence[BaseCommand] | None = None,
|
|
135
140
|
) -> None:
|
|
136
141
|
"""Initialize AG-UI agent client.
|
|
137
142
|
|
|
@@ -153,6 +158,7 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
153
158
|
event_configs: Event trigger configurations
|
|
154
159
|
event_handlers: Sequence of event handlers to register
|
|
155
160
|
tool_confirmation_mode: Tool confirmation mode
|
|
161
|
+
commands: Slash commands
|
|
156
162
|
"""
|
|
157
163
|
super().__init__(
|
|
158
164
|
name=name,
|
|
@@ -164,6 +170,7 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
164
170
|
event_configs=event_configs,
|
|
165
171
|
tool_confirmation_mode=tool_confirmation_mode,
|
|
166
172
|
event_handlers=event_handlers,
|
|
173
|
+
commands=commands,
|
|
167
174
|
)
|
|
168
175
|
|
|
169
176
|
# AG-UI specific configuration
|
|
@@ -187,6 +194,50 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
187
194
|
# Chunk transformer for normalizing CHUNK events
|
|
188
195
|
self._chunk_transformer = ChunkTransformer()
|
|
189
196
|
|
|
197
|
+
@classmethod
|
|
198
|
+
def from_config(
|
|
199
|
+
cls,
|
|
200
|
+
config: AGUIAgentConfig,
|
|
201
|
+
*,
|
|
202
|
+
event_handlers: Sequence[IndividualEventHandler | BuiltinEventHandlerType] | None = None,
|
|
203
|
+
input_provider: InputProvider | None = None,
|
|
204
|
+
agent_pool: AgentPool[Any] | None = None,
|
|
205
|
+
) -> Self:
|
|
206
|
+
"""Create an AGUIAgent from a config object.
|
|
207
|
+
|
|
208
|
+
This is the preferred way to instantiate an AGUIAgent from configuration.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
config: AG-UI agent configuration
|
|
212
|
+
event_handlers: Optional event handlers (merged with config handlers)
|
|
213
|
+
input_provider: Optional input provider for user interactions
|
|
214
|
+
agent_pool: Optional agent pool for coordination
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Configured AGUIAgent instance
|
|
218
|
+
"""
|
|
219
|
+
# Merge config-level handlers with provided handlers
|
|
220
|
+
config_handlers = config.get_event_handlers()
|
|
221
|
+
merged_handlers: list[IndividualEventHandler | BuiltinEventHandlerType] = [
|
|
222
|
+
*config_handlers,
|
|
223
|
+
*(event_handlers or []),
|
|
224
|
+
]
|
|
225
|
+
return cls(
|
|
226
|
+
endpoint=config.endpoint,
|
|
227
|
+
name=config.name or "agui-agent",
|
|
228
|
+
description=config.description,
|
|
229
|
+
display_name=config.display_name,
|
|
230
|
+
event_handlers=merged_handlers or None,
|
|
231
|
+
timeout=config.timeout,
|
|
232
|
+
headers=config.headers,
|
|
233
|
+
startup_command=config.startup_command,
|
|
234
|
+
startup_delay=config.startup_delay,
|
|
235
|
+
tools=[tool_config.get_tool() for tool_config in config.tools],
|
|
236
|
+
mcp_servers=config.mcp_servers,
|
|
237
|
+
tool_confirmation_mode=config.requires_tool_confirmation,
|
|
238
|
+
agent_pool=agent_pool,
|
|
239
|
+
)
|
|
240
|
+
|
|
190
241
|
def get_context(self, data: Any = None) -> AgentContext:
|
|
191
242
|
"""Create a new context for this agent.
|
|
192
243
|
|
|
@@ -200,7 +251,7 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
200
251
|
from agentpool.models.agui_agents import AGUIAgentConfig
|
|
201
252
|
from agentpool.models.manifest import AgentsManifest
|
|
202
253
|
|
|
203
|
-
cfg = AGUIAgentConfig(
|
|
254
|
+
cfg = AGUIAgentConfig( # type: ignore[call-arg]
|
|
204
255
|
name=self.name,
|
|
205
256
|
description=self.description,
|
|
206
257
|
display_name=self.display_name,
|
|
@@ -212,7 +263,14 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
212
263
|
startup_delay=self._startup_delay,
|
|
213
264
|
)
|
|
214
265
|
defn = self.agent_pool.manifest if self.agent_pool else AgentsManifest()
|
|
215
|
-
return AgentContext(
|
|
266
|
+
return AgentContext(
|
|
267
|
+
node=self,
|
|
268
|
+
pool=self.agent_pool,
|
|
269
|
+
config=cfg,
|
|
270
|
+
definition=defn,
|
|
271
|
+
input_provider=self._input_provider,
|
|
272
|
+
data=data,
|
|
273
|
+
)
|
|
216
274
|
|
|
217
275
|
async def __aenter__(self) -> Self:
|
|
218
276
|
"""Enter async context - initialize client and base resources."""
|
|
@@ -302,71 +360,38 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
302
360
|
self._startup_process = None
|
|
303
361
|
self.log.info("AG-UI server stopped")
|
|
304
362
|
|
|
305
|
-
async def
|
|
306
|
-
self,
|
|
307
|
-
*prompts: PromptCompatible,
|
|
308
|
-
message_id: str | None = None,
|
|
309
|
-
input_provider: InputProvider | None = None,
|
|
310
|
-
message_history: MessageHistory | None = None,
|
|
311
|
-
**kwargs: Any,
|
|
312
|
-
) -> ChatMessage[str]:
|
|
313
|
-
"""Execute prompt against AG-UI agent.
|
|
314
|
-
|
|
315
|
-
Sends the prompt to the AG-UI server and waits for completion.
|
|
316
|
-
Events are collected via run_stream and event handlers are called.
|
|
317
|
-
The final text content is returned as a ChatMessage.
|
|
318
|
-
|
|
319
|
-
Args:
|
|
320
|
-
prompts: Prompts to send (will be joined with spaces)
|
|
321
|
-
message_id: Optional message id for the returned message
|
|
322
|
-
input_provider: Optional input provider for tool confirmation requests
|
|
323
|
-
message_history: Optional MessageHistory to use instead of agent's own
|
|
324
|
-
**kwargs: Additional arguments (ignored for compatibility)
|
|
325
|
-
|
|
326
|
-
Returns:
|
|
327
|
-
ChatMessage containing the agent's aggregated text response
|
|
328
|
-
"""
|
|
329
|
-
final_message: ChatMessage[str] | None = None
|
|
330
|
-
async for event in self.run_stream(
|
|
331
|
-
*prompts,
|
|
332
|
-
message_id=message_id,
|
|
333
|
-
input_provider=input_provider,
|
|
334
|
-
message_history=message_history,
|
|
335
|
-
):
|
|
336
|
-
if isinstance(event, StreamCompleteEvent):
|
|
337
|
-
final_message = event.message
|
|
338
|
-
|
|
339
|
-
if final_message is None:
|
|
340
|
-
raise RuntimeError("No final message received from stream")
|
|
341
|
-
return final_message
|
|
342
|
-
|
|
343
|
-
async def run_stream( # noqa: PLR0915
|
|
363
|
+
async def _stream_events( # noqa: PLR0915
|
|
344
364
|
self,
|
|
345
|
-
|
|
365
|
+
prompts: list[UserContent],
|
|
366
|
+
*,
|
|
367
|
+
user_msg: ChatMessage[Any],
|
|
368
|
+
effective_parent_id: str | None,
|
|
346
369
|
message_id: str | None = None,
|
|
370
|
+
conversation_id: str | None = None,
|
|
371
|
+
parent_id: str | None = None,
|
|
347
372
|
input_provider: InputProvider | None = None,
|
|
348
373
|
message_history: MessageHistory | None = None,
|
|
349
|
-
|
|
374
|
+
deps: TDeps | None = None,
|
|
375
|
+
event_handlers: Sequence[IndividualEventHandler | BuiltinEventHandlerType] | None = None,
|
|
376
|
+
wait_for_connections: bool | None = None,
|
|
377
|
+
store_history: bool = True,
|
|
350
378
|
) -> AsyncIterator[RichAgentStreamEvent[str]]:
|
|
351
|
-
"""Execute prompt with streaming events.
|
|
352
|
-
|
|
353
|
-
Sends the prompt to the remote AG-UI agent along with any registered tools.
|
|
354
|
-
When the agent requests a tool call, the tool is executed locally and the
|
|
355
|
-
result is sent back in a continuation request.
|
|
356
|
-
|
|
357
|
-
Args:
|
|
358
|
-
prompts: Prompts to send
|
|
359
|
-
message_id: Optional message ID
|
|
360
|
-
input_provider: Optional input provider for tool confirmation requests
|
|
361
|
-
message_history: Optional MessageHistory to use instead of agent's own
|
|
362
|
-
**kwargs: Additional arguments (ignored for compatibility)
|
|
363
|
-
|
|
364
|
-
Yields:
|
|
365
|
-
Native streaming events converted from AG-UI protocol
|
|
366
|
-
"""
|
|
367
379
|
# Update input provider if provided
|
|
368
380
|
if input_provider is not None:
|
|
369
381
|
self._input_provider = input_provider
|
|
382
|
+
|
|
383
|
+
# Use provided event handlers or fall back to agent's handlers
|
|
384
|
+
if event_handlers is not None:
|
|
385
|
+
from anyenv import MultiEventHandler
|
|
386
|
+
|
|
387
|
+
from agentpool.agents.events import resolve_event_handlers
|
|
388
|
+
|
|
389
|
+
handler: MultiEventHandler[IndividualEventHandler] = MultiEventHandler(
|
|
390
|
+
resolve_event_handlers(event_handlers)
|
|
391
|
+
)
|
|
392
|
+
else:
|
|
393
|
+
handler = self.event_handler
|
|
394
|
+
|
|
370
395
|
from ag_ui.core import (
|
|
371
396
|
RunAgentInput,
|
|
372
397
|
TextMessageChunkEvent,
|
|
@@ -379,22 +404,27 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
379
404
|
)
|
|
380
405
|
|
|
381
406
|
from agentpool.agents.agui_agent.agui_converters import (
|
|
382
|
-
ToolCallAccumulator,
|
|
383
407
|
agui_to_native_event,
|
|
384
408
|
to_agui_input_content,
|
|
385
409
|
to_agui_tool,
|
|
386
410
|
)
|
|
411
|
+
from agentpool.agents.tool_call_accumulator import ToolCallAccumulator
|
|
387
412
|
|
|
388
|
-
if not self._client
|
|
413
|
+
if not self._client:
|
|
389
414
|
msg = "Agent not initialized - use async context manager"
|
|
390
415
|
raise RuntimeError(msg)
|
|
391
416
|
|
|
392
417
|
# Reset cancellation state
|
|
393
418
|
self._cancelled = False
|
|
394
|
-
|
|
419
|
+
|
|
420
|
+
# Conversation ID initialization handled by BaseAgent
|
|
421
|
+
|
|
422
|
+
# Set thread_id from conversation_id (needed for AG-UI protocol)
|
|
423
|
+
if self._thread_id is None:
|
|
424
|
+
self._thread_id = self.conversation_id
|
|
395
425
|
|
|
396
426
|
conversation = message_history if message_history is not None else self.conversation
|
|
397
|
-
|
|
427
|
+
processed_prompts = prompts
|
|
398
428
|
self._run_id = str(uuid4()) # New run ID for each run
|
|
399
429
|
self._chunk_transformer.reset() # Reset chunk transformer
|
|
400
430
|
# Track messages in pydantic-ai format: ModelRequest -> ModelResponse -> ModelRequest...
|
|
@@ -406,15 +436,15 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
406
436
|
current_response_parts: list[TextPart | ThinkingPart | ToolCallPart] = []
|
|
407
437
|
text_chunks: list[str] = [] # For final content string
|
|
408
438
|
|
|
439
|
+
assert self.conversation_id is not None # Initialized by BaseAgent.run_stream()
|
|
409
440
|
run_started = RunStartedEvent(
|
|
410
441
|
thread_id=self._thread_id or self.conversation_id,
|
|
411
442
|
run_id=self._run_id or str(uuid4()),
|
|
412
443
|
agent_name=self.name,
|
|
413
444
|
)
|
|
414
|
-
for handler in self.event_handler._wrapped_handlers:
|
|
415
|
-
await handler(None, run_started)
|
|
416
|
-
yield run_started
|
|
417
445
|
|
|
446
|
+
await handler(None, run_started)
|
|
447
|
+
yield run_started
|
|
418
448
|
# Get pending parts from conversation and convert them
|
|
419
449
|
pending_parts = conversation.get_pending_parts()
|
|
420
450
|
pending_content = to_agui_input_content(pending_parts)
|
|
@@ -432,6 +462,8 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
432
462
|
tool_accumulator = ToolCallAccumulator()
|
|
433
463
|
pending_tool_results: list[ToolMessage] = []
|
|
434
464
|
self.log.debug("Sending prompt to AG-UI agent", tool_names=[t.name for t in agui_tools])
|
|
465
|
+
# Track files modified during this run
|
|
466
|
+
file_tracker = FileTracker()
|
|
435
467
|
# Loop to handle tool calls - agent may request multiple rounds
|
|
436
468
|
try:
|
|
437
469
|
while True:
|
|
@@ -509,25 +541,24 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
509
541
|
|
|
510
542
|
# Convert to native event and distribute to handlers
|
|
511
543
|
if native_event := agui_to_native_event(event):
|
|
544
|
+
# Track file modifications
|
|
545
|
+
file_tracker.process_event(native_event)
|
|
512
546
|
# Check for queued custom events first
|
|
513
547
|
while not self._event_queue.empty():
|
|
514
548
|
try:
|
|
515
549
|
custom_event = self._event_queue.get_nowait()
|
|
516
|
-
|
|
517
|
-
await handler(None, custom_event)
|
|
550
|
+
await handler(None, custom_event)
|
|
518
551
|
yield custom_event
|
|
519
552
|
except asyncio.QueueEmpty:
|
|
520
553
|
break
|
|
521
554
|
# Distribute to handlers
|
|
522
|
-
|
|
523
|
-
await handler(None, native_event)
|
|
555
|
+
await handler(None, native_event)
|
|
524
556
|
yield native_event
|
|
525
557
|
|
|
526
558
|
# Flush any pending chunk events at end of stream
|
|
527
559
|
for event in self._chunk_transformer.flush():
|
|
528
560
|
if native_event := agui_to_native_event(event):
|
|
529
|
-
|
|
530
|
-
await handler(None, native_event)
|
|
561
|
+
await handler(None, native_event)
|
|
531
562
|
yield native_event
|
|
532
563
|
|
|
533
564
|
except httpx.HTTPError:
|
|
@@ -592,14 +623,14 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
592
623
|
name=self.name,
|
|
593
624
|
message_id=message_id or str(uuid4()),
|
|
594
625
|
conversation_id=self.conversation_id,
|
|
626
|
+
parent_id=user_msg.message_id,
|
|
595
627
|
messages=model_messages,
|
|
596
628
|
finish_reason="stop",
|
|
629
|
+
metadata=file_tracker.get_metadata(),
|
|
597
630
|
)
|
|
598
631
|
complete_event = StreamCompleteEvent(message=final_message)
|
|
599
|
-
|
|
600
|
-
await handler(None, complete_event)
|
|
632
|
+
await handler(None, complete_event)
|
|
601
633
|
yield complete_event
|
|
602
|
-
self._current_stream_task = None
|
|
603
634
|
return
|
|
604
635
|
|
|
605
636
|
# Flush any remaining response parts
|
|
@@ -610,56 +641,91 @@ class AGUIAgent[TDeps = None](BaseAgent[TDeps, str]):
|
|
|
610
641
|
while not self._event_queue.empty():
|
|
611
642
|
try:
|
|
612
643
|
queued_event = self._event_queue.get_nowait()
|
|
613
|
-
|
|
614
|
-
await handler(None, queued_event)
|
|
644
|
+
await handler(None, queued_event)
|
|
615
645
|
yield queued_event
|
|
616
646
|
except asyncio.QueueEmpty:
|
|
617
647
|
break
|
|
618
648
|
|
|
619
649
|
text_content = "".join(text_chunks)
|
|
650
|
+
|
|
651
|
+
# Calculate approximate token usage from what we can observe
|
|
652
|
+
input_parts = [*processed_prompts, *pending_parts]
|
|
653
|
+
usage, cost_info = await calculate_usage_from_parts(
|
|
654
|
+
input_parts=input_parts,
|
|
655
|
+
response_parts=current_response_parts,
|
|
656
|
+
text_content=text_content,
|
|
657
|
+
model_name=self.model_name,
|
|
658
|
+
)
|
|
659
|
+
|
|
620
660
|
final_message = ChatMessage[str](
|
|
621
661
|
content=text_content,
|
|
622
662
|
role="assistant",
|
|
623
663
|
name=self.name,
|
|
624
664
|
message_id=message_id or str(uuid4()),
|
|
625
665
|
conversation_id=self.conversation_id,
|
|
666
|
+
parent_id=user_msg.message_id,
|
|
626
667
|
messages=model_messages,
|
|
668
|
+
metadata=file_tracker.get_metadata(),
|
|
669
|
+
usage=usage,
|
|
670
|
+
cost_info=cost_info,
|
|
627
671
|
)
|
|
628
672
|
complete_event = StreamCompleteEvent(message=final_message)
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
yield complete_event
|
|
632
|
-
# Record to conversation history
|
|
633
|
-
conversation.add_chat_messages([user_msg, final_message])
|
|
634
|
-
|
|
635
|
-
async def run_iter(
|
|
636
|
-
self,
|
|
637
|
-
*prompt_groups: Sequence[PromptCompatible],
|
|
638
|
-
message_id: str | None = None,
|
|
639
|
-
**kwargs: Any,
|
|
640
|
-
) -> AsyncIterator[ChatMessage[str]]:
|
|
641
|
-
"""Execute multiple prompt groups sequentially.
|
|
642
|
-
|
|
643
|
-
Args:
|
|
644
|
-
prompt_groups: Groups of prompts to execute
|
|
645
|
-
message_id: Optional message ID base
|
|
646
|
-
**kwargs: Additional arguments (ignored for compatibility)
|
|
647
|
-
|
|
648
|
-
Yields:
|
|
649
|
-
ChatMessage for each completed prompt group
|
|
650
|
-
"""
|
|
651
|
-
for i, prompts in enumerate(prompt_groups):
|
|
652
|
-
mid = f"{message_id or 'msg'}_{i}" if message_id else None
|
|
653
|
-
yield await self.run(*prompts, message_id=mid)
|
|
673
|
+
await handler(None, complete_event)
|
|
674
|
+
yield complete_event # Post-processing handled by base class
|
|
654
675
|
|
|
655
676
|
@property
|
|
656
677
|
def model_name(self) -> str | None:
|
|
657
678
|
"""Get model name (AG-UI doesn't expose this)."""
|
|
658
679
|
return None
|
|
659
680
|
|
|
660
|
-
async def
|
|
661
|
-
"""
|
|
662
|
-
|
|
681
|
+
async def set_model(self, model: str) -> None:
|
|
682
|
+
"""Set model (no-op for AG-UI as model is controlled by remote server)."""
|
|
683
|
+
# AG-UI agents don't support model selection - the model is
|
|
684
|
+
# determined by the remote server configuration
|
|
685
|
+
|
|
686
|
+
async def get_available_models(self) -> list[ModelInfo] | None:
|
|
687
|
+
"""Get available models for AG-UI agent.
|
|
688
|
+
|
|
689
|
+
AG-UI doesn't expose model information, so returns a placeholder model
|
|
690
|
+
indicating the model is determined by the remote server.
|
|
691
|
+
|
|
692
|
+
Returns:
|
|
693
|
+
List with a single placeholder ModelInfo
|
|
694
|
+
"""
|
|
695
|
+
from tokonomics.model_discovery.model_info import ModelInfo
|
|
696
|
+
|
|
697
|
+
return [
|
|
698
|
+
ModelInfo(
|
|
699
|
+
id="server-determined",
|
|
700
|
+
name="Determined by server",
|
|
701
|
+
description="The model is determined by the remote AG-UI server",
|
|
702
|
+
)
|
|
703
|
+
]
|
|
704
|
+
|
|
705
|
+
async def get_modes(self) -> list[ModeCategory]:
|
|
706
|
+
"""Get available modes for AG-UI agent.
|
|
707
|
+
|
|
708
|
+
AG-UI doesn't expose any configurable modes - model is server-controlled.
|
|
709
|
+
|
|
710
|
+
Returns:
|
|
711
|
+
Empty list - no modes supported
|
|
712
|
+
"""
|
|
713
|
+
return []
|
|
714
|
+
|
|
715
|
+
async def set_mode(self, mode: ModeInfo | str, category_id: str | None = None) -> None:
|
|
716
|
+
"""Set a mode for AG-UI agent.
|
|
717
|
+
|
|
718
|
+
AG-UI doesn't support mode switching - model is controlled by remote server.
|
|
719
|
+
|
|
720
|
+
Args:
|
|
721
|
+
mode: The mode to set (not supported)
|
|
722
|
+
category_id: Category ID (not supported)
|
|
723
|
+
|
|
724
|
+
Raises:
|
|
725
|
+
ValueError: Always - AG-UI doesn't support modes
|
|
726
|
+
"""
|
|
727
|
+
msg = "AG-UI agent does not support mode switching - model is controlled by remote server"
|
|
728
|
+
raise ValueError(msg)
|
|
663
729
|
|
|
664
730
|
|
|
665
731
|
if __name__ == "__main__":
|
|
@@ -12,7 +12,6 @@ from __future__ import annotations
|
|
|
12
12
|
import base64
|
|
13
13
|
from typing import TYPE_CHECKING, Any
|
|
14
14
|
|
|
15
|
-
import anyenv
|
|
16
15
|
from pydantic_ai import (
|
|
17
16
|
AudioUrl,
|
|
18
17
|
BinaryContent,
|
|
@@ -291,133 +290,3 @@ def to_agui_tool(tool: Tool) -> AGUITool:
|
|
|
291
290
|
description=func_schema.get("description", ""),
|
|
292
291
|
parameters=func_schema.get("parameters", {"type": "object", "properties": {}}),
|
|
293
292
|
)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
def _repair_partial_json(buffer: str) -> str:
|
|
297
|
-
"""Attempt to repair truncated JSON for preview purposes.
|
|
298
|
-
|
|
299
|
-
Handles common truncation cases:
|
|
300
|
-
- Unclosed strings
|
|
301
|
-
- Missing closing braces/brackets
|
|
302
|
-
- Trailing commas
|
|
303
|
-
|
|
304
|
-
Args:
|
|
305
|
-
buffer: Potentially incomplete JSON string
|
|
306
|
-
|
|
307
|
-
Returns:
|
|
308
|
-
Repaired JSON string (may still be invalid in edge cases)
|
|
309
|
-
"""
|
|
310
|
-
if not buffer:
|
|
311
|
-
return "{}"
|
|
312
|
-
|
|
313
|
-
result = buffer.rstrip()
|
|
314
|
-
|
|
315
|
-
# Check if we're in the middle of a string by counting unescaped quotes
|
|
316
|
-
in_string = False
|
|
317
|
-
i = 0
|
|
318
|
-
while i < len(result):
|
|
319
|
-
char = result[i]
|
|
320
|
-
if char == "\\" and i + 1 < len(result):
|
|
321
|
-
i += 2 # Skip escaped character
|
|
322
|
-
continue
|
|
323
|
-
if char == '"':
|
|
324
|
-
in_string = not in_string
|
|
325
|
-
i += 1
|
|
326
|
-
|
|
327
|
-
# Close unclosed string
|
|
328
|
-
if in_string:
|
|
329
|
-
result += '"'
|
|
330
|
-
|
|
331
|
-
# Remove trailing comma (invalid JSON)
|
|
332
|
-
result = result.rstrip()
|
|
333
|
-
if result.endswith(","):
|
|
334
|
-
result = result[:-1]
|
|
335
|
-
|
|
336
|
-
# Balance braces and brackets
|
|
337
|
-
open_braces = result.count("{") - result.count("}")
|
|
338
|
-
open_brackets = result.count("[") - result.count("]")
|
|
339
|
-
|
|
340
|
-
result += "]" * max(0, open_brackets)
|
|
341
|
-
result += "}" * max(0, open_braces)
|
|
342
|
-
|
|
343
|
-
return result
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
class ToolCallAccumulator:
|
|
347
|
-
"""Accumulates streamed tool call arguments.
|
|
348
|
-
|
|
349
|
-
AG-UI streams tool call arguments as deltas, this class accumulates them
|
|
350
|
-
and provides the complete arguments when the tool call ends.
|
|
351
|
-
"""
|
|
352
|
-
|
|
353
|
-
def __init__(self) -> None:
|
|
354
|
-
self._calls: dict[str, dict[str, Any]] = {}
|
|
355
|
-
|
|
356
|
-
def start(self, tool_call_id: str, tool_name: str) -> None:
|
|
357
|
-
"""Start tracking a new tool call."""
|
|
358
|
-
self._calls[tool_call_id] = {"name": tool_name, "args_buffer": ""}
|
|
359
|
-
|
|
360
|
-
def add_args(self, tool_call_id: str, delta: str) -> None:
|
|
361
|
-
"""Add argument delta to a tool call."""
|
|
362
|
-
if tool_call_id in self._calls:
|
|
363
|
-
self._calls[tool_call_id]["args_buffer"] += delta
|
|
364
|
-
|
|
365
|
-
def complete(self, tool_call_id: str) -> tuple[str, dict[str, Any]] | None:
|
|
366
|
-
"""Complete a tool call and return (tool_name, parsed_args).
|
|
367
|
-
|
|
368
|
-
Returns:
|
|
369
|
-
Tuple of (tool_name, args_dict) or None if call not found
|
|
370
|
-
"""
|
|
371
|
-
if tool_call_id not in self._calls:
|
|
372
|
-
return None
|
|
373
|
-
|
|
374
|
-
call_data = self._calls.pop(tool_call_id)
|
|
375
|
-
args_str = call_data["args_buffer"]
|
|
376
|
-
try:
|
|
377
|
-
args = anyenv.load_json(args_str) if args_str else {}
|
|
378
|
-
except anyenv.JsonLoadError:
|
|
379
|
-
args = {"raw": args_str}
|
|
380
|
-
return call_data["name"], args
|
|
381
|
-
|
|
382
|
-
def get_pending(self, tool_call_id: str) -> tuple[str, str] | None:
|
|
383
|
-
"""Get pending call data (tool_name, args_buffer) without completing."""
|
|
384
|
-
if tool_call_id not in self._calls:
|
|
385
|
-
return None
|
|
386
|
-
data = self._calls[tool_call_id]
|
|
387
|
-
return data["name"], data["args_buffer"]
|
|
388
|
-
|
|
389
|
-
def get_partial_args(self, tool_call_id: str) -> dict[str, Any]:
|
|
390
|
-
"""Get best-effort parsed args from incomplete JSON stream.
|
|
391
|
-
|
|
392
|
-
Uses heuristics to complete truncated JSON for preview purposes.
|
|
393
|
-
Handles unclosed strings, missing braces/brackets, and trailing commas.
|
|
394
|
-
|
|
395
|
-
Args:
|
|
396
|
-
tool_call_id: Tool call ID
|
|
397
|
-
|
|
398
|
-
Returns:
|
|
399
|
-
Partially parsed arguments or empty dict
|
|
400
|
-
"""
|
|
401
|
-
if tool_call_id not in self._calls:
|
|
402
|
-
return {}
|
|
403
|
-
|
|
404
|
-
buffer = self._calls[tool_call_id]["args_buffer"]
|
|
405
|
-
if not buffer:
|
|
406
|
-
return {}
|
|
407
|
-
|
|
408
|
-
# Try direct parse first
|
|
409
|
-
try:
|
|
410
|
-
return anyenv.load_json(buffer)
|
|
411
|
-
except anyenv.JsonLoadError:
|
|
412
|
-
pass
|
|
413
|
-
|
|
414
|
-
# Try to repair truncated JSON
|
|
415
|
-
try:
|
|
416
|
-
repaired = _repair_partial_json(buffer)
|
|
417
|
-
return anyenv.load_json(repaired)
|
|
418
|
-
except anyenv.JsonLoadError:
|
|
419
|
-
return {}
|
|
420
|
-
|
|
421
|
-
def clear(self) -> None:
|
|
422
|
-
"""Clear all pending tool calls."""
|
|
423
|
-
self._calls.clear()
|
|
@@ -16,8 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
from ag_ui.core import Event, ToolMessage
|
|
17
17
|
import httpx
|
|
18
18
|
|
|
19
|
-
from agentpool.agents.context import ConfirmationResult
|
|
20
|
-
from agentpool.messaging.context import NodeContext
|
|
19
|
+
from agentpool.agents.context import AgentContext, ConfirmationResult
|
|
21
20
|
from agentpool.tools import Tool
|
|
22
21
|
from agentpool.ui.base import InputProvider
|
|
23
22
|
from agentpool_config.nodes import ToolConfirmationMode
|
|
@@ -51,7 +50,7 @@ async def _get_tool_confirmation(
|
|
|
51
50
|
tool: Tool,
|
|
52
51
|
args: dict[str, Any],
|
|
53
52
|
input_provider: InputProvider,
|
|
54
|
-
context:
|
|
53
|
+
context: AgentContext[Any],
|
|
55
54
|
) -> ConfirmationResult:
|
|
56
55
|
"""Get confirmation for tool execution.
|
|
57
56
|
|
|
@@ -78,7 +77,7 @@ async def execute_tool_calls(
|
|
|
78
77
|
*,
|
|
79
78
|
confirmation_mode: ToolConfirmationMode = "never",
|
|
80
79
|
input_provider: InputProvider | None = None,
|
|
81
|
-
context:
|
|
80
|
+
context: AgentContext[Any] | None = None,
|
|
82
81
|
) -> list[ToolMessage]:
|
|
83
82
|
"""Execute tool calls locally and return results.
|
|
84
83
|
|