agentpool 2.2.3__py3-none-any.whl → 2.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acp/__init__.py +0 -4
- acp/acp_requests.py +20 -77
- acp/agent/connection.py +8 -0
- acp/agent/implementations/debug_server/debug_server.py +6 -2
- acp/agent/protocol.py +6 -0
- acp/client/connection.py +38 -29
- acp/client/implementations/default_client.py +3 -2
- acp/client/implementations/headless_client.py +2 -2
- acp/connection.py +2 -2
- acp/notifications.py +18 -49
- acp/schema/__init__.py +2 -0
- acp/schema/agent_responses.py +21 -0
- acp/schema/client_requests.py +3 -3
- acp/schema/session_state.py +63 -29
- acp/task/supervisor.py +2 -2
- acp/utils.py +2 -2
- agentpool/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +278 -263
- agentpool/agents/acp_agent/acp_converters.py +150 -17
- agentpool/agents/acp_agent/client_handler.py +35 -24
- agentpool/agents/acp_agent/session_state.py +14 -6
- agentpool/agents/agent.py +471 -643
- agentpool/agents/agui_agent/agui_agent.py +104 -107
- agentpool/agents/agui_agent/helpers.py +3 -4
- agentpool/agents/base_agent.py +485 -32
- agentpool/agents/claude_code_agent/FORKING.md +191 -0
- agentpool/agents/claude_code_agent/__init__.py +13 -1
- agentpool/agents/claude_code_agent/claude_code_agent.py +654 -334
- agentpool/agents/claude_code_agent/converters.py +4 -141
- agentpool/agents/claude_code_agent/models.py +77 -0
- agentpool/agents/claude_code_agent/static_info.py +100 -0
- agentpool/agents/claude_code_agent/usage.py +242 -0
- agentpool/agents/events/__init__.py +22 -0
- agentpool/agents/events/builtin_handlers.py +65 -0
- agentpool/agents/events/event_emitter.py +3 -0
- agentpool/agents/events/events.py +84 -3
- agentpool/agents/events/infer_info.py +145 -0
- agentpool/agents/events/processors.py +254 -0
- agentpool/agents/interactions.py +41 -6
- agentpool/agents/modes.py +13 -0
- agentpool/agents/slashed_agent.py +5 -4
- agentpool/agents/tool_wrapping.py +18 -6
- agentpool/common_types.py +35 -21
- agentpool/config_resources/acp_assistant.yml +2 -2
- agentpool/config_resources/agents.yml +3 -0
- agentpool/config_resources/agents_template.yml +1 -0
- agentpool/config_resources/claude_code_agent.yml +9 -8
- agentpool/config_resources/external_acp_agents.yml +2 -1
- agentpool/delegation/base_team.py +4 -30
- agentpool/delegation/pool.py +104 -265
- agentpool/delegation/team.py +57 -57
- agentpool/delegation/teamrun.py +50 -55
- agentpool/functional/run.py +10 -4
- agentpool/mcp_server/client.py +73 -38
- agentpool/mcp_server/conversions.py +54 -13
- agentpool/mcp_server/manager.py +9 -23
- agentpool/mcp_server/registries/official_registry_client.py +10 -1
- agentpool/mcp_server/tool_bridge.py +114 -79
- agentpool/messaging/connection_manager.py +11 -10
- agentpool/messaging/event_manager.py +5 -5
- agentpool/messaging/message_container.py +6 -30
- agentpool/messaging/message_history.py +87 -8
- agentpool/messaging/messagenode.py +52 -14
- agentpool/messaging/messages.py +2 -26
- agentpool/messaging/processing.py +10 -22
- agentpool/models/__init__.py +1 -1
- agentpool/models/acp_agents/base.py +6 -2
- agentpool/models/acp_agents/mcp_capable.py +124 -15
- agentpool/models/acp_agents/non_mcp.py +0 -23
- agentpool/models/agents.py +66 -66
- agentpool/models/agui_agents.py +1 -1
- agentpool/models/claude_code_agents.py +111 -17
- agentpool/models/file_parsing.py +0 -1
- agentpool/models/manifest.py +70 -50
- agentpool/prompts/conversion_manager.py +1 -1
- agentpool/prompts/prompts.py +5 -2
- agentpool/resource_providers/__init__.py +2 -0
- agentpool/resource_providers/aggregating.py +4 -2
- agentpool/resource_providers/base.py +13 -3
- agentpool/resource_providers/codemode/code_executor.py +72 -5
- agentpool/resource_providers/codemode/helpers.py +2 -2
- agentpool/resource_providers/codemode/provider.py +64 -12
- agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
- agentpool/resource_providers/codemode/remote_provider.py +9 -12
- agentpool/resource_providers/filtering.py +3 -1
- agentpool/resource_providers/mcp_provider.py +66 -12
- agentpool/resource_providers/plan_provider.py +111 -18
- agentpool/resource_providers/pool.py +5 -3
- agentpool/resource_providers/resource_info.py +111 -0
- agentpool/resource_providers/static.py +2 -2
- agentpool/sessions/__init__.py +2 -0
- agentpool/sessions/manager.py +2 -3
- agentpool/sessions/models.py +9 -6
- agentpool/sessions/protocol.py +28 -0
- agentpool/sessions/session.py +11 -55
- agentpool/storage/manager.py +361 -54
- agentpool/talk/registry.py +4 -4
- agentpool/talk/talk.py +9 -10
- agentpool/testing.py +1 -1
- agentpool/tool_impls/__init__.py +6 -0
- agentpool/tool_impls/agent_cli/__init__.py +42 -0
- agentpool/tool_impls/agent_cli/tool.py +95 -0
- agentpool/tool_impls/bash/__init__.py +64 -0
- agentpool/tool_impls/bash/helpers.py +35 -0
- agentpool/tool_impls/bash/tool.py +171 -0
- agentpool/tool_impls/delete_path/__init__.py +70 -0
- agentpool/tool_impls/delete_path/tool.py +142 -0
- agentpool/tool_impls/download_file/__init__.py +80 -0
- agentpool/tool_impls/download_file/tool.py +183 -0
- agentpool/tool_impls/execute_code/__init__.py +55 -0
- agentpool/tool_impls/execute_code/tool.py +163 -0
- agentpool/tool_impls/grep/__init__.py +80 -0
- agentpool/tool_impls/grep/tool.py +200 -0
- agentpool/tool_impls/list_directory/__init__.py +73 -0
- agentpool/tool_impls/list_directory/tool.py +197 -0
- agentpool/tool_impls/question/__init__.py +42 -0
- agentpool/tool_impls/question/tool.py +127 -0
- agentpool/tool_impls/read/__init__.py +104 -0
- agentpool/tool_impls/read/tool.py +305 -0
- agentpool/tools/__init__.py +2 -1
- agentpool/tools/base.py +114 -34
- agentpool/tools/manager.py +57 -1
- agentpool/ui/base.py +2 -2
- agentpool/ui/mock_provider.py +2 -2
- agentpool/ui/stdlib_provider.py +2 -2
- agentpool/utils/streams.py +21 -96
- agentpool/vfs_registry.py +7 -2
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/METADATA +16 -22
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/RECORD +242 -195
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +20 -0
- agentpool_cli/create.py +1 -1
- agentpool_cli/serve_acp.py +59 -1
- agentpool_cli/serve_opencode.py +1 -1
- agentpool_cli/ui.py +557 -0
- agentpool_commands/__init__.py +12 -5
- agentpool_commands/agents.py +1 -1
- agentpool_commands/pool.py +260 -0
- agentpool_commands/session.py +1 -1
- agentpool_commands/text_sharing/__init__.py +119 -0
- agentpool_commands/text_sharing/base.py +123 -0
- agentpool_commands/text_sharing/github_gist.py +80 -0
- agentpool_commands/text_sharing/opencode.py +462 -0
- agentpool_commands/text_sharing/paste_rs.py +59 -0
- agentpool_commands/text_sharing/pastebin.py +116 -0
- agentpool_commands/text_sharing/shittycodingagent.py +112 -0
- agentpool_commands/utils.py +31 -32
- agentpool_config/__init__.py +30 -2
- agentpool_config/agentpool_tools.py +498 -0
- agentpool_config/converters.py +1 -1
- agentpool_config/event_handlers.py +42 -0
- agentpool_config/events.py +1 -1
- agentpool_config/forward_targets.py +1 -4
- agentpool_config/jinja.py +3 -3
- agentpool_config/mcp_server.py +1 -5
- agentpool_config/nodes.py +1 -1
- agentpool_config/observability.py +44 -0
- agentpool_config/session.py +0 -3
- agentpool_config/storage.py +38 -39
- agentpool_config/task.py +3 -3
- agentpool_config/tools.py +11 -28
- agentpool_config/toolsets.py +22 -90
- agentpool_server/a2a_server/agent_worker.py +307 -0
- agentpool_server/a2a_server/server.py +23 -18
- agentpool_server/acp_server/acp_agent.py +125 -56
- agentpool_server/acp_server/commands/acp_commands.py +46 -216
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +8 -7
- agentpool_server/acp_server/event_converter.py +651 -0
- agentpool_server/acp_server/input_provider.py +53 -10
- agentpool_server/acp_server/server.py +1 -11
- agentpool_server/acp_server/session.py +90 -410
- agentpool_server/acp_server/session_manager.py +8 -34
- agentpool_server/agui_server/server.py +3 -1
- agentpool_server/mcp_server/server.py +5 -2
- agentpool_server/opencode_server/ENDPOINTS.md +53 -14
- agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
- agentpool_server/opencode_server/__init__.py +0 -8
- agentpool_server/opencode_server/converters.py +132 -26
- agentpool_server/opencode_server/input_provider.py +160 -8
- agentpool_server/opencode_server/models/__init__.py +42 -20
- agentpool_server/opencode_server/models/app.py +12 -0
- agentpool_server/opencode_server/models/events.py +203 -29
- agentpool_server/opencode_server/models/mcp.py +19 -0
- agentpool_server/opencode_server/models/message.py +18 -1
- agentpool_server/opencode_server/models/parts.py +134 -1
- agentpool_server/opencode_server/models/question.py +56 -0
- agentpool_server/opencode_server/models/session.py +13 -1
- agentpool_server/opencode_server/routes/__init__.py +4 -0
- agentpool_server/opencode_server/routes/agent_routes.py +33 -2
- agentpool_server/opencode_server/routes/app_routes.py +66 -3
- agentpool_server/opencode_server/routes/config_routes.py +66 -5
- agentpool_server/opencode_server/routes/file_routes.py +184 -5
- agentpool_server/opencode_server/routes/global_routes.py +1 -1
- agentpool_server/opencode_server/routes/lsp_routes.py +1 -1
- agentpool_server/opencode_server/routes/message_routes.py +122 -66
- agentpool_server/opencode_server/routes/permission_routes.py +63 -0
- agentpool_server/opencode_server/routes/pty_routes.py +23 -22
- agentpool_server/opencode_server/routes/question_routes.py +128 -0
- agentpool_server/opencode_server/routes/session_routes.py +139 -68
- agentpool_server/opencode_server/routes/tui_routes.py +1 -1
- agentpool_server/opencode_server/server.py +47 -2
- agentpool_server/opencode_server/state.py +30 -0
- agentpool_storage/__init__.py +0 -4
- agentpool_storage/base.py +81 -2
- agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
- agentpool_storage/claude_provider/__init__.py +42 -0
- agentpool_storage/{claude_provider.py → claude_provider/provider.py} +190 -8
- agentpool_storage/file_provider.py +149 -15
- agentpool_storage/memory_provider.py +132 -12
- agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
- agentpool_storage/opencode_provider/__init__.py +16 -0
- agentpool_storage/opencode_provider/helpers.py +414 -0
- agentpool_storage/opencode_provider/provider.py +895 -0
- agentpool_storage/session_store.py +20 -6
- agentpool_storage/sql_provider/sql_provider.py +135 -2
- agentpool_storage/sql_provider/utils.py +2 -12
- agentpool_storage/zed_provider/__init__.py +16 -0
- agentpool_storage/zed_provider/helpers.py +281 -0
- agentpool_storage/zed_provider/models.py +130 -0
- agentpool_storage/zed_provider/provider.py +442 -0
- agentpool_storage/zed_provider.py +803 -0
- agentpool_toolsets/__init__.py +0 -2
- agentpool_toolsets/builtin/__init__.py +2 -4
- agentpool_toolsets/builtin/code.py +4 -4
- agentpool_toolsets/builtin/debug.py +115 -40
- agentpool_toolsets/builtin/execution_environment.py +54 -165
- agentpool_toolsets/builtin/skills.py +0 -77
- agentpool_toolsets/builtin/subagent_tools.py +64 -51
- agentpool_toolsets/builtin/workers.py +4 -2
- agentpool_toolsets/composio_toolset.py +2 -2
- agentpool_toolsets/entry_points.py +3 -1
- agentpool_toolsets/fsspec_toolset/grep.py +25 -5
- agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
- agentpool_toolsets/fsspec_toolset/toolset.py +350 -66
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +74 -17
- agentpool_toolsets/mcp_run_toolset.py +8 -11
- agentpool_toolsets/notifications.py +33 -33
- agentpool_toolsets/openapi.py +3 -1
- agentpool_toolsets/search_toolset.py +3 -1
- agentpool_config/resources.py +0 -33
- agentpool_server/acp_server/acp_tools.py +0 -43
- agentpool_server/acp_server/commands/spawn.py +0 -210
- agentpool_storage/opencode_provider.py +0 -730
- agentpool_storage/text_log_provider.py +0 -276
- agentpool_toolsets/builtin/chain.py +0 -288
- agentpool_toolsets/builtin/user_interaction.py +0 -52
- agentpool_toolsets/semantic_memory_toolset.py +0 -536
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
- {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# OpenCode Storage Architecture
|
|
2
|
+
|
|
3
|
+
This document explains how OpenCode persists conversation data to the filesystem.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
~/.local/share/opencode/
|
|
9
|
+
├── storage/
|
|
10
|
+
│ ├── message/ # Message metadata by session
|
|
11
|
+
│ │ └── {sessionID}/
|
|
12
|
+
│ │ └── {messageID}.json # Message metadata
|
|
13
|
+
│ ├── part/ # Message content parts
|
|
14
|
+
│ │ └── {messageID}/
|
|
15
|
+
│ │ └── {partID}.json # Content blocks (text, tool_use, etc.)
|
|
16
|
+
│ ├── session/ # Session metadata by project
|
|
17
|
+
│ │ ├── global/ # Sessions not tied to a project
|
|
18
|
+
│ │ │ └── {sessionID}.json # Session metadata
|
|
19
|
+
│ │ └── {projectID}/ # Project-specific sessions
|
|
20
|
+
│ │ └── {sessionID}.json # Session metadata
|
|
21
|
+
│ ├── session_diff/ # Session diffs (unused?)
|
|
22
|
+
│ ├── session_share/ # Shared sessions (unused?)
|
|
23
|
+
│ └── project/ # Project metadata
|
|
24
|
+
├── snapshot/ # Project snapshots
|
|
25
|
+
├── log/ # Application logs
|
|
26
|
+
└── auth.json # Authentication credentials
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Core Concepts
|
|
30
|
+
|
|
31
|
+
### 1. Storage Model: Normalized Database on Filesystem
|
|
32
|
+
|
|
33
|
+
OpenCode uses a **normalized relational model** stored as JSON files:
|
|
34
|
+
- **Sessions** → Metadata about conversations
|
|
35
|
+
- **Messages** → Message-level metadata (role, time, agent)
|
|
36
|
+
- **Parts** → Content blocks within messages (text, tool_use, tool_result)
|
|
37
|
+
|
|
38
|
+
This is fundamentally different from Claude Code's append-only JSONL approach.
|
|
39
|
+
|
|
40
|
+
### 2. ID Format
|
|
41
|
+
|
|
42
|
+
All IDs use a custom format with prefixes:
|
|
43
|
+
- **Session**: `ses_{random}` (e.g., `ses_4afbda00cffeVl5YERm4op7JEG`)
|
|
44
|
+
- **Message**: `msg_{random}` (e.g., `msg_b50425ff7001vgFiMUNFzLtCda`)
|
|
45
|
+
- **Part**: `prt_{random}` (e.g., `prt_b50425ff7002egcP330jM5wQcU`)
|
|
46
|
+
- **Project**: SHA1 hash of directory path (e.g., `486ce75a8fddd4372018ab816ac62d8004dc52fd`)
|
|
47
|
+
|
|
48
|
+
The random portion appears to be a timestamp-based identifier.
|
|
49
|
+
|
|
50
|
+
### 3. Projects
|
|
51
|
+
|
|
52
|
+
**Project ID**: SHA1 hash of the absolute directory path
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
```bash
|
|
56
|
+
echo -n "/home/phil65/dev/oss/agentpool" | sha1sum
|
|
57
|
+
# → 486ce75a8fddd4372018ab816ac62d8004dc52fd
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Special Project**: `global`
|
|
61
|
+
- Used for sessions not tied to a specific directory
|
|
62
|
+
- Sessions created from home directory or no working directory
|
|
63
|
+
|
|
64
|
+
**Storage**:
|
|
65
|
+
- Session files: `storage/session/{projectID}/{sessionID}.json`
|
|
66
|
+
- Global sessions: `storage/session/global/{sessionID}.json`
|
|
67
|
+
|
|
68
|
+
### 4. Sessions
|
|
69
|
+
|
|
70
|
+
**Session File**: `storage/session/{projectID}/{sessionID}.json`
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"id": "ses_4afbda00cffeVl5YERm4op7JEG",
|
|
75
|
+
"version": "1.0.193",
|
|
76
|
+
"projectID": "486ce75a8fddd4372018ab816ac62d8004dc52fd",
|
|
77
|
+
"directory": "/home/phil65/dev/oss/agentpool",
|
|
78
|
+
"title": "Claude capabilities overview",
|
|
79
|
+
"time": {
|
|
80
|
+
"created": 1766578085876,
|
|
81
|
+
"updated": 1766578154946
|
|
82
|
+
},
|
|
83
|
+
"summary": {
|
|
84
|
+
"additions": 0,
|
|
85
|
+
"deletions": 0,
|
|
86
|
+
"files": 0
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Fields**:
|
|
92
|
+
- `id`: Session identifier
|
|
93
|
+
- `version`: OpenCode version that created the session
|
|
94
|
+
- `projectID`: SHA1 hash of directory or "global"
|
|
95
|
+
- `directory`: Absolute path to working directory
|
|
96
|
+
- `title`: Auto-generated summary of session topic
|
|
97
|
+
- `time.created`: Unix timestamp (milliseconds)
|
|
98
|
+
- `time.updated`: Unix timestamp (milliseconds)
|
|
99
|
+
- `summary`: File change statistics
|
|
100
|
+
|
|
101
|
+
### 5. Messages
|
|
102
|
+
|
|
103
|
+
**Message File**: `storage/message/{sessionID}/{messageID}.json`
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"id": "msg_b50425ff7001vgFiMUNFzLtCda",
|
|
108
|
+
"sessionID": "ses_4afbda00cffeVl5YERm4op7JEG",
|
|
109
|
+
"role": "user",
|
|
110
|
+
"time": {
|
|
111
|
+
"created": 1766578085884
|
|
112
|
+
},
|
|
113
|
+
"summary": {
|
|
114
|
+
"title": "Exploring available tools",
|
|
115
|
+
"diffs": []
|
|
116
|
+
},
|
|
117
|
+
"agent": "build",
|
|
118
|
+
"model": {
|
|
119
|
+
"providerID": "anthropic",
|
|
120
|
+
"modelID": "claude-opus-4-5-20251101"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Fields**:
|
|
126
|
+
- `id`: Message identifier
|
|
127
|
+
- `sessionID`: Parent session
|
|
128
|
+
- `role`: "user" | "assistant"
|
|
129
|
+
- `time.created`: Unix timestamp (milliseconds)
|
|
130
|
+
- `summary.title`: Auto-generated message summary
|
|
131
|
+
- `summary.diffs`: File changes in this message
|
|
132
|
+
- `agent`: Agent name (e.g., "build", custom agent names)
|
|
133
|
+
- `model`: Model configuration (for assistant messages)
|
|
134
|
+
- `providerID`: "anthropic", "openai", etc.
|
|
135
|
+
- `modelID`: Full model identifier
|
|
136
|
+
|
|
137
|
+
### 6. Parts (Message Content)
|
|
138
|
+
|
|
139
|
+
**Part File**: `storage/part/{messageID}/{partID}.json`
|
|
140
|
+
|
|
141
|
+
Parts represent the actual content blocks within a message.
|
|
142
|
+
|
|
143
|
+
#### Text Part
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"id": "prt_b50425ff7002egcP330jM5wQcU",
|
|
147
|
+
"sessionID": "ses_4afbda00cffeVl5YERm4op7JEG",
|
|
148
|
+
"messageID": "msg_b50425ff7001vgFiMUNFzLtCda",
|
|
149
|
+
"type": "text",
|
|
150
|
+
"text": "what tools do you have?"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Tool Use Part
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"id": "prt_...",
|
|
158
|
+
"sessionID": "ses_...",
|
|
159
|
+
"messageID": "msg_...",
|
|
160
|
+
"type": "tool_use",
|
|
161
|
+
"name": "read_file",
|
|
162
|
+
"input": {
|
|
163
|
+
"path": "src/main.py"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Tool Result Part
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"id": "prt_...",
|
|
172
|
+
"sessionID": "ses_...",
|
|
173
|
+
"messageID": "msg_...",
|
|
174
|
+
"type": "tool_result",
|
|
175
|
+
"tool_use_id": "toolu_...",
|
|
176
|
+
"content": "file contents here..."
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Part Types**:
|
|
181
|
+
- `text`: Text content
|
|
182
|
+
- `tool_use`: Tool invocation
|
|
183
|
+
- `tool_result`: Tool execution result
|
|
184
|
+
- `thinking`: Claude's thinking process (extended thinking)
|
|
185
|
+
- `image`: Image content (base64 or URL)
|
|
186
|
+
|
|
187
|
+
### 7. Message Flow
|
|
188
|
+
|
|
189
|
+
Unlike Claude Code's linked list, OpenCode doesn't store parent-child relationships explicitly in the storage layer. The conversation flow is determined by:
|
|
190
|
+
|
|
191
|
+
1. **Message order**: Files in `storage/message/{sessionID}/` directory
|
|
192
|
+
2. **Timestamp**: `time.created` field determines chronological order
|
|
193
|
+
3. **No parent references**: Must reconstruct flow from timestamps
|
|
194
|
+
|
|
195
|
+
To read a conversation:
|
|
196
|
+
```python
|
|
197
|
+
# 1. List all message files in session directory
|
|
198
|
+
messages = list_files(f"storage/message/{session_id}/")
|
|
199
|
+
|
|
200
|
+
# 2. Read each message
|
|
201
|
+
for msg_file in messages:
|
|
202
|
+
msg = load_json(msg_file)
|
|
203
|
+
parts = load_parts(f"storage/part/{msg['id']}/")
|
|
204
|
+
# Combine message + parts
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Key Differences from Claude Code
|
|
208
|
+
|
|
209
|
+
| Aspect | OpenCode | Claude Code |
|
|
210
|
+
|--------|----------|-------------|
|
|
211
|
+
| **Format** | Normalized JSON files | Append-only JSONL |
|
|
212
|
+
| **Structure** | Relational (sessions → messages → parts) | Linear log with parent refs |
|
|
213
|
+
| **Message Flow** | Timestamp-based ordering | Explicit parent-child links |
|
|
214
|
+
| **Updates** | Files can be updated in place | Append-only, immutable |
|
|
215
|
+
| **Branches** | Not supported | Sidechains with `isSidechain` flag |
|
|
216
|
+
| **Projects** | SHA1 hash of directory | URL-encoded path |
|
|
217
|
+
| **IDs** | Custom prefixed format | UUIDs or short hex |
|
|
218
|
+
| **Content** | Separated into parts | Inline in message entry |
|
|
219
|
+
|
|
220
|
+
## Storage Provider Implementation
|
|
221
|
+
|
|
222
|
+
### Key Responsibilities
|
|
223
|
+
|
|
224
|
+
1. **Path Management**
|
|
225
|
+
- Hash directory paths to project IDs
|
|
226
|
+
- Organize sessions by project
|
|
227
|
+
- Handle "global" project for unscoped sessions
|
|
228
|
+
|
|
229
|
+
2. **Message Reconstruction**
|
|
230
|
+
- Load message metadata from `message/` directory
|
|
231
|
+
- Load content parts from `part/` directory
|
|
232
|
+
- Combine into unified message representation
|
|
233
|
+
|
|
234
|
+
3. **Conversation Queries**
|
|
235
|
+
- List sessions for a project
|
|
236
|
+
- Get message count and statistics
|
|
237
|
+
- Retrieve messages in chronological order
|
|
238
|
+
|
|
239
|
+
4. **Format Conversion**
|
|
240
|
+
- OpenCode format → `ChatMessage` (for agentpool)
|
|
241
|
+
- `ChatMessage` → OpenCode format (for persistence)
|
|
242
|
+
|
|
243
|
+
### Challenges
|
|
244
|
+
|
|
245
|
+
1. **No Parent Links**
|
|
246
|
+
- Cannot trace message ancestry efficiently
|
|
247
|
+
- Must rely on timestamps for ordering
|
|
248
|
+
- Forking/branching not supported
|
|
249
|
+
|
|
250
|
+
2. **Scattered Data**
|
|
251
|
+
- Each message requires multiple file reads
|
|
252
|
+
- Parts are in separate directories
|
|
253
|
+
- No atomic transactions across files
|
|
254
|
+
|
|
255
|
+
3. **No Versioning**
|
|
256
|
+
- Files can be updated in place
|
|
257
|
+
- No history of edits
|
|
258
|
+
- No way to detect concurrent modifications
|
|
259
|
+
|
|
260
|
+
## Data Consistency
|
|
261
|
+
|
|
262
|
+
### File Organization
|
|
263
|
+
- Messages grouped by session in directories
|
|
264
|
+
- Parts grouped by message in directories
|
|
265
|
+
- Sessions grouped by project in directories
|
|
266
|
+
|
|
267
|
+
### Atomic Operations
|
|
268
|
+
- Individual JSON file writes are atomic
|
|
269
|
+
- No atomicity across multiple files
|
|
270
|
+
- No transaction support
|
|
271
|
+
|
|
272
|
+
### Concurrent Access
|
|
273
|
+
- No locking mechanism
|
|
274
|
+
- Last write wins on conflicts
|
|
275
|
+
- Reading while writing may see partial state
|
|
276
|
+
|
|
277
|
+
## Integration Points
|
|
278
|
+
|
|
279
|
+
### With Agentpool
|
|
280
|
+
- Implements `StorageProvider` protocol
|
|
281
|
+
- Converts between OpenCode format and domain models
|
|
282
|
+
- Enables conversation persistence
|
|
283
|
+
|
|
284
|
+
### Missing Features
|
|
285
|
+
- **Todos/Plans**: No built-in todo tracking
|
|
286
|
+
- **File History**: Separate from message storage
|
|
287
|
+
- **Branching**: No conversation forking support
|
|
288
|
+
- **Ancestry**: No parent-child relationships
|
|
289
|
+
|
|
290
|
+
## Usage Patterns
|
|
291
|
+
|
|
292
|
+
### Reading a Session
|
|
293
|
+
```python
|
|
294
|
+
provider = OpenCodeStorageProvider()
|
|
295
|
+
|
|
296
|
+
# 1. Get session metadata
|
|
297
|
+
session_file = f"~/.local/share/opencode/storage/session/{project_id}/{session_id}.json"
|
|
298
|
+
session = load_json(session_file)
|
|
299
|
+
|
|
300
|
+
# 2. List messages in session
|
|
301
|
+
message_dir = f"~/.local/share/opencode/storage/message/{session_id}/"
|
|
302
|
+
message_files = list_files(message_dir)
|
|
303
|
+
|
|
304
|
+
# 3. Load each message + parts
|
|
305
|
+
messages = []
|
|
306
|
+
for msg_file in sorted(message_files): # Sort by timestamp in ID
|
|
307
|
+
msg = load_json(msg_file)
|
|
308
|
+
|
|
309
|
+
# Load parts
|
|
310
|
+
part_dir = f"~/.local/share/opencode/storage/part/{msg['id']}/"
|
|
311
|
+
parts = [load_json(p) for p in list_files(part_dir)]
|
|
312
|
+
|
|
313
|
+
messages.append(combine(msg, parts))
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Writing a Message
|
|
317
|
+
```python
|
|
318
|
+
# 1. Create message metadata
|
|
319
|
+
message = {
|
|
320
|
+
"id": f"msg_{generate_id()}",
|
|
321
|
+
"sessionID": session_id,
|
|
322
|
+
"role": "user",
|
|
323
|
+
"time": {"created": time_ms()},
|
|
324
|
+
"summary": {"title": "...", "diffs": []},
|
|
325
|
+
"agent": "default",
|
|
326
|
+
}
|
|
327
|
+
write_json(f"storage/message/{session_id}/{message['id']}.json", message)
|
|
328
|
+
|
|
329
|
+
# 2. Create parts
|
|
330
|
+
for part in content_parts:
|
|
331
|
+
part_data = {
|
|
332
|
+
"id": f"prt_{generate_id()}",
|
|
333
|
+
"sessionID": session_id,
|
|
334
|
+
"messageID": message['id'],
|
|
335
|
+
"type": part['type'],
|
|
336
|
+
**part['data']
|
|
337
|
+
}
|
|
338
|
+
write_json(f"storage/part/{message['id']}/{part_data['id']}.json", part_data)
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Design Rationale
|
|
342
|
+
|
|
343
|
+
### Why Normalized Structure?
|
|
344
|
+
- **Flexibility**: Can update individual components
|
|
345
|
+
- **Modularity**: Parts can be processed independently
|
|
346
|
+
- **Extensibility**: Easy to add new part types
|
|
347
|
+
|
|
348
|
+
### Why Separate Parts?
|
|
349
|
+
- **Streaming**: Can load message metadata without content
|
|
350
|
+
- **Lazy Loading**: Only load parts when needed
|
|
351
|
+
- **Type Safety**: Each part type has specific schema
|
|
352
|
+
|
|
353
|
+
### Why SHA1 for Project ID?
|
|
354
|
+
- **Deterministic**: Same path always gives same ID
|
|
355
|
+
- **Collision-resistant**: Very unlikely hash collisions
|
|
356
|
+
- **Path-independent**: ID doesn't reveal directory structure
|
|
357
|
+
|
|
358
|
+
### Drawbacks
|
|
359
|
+
- **Performance**: Many small files, lots of I/O
|
|
360
|
+
- **Consistency**: No atomic multi-file operations
|
|
361
|
+
- **Complexity**: More complex than append-only log
|
|
362
|
+
- **No History**: Can't track conversation evolution
|
|
363
|
+
|
|
364
|
+
## Future Considerations
|
|
365
|
+
|
|
366
|
+
### Performance
|
|
367
|
+
- Consider SQLite for better query performance
|
|
368
|
+
- Index sessions by project and timestamp
|
|
369
|
+
- Cache frequently accessed metadata
|
|
370
|
+
|
|
371
|
+
### Consistency
|
|
372
|
+
- Implement write-ahead logging
|
|
373
|
+
- Add transaction support
|
|
374
|
+
- Version individual files
|
|
375
|
+
|
|
376
|
+
### Features
|
|
377
|
+
- Add parent-child message links
|
|
378
|
+
- Support conversation branching
|
|
379
|
+
- Track message edit history
|
|
380
|
+
- Implement proper locking
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
**Related Files:**
|
|
385
|
+
- Implementation: [`provider.py`](./provider.py)
|
|
386
|
+
- Base Protocol: [`../base.py`](../base.py)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""OpenCode storage provider.
|
|
2
|
+
|
|
3
|
+
This package implements the storage backend compatible with OpenCode's
|
|
4
|
+
normalized JSON file format.
|
|
5
|
+
|
|
6
|
+
See ARCHITECTURE.md for detailed documentation of the storage format and
|
|
7
|
+
design decisions.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from agentpool_storage.opencode_provider.provider import OpenCodeStorageProvider
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"OpenCodeStorageProvider",
|
|
16
|
+
]
|