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
|
@@ -5,9 +5,8 @@ from __future__ import annotations
|
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from collections.abc import Sequence
|
|
7
7
|
from typing import TYPE_CHECKING, Any, Literal, Self, overload
|
|
8
|
-
from uuid import uuid4
|
|
9
8
|
|
|
10
|
-
from
|
|
9
|
+
from anyenv.signals import Signal
|
|
11
10
|
|
|
12
11
|
from agentpool.log import get_logger
|
|
13
12
|
from agentpool.messaging import ChatMessage
|
|
@@ -20,8 +19,8 @@ if TYPE_CHECKING:
|
|
|
20
19
|
from datetime import timedelta
|
|
21
20
|
from types import TracebackType
|
|
22
21
|
|
|
23
|
-
from evented.configs import EventConfig
|
|
24
22
|
from evented.event_data import EventData
|
|
23
|
+
from evented_config import EventConfig
|
|
25
24
|
|
|
26
25
|
from agentpool.common_types import (
|
|
27
26
|
AnyTransformFn,
|
|
@@ -34,7 +33,7 @@ if TYPE_CHECKING:
|
|
|
34
33
|
from agentpool.storage import StorageManager
|
|
35
34
|
from agentpool.talk import Talk, TeamTalk
|
|
36
35
|
from agentpool.talk.stats import AggregatedMessageStats, MessageStats
|
|
37
|
-
from agentpool.tools.base import
|
|
36
|
+
from agentpool.tools.base import FunctionTool
|
|
38
37
|
from agentpool_config.forward_targets import ConnectionType
|
|
39
38
|
from agentpool_config.mcp_server import MCPServerConfig
|
|
40
39
|
|
|
@@ -45,10 +44,10 @@ logger = get_logger(__name__)
|
|
|
45
44
|
class MessageNode[TDeps, TResult](ABC):
|
|
46
45
|
"""Base class for all message processing nodes."""
|
|
47
46
|
|
|
48
|
-
message_received = Signal(
|
|
47
|
+
message_received = Signal[ChatMessage[Any]]()
|
|
49
48
|
"""Signal emitted when node receives a message."""
|
|
50
49
|
|
|
51
|
-
message_sent = Signal(
|
|
50
|
+
message_sent = Signal[ChatMessage[Any]]()
|
|
52
51
|
"""Signal emitted when node creates a message."""
|
|
53
52
|
|
|
54
53
|
def __init__(
|
|
@@ -86,18 +85,33 @@ class MessageNode[TDeps, TResult](ABC):
|
|
|
86
85
|
name_ = f"node_{self._name}"
|
|
87
86
|
self.mcp = MCPManager(name_, servers=mcp_servers, owner=self.name)
|
|
88
87
|
self.enable_db_logging = enable_logging
|
|
89
|
-
self.conversation_id =
|
|
90
|
-
|
|
91
|
-
# TODO: need to check this
|
|
92
|
-
# node.message_received.connect(self.log_message)
|
|
88
|
+
self.conversation_id: str | None = None
|
|
89
|
+
self.conversation_title: str | None = None
|
|
93
90
|
|
|
94
|
-
|
|
95
|
-
"""
|
|
96
|
-
|
|
91
|
+
def _set_conversation_title(self, title: str) -> None:
|
|
92
|
+
"""Callback for setting conversation title (called by storage manager)."""
|
|
93
|
+
self.conversation_title = title
|
|
94
|
+
|
|
95
|
+
async def log_conversation(self, initial_prompt: str | None = None) -> None:
|
|
96
|
+
"""Log conversation to storage if enabled.
|
|
97
|
+
|
|
98
|
+
Should be called at the start of run_stream() after conversation_id is set.
|
|
99
|
+
For native agents, generate conversation_id first with uuid4().
|
|
100
|
+
For wrapped agents (Claude Code), set conversation_id from SDK session first.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
initial_prompt: Optional initial prompt to trigger title generation.
|
|
104
|
+
"""
|
|
105
|
+
if self.enable_db_logging and self.storage and self.conversation_id:
|
|
97
106
|
await self.storage.log_conversation(
|
|
98
107
|
conversation_id=self.conversation_id,
|
|
99
108
|
node_name=self.name,
|
|
109
|
+
initial_prompt=initial_prompt,
|
|
110
|
+
on_title_generated=self._set_conversation_title,
|
|
100
111
|
)
|
|
112
|
+
|
|
113
|
+
async def __aenter__(self) -> Self:
|
|
114
|
+
"""Initialize base message node."""
|
|
101
115
|
try:
|
|
102
116
|
await self._events.__aenter__()
|
|
103
117
|
await self.mcp.__aenter__()
|
|
@@ -161,7 +175,7 @@ class MessageNode[TDeps, TResult](ABC):
|
|
|
161
175
|
|
|
162
176
|
def to_tool(
|
|
163
177
|
self, *, name: str | None = None, description: str | None = None, **kwargs: Any
|
|
164
|
-
) ->
|
|
178
|
+
) -> FunctionTool[TResult]:
|
|
165
179
|
"""Convert node to a callable tool.
|
|
166
180
|
|
|
167
181
|
Args:
|
|
@@ -354,6 +368,30 @@ class MessageNode[TDeps, TResult](ABC):
|
|
|
354
368
|
async def run(self, *prompts: Any, **kwargs: Any) -> ChatMessage[TResult]:
|
|
355
369
|
"""Execute node with prompts. Implementation-specific run logic."""
|
|
356
370
|
|
|
371
|
+
async def run_message(
|
|
372
|
+
self,
|
|
373
|
+
message: ChatMessage[Any],
|
|
374
|
+
**kwargs: Any,
|
|
375
|
+
) -> ChatMessage[TResult]:
|
|
376
|
+
"""Run with an incoming ChatMessage (e.g., from Talk routing).
|
|
377
|
+
|
|
378
|
+
Extracts content from the message, preserves conversation_id,
|
|
379
|
+
and sets parent_id to track the message chain.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
message: The incoming ChatMessage to process
|
|
383
|
+
**kwargs: Additional arguments passed to run()
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
Response ChatMessage with message chain tracked via parent_id
|
|
387
|
+
"""
|
|
388
|
+
return await self.run(
|
|
389
|
+
message.content,
|
|
390
|
+
conversation_id=message.conversation_id,
|
|
391
|
+
parent_id=message.message_id,
|
|
392
|
+
**kwargs,
|
|
393
|
+
)
|
|
394
|
+
|
|
357
395
|
async def get_message_history(self, limit: int | None = None) -> list[ChatMessage[Any]]:
|
|
358
396
|
"""Get message history from storage."""
|
|
359
397
|
from agentpool_config.session import SessionQuery
|
agentpool/messaging/messages.py
CHANGED
|
@@ -30,6 +30,7 @@ from agentpool.common_types import MessageRole, SimpleJsonType # noqa: TC001
|
|
|
30
30
|
from agentpool.log import get_logger
|
|
31
31
|
from agentpool.utils.inspection import dataclasses_no_defaults_repr
|
|
32
32
|
from agentpool.utils.now import get_now
|
|
33
|
+
from agentpool.utils.pydantic_ai_helpers import safe_args_as_dict
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
if TYPE_CHECKING:
|
|
@@ -71,9 +72,7 @@ Metadata:
|
|
|
71
72
|
{{ key }}: {{ value }}
|
|
72
73
|
{%- endfor %}
|
|
73
74
|
{%- endif %}
|
|
74
|
-
|
|
75
|
-
Forwarded via: {{ forwarded_from|join(' -> ') }}
|
|
76
|
-
{%- endif %}"""
|
|
75
|
+
"""
|
|
77
76
|
|
|
78
77
|
MARKDOWN_TEMPLATE = """## {{ name or role.title() }}
|
|
79
78
|
*{{ timestamp.strftime('%Y-%m-%d %H:%M:%S') }}*
|
|
@@ -97,10 +96,7 @@ MARKDOWN_TEMPLATE = """## {{ name or role.title() }}
|
|
|
97
96
|
```
|
|
98
97
|
{%- endif %}
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
*Forwarded via: {{ forwarded_from|join(' → ') }}*
|
|
103
|
-
{% endif %}"""
|
|
99
|
+
"""
|
|
104
100
|
|
|
105
101
|
MESSAGE_TEMPLATES = {
|
|
106
102
|
"simple": SIMPLE_TEMPLATE,
|
|
@@ -198,6 +194,14 @@ class ChatMessage[TContent]:
|
|
|
198
194
|
conversation_id: str | None = None
|
|
199
195
|
"""ID of the conversation this message belongs to."""
|
|
200
196
|
|
|
197
|
+
parent_id: str | None = None
|
|
198
|
+
"""ID of the parent message for tree-structured conversations.
|
|
199
|
+
|
|
200
|
+
This enables branching conversations where each message knows its predecessor.
|
|
201
|
+
For user messages, this typically points to the previous assistant response.
|
|
202
|
+
For assistant responses, this points to the user message being responded to.
|
|
203
|
+
"""
|
|
204
|
+
|
|
201
205
|
response_time: float | None = None
|
|
202
206
|
"""Time it took the LLM to respond."""
|
|
203
207
|
|
|
@@ -207,9 +211,6 @@ class ChatMessage[TContent]:
|
|
|
207
211
|
name: str | None = None
|
|
208
212
|
"""Display name for the message sender in UI."""
|
|
209
213
|
|
|
210
|
-
forwarded_from: list[str] = field(default_factory=list)
|
|
211
|
-
"""List of agent names (the chain) that forwarded this message to the sender."""
|
|
212
|
-
|
|
213
214
|
provider_details: dict[str, Any] = field(default_factory=dict)
|
|
214
215
|
"""Provider specific metadata / extra information."""
|
|
215
216
|
|
|
@@ -295,12 +296,29 @@ class ChatMessage[TContent]:
|
|
|
295
296
|
message: TPromptContent,
|
|
296
297
|
conversation_id: str | None = None,
|
|
297
298
|
instructions: str | None = None,
|
|
299
|
+
parent_id: str | None = None,
|
|
298
300
|
) -> ChatMessage[TPromptContent]:
|
|
299
|
-
"""Create a user prompt message.
|
|
301
|
+
"""Create a user prompt message.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
message: The prompt content
|
|
305
|
+
conversation_id: ID of the conversation
|
|
306
|
+
instructions: Optional instructions for the model
|
|
307
|
+
parent_id: ID of the parent message (typically the previous assistant response)
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
A ChatMessage representing the user prompt
|
|
311
|
+
"""
|
|
300
312
|
part = UserPromptPart(content=message)
|
|
301
313
|
request = ModelRequest(parts=[part], instructions=instructions)
|
|
302
314
|
id_ = conversation_id or str(uuid4())
|
|
303
|
-
return ChatMessage(
|
|
315
|
+
return ChatMessage(
|
|
316
|
+
messages=[request],
|
|
317
|
+
role="user",
|
|
318
|
+
content=message,
|
|
319
|
+
conversation_id=id_,
|
|
320
|
+
parent_id=parent_id,
|
|
321
|
+
)
|
|
304
322
|
|
|
305
323
|
@classmethod
|
|
306
324
|
def from_pydantic_ai[TContentType](
|
|
@@ -309,7 +327,7 @@ class ChatMessage[TContent]:
|
|
|
309
327
|
message: ModelMessage,
|
|
310
328
|
conversation_id: str | None = None,
|
|
311
329
|
name: str | None = None,
|
|
312
|
-
|
|
330
|
+
parent_id: str | None = None,
|
|
313
331
|
) -> ChatMessage[TContentType]:
|
|
314
332
|
"""Convert a Pydantic model to a ChatMessage."""
|
|
315
333
|
match message:
|
|
@@ -319,9 +337,8 @@ class ChatMessage[TContent]:
|
|
|
319
337
|
content=content,
|
|
320
338
|
role="user",
|
|
321
339
|
message_id=run_id or str(uuid.uuid4()),
|
|
322
|
-
# instructions=instructions,
|
|
323
|
-
forwarded_from=forwarded_from or [],
|
|
324
340
|
name=name,
|
|
341
|
+
parent_id=parent_id,
|
|
325
342
|
)
|
|
326
343
|
case ModelResponse(
|
|
327
344
|
usage=usage,
|
|
@@ -347,7 +364,7 @@ class ChatMessage[TContent]:
|
|
|
347
364
|
finish_reason=finish_reason,
|
|
348
365
|
provider_response_id=provider_response_id,
|
|
349
366
|
name=name,
|
|
350
|
-
|
|
367
|
+
parent_id=parent_id,
|
|
351
368
|
)
|
|
352
369
|
case _ as unreachable:
|
|
353
370
|
assert_never(unreachable)
|
|
@@ -360,7 +377,9 @@ class ChatMessage[TContent]:
|
|
|
360
377
|
agent_name: str | None = None,
|
|
361
378
|
message_id: str | None = None,
|
|
362
379
|
conversation_id: str | None = None,
|
|
380
|
+
parent_id: str | None = None,
|
|
363
381
|
response_time: float,
|
|
382
|
+
metadata: SimpleJsonType | None = None,
|
|
364
383
|
) -> ChatMessage[OutputDataT]:
|
|
365
384
|
"""Create a ChatMessage from a PydanticAI run result.
|
|
366
385
|
|
|
@@ -369,19 +388,29 @@ class ChatMessage[TContent]:
|
|
|
369
388
|
agent_name: Name of the agent that generated this response
|
|
370
389
|
message_id: Unique message identifier
|
|
371
390
|
conversation_id: Conversation identifier
|
|
391
|
+
parent_id: ID of the parent message (typically the user message)
|
|
372
392
|
response_time: Total time taken for the response
|
|
393
|
+
metadata: Optional metadata to attach to the message
|
|
373
394
|
|
|
374
395
|
Returns:
|
|
375
396
|
A ChatMessage with all fields populated from the result
|
|
376
397
|
"""
|
|
377
|
-
# Calculate costs
|
|
398
|
+
# Calculate costs - prefer provider-reported cost if available
|
|
378
399
|
run_usage = result.usage()
|
|
379
400
|
usage = result.response.usage
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
401
|
+
provider_cost = (result.response.provider_details or {}).get("cost")
|
|
402
|
+
if provider_cost is not None:
|
|
403
|
+
# Use actual cost from provider (e.g., OpenRouter returns this)
|
|
404
|
+
cost_info: TokenCost | None = TokenCost(
|
|
405
|
+
token_usage=run_usage, total_cost=Decimal(str(provider_cost))
|
|
406
|
+
)
|
|
407
|
+
else:
|
|
408
|
+
# Fall back to calculated cost
|
|
409
|
+
cost_info = await TokenCost.from_usage(
|
|
410
|
+
model=result.response.model_name or "",
|
|
411
|
+
usage=run_usage,
|
|
412
|
+
provider=result.response.provider_name,
|
|
413
|
+
)
|
|
385
414
|
|
|
386
415
|
return ChatMessage[OutputDataT](
|
|
387
416
|
content=result.output,
|
|
@@ -395,23 +424,13 @@ class ChatMessage[TContent]:
|
|
|
395
424
|
provider_name=result.response.provider_name,
|
|
396
425
|
message_id=message_id or str(uuid4()),
|
|
397
426
|
conversation_id=conversation_id,
|
|
427
|
+
parent_id=parent_id,
|
|
398
428
|
cost_info=cost_info,
|
|
399
429
|
response_time=response_time,
|
|
400
430
|
provider_details={},
|
|
431
|
+
metadata=metadata or {},
|
|
401
432
|
)
|
|
402
433
|
|
|
403
|
-
def forwarded(self, previous_message: ChatMessage[Any]) -> Self:
|
|
404
|
-
"""Create new message showing it was forwarded from another message.
|
|
405
|
-
|
|
406
|
-
Args:
|
|
407
|
-
previous_message: The message that led to this one's creation
|
|
408
|
-
|
|
409
|
-
Returns:
|
|
410
|
-
New message with updated chain showing the path through previous message
|
|
411
|
-
"""
|
|
412
|
-
from_ = [*previous_message.forwarded_from, previous_message.name or "unknown"]
|
|
413
|
-
return replace(self, forwarded_from=from_)
|
|
414
|
-
|
|
415
434
|
@property
|
|
416
435
|
def response(self) -> ModelResponse:
|
|
417
436
|
"""Return the last response from the message history."""
|
|
@@ -509,7 +528,7 @@ class ChatMessage[TContent]:
|
|
|
509
528
|
call_part = call_parts[part.tool_call_id]
|
|
510
529
|
tool_info = ToolCallInfo(
|
|
511
530
|
tool_name=call_part.tool_name,
|
|
512
|
-
args=call_part
|
|
531
|
+
args=safe_args_as_dict(call_part),
|
|
513
532
|
agent_name=agent_name or "UNSET",
|
|
514
533
|
result=part.content,
|
|
515
534
|
tool_call_id=call_part.tool_call_id or str(uuid4()),
|
|
@@ -17,32 +17,27 @@ if TYPE_CHECKING:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
async def prepare_prompts(
|
|
20
|
-
*prompt: PromptCompatible
|
|
21
|
-
|
|
20
|
+
*prompt: PromptCompatible,
|
|
21
|
+
parent_id: str | None = None,
|
|
22
|
+
conversation_id: str | None = None,
|
|
23
|
+
) -> tuple[ChatMessage[Any], list[UserContent]]:
|
|
22
24
|
"""Prepare prompts for processing.
|
|
23
25
|
|
|
24
|
-
Extracted from MessageNode.pre_run logic.
|
|
25
|
-
|
|
26
26
|
Args:
|
|
27
27
|
*prompt: The prompt(s) to prepare.
|
|
28
|
+
parent_id: Optional ID of the parent message (typically the previous response).
|
|
29
|
+
conversation_id: Optional conversation ID for the user message.
|
|
28
30
|
|
|
29
31
|
Returns:
|
|
30
32
|
A tuple of:
|
|
31
|
-
-
|
|
32
|
-
on the prompt(s).
|
|
33
|
+
- A ChatMessage representing the user prompt.
|
|
33
34
|
- A list of prompts to be sent to the model.
|
|
34
|
-
- The original ChatMessage if forwarded, None otherwise
|
|
35
35
|
"""
|
|
36
|
-
if len(prompt) == 1 and isinstance(prompt[0], ChatMessage):
|
|
37
|
-
original_msg = prompt[0]
|
|
38
|
-
# Update received message's chain to show it came through its source
|
|
39
|
-
user_msg = original_msg.forwarded(original_msg).to_request()
|
|
40
|
-
prompts = await convert_prompts([user_msg.content])
|
|
41
|
-
# clear cost info to avoid double-counting
|
|
42
|
-
return user_msg, prompts, original_msg
|
|
43
36
|
prompts = await convert_prompts(prompt)
|
|
44
|
-
user_msg = ChatMessage.user_prompt(
|
|
45
|
-
|
|
37
|
+
user_msg = ChatMessage.user_prompt(
|
|
38
|
+
message=prompts, parent_id=parent_id, conversation_id=conversation_id
|
|
39
|
+
)
|
|
40
|
+
return user_msg, prompts
|
|
46
41
|
|
|
47
42
|
|
|
48
43
|
async def finalize_message(
|
|
@@ -50,7 +45,6 @@ async def finalize_message(
|
|
|
50
45
|
previous_message: ChatMessage[Any] | None,
|
|
51
46
|
node: MessageNode[Any, Any],
|
|
52
47
|
connections: ConnectionManager,
|
|
53
|
-
original_message: ChatMessage[Any] | None,
|
|
54
48
|
wait_for_connections: bool | None = None,
|
|
55
49
|
) -> ChatMessage[Any]:
|
|
56
50
|
"""Handle message finalization and routing.
|
|
@@ -60,16 +54,12 @@ async def finalize_message(
|
|
|
60
54
|
previous_message: The original user message (if any)
|
|
61
55
|
node: The message node that produced the message
|
|
62
56
|
connections: Connection manager for routing
|
|
63
|
-
original_message: The original ChatMessage if forwarded, None otherwise
|
|
64
57
|
wait_for_connections: Whether to wait for connected nodes
|
|
65
58
|
|
|
66
59
|
Returns:
|
|
67
60
|
The finalized message
|
|
68
61
|
"""
|
|
69
|
-
#
|
|
70
|
-
if original_message:
|
|
71
|
-
message = message.forwarded(original_message)
|
|
72
|
-
node.message_sent.emit(message) # Emit signals
|
|
62
|
+
await node.message_sent.emit(message) # Emit signals
|
|
73
63
|
await node.log_message(message) # Log message if enabled
|
|
74
64
|
# Route to connections
|
|
75
65
|
await connections.route_message(message, wait=wait_for_connections)
|
agentpool/models/__init__.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from agentpool.models.acp_agents import ACPAgentConfig, ACPAgentConfigTypes, BaseACPAgentConfig
|
|
6
|
-
from agentpool.models.agents import NativeAgentConfig
|
|
6
|
+
from agentpool.models.agents import AnyToolConfig, NativeAgentConfig # noqa: F401
|
|
7
7
|
from agentpool.models.agui_agents import AGUIAgentConfig
|
|
8
8
|
from agentpool.models.claude_code_agents import ClaudeCodeAgentConfig
|
|
9
9
|
from agentpool.models.manifest import AgentsManifest, AnyAgentConfig
|
|
@@ -7,13 +7,12 @@ import os
|
|
|
7
7
|
import tempfile
|
|
8
8
|
from typing import TYPE_CHECKING, Annotated, Any, Literal
|
|
9
9
|
|
|
10
|
-
from
|
|
11
|
-
from exxec.configs import (
|
|
10
|
+
from exxec_config import (
|
|
12
11
|
E2bExecutionEnvironmentConfig,
|
|
13
12
|
ExecutionEnvironmentConfig, # noqa: TC002
|
|
13
|
+
ExecutionEnvironmentStr, # noqa: TC002
|
|
14
14
|
)
|
|
15
15
|
from pydantic import ConfigDict, Field
|
|
16
|
-
from tokonomics.model_discovery import ProviderType # noqa: TC002
|
|
17
16
|
|
|
18
17
|
from agentpool_config.nodes import NodeConfig
|
|
19
18
|
from agentpool_config.system_prompts import PromptConfig # noqa: TC001
|
|
@@ -224,6 +223,8 @@ class BaseACPAgentConfig(NodeConfig):
|
|
|
224
223
|
|
|
225
224
|
def get_execution_environment(self) -> ExecutionEnvironment:
|
|
226
225
|
"""Create execution environment from config."""
|
|
226
|
+
from exxec import get_environment
|
|
227
|
+
|
|
227
228
|
if isinstance(self.execution_environment, str):
|
|
228
229
|
return get_environment(self.execution_environment)
|
|
229
230
|
return self.execution_environment.get_provider()
|
|
@@ -233,21 +234,14 @@ class BaseACPAgentConfig(NodeConfig):
|
|
|
233
234
|
|
|
234
235
|
Returns None if not configured (caller should fall back to main env).
|
|
235
236
|
"""
|
|
237
|
+
from exxec import get_environment
|
|
238
|
+
|
|
236
239
|
if self.client_execution_environment is None:
|
|
237
240
|
return None
|
|
238
241
|
if isinstance(self.client_execution_environment, str):
|
|
239
242
|
return get_environment(self.client_execution_environment)
|
|
240
243
|
return self.client_execution_environment.get_provider()
|
|
241
244
|
|
|
242
|
-
@property
|
|
243
|
-
def model_providers(self) -> list[ProviderType]:
|
|
244
|
-
"""Return the model providers used by this ACP agent.
|
|
245
|
-
|
|
246
|
-
Override in subclasses to specify which providers the agent uses.
|
|
247
|
-
Used for intelligent model discovery and fallback configuration.
|
|
248
|
-
"""
|
|
249
|
-
return []
|
|
250
|
-
|
|
251
245
|
|
|
252
246
|
class ACPAgentConfig(BaseACPAgentConfig):
|
|
253
247
|
"""Configuration for a custom ACP agent with explicit command.
|
|
@@ -286,18 +280,6 @@ class ACPAgentConfig(BaseACPAgentConfig):
|
|
|
286
280
|
)
|
|
287
281
|
"""Arguments to pass to the command."""
|
|
288
282
|
|
|
289
|
-
providers: list[ProviderType] = Field(
|
|
290
|
-
default_factory=list,
|
|
291
|
-
title="Providers",
|
|
292
|
-
examples=[["openai", "anthropic"], ["gemini"]],
|
|
293
|
-
)
|
|
294
|
-
"""Model providers this agent can use."""
|
|
295
|
-
|
|
296
|
-
@property
|
|
297
|
-
def model_providers(self) -> list[ProviderType]:
|
|
298
|
-
"""Return configured providers for custom ACP agents."""
|
|
299
|
-
return list(self.providers)
|
|
300
|
-
|
|
301
283
|
def get_command(self) -> str:
|
|
302
284
|
"""Get the command to spawn the ACP server."""
|
|
303
285
|
return self.command
|