@asaidimu/utils-workspace 6.1.0 → 6.2.1
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.
- package/README.md +157 -88
- package/index.d.mts +444 -689
- package/index.d.ts +444 -689
- package/index.js +288 -1
- package/index.mjs +287 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -10,44 +10,44 @@
|
|
|
10
10
|
2. [**2. Mental Model: Conversation as a Directed Acyclic Graph (DAG)**](#2-mental-model)
|
|
11
11
|
3. [**3. Core Design Philosophy: The Four Pillars of AI State**](#3-philosophy)
|
|
12
12
|
4. [**4. System Architecture: The "Engine Under the Hood"**](#4-architecture)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
- [4.1. CQRS: Decoupling Write and Read Paths](#41-cqrs)
|
|
14
|
+
- [4.2. The Index: Reactive Read Projections](#42-the-index)
|
|
15
|
+
- [4.3. The Sequential Serializer: Race Condition Prevention](#43-serializer)
|
|
16
|
+
- [4.4. Event Bus and Reactivity](#44-event-bus)
|
|
17
17
|
5. [**5. Domain Entities: Deep Dive into the State**](#5-entities)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
- [5.1. Sessions: The Contextual Roots](#51-sessions)
|
|
19
|
+
- [5.2. Turns: The Atoms of Hyper-History](#52-turns)
|
|
20
|
+
- [5.3. Blobs: Deduplicated, Content-Addressed Asset Management](#53-blobs)
|
|
21
|
+
- [5.4. Roles: Persistent Personas and AI Identity](#54-roles)
|
|
22
|
+
- [5.5. Preferences & Context: The Multi-Tier Memory Layer](#55-memory)
|
|
23
23
|
6. [**6. The Prompt Pipeline: Anatomy of a Request**](#6-pipeline)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
- [6.1. Stage 1: DAG Snapshotting and Ancestry Walking](#61-snapshotting)
|
|
25
|
+
- [6.2. Stage 2: Semantic Retrieval and Topic Alignment](#62-retrieval)
|
|
26
|
+
- [6.3. Stage 3: Conflict Resolution in Instructions](#63-conflict-resolution)
|
|
27
|
+
- [6.4. Stage 4: Multi-Modal Blob Resolution Protocols](#64-resolution)
|
|
28
|
+
- [6.5. Stage 5: Provider-Specific Adapter Mapping](#65-mapping)
|
|
29
29
|
7. [**7. The Content Block Specification: Standardized Interoperability**](#7-blocks)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
- [7.1. Basic Blocks: Text and Thinking](#71-basic-blocks)
|
|
31
|
+
- [7.2. Asset Blocks: Image and Document](#72-asset-blocks)
|
|
32
|
+
- [7.3. Functional Blocks: ToolUse and ToolResult](#73-functional-blocks)
|
|
33
|
+
- [7.4. Structural Blocks: Summary and RoleTransition](#74-structural-blocks)
|
|
34
34
|
8. [**8. Command Reference: The Mutation API Manual**](#8-commands)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
- [8.1. Workspace Domain Commands](#81-workspace-cmds)
|
|
36
|
+
- [8.2. Session Domain Commands](#82-session-cmds)
|
|
37
|
+
- [8.3. Turn & DAG Domain Commands](#83-turn-cmds)
|
|
38
|
+
- [8.4. Role & Persona Domain Commands](#84-role-cmds)
|
|
39
|
+
- [8.5. Blob & Asset Domain Commands](#85-blob-cmds)
|
|
40
|
+
- [8.6. Resource (Context/Preference) Domain Commands](#86-resource-cmds)
|
|
41
41
|
9. [**9. Extension Framework: Building the Plugin Ecosystem**](#9-extension)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
- [9.1. WorkspaceExtensions: Packaging Domain Logic](#91-extensions)
|
|
43
|
+
- [9.2. Middleware: The Request Interceptor Pipeline](#92-middleware)
|
|
44
|
+
- [9.3. TurnProcessors: Giving the AI Agency](#93-turnprocessors)
|
|
45
|
+
- [9.4. Custom Indexers: Expanding the Read Model](#94-indexers)
|
|
46
46
|
10. [**10. Persistence Layer: Schema and Collections**](#10-persistence)
|
|
47
47
|
11. [**11. Implementation Guide: Building Your Workspace**](#11-implementation)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
- [11.1. Implementing a Database Boundary](#111-db-impl)
|
|
49
|
+
- [11.2. Implementing a BlobStorage Boundary](#112-blob-impl)
|
|
50
|
+
- [11.3. Bootstrapping the Manager](#113-bootstrap)
|
|
51
51
|
12. [**12. Design Decisions: The "Why" Behind the "What"**](#12-decisions)
|
|
52
52
|
13. [**13. Comparison with Industry Standards**](#13-comparison)
|
|
53
53
|
14. [**14. Advanced Recipes & Design Patterns**](#14-recipes)
|
|
@@ -67,9 +67,10 @@ In the first wave of LLM integration, "conversation" was modeled as a disposable
|
|
|
67
67
|
A workspace isn't just a chat; it's a collaborative environment where AI agents act on artifacts, remember user preferences across months, navigate complex branching decision trees, and handle multi-gigabyte document libraries without breaking a sweat.
|
|
68
68
|
|
|
69
69
|
`@asaidimu/utils-workspace` is the state engine designed for this complexity. It provides a high-integrity, content-addressed foundation that treats:
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
70
|
+
|
|
71
|
+
- **Conversation as Graph Architecture**: Enabling non-destructive editing and infinite branching.
|
|
72
|
+
- **Data as Content-Addressed Assets**: Eliminating redundancy and ensuring asset integrity.
|
|
73
|
+
- **State as Observable Commands**: Providing a perfect audit trail and reactive UI projections.
|
|
73
74
|
|
|
74
75
|
If you are building an IDE, a research lab, or an autonomous agent platform, this is the engine you've been looking for.
|
|
75
76
|
|
|
@@ -80,35 +81,43 @@ If you are building an IDE, a research lab, or an autonomous agent platform, thi
|
|
|
80
81
|
Most developers think of chat history as an `Array<Message>`. In this framework, we discard that model in favor of a **Directed Acyclic Graph (DAG)**.
|
|
81
82
|
|
|
82
83
|
### 2.1. The Hyper-History Concept
|
|
84
|
+
|
|
83
85
|
In a standard chat, each message points to the one before it. In our `TurnTree` model, we introduce a layer of abstraction between the "Sequence" and the "Content."
|
|
84
86
|
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
+
- **TurnNode**: Represents a logical "moment" or "slot" in the conversation timeline. It is a stable identifier that does not change.
|
|
88
|
+
- **Turn**: Represents the actual data (text, images, tool results) at that moment.
|
|
87
89
|
|
|
88
90
|
By separating these, we enable **Non-Destructive Editing**. When a user "edits" a prompt at TurnNode X, we don't update the database. We create `Turn (Version 2)` under `TurnNode X`. The graph now has two possible paths forward from X's parent.
|
|
89
91
|
|
|
90
92
|
### 2.2. Forking and Divergent Timelines
|
|
93
|
+
|
|
91
94
|
Sessions are merely pointers to a "Head" in the global graph of TurnNodes. This means "Forking" a session is an $O(1)$ metadata operation. You can create 1,000 different sessions that all share the same first 50 turns. This is critical for:
|
|
92
|
-
|
|
93
|
-
-
|
|
95
|
+
|
|
96
|
+
- **A/B Testing**: Testing how different model instructions respond to the same conversation.
|
|
97
|
+
- **Collaborative Branching**: Allowing multiple team members to explore different paths from a shared starting point.
|
|
94
98
|
|
|
95
99
|
---
|
|
96
100
|
|
|
97
101
|
## 3. Core Design Philosophy: The Four Pillars of AI State
|
|
98
102
|
|
|
99
103
|
### 3.1. Immutability and Versioning
|
|
104
|
+
|
|
100
105
|
We believe that AI history should be a permanent record. Every AI response and user prompt is immutable. To "change" the past, you must create a new branch. This ensures that the "reasoning path" of an agent is always recoverable.
|
|
101
106
|
|
|
102
107
|
### 3.2. Content-Addressability (SHA-256)
|
|
108
|
+
|
|
103
109
|
Assets (images, PDFs, source code) are identified by the cryptographic hash of their contents. This solves the "State Bloat" problem. If 100 sessions all reference the same 5MB system manual, the workspace only stores one copy.
|
|
104
110
|
|
|
105
111
|
### 3.3. Command-Driven Mutations (CQRS)
|
|
112
|
+
|
|
106
113
|
We strictly follow the **Command Query Responsibility Segregation (CQRS)** pattern.
|
|
107
|
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
114
|
+
|
|
115
|
+
- **Commands**: Describe intent (e.g., `session:fork`).
|
|
116
|
+
- **Reducers**: Pure-ish functions that execute the intent against the persistent stores.
|
|
117
|
+
- **Projections**: In-memory read models (The Index) that allow for sub-millisecond retrieval of workspace state.
|
|
110
118
|
|
|
111
119
|
### 3.4. Portability and LLM Agnosticism
|
|
120
|
+
|
|
112
121
|
The workspace core does not know what "OpenAI" or "Gemini" is. It operates on an abstract `Prompt` model. This allows you to build your entire application logic once and swap between different LLM providers just by changing the `LLMAdapter`.
|
|
113
122
|
|
|
114
123
|
---
|
|
@@ -116,18 +125,23 @@ The workspace core does not know what "OpenAI" or "Gemini" is. It operates on an
|
|
|
116
125
|
## 4. System Architecture: The "Engine Under the Hood"
|
|
117
126
|
|
|
118
127
|
### 4.1. Write Model: Atomic Entity Stores
|
|
128
|
+
|
|
119
129
|
The library organizes data into atomic "Stores." Each store is responsible for a single domain entity (e.g., `RoleStore`, `SessionStore`). These stores are designed to be backed by any persistent database via a standardized `Database` boundary.
|
|
120
130
|
|
|
121
131
|
### 4.2. Read Model: Reactive Index Projections
|
|
132
|
+
|
|
122
133
|
Querying a database for every prompt is too slow. To solve this, the `WorkspaceManager` maintains a **Workspace Index**. This index is a reactive, in-memory projection of the underlying stores.
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
134
|
+
|
|
135
|
+
- When a command is executed, the reducer returns a "Patch."
|
|
136
|
+
- The manager applies the patch to the Index.
|
|
137
|
+
- Subscribers are notified via the Event Bus.
|
|
126
138
|
|
|
127
139
|
### 4.3. The Sequential Serializer (Race Condition Prevention)
|
|
140
|
+
|
|
128
141
|
Concurrency in graph-based history leads to "phantom branches" and corrupt heads. The `WorkspaceManager` uses a **Sequential Serializer** (a promise-chaining queue) to ensure that only one mutation can happen at a time.
|
|
129
142
|
|
|
130
143
|
### 4.4. Event Bus and Reactivity
|
|
144
|
+
|
|
131
145
|
The workspace is "Alive." Every mutation emits events that can be listened to by the UI, external logging services, or other parts of the application.
|
|
132
146
|
|
|
133
147
|
---
|
|
@@ -135,19 +149,25 @@ The workspace is "Alive." Every mutation emits events that can be listened to by
|
|
|
135
149
|
## 5. Domain Entities: Deep Dive into the State
|
|
136
150
|
|
|
137
151
|
### 5.1. Sessions: The Contextual Roots
|
|
152
|
+
|
|
138
153
|
A `Session` is the user's primary unit of interaction. It manages the "active timeline."
|
|
139
|
-
|
|
140
|
-
-
|
|
154
|
+
|
|
155
|
+
- **Head Pointer**: A `TurnRef` (UUID + Version) identifying the current leaf of the DAG.
|
|
156
|
+
- **Topic Affinity**: Semantic tags that act as "magnets" for RAG context and user preferences.
|
|
141
157
|
|
|
142
158
|
### 5.2. Turns: The Atoms of Hyper-History
|
|
159
|
+
|
|
143
160
|
A `Turn` is the smallest unit of conversation. It is a multi-modal container that can hold anything from a text string to a sequence of tool executions and internal "thinking" blocks.
|
|
144
161
|
|
|
145
162
|
### 5.3. Blobs: Deduplicated Asset Management
|
|
163
|
+
|
|
146
164
|
Blobs represent the library's solution for large binary data. They utilize a **Reference Counting** garbage collector.
|
|
147
|
-
|
|
148
|
-
-
|
|
165
|
+
|
|
166
|
+
- **Registration**: Calculate hash -> Check for existence -> Create or increment ref-count.
|
|
167
|
+
- **Automatic Cleanup**: When a turn is deleted, the system decrements the blob's ref-count. Only when it hits zero is the physical file deleted from storage.
|
|
149
168
|
|
|
150
169
|
### 5.4. Roles: Persistent Personas
|
|
170
|
+
|
|
151
171
|
A `Role` encapsulates the AI's identity. It includes the "System Prompt" (Persona), model-specific constraints (e.g., `temperature`, `window size`), and a set of topics that the role is "interested" in.
|
|
152
172
|
|
|
153
173
|
---
|
|
@@ -157,18 +177,23 @@ A `Role` encapsulates the AI's identity. It includes the "System Prompt" (Person
|
|
|
157
177
|
The `PromptBuilder` follows a 5-step lifecycle:
|
|
158
178
|
|
|
159
179
|
### 6.1. Stage 1: DAG Snapshotting and Ancestry Walking
|
|
180
|
+
|
|
160
181
|
Starting from the session's `Head`, the builder performs a recursive walk up the parent pointers. This flattens the graph into a linear `Transcript`.
|
|
161
182
|
|
|
162
183
|
### 6.2. Stage 2: Semantic Retrieval and Topic Alignment
|
|
184
|
+
|
|
163
185
|
The builder identifies the active `Topics` of the session. It then queries the `ContextIndex`. It uses the `ContextRetriever` to rank entries by relevance.
|
|
164
186
|
|
|
165
187
|
### 6.3. Stage 3: Conflict Resolution in Instructions
|
|
188
|
+
|
|
166
189
|
It assembles the final "System Instruction." It merges the `Role` instructions with any active `Preferences`.
|
|
167
190
|
|
|
168
191
|
### 6.4. Stage 4: Multi-Modal Blob Resolution Protocols
|
|
192
|
+
|
|
169
193
|
Every `BlobRef` in the transcript is resolved. The builder contacts the `BlobStore` to determine if the data should be sent as `inlineData` (Base64) or if it has a pre-existing `fileId`.
|
|
170
194
|
|
|
171
195
|
### 6.5. Stage 5: Provider-Specific Adapter Mapping
|
|
196
|
+
|
|
172
197
|
The finalized, agnostic `Prompt` is passed to the `LLMAdapter`. This is where the mapping to the provider's specific wire format occurs.
|
|
173
198
|
|
|
174
199
|
---
|
|
@@ -176,52 +201,61 @@ The finalized, agnostic `Prompt` is passed to the `LLMAdapter`. This is where th
|
|
|
176
201
|
## 7. The Content Block Specification
|
|
177
202
|
|
|
178
203
|
### 7.1. Basic Blocks
|
|
179
|
-
|
|
180
|
-
-
|
|
204
|
+
|
|
205
|
+
- **`text`**: Standard text communication.
|
|
206
|
+
- **`thinking`**: Internal CoT reasoning. Separate to allow UI to hide/show reasoning paths.
|
|
181
207
|
|
|
182
208
|
### 7.2. Asset Blocks
|
|
183
|
-
|
|
184
|
-
-
|
|
209
|
+
|
|
210
|
+
- **`image`**: References a `BlobRef`. Supports `mediaType` and `filename`.
|
|
211
|
+
- **`document`**: Used for PDFs, code snippets, or long-form text files.
|
|
185
212
|
|
|
186
213
|
### 7.3. Functional Blocks
|
|
187
|
-
|
|
188
|
-
-
|
|
214
|
+
|
|
215
|
+
- **`tool_use`**: A structured request for tool execution. Contains `callId`, `name`, and `args`.
|
|
216
|
+
- **`tool_result`**: The output of a tool, linked via `callId`.
|
|
189
217
|
|
|
190
218
|
### 7.4. Structural Blocks
|
|
191
|
-
|
|
192
|
-
-
|
|
219
|
+
|
|
220
|
+
- **`summary`**: A "compression" block. Replaces older history turns.
|
|
221
|
+
- **`role:transition`**: Notates that the session persona changed.
|
|
193
222
|
|
|
194
223
|
---
|
|
195
224
|
|
|
196
225
|
## 8. Command Reference: The Mutation API Manual
|
|
197
226
|
|
|
198
227
|
### 8.1. Workspace Domain Commands
|
|
228
|
+
|
|
199
229
|
- **`workspace:create`**: Initializes root metadata.
|
|
200
230
|
- **`workspace:sync`**: Forces a full re-indexing of all stores.
|
|
201
231
|
|
|
202
232
|
### 8.2. Session Domain Commands
|
|
203
|
-
|
|
204
|
-
|
|
|
205
|
-
|
|
|
206
|
-
| **`session:
|
|
207
|
-
| **`session:
|
|
208
|
-
| **`session:
|
|
209
|
-
| **`session:
|
|
233
|
+
|
|
234
|
+
| Command | Payload | Side Effects |
|
|
235
|
+
| :------------------------ | :------------------------ | :------------------------------------- |
|
|
236
|
+
| **`session:create`** | `id, role, topics, label` | Creates database record + Index entry. |
|
|
237
|
+
| **`session:fork`** | `sessionId, turnId` | Metadata-only clone of history. |
|
|
238
|
+
| **`session:update`** | `sessionId, updates` | Patch Index + Update store. |
|
|
239
|
+
| **`session:delete`** | `sessionId` | Recursive release of all blob refs. |
|
|
240
|
+
| **`session:role:switch`** | `sessionId, newRole` | Insert transition block + Update role. |
|
|
210
241
|
|
|
211
242
|
### 8.3. Turn & DAG Domain Commands
|
|
212
|
-
|
|
213
|
-
|
|
|
214
|
-
|
|
|
215
|
-
| **`turn:
|
|
216
|
-
| **`turn:
|
|
217
|
-
| **`turn:
|
|
243
|
+
|
|
244
|
+
| Command | Payload | Description |
|
|
245
|
+
| :---------------- | :----------------------------- | :-------------------------------- |
|
|
246
|
+
| **`turn:add`** | `sessionId, turn` | Appends turn. Retains blobs. |
|
|
247
|
+
| **`turn:edit`** | `sessionId, turnId, newBlocks` | New Version in DAG. Moves Head. |
|
|
248
|
+
| **`turn:branch`** | `sessionId, turn` | Diverge from non-head node. |
|
|
249
|
+
| **`turn:delete`** | `sessionId, turnId, version` | Removes Version + Releases blobs. |
|
|
218
250
|
|
|
219
251
|
### 8.4. Role & Persona Domain Commands
|
|
252
|
+
|
|
220
253
|
- **`role:add`**: Register new persona.
|
|
221
254
|
- **`role:update`**: Modify instructions/constraints.
|
|
222
255
|
- **`role:delete`**: Remove role.
|
|
223
256
|
|
|
224
257
|
### 8.5. Blob & Asset Domain Commands
|
|
258
|
+
|
|
225
259
|
- **`blob:register`**: Calculate hash + Create storage record + Increment ref-count.
|
|
226
260
|
- **`blob:retain`**: Increment ref-count.
|
|
227
261
|
- **`blob:release`**: Decrement ref-count + Trigger purge if 0.
|
|
@@ -232,67 +266,89 @@ The finalized, agnostic `Prompt` is passed to the `LLMAdapter`. This is where th
|
|
|
232
266
|
## 9. Extension Framework
|
|
233
267
|
|
|
234
268
|
### 9.1. WorkspaceExtensions
|
|
269
|
+
|
|
235
270
|
Packaging custom logic into a single plugin.
|
|
271
|
+
|
|
236
272
|
```typescript
|
|
237
273
|
const MyPlugin: WorkspaceExtension = {
|
|
238
|
-
schemas: [
|
|
239
|
-
|
|
240
|
-
|
|
274
|
+
schemas: [
|
|
275
|
+
/* schemas */
|
|
276
|
+
],
|
|
277
|
+
reducers: { "custom:cmd": myReducer },
|
|
278
|
+
middleware: [myMiddleware],
|
|
241
279
|
};
|
|
242
280
|
```
|
|
243
281
|
|
|
244
282
|
### 9.2. Middleware: Intercepting the State Stream
|
|
283
|
+
|
|
245
284
|
Guardians of the workspace. Can abort, augment, or observe commands.
|
|
246
285
|
|
|
247
286
|
### 9.3. TurnProcessors: Giving the AI Agency
|
|
287
|
+
|
|
248
288
|
Scans AI response blocks for side-effects (e.g., auto-saving memories or tasks).
|
|
249
289
|
|
|
250
290
|
### 9.4. Custom Indexers
|
|
291
|
+
|
|
251
292
|
Expanding the Read Model with custom read-projections.
|
|
252
293
|
|
|
253
294
|
---
|
|
254
295
|
|
|
255
296
|
## 10. Persistence Layer: Schema and Collections
|
|
256
297
|
|
|
257
|
-
| Collection
|
|
258
|
-
|
|
|
259
|
-
| `workspace`
|
|
260
|
-
| `role`
|
|
261
|
-
| `preference`
|
|
262
|
-
| `context`
|
|
263
|
-
| `session`
|
|
264
|
-
| `turn`
|
|
265
|
-
| `blob_records` | `sha256`
|
|
298
|
+
| Collection | Key | Description |
|
|
299
|
+
| :------------- | :-------------- | :---------------------------- |
|
|
300
|
+
| `workspace` | `id` | Global metadata and settings. |
|
|
301
|
+
| `role` | `name` | Persona instructions. |
|
|
302
|
+
| `preference` | `id` | User instructions. |
|
|
303
|
+
| `context` | `key` | RAG snippets. |
|
|
304
|
+
| `session` | `id` | Session metadata + Head. |
|
|
305
|
+
| `turn` | `(id, version)` | Immutable history records. |
|
|
306
|
+
| `blob_records` | `sha256` | Metadata + RefCount. |
|
|
266
307
|
|
|
267
308
|
---
|
|
268
309
|
|
|
269
310
|
## 11. Implementation Guide
|
|
270
311
|
|
|
271
312
|
### 11.1. Implementing a Database Boundary
|
|
313
|
+
|
|
272
314
|
```typescript
|
|
273
315
|
class MyDb implements WorkspaceDatabase {
|
|
274
|
-
async collection(name: string) {
|
|
275
|
-
|
|
316
|
+
async collection(name: string) {
|
|
317
|
+
/* ... */
|
|
318
|
+
}
|
|
319
|
+
async open(schemas: SchemaDefinition[]) {
|
|
320
|
+
/* ... */
|
|
321
|
+
}
|
|
276
322
|
}
|
|
277
323
|
```
|
|
278
324
|
|
|
279
325
|
### 11.2. Implementing a BlobStorage Boundary
|
|
326
|
+
|
|
280
327
|
```typescript
|
|
281
328
|
class MyStorage implements BlobStorage {
|
|
282
|
-
async put(data: Uint8Array): Promise<string> {
|
|
283
|
-
|
|
284
|
-
|
|
329
|
+
async put(data: Uint8Array): Promise<string> {
|
|
330
|
+
/* return sha256 */
|
|
331
|
+
}
|
|
332
|
+
async get(sha256: string): Promise<Uint8Array | null> {
|
|
333
|
+
/* ... */
|
|
334
|
+
}
|
|
335
|
+
async delete(sha256: string): Promise<void> {
|
|
336
|
+
/* ... */
|
|
337
|
+
}
|
|
285
338
|
}
|
|
286
339
|
```
|
|
287
340
|
|
|
288
341
|
### 11.3. Bootstrapping the Manager
|
|
342
|
+
|
|
289
343
|
```typescript
|
|
290
344
|
const { manager, sessions, ctx } = await createWorkspace({
|
|
291
345
|
db: new MyDb(),
|
|
292
346
|
blobStorage: new MyStorage(),
|
|
293
347
|
getWorkspace: () => state,
|
|
294
|
-
setWorkspace: (patch) => {
|
|
295
|
-
|
|
348
|
+
setWorkspace: (patch) => {
|
|
349
|
+
state = merge(state, patch);
|
|
350
|
+
},
|
|
351
|
+
processor: new MyProcessor(),
|
|
296
352
|
});
|
|
297
353
|
```
|
|
298
354
|
|
|
@@ -301,12 +357,15 @@ const { manager, sessions, ctx } = await createWorkspace({
|
|
|
301
357
|
## 12. Design Decisions
|
|
302
358
|
|
|
303
359
|
### Why a DAG?
|
|
360
|
+
|
|
304
361
|
A tree allows branching, but a DAG allows for **Merging** and **Non-Destructive Versioning**. It accurately represents the way conversation evolved into multiple "what-if" scenarios.
|
|
305
362
|
|
|
306
363
|
### Why SHA-256?
|
|
364
|
+
|
|
307
365
|
UUIDs lead to "Asset Proliferation." SHA-256 enables **Global Deduplication**, critical for reducing storage in RAG-heavy apps.
|
|
308
366
|
|
|
309
367
|
### Why CQRS?
|
|
368
|
+
|
|
310
369
|
Read patterns (building prompts) are vastly different from Write patterns (saving turns). CQRS optimizes both independently.
|
|
311
370
|
|
|
312
371
|
---
|
|
@@ -321,9 +380,11 @@ Read patterns (building prompts) are vastly different from Write patterns (savin
|
|
|
321
380
|
## 14. Advanced Recipes & Design Patterns
|
|
322
381
|
|
|
323
382
|
### The "Shadow Turn" Pattern
|
|
383
|
+
|
|
324
384
|
Intercept `turn:add` and inject a hidden system turn before the user message for real-time situational awareness.
|
|
325
385
|
|
|
326
386
|
### Automatic Topic Discovery
|
|
387
|
+
|
|
327
388
|
Use a cheap model to scan every user turn and suggest new topics to refine RAG retrieval dynamically.
|
|
328
389
|
|
|
329
390
|
---
|
|
@@ -331,9 +392,11 @@ Use a cheap model to scan every user turn and suggest new topics to refine RAG r
|
|
|
331
392
|
## 15. Technical Specifications
|
|
332
393
|
|
|
333
394
|
### Blob Hash Protocol
|
|
395
|
+
|
|
334
396
|
SHA-256 hex digest -> stored under `blobs/{sha256}`. RefCount = 0 triggers deletion.
|
|
335
397
|
|
|
336
398
|
### Index Sync Protocol
|
|
399
|
+
|
|
337
400
|
Full re-build of Index via parallel execution of all registered `Indexers`.
|
|
338
401
|
|
|
339
402
|
---
|
|
@@ -341,9 +404,11 @@ Full re-build of Index via parallel execution of all registered `Indexers`.
|
|
|
341
404
|
## 16. Troubleshooting
|
|
342
405
|
|
|
343
406
|
### Stale Index
|
|
407
|
+
|
|
344
408
|
Ensure reducers return the correct patch. Call `workspace:sync` to force a rebuild.
|
|
345
409
|
|
|
346
410
|
### Blob Reference Leak
|
|
411
|
+
|
|
347
412
|
Use `session:delete` to ensure all blobs in the session DAG are released.
|
|
348
413
|
|
|
349
414
|
---
|
|
@@ -351,6 +416,7 @@ Use `session:delete` to ensure all blobs in the session DAG are released.
|
|
|
351
416
|
## 17. Testing Strategy
|
|
352
417
|
|
|
353
418
|
### Integration Testing the DAG
|
|
419
|
+
|
|
354
420
|
```typescript
|
|
355
421
|
test('can branch history', async () => {
|
|
356
422
|
const session = await sessions.create({ ... });
|
|
@@ -362,6 +428,7 @@ test('can branch history', async () => {
|
|
|
362
428
|
```
|
|
363
429
|
|
|
364
430
|
### Unit Testing Reducers
|
|
431
|
+
|
|
365
432
|
Reducers are pure-ish and can be tested in isolation by providing a mock `WorkspaceContext`.
|
|
366
433
|
|
|
367
434
|
---
|
|
@@ -379,11 +446,13 @@ Reducers are pure-ish and can be tested in isolation by providing a mock `Worksp
|
|
|
379
446
|
## 19. API Reference Appendix
|
|
380
447
|
|
|
381
448
|
### WorkspaceManager
|
|
449
|
+
|
|
382
450
|
- `dispatch(command)`: Atomic mutation.
|
|
383
451
|
- `workspace()`: Sync Index access.
|
|
384
452
|
- `use(middleware)`: Register interceptor.
|
|
385
453
|
|
|
386
454
|
### Session
|
|
455
|
+
|
|
387
456
|
- `snapshot()`: Prepare prompt data.
|
|
388
457
|
- `addTurn(blocks)`: Append to head.
|
|
389
458
|
- `branchInfo(turnId)`: Retrieve all versions.
|