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
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Server state management."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Coroutine
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
import time
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
import asyncio
|
|
13
|
+
|
|
14
|
+
from agentpool import AgentPool
|
|
15
|
+
from agentpool.agents.base_agent import BaseAgent
|
|
16
|
+
from agentpool.diagnostics.lsp_manager import LSPManager
|
|
17
|
+
from agentpool_server.opencode_server.input_provider import OpenCodeInputProvider
|
|
18
|
+
from agentpool_server.opencode_server.models import (
|
|
19
|
+
Config,
|
|
20
|
+
Event,
|
|
21
|
+
MessageWithParts,
|
|
22
|
+
QuestionInfo,
|
|
23
|
+
Session,
|
|
24
|
+
SessionStatus,
|
|
25
|
+
Todo,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Type alias for async callback
|
|
29
|
+
OnFirstSubscriberCallback = Callable[[], Coroutine[Any, Any, None]]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class PendingQuestion:
|
|
34
|
+
"""Pending question awaiting user response."""
|
|
35
|
+
|
|
36
|
+
session_id: str
|
|
37
|
+
"""Session that owns this question."""
|
|
38
|
+
|
|
39
|
+
questions: list[QuestionInfo]
|
|
40
|
+
"""Questions to ask."""
|
|
41
|
+
|
|
42
|
+
future: asyncio.Future[list[list[str]]]
|
|
43
|
+
"""Future that resolves when user answers."""
|
|
44
|
+
|
|
45
|
+
tool: dict[str, str] | None = None
|
|
46
|
+
"""Optional tool context: {message_id, call_id}."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class ServerState:
|
|
51
|
+
"""Shared state for the OpenCode server.
|
|
52
|
+
|
|
53
|
+
Uses AgentPool for session persistence and storage.
|
|
54
|
+
In-memory state tracks active sessions and runtime data.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
working_dir: str
|
|
58
|
+
pool: AgentPool[Any]
|
|
59
|
+
agent: BaseAgent[Any, Any]
|
|
60
|
+
start_time: float = field(default_factory=time.time)
|
|
61
|
+
|
|
62
|
+
# Configuration (mutable runtime config)
|
|
63
|
+
# Initialized after state creation
|
|
64
|
+
config: Config | None = None
|
|
65
|
+
|
|
66
|
+
# Active sessions cache (session_id -> OpenCode Session model)
|
|
67
|
+
# This is a cache of sessions loaded from pool.sessions
|
|
68
|
+
sessions: dict[str, Session] = field(default_factory=dict)
|
|
69
|
+
session_status: dict[str, SessionStatus] = field(default_factory=dict)
|
|
70
|
+
|
|
71
|
+
# Message storage (session_id -> messages)
|
|
72
|
+
# Runtime cache - messages are also persisted via pool.storage
|
|
73
|
+
messages: dict[str, list[MessageWithParts]] = field(default_factory=dict)
|
|
74
|
+
|
|
75
|
+
# Reverted messages storage (session_id -> removed messages)
|
|
76
|
+
# Stores messages removed during revert for unrevert operation
|
|
77
|
+
reverted_messages: dict[str, list[MessageWithParts]] = field(default_factory=dict)
|
|
78
|
+
|
|
79
|
+
# Todo storage (session_id -> todos)
|
|
80
|
+
# Uses pool.todos for persistence
|
|
81
|
+
todos: dict[str, list[Todo]] = field(default_factory=dict)
|
|
82
|
+
|
|
83
|
+
# Input providers for permission handling (session_id -> provider)
|
|
84
|
+
input_providers: dict[str, OpenCodeInputProvider] = field(default_factory=dict)
|
|
85
|
+
|
|
86
|
+
# Question storage (question_id -> pending question info)
|
|
87
|
+
pending_questions: dict[str, PendingQuestion] = field(default_factory=dict)
|
|
88
|
+
|
|
89
|
+
# SSE event subscribers
|
|
90
|
+
event_subscribers: list[asyncio.Queue[Event]] = field(default_factory=list)
|
|
91
|
+
|
|
92
|
+
# Callback for first subscriber connection (e.g., for update check)
|
|
93
|
+
on_first_subscriber: OnFirstSubscriberCallback | None = None
|
|
94
|
+
_first_subscriber_triggered: bool = field(default=False, repr=False)
|
|
95
|
+
|
|
96
|
+
# Background tasks (for cleanup on shutdown)
|
|
97
|
+
background_tasks: set[asyncio.Task[Any]] = field(default_factory=set)
|
|
98
|
+
|
|
99
|
+
# LSP manager for language server integration (initialized lazily)
|
|
100
|
+
lsp_manager: LSPManager | None = None
|
|
101
|
+
|
|
102
|
+
def create_background_task(self, coro: Any, *, name: str | None = None) -> asyncio.Task[Any]:
|
|
103
|
+
"""Create and track a background task."""
|
|
104
|
+
import asyncio
|
|
105
|
+
|
|
106
|
+
task = asyncio.create_task(coro, name=name)
|
|
107
|
+
self.background_tasks.add(task)
|
|
108
|
+
task.add_done_callback(self.background_tasks.discard)
|
|
109
|
+
return task
|
|
110
|
+
|
|
111
|
+
async def cleanup_tasks(self) -> None:
|
|
112
|
+
"""Cancel and wait for all background tasks."""
|
|
113
|
+
for task in self.background_tasks:
|
|
114
|
+
task.cancel()
|
|
115
|
+
if self.background_tasks:
|
|
116
|
+
import asyncio
|
|
117
|
+
|
|
118
|
+
await asyncio.gather(*self.background_tasks, return_exceptions=True)
|
|
119
|
+
self.background_tasks.clear()
|
|
120
|
+
|
|
121
|
+
async def broadcast_event(self, event: Event) -> None:
|
|
122
|
+
"""Broadcast an event to all SSE subscribers."""
|
|
123
|
+
print(f"Broadcasting event: {event.type} to {len(self.event_subscribers)} subscribers")
|
|
124
|
+
for queue in self.event_subscribers:
|
|
125
|
+
await queue.put(event)
|
|
126
|
+
|
|
127
|
+
def get_or_create_lsp_manager(self) -> LSPManager:
|
|
128
|
+
"""Get or create the LSP manager.
|
|
129
|
+
|
|
130
|
+
Creates the LSP manager lazily using the agent's execution environment.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
The LSP manager instance.
|
|
134
|
+
|
|
135
|
+
Raises:
|
|
136
|
+
RuntimeError: If the agent doesn't have an execution environment.
|
|
137
|
+
"""
|
|
138
|
+
if self.lsp_manager is not None:
|
|
139
|
+
return self.lsp_manager
|
|
140
|
+
|
|
141
|
+
from agentpool.diagnostics.lsp_manager import LSPManager
|
|
142
|
+
|
|
143
|
+
# Get the execution environment from the agent
|
|
144
|
+
env = getattr(self.agent, "env", None)
|
|
145
|
+
if env is None:
|
|
146
|
+
msg = "Agent does not have an execution environment for LSP"
|
|
147
|
+
raise RuntimeError(msg)
|
|
148
|
+
|
|
149
|
+
self.lsp_manager = LSPManager(env=env)
|
|
150
|
+
self.lsp_manager.register_defaults()
|
|
151
|
+
return self.lsp_manager
|
agentpool_storage/__init__.py
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
"""Storage provider package."""
|
|
2
2
|
|
|
3
3
|
from agentpool_storage.base import StorageProvider
|
|
4
|
+
from agentpool_storage.project_store import (
|
|
5
|
+
ProjectStore,
|
|
6
|
+
detect_project_root,
|
|
7
|
+
discover_config_path,
|
|
8
|
+
generate_project_id,
|
|
9
|
+
resolve_config,
|
|
10
|
+
)
|
|
4
11
|
from agentpool_storage.session_store import SQLSessionStore
|
|
5
12
|
|
|
6
13
|
__all__ = [
|
|
14
|
+
"ProjectStore",
|
|
7
15
|
"SQLSessionStore",
|
|
8
16
|
"StorageProvider",
|
|
17
|
+
"detect_project_root",
|
|
18
|
+
"discover_config_path",
|
|
19
|
+
"generate_project_id",
|
|
20
|
+
"resolve_config",
|
|
9
21
|
]
|
agentpool_storage/base.py
CHANGED
|
@@ -19,6 +19,7 @@ if TYPE_CHECKING:
|
|
|
19
19
|
|
|
20
20
|
from agentpool.common_types import JsonValue
|
|
21
21
|
from agentpool.messaging import ChatMessage, TokenCost
|
|
22
|
+
from agentpool.sessions.models import ProjectData
|
|
22
23
|
from agentpool_config.session import SessionQuery
|
|
23
24
|
from agentpool_config.storage import BaseStorageProviderConfig
|
|
24
25
|
from agentpool_storage.models import ConversationData, QueryFilters, StatsFilters
|
|
@@ -37,7 +38,6 @@ class StoredMessage:
|
|
|
37
38
|
token_usage: dict[str, int] | None = None
|
|
38
39
|
cost: float | None = None
|
|
39
40
|
response_time: float | None = None
|
|
40
|
-
forwarded_from: list[str] | None = None
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class StoredConversation:
|
|
@@ -98,10 +98,10 @@ class StorageProvider:
|
|
|
98
98
|
content: str,
|
|
99
99
|
role: str,
|
|
100
100
|
name: str | None = None,
|
|
101
|
+
parent_id: str | None = None,
|
|
101
102
|
cost_info: TokenCost | None = None,
|
|
102
103
|
model: str | None = None,
|
|
103
104
|
response_time: float | None = None,
|
|
104
|
-
forwarded_from: list[str] | None = None,
|
|
105
105
|
provider_name: str | None = None,
|
|
106
106
|
provider_response_id: str | None = None,
|
|
107
107
|
messages: str | None = None,
|
|
@@ -144,6 +144,87 @@ class StorageProvider:
|
|
|
144
144
|
"""
|
|
145
145
|
return None
|
|
146
146
|
|
|
147
|
+
async def get_conversation_messages(
|
|
148
|
+
self,
|
|
149
|
+
conversation_id: str,
|
|
150
|
+
*,
|
|
151
|
+
include_ancestors: bool = False,
|
|
152
|
+
) -> list[ChatMessage[str]]:
|
|
153
|
+
"""Get all messages for a conversation.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
conversation_id: ID of the conversation
|
|
157
|
+
include_ancestors: If True, also include messages from ancestor
|
|
158
|
+
conversations (following parent_id chain). Useful for forked
|
|
159
|
+
conversations where you want the full history.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
List of messages ordered by timestamp.
|
|
163
|
+
"""
|
|
164
|
+
msg = f"{self.__class__.__name__} does not support getting conversation messages"
|
|
165
|
+
raise NotImplementedError(msg)
|
|
166
|
+
|
|
167
|
+
async def get_message(
|
|
168
|
+
self,
|
|
169
|
+
message_id: str,
|
|
170
|
+
) -> ChatMessage[str] | None:
|
|
171
|
+
"""Get a single message by ID.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
message_id: ID of the message
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
The message if found, None otherwise.
|
|
178
|
+
"""
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
async def get_message_ancestry(
|
|
182
|
+
self,
|
|
183
|
+
message_id: str,
|
|
184
|
+
) -> list[ChatMessage[str]]:
|
|
185
|
+
"""Get the ancestry chain of a message.
|
|
186
|
+
|
|
187
|
+
Traverses the parent_id chain to build full history leading to this message.
|
|
188
|
+
Useful for forked conversations where you need context from the fork point.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
message_id: ID of the message to get ancestry for
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
List of messages from oldest ancestor to the specified message.
|
|
195
|
+
"""
|
|
196
|
+
msg = f"{self.__class__.__name__} does not support message ancestry"
|
|
197
|
+
raise NotImplementedError(msg)
|
|
198
|
+
|
|
199
|
+
async def fork_conversation(
|
|
200
|
+
self,
|
|
201
|
+
*,
|
|
202
|
+
source_conversation_id: str,
|
|
203
|
+
new_conversation_id: str,
|
|
204
|
+
fork_from_message_id: str | None = None,
|
|
205
|
+
new_agent_name: str | None = None,
|
|
206
|
+
) -> str | None:
|
|
207
|
+
"""Fork a conversation at a specific point.
|
|
208
|
+
|
|
209
|
+
Creates a new conversation that branches from the source conversation.
|
|
210
|
+
The new conversation's first message will have parent_id pointing to
|
|
211
|
+
the fork point, allowing history traversal.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
source_conversation_id: ID of the conversation to fork from
|
|
215
|
+
new_conversation_id: ID for the new forked conversation
|
|
216
|
+
fork_from_message_id: Message ID to fork from. If None, forks from
|
|
217
|
+
the last message in the source conversation.
|
|
218
|
+
new_agent_name: Agent name for the new conversation. If None,
|
|
219
|
+
inherits from source.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
The message_id of the fork point (the parent for new messages),
|
|
223
|
+
or None if the source conversation is empty.
|
|
224
|
+
"""
|
|
225
|
+
msg = f"{self.__class__.__name__} does not support forking conversations"
|
|
226
|
+
raise NotImplementedError(msg)
|
|
227
|
+
|
|
147
228
|
async def log_command(
|
|
148
229
|
self,
|
|
149
230
|
*,
|
|
@@ -308,3 +389,104 @@ class StorageProvider:
|
|
|
308
389
|
Tuple of (conversation count, message count)
|
|
309
390
|
"""
|
|
310
391
|
raise NotImplementedError
|
|
392
|
+
|
|
393
|
+
async def delete_conversation_messages(
|
|
394
|
+
self,
|
|
395
|
+
conversation_id: str,
|
|
396
|
+
) -> int:
|
|
397
|
+
"""Delete all messages for a conversation.
|
|
398
|
+
|
|
399
|
+
Used for compaction - removes existing messages so they can be
|
|
400
|
+
replaced with compacted versions.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
conversation_id: ID of the conversation to clear
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
Number of messages deleted
|
|
407
|
+
"""
|
|
408
|
+
msg = f"{self.__class__.__name__} does not support deleting messages"
|
|
409
|
+
raise NotImplementedError(msg)
|
|
410
|
+
|
|
411
|
+
# Project methods
|
|
412
|
+
|
|
413
|
+
async def save_project(self, project: ProjectData) -> None:
|
|
414
|
+
"""Save or update a project.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
project: Project data to persist
|
|
418
|
+
"""
|
|
419
|
+
msg = f"{self.__class__.__name__} does not support project storage"
|
|
420
|
+
raise NotImplementedError(msg)
|
|
421
|
+
|
|
422
|
+
async def get_project(self, project_id: str) -> ProjectData | None:
|
|
423
|
+
"""Get a project by ID.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
project_id: Project identifier
|
|
427
|
+
|
|
428
|
+
Returns:
|
|
429
|
+
Project data if found, None otherwise
|
|
430
|
+
"""
|
|
431
|
+
msg = f"{self.__class__.__name__} does not support project storage"
|
|
432
|
+
raise NotImplementedError(msg)
|
|
433
|
+
|
|
434
|
+
async def get_project_by_worktree(self, worktree: str) -> ProjectData | None:
|
|
435
|
+
"""Get a project by worktree path.
|
|
436
|
+
|
|
437
|
+
Args:
|
|
438
|
+
worktree: Absolute path to the project worktree
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
Project data if found, None otherwise
|
|
442
|
+
"""
|
|
443
|
+
msg = f"{self.__class__.__name__} does not support project storage"
|
|
444
|
+
raise NotImplementedError(msg)
|
|
445
|
+
|
|
446
|
+
async def get_project_by_name(self, name: str) -> ProjectData | None:
|
|
447
|
+
"""Get a project by friendly name.
|
|
448
|
+
|
|
449
|
+
Args:
|
|
450
|
+
name: Project name
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
Project data if found, None otherwise
|
|
454
|
+
"""
|
|
455
|
+
msg = f"{self.__class__.__name__} does not support project storage"
|
|
456
|
+
raise NotImplementedError(msg)
|
|
457
|
+
|
|
458
|
+
async def list_projects(
|
|
459
|
+
self,
|
|
460
|
+
limit: int | None = None,
|
|
461
|
+
) -> list[ProjectData]:
|
|
462
|
+
"""List all projects, ordered by last_active descending.
|
|
463
|
+
|
|
464
|
+
Args:
|
|
465
|
+
limit: Maximum number of projects to return
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
List of project data objects
|
|
469
|
+
"""
|
|
470
|
+
msg = f"{self.__class__.__name__} does not support project storage"
|
|
471
|
+
raise NotImplementedError(msg)
|
|
472
|
+
|
|
473
|
+
async def delete_project(self, project_id: str) -> bool:
|
|
474
|
+
"""Delete a project.
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
project_id: Project identifier
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
True if project was deleted, False if not found
|
|
481
|
+
"""
|
|
482
|
+
msg = f"{self.__class__.__name__} does not support project storage"
|
|
483
|
+
raise NotImplementedError(msg)
|
|
484
|
+
|
|
485
|
+
async def touch_project(self, project_id: str) -> None:
|
|
486
|
+
"""Update project's last_active timestamp.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
project_id: Project identifier
|
|
490
|
+
"""
|
|
491
|
+
msg = f"{self.__class__.__name__} does not support project storage"
|
|
492
|
+
raise NotImplementedError(msg)
|