@asaidimu/utils-workspace 6.1.0 → 6.2.0

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 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
- * [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)
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
- * [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)
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
- * [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)
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
- * [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)
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
- * [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)
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
- * [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)
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
- * [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)
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
- - **Conversation as Graph Architecture**: Enabling non-destructive editing and infinite branching.
71
- - **Data as Content-Addressed Assets**: Eliminating redundancy and ensuring asset integrity.
72
- - **State as Observable Commands**: Providing a perfect audit trail and reactive UI projections.
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
- - **TurnNode**: Represents a logical "moment" or "slot" in the conversation timeline. It is a stable identifier that does not change.
86
- - **Turn**: Represents the actual data (text, images, tool results) at that moment.
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
- - **A/B Testing**: Testing how different model instructions respond to the same conversation.
93
- - **Collaborative Branching**: Allowing multiple team members to explore different paths from a shared starting point.
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
- - **Commands**: Describe intent (e.g., `session:fork`).
108
- - **Reducers**: Pure-ish functions that execute the intent against the persistent stores.
109
- - **Projections**: In-memory read models (The Index) that allow for sub-millisecond retrieval of workspace state.
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
- - When a command is executed, the reducer returns a "Patch."
124
- - The manager applies the patch to the Index.
125
- - Subscribers are notified via the Event Bus.
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
- - **Head Pointer**: A `TurnRef` (UUID + Version) identifying the current leaf of the DAG.
140
- - **Topic Affinity**: Semantic tags that act as "magnets" for RAG context and user preferences.
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
- - **Registration**: Calculate hash -> Check for existence -> Create or increment ref-count.
148
- - **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.
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
- - **`text`**: Standard text communication.
180
- - **`thinking`**: Internal CoT reasoning. Separate to allow UI to hide/show reasoning paths.
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
- - **`image`**: References a `BlobRef`. Supports `mediaType` and `filename`.
184
- - **`document`**: Used for PDFs, code snippets, or long-form text files.
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
- - **`tool_use`**: A structured request for tool execution. Contains `callId`, `name`, and `args`.
188
- - **`tool_result`**: The output of a tool, linked via `callId`.
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
- - **`summary`**: A "compression" block. Replaces older history turns.
192
- - **`role:transition`**: Notates that the session persona changed.
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
- | Command | Payload | Side Effects |
204
- | :--- | :--- | :--- |
205
- | **`session:create`** | `id, role, topics, label` | Creates database record + Index entry. |
206
- | **`session:fork`** | `sessionId, turnId` | Metadata-only clone of history. |
207
- | **`session:update`** | `sessionId, updates` | Patch Index + Update store. |
208
- | **`session:delete`** | `sessionId` | Recursive release of all blob refs. |
209
- | **`session:role:switch`** | `sessionId, newRole` | Insert transition block + Update role. |
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
- | Command | Payload | Description |
213
- | :--- | :--- | :--- |
214
- | **`turn:add`** | `sessionId, turn` | Appends turn. Retains blobs. |
215
- | **`turn:edit`** | `sessionId, turnId, newBlocks`| New Version in DAG. Moves Head. |
216
- | **`turn:branch`** | `sessionId, turn` | Diverge from non-head node. |
217
- | **`turn:delete`** | `sessionId, turnId, version`| Removes Version + Releases blobs. |
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: [ /* schemas */ ],
239
- reducers: { 'custom:cmd': myReducer },
240
- middleware: [ myMiddleware ],
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 | Key | Description |
258
- | :--- | :--- | :--- |
259
- | `workspace` | `id` | Global metadata and settings. |
260
- | `role` | `name` | Persona instructions. |
261
- | `preference` | `id` | User instructions. |
262
- | `context` | `key` | RAG snippets. |
263
- | `session` | `id` | Session metadata + Head. |
264
- | `turn` | `(id, version)`| Immutable history records. |
265
- | `blob_records` | `sha256` | Metadata + RefCount. |
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
- async open(schemas: SchemaDefinition[]) { /* ... */ }
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> { /* return sha256 */ }
283
- async get(sha256: string): Promise<Uint8Array | null> { /* ... */ }
284
- async delete(sha256: string): Promise<void> { /* ... */ }
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) => { state = merge(state, patch); },
295
- processor: new MyProcessor()
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.