@asaidimu/utils-workspace 4.0.3 → 6.0.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.
Files changed (5) hide show
  1. package/index.d.mts +1872 -1599
  2. package/index.d.ts +1872 -1599
  3. package/index.js +1 -288
  4. package/index.mjs +1 -287
  5. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -1,484 +1,1096 @@
1
- import { QueryFilter, PaginationOptions } from '@asaidimu/query';
2
1
  import { IndexDefinition, SchemaDefinition, SchemaChange, DataTransform } from '@asaidimu/anansi';
3
- import { EventBus } from '@asaidimu/events';
4
- import * as _google_genai from '@google/genai';
5
- import { GenerateContentParameters, GenerateContentResponse, GoogleGenAI } from '@google/genai';
2
+ import { QueryFilter, PaginationOptions } from '@asaidimu/query';
6
3
 
7
4
  /**
8
- * Utility type for representing partial updates to the state, allowing deep nesting.
9
- * It makes all properties optional and applies the same transformation recursively
10
- * to nested objects and array elements, allowing for selective updates while
11
- * preserving the original structure. It also includes the original type T and
12
- * undefined as possibilities for the top level and nested values.
5
+ * Buffers write operations across one or more stores and commits them atomically.
6
+ *
7
+ * ## How atomicity works
8
+ *
9
+ * ### IndexedDB stores (same database)
10
+ * At commit time, TransactionContext collects the names of every IDB store that
11
+ * received operations, then opens a **single** `IDBTransaction` spanning all of
12
+ * them via `ConnectionManager.openTransaction`. Each store's `executeInTransaction`
13
+ * receives that shared transaction object and performs its writes against it
14
+ * without opening a new transaction of its own. IDB commits or aborts the
15
+ * entire multi-store transaction as one unit.
16
+ *
17
+ * ### MemoryStore
18
+ * MemoryStore's `executeInTransaction` receives `null` for the shared transaction.
19
+ * It applies ops against an internal staging map and returns. If a later
20
+ * participant fails, TransactionContext calls `rollbackMemory` on each
21
+ * MemoryStore that already applied its staged ops. MemoryStore restores its
22
+ * pre-transaction snapshot.
23
+ *
24
+ * ### Mixed (IDB + Memory in the same transaction)
25
+ * All IDB stores are committed first as a single atomic IDB transaction, then
26
+ * each MemoryStore is committed. If a MemoryStore fails after IDB has already
27
+ * committed, the IDB side cannot be rolled back — this is an inherent limitation
28
+ * of mixing two different storage engines. In practice the schema store is
29
+ * always MemoryStore-or-IDB consistently, so mixed transactions should not arise
30
+ * in normal usage.
13
31
  */
14
- type DeepPartial<T> = T extends object ? T extends readonly (infer U)[] ? readonly (DeepPartial<U> | undefined)[] | undefined | T : T extends (infer U)[] ? (DeepPartial<U> | undefined)[] | undefined | T : {
15
- [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined;
16
- } | undefined | T : T | undefined;
32
+ declare class TransactionContext {
33
+ readonly id: string;
34
+ /**
35
+ * Flat list of every operation staged so far, in the order they were added.
36
+ * We keep the store reference alongside the op so commit() can group them.
37
+ */
38
+ private staged;
39
+ private done;
40
+ constructor();
41
+ /**
42
+ * Stages a single write operation against a store.
43
+ * Does NOT touch the store — no I/O happens until commit().
44
+ */
45
+ addOp<T extends Record<string, any>>(store: Store<T>, type: "put" | "delete" | "add", data: any): Promise<void>;
46
+ /**
47
+ * Commits all staged operations atomically.
48
+ *
49
+ * For IDB stores: opens one shared IDBTransaction across all participating
50
+ * stores, then dispatches ops to each store's executeInTransaction.
51
+ * For MemoryStores: dispatches sequentially; rolls back on failure.
52
+ */
53
+ commit(): Promise<void>;
54
+ /**
55
+ * Discards all staged operations. No I/O has occurred so there is nothing
56
+ * to undo — we simply clear the buffer.
57
+ */
58
+ rollback(): void;
59
+ /**
60
+ * Opens ONE IDBTransaction across all participating IDB stores and lets
61
+ * each store execute its ops against the shared transaction handle.
62
+ *
63
+ * We obtain the IDBDatabase from the first store (they all share the same
64
+ * ConnectionManager / database) and open the transaction ourselves so that
65
+ * the commit/abort lifecycle belongs entirely to this method.
66
+ */
67
+ private commitIDB;
68
+ /**
69
+ * Commits MemoryStore groups sequentially.
70
+ * Maintains a list of stores that have already applied their ops; if any
71
+ * store throws, all previously-applied stores are rolled back via the
72
+ * store-level `_rollbackMemory(snapshot)` escape hatch.
73
+ */
74
+ private commitMemory;
75
+ completed(): boolean;
76
+ }
17
77
 
78
+ interface CursorCallbackResult<T> {
79
+ value: T | null;
80
+ done: boolean;
81
+ offset?: number;
82
+ }
18
83
  /**
19
- * core/types.ts
20
- * * This file contains the primary domain models, data structures, and command types
21
- * for the AI Workspace. It acts as the "Source of Truth" for all modules.
84
+ * Callback function for cursor iteration over store records.
85
+ *
86
+ * @template T - The type of records stored.
87
+ * @param value - The current record value (cloned, not a live reference).
88
+ * @param key - The key (ID) of the current record.
89
+ * @param cursor - The underlying cursor object (implementation-specific; may be `null` in memory adapters).
90
+ * @returns A promise resolving to an object indicating whether iteration should stop,
91
+ * and an optional offset to advance.
22
92
  */
23
-
24
- /** RFC 4122 compliant Universally Unique Identifier. */
25
- type UUID = string;
26
- /** ISO-8601 formatted UTC timestamp string. */
27
- type Timestamp = string;
28
- /** Uniform Resource Identifier string. */
29
- type URI = string;
30
- /** Hexadecimal representation of a SHA-256 hash. */
31
- type SHA256 = string;
32
- /** Special marker used to denote a role with no specific instructions or identity. */
33
- declare const EMPTY_SYSTEM_ROLE = "__system__";
93
+ type CursorCallback<T> = (value: T, key: string | number, cursor: any) => Promise<CursorCallbackResult<T>>;
34
94
  /**
35
- * A functional wrapper for operations that can fail.
36
- * Encourages explicit error handling over try/catch blocks.
95
+ * A generic representation of a key range, replacing the browser-specific IDBKeyRange.
37
96
  */
38
- type Result<T, E = WorkspaceError> = {
39
- ok: true;
40
- value: T;
41
- } | {
42
- ok: false;
43
- error: E;
44
- };
45
- /** Occurs when attempting to create a resource with a key that already exists. */
46
- type DuplicateKeyError = {
47
- code: 'DUPLICATE_KEY';
48
- resource: string;
49
- key: string;
50
- };
51
- /** Occurs when a requested resource cannot be found by its unique identifier. */
52
- type NotFoundError = {
53
- code: 'NOT_FOUND';
54
- resource: string;
55
- id: string;
56
- };
57
- /** Triggered when a command payload fails validation or is logically inconsistent. */
58
- type InvalidCommandError = {
59
- code: 'INVALID_COMMAND';
60
- reason: string;
61
- };
62
- /** Generic wrapper for unexpected infrastructure or downstream service failures. */
63
- type BackendError = {
64
- code: 'BACKEND_ERROR';
65
- reason: string;
66
- };
67
- /** Specific errors related to blob storage, retrieval, or corruption. */
68
- type BlobError = {
69
- code: 'BLOB_ERROR';
70
- reason: string;
71
- };
72
- /** Triggered when the current actor lacks sufficient privileges for a command. */
73
- type PermissionDeniedError = {
74
- code: 'PERMISSION_DENIED';
75
- command: Command;
76
- reason: string;
77
- };
78
- /** Union of all possible error types within the Workspace domain. */
79
- type WorkspaceError = DuplicateKeyError | NotFoundError | InvalidCommandError | BackendError | PermissionDeniedError | BlobError;
80
- /** Global user preferences and defaults for the workspace. */
81
- interface Settings {
82
- /** Default language code (e.g., 'en-US'). */
83
- language: string;
84
- /** The name of the role used when starting a new session. */
85
- defaultRole?: string;
86
- /** Global instructions appended to all system prompts. */
87
- prompt?: string;
97
+ interface StoreKeyRange {
98
+ lower?: any;
99
+ upper?: any;
100
+ lowerOpen?: boolean;
101
+ upperOpen?: boolean;
88
102
  }
89
- /** * Represents the project-level metadata.
90
- * Allows for extensible metadata fields via the generic Metadata type.
91
- */
92
- type Project<Metadata extends Record<string, any> = Record<string, any>> = Metadata & {
93
- id: UUID;
94
- name: string;
95
- };
96
- /** Supported mime-types for image assets. */
97
- type ImageMediaType = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp';
98
- /** Supported mime-types for text-based or structured documents. */
99
- type DocumentMediaType = 'application/pdf' | 'application/json' | 'text/plain' | 'text/html' | 'text/markdown' | 'text/csv' | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
100
- /** Union of all media types handled by the blob system. */
101
- type BlobMediaType = ImageMediaType | DocumentMediaType;
102
- /**
103
- * A lightweight reference to a blob.
104
- * Used in content blocks to avoid passing heavy metadata or binary data.
105
- */
106
- type BlobRef = Pick<BlobRecord, 'sha256' | 'mediaType' | 'sizeBytes' | 'filename' | 'previewUrl'>;
107
103
  /**
108
- * Represents a blob that has been fetched into memory.
109
- * Can be 'inline' (binary data present) or 'remote' (stored in an external provider).
104
+ * A single buffered operation staged inside a TransactionContext.
105
+ * Kept intentionally minimal the context only needs to know what to
106
+ * replay against a store during commit.
110
107
  */
111
- type ResolvedBlob = {
112
- kind: 'inline';
113
- sha256: SHA256;
114
- mediaType: BlobMediaType;
115
- data: Uint8Array;
108
+ type BufferedOperation<T> = {
109
+ type: "add" | "put";
110
+ data: T | T[];
116
111
  } | {
117
- kind: 'remote';
118
- sha256: SHA256;
119
- mediaType: BlobMediaType;
120
- fileId: string;
121
- providerId: string;
122
- timestamp: Timestamp;
112
+ type: "delete";
113
+ data: string | number | (string | number)[];
123
114
  };
124
115
  /**
125
- * The authoritative registry entry for a file in the system.
126
- * Includes reference counting for garbage collection and remote mappings.
116
+ * Storage adapter interface for a single object store (collection).
117
+ *
118
+ * Stores own their indexes. Index lifecycle (create, drop) and index-aware reads
119
+ * (findByIndex) are part of this contract so that both MemoryStore and IndexedDBStore
120
+ * implement them natively — MemoryStore via in-memory index maps, IndexedDB via its
121
+ * native index mechanism.
122
+ *
123
+ * @template T - The type of objects stored. Must include the key path property.
127
124
  */
128
- interface BlobRecord {
129
- sha256: SHA256;
130
- mediaType: BlobMediaType;
131
- sizeBytes: number;
132
- filename?: string;
133
- previewUrl?: string;
134
- /** Number of content blocks currently referencing this blob. */
135
- refCount: number;
136
- /** Map of provider IDs to their specific external file identifiers. */
137
- remoteIds: Record<string, {
138
- id: string;
139
- timestamp: Timestamp;
140
- }>;
141
- createdAt: Timestamp;
142
- lastUsedAt: Timestamp;
143
- }
144
- /** Standard text content within a turn. */
145
- interface TextBlock {
146
- id: UUID;
147
- type: 'text';
148
- text: string;
149
- }
150
- /** An image asset within a turn, optionally containing the resolved binary data. */
151
- interface ImageBlock {
152
- id: UUID;
153
- type: 'image';
154
- ref?: BlobRef;
155
- blob?: ResolvedBlob;
156
- altText?: string;
157
- }
158
- /** A document asset within a turn. */
159
- interface DocumentBlock {
160
- id: UUID;
161
- type: 'document';
162
- ref?: BlobRef;
163
- blob?: ResolvedBlob;
164
- title?: string;
165
- }
166
- /** Represents a structured proposal to create or modify a task. */
167
- interface TaskProposalBlock {
168
- id?: UUID;
169
- ref?: string;
170
- type: 'task:proposal';
171
- title: string;
172
- steps: {
173
- ref?: string;
174
- text: string;
175
- status: 'todo' | 'done';
176
- }[];
177
- action: 'create' | 'update' | 'complete';
178
- }
179
- /** Captured request from the AI to execute a specific tool. */
180
- interface ToolUseBlock {
181
- id: UUID;
182
- type: 'tool:use';
183
- name: string;
184
- input: Record<string, unknown>;
185
- }
186
- /** The resulting output (or error) from a tool execution. */
187
- interface ToolResultBlock {
188
- id: UUID;
189
- type: 'tool:result';
190
- /** References the ToolUseBlock ID that generated this result. */
191
- useId: UUID;
192
- content: string | Record<string, unknown>;
193
- isError?: boolean;
194
- }
195
- /** Internal "Chain of Thought" or reasoning generated by the model. */
196
- interface ThinkingBlock {
197
- id: UUID;
198
- type: 'thinking';
199
- thinking: string;
200
- }
201
- /** A condensed summary of previous conversation history. */
202
- interface SummaryBlock {
203
- id: UUID;
204
- type: 'summary';
205
- text: string;
206
- }
207
- /** Notates that the session has switched from one Role persona to another. */
208
- interface RoleTransitionBlock {
209
- id: UUID;
210
- type: 'role:transition';
211
- previousRole: string | null;
212
- newRole: string;
213
- }
214
- /** Union of all possible content types that can exist within a conversation Turn. */
215
- type ContentBlock = TextBlock | ImageBlock | DocumentBlock | ToolUseBlock | ToolResultBlock | SummaryBlock | RoleTransitionBlock | ThinkingBlock | TaskProposalBlock;
216
- /** Definition of a tool available to the AI. */
217
- interface ToolSummary {
218
- name: string;
219
- description: string;
220
- /** JSON Schema defining the required input arguments. */
125
+ interface Store<T extends Record<string, any> = Record<string, any>> {
126
+ /**
127
+ * Returns the name of this store (the IDB object store / collection name).
128
+ * Used by TransactionContext to group operations and open a correctly-scoped
129
+ * multi-store IDB transaction at commit time.
130
+ */
131
+ name(): string;
132
+ /**
133
+ * Opens the store, ensuring underlying storage structures exist.
134
+ */
135
+ open(): Promise<void>;
136
+ /**
137
+ * Adds one or more records to the store.
138
+ * If a record does not have a value for the store's key path, an automatic
139
+ * key may be assigned. Throws if a record with the same key already exists.
140
+ */
141
+ add(data: T | T[]): Promise<string | number | (string | number)[]>;
142
+ /**
143
+ * Removes all records from the store without destroying index structures.
144
+ */
145
+ clear(): Promise<void>;
146
+ /**
147
+ * Returns the total number of records in the store.
148
+ */
149
+ count(): Promise<number>;
150
+ /**
151
+ * Deletes one or more records by their keys.
152
+ */
153
+ delete(id: string | number | (string | number)[]): Promise<void>;
154
+ /**
155
+ * Retrieves a single record by its primary key.
156
+ */
157
+ getById(id: string | number): Promise<T | undefined>;
158
+ /**
159
+ * Retrieves the first record matching an exact index key (point lookup).
160
+ * Useful for unique indexes — returns the single matching record or undefined.
161
+ *
162
+ * @param indexName - The name of the index to query.
163
+ * @param key - The exact key value to look up.
164
+ */
165
+ getByIndex(indexName: string, key: any): Promise<T | undefined>;
166
+ /**
167
+ * Retrieves all records from a named index, optionally filtered by a key range.
168
+ * Use this for range scans over an index (e.g. all records where age >= 18).
169
+ *
170
+ * @param indexName - The name of the index to query.
171
+ * @param keyRange - Optional range to filter results.
172
+ */
173
+ getByKeyRange(indexName: string, keyRange?: StoreKeyRange): Promise<T[]>;
174
+ /**
175
+ * Retrieves all records from the store without index involvement.
176
+ */
177
+ getAll(): Promise<T[]>;
178
+ /**
179
+ * Inserts or replaces a record. Validates OCC if a record with the same key exists.
180
+ */
181
+ put(data: T): Promise<string | number>;
182
+ /**
183
+ * Iterates over records using a cursor, allowing early termination and skipping.
184
+ *
185
+ * @param callback - Invoked for each record; return `{ done: true }` to stop,
186
+ * `{ offset: n }` to skip ahead n records.
187
+ * @param direction - Iteration order.
188
+ * @param keyRange - Optional range to restrict iteration.
189
+ */
190
+ cursor(callback: CursorCallback<T>, direction?: "forward" | "backward", keyRange?: StoreKeyRange): Promise<T | null>;
191
+ /**
192
+ * Executes a batch of write operations atomically within this store.
193
+ * All operations succeed or fail together.
194
+ *
195
+ * Used for standalone (single-store) atomic writes. For cross-store atomicity,
196
+ * use executeInTransaction instead.
197
+ */
198
+ batch(operations: Array<{
199
+ type: "add" | "put";
200
+ data: T | T[];
201
+ } | {
202
+ type: "delete";
203
+ data: string | number | (string | number)[];
204
+ }>): Promise<void>;
205
+ /**
206
+ * Registers a new index on the store. Idempotent — no-op if the index already exists.
207
+ * For IndexedDB, this triggers a database version upgrade.
208
+ * For MemoryStore, this builds the index map from existing records.
209
+ *
210
+ * @param definition - The full index definition from the schema.
211
+ */
212
+ createIndex(definition: IndexDefinition): Promise<void>;
213
+ /**
214
+ * Removes a named index from the store.
215
+ * For IndexedDB, this triggers a database version upgrade.
216
+ * For MemoryStore, this drops the in-memory index map.
217
+ *
218
+ * @param name - The index name as declared in IndexDefinition.name.
219
+ */
220
+ dropIndex(name: string): Promise<void>;
221
+ /**
222
+ * Returns all records matching an exact index key.
223
+ * Unlike getByIndex (which returns only the first match), this returns all matches —
224
+ * essential for non-unique indexes where multiple records share the same indexed value.
225
+ *
226
+ * @param indexName - The name of the index to query.
227
+ * @param value - The exact value to look up.
228
+ */
229
+ findByIndex(indexName: string, value: any): Promise<T[]>;
230
+ /**
231
+ * Executes a set of buffered operations as part of a cross-store atomic transaction.
232
+ *
233
+ * For IndexedDBStore: `sharedTx` is the single IDBTransaction opened across all
234
+ * participating stores. Operations are applied directly to `sharedTx.objectStore(name)`
235
+ * without opening a new transaction — IDB commits or aborts the whole thing atomically.
236
+ *
237
+ * For MemoryStore: `sharedTx` is null. The store applies ops against its own staging
238
+ * area. The caller (TransactionContext) is responsible for coordinating rollback across
239
+ * all MemoryStores if any participant fails.
240
+ *
241
+ * This method must NOT open, commit, or abort any transaction itself.
242
+ *
243
+ * @param ops - The buffered operations to apply.
244
+ * @param sharedTx - The shared IDBTransaction (IndexedDB only), or null (MemoryStore).
245
+ */
246
+ executeInTransaction(ops: BufferedOperation<T>[], sharedTx: IDBTransaction | null): Promise<void>;
247
+ }
248
+ interface Collection<T> {
249
+ /**
250
+ * Finds a single document matching the query.
251
+ */
252
+ find: (query: QueryFilter<T>) => Promise<Document<T> | null>;
253
+ /**
254
+ * Lists documents with pagination. Returns an AsyncIterator so consumers can
255
+ * wrap it in their own iteration protocol (e.g. for-await-of via AsyncIterable).
256
+ */
257
+ list: (query: PaginationOptions) => Promise<AsyncIterator<Document<T>[]>>;
258
+ /**
259
+ * Filters all documents matching the query.
260
+ */
261
+ filter: (query: QueryFilter<T>) => Promise<Document<T>[]>;
262
+ /**
263
+ * Creates a new document in the collection.
264
+ *
265
+ * When a TransactionContext is provided the initial store.add is buffered into
266
+ * the transaction rather than written immediately. The document is returned in
267
+ * its fully initialised in-memory state regardless — callers can use it before
268
+ * the transaction commits.
269
+ *
270
+ * @param initial - The initial data for the document.
271
+ * @param tx - Optional transaction to buffer the write into.
272
+ */
273
+ create: (initial: T, tx?: TransactionContext) => Promise<Document<T>>;
274
+ /**
275
+ * Updates all documents matching the query with the provided partial data.
276
+ * Returns the number of documents updated.
277
+ */
278
+ update: (query: QueryFilter<T>, data: Partial<T>, tx?: TransactionContext) => Promise<number>;
279
+ /**
280
+ * Deletes all documents matching the query.
281
+ * Returns the number of documents deleted.
282
+ */
283
+ delete: (query: QueryFilter<T>, tx?: TransactionContext) => Promise<number>;
284
+ /**
285
+ * Subscribes to collection-level events.
286
+ */
287
+ subscribe: (event: CollectionEventType | TelemetryEventType, callback: (event: CollectionEvent<T> | TelemetryEvent) => void) => () => void;
288
+ /**
289
+ * Validates data against the collection's schema.
290
+ */
291
+ validate(data: Record<string, any>): Promise<{
292
+ value?: any;
293
+ issues: Array<{
294
+ message: string;
295
+ path: Array<string>;
296
+ }>;
297
+ }>;
298
+ invalidate(): void;
299
+ }
300
+ /**
301
+ * Event payload for Collection events.
302
+ */
303
+ type CollectionEventType = "document:create" | "collection:read" | "migration:start" | "migration:end";
304
+ type CollectionEvent<T> = {
305
+ type: CollectionEventType;
306
+ document?: T;
307
+ model?: string;
308
+ method?: keyof Collection<T>;
309
+ metadata?: Record<string, unknown>;
310
+ timestamp: number;
311
+ };
312
+ interface Database {
313
+ /**
314
+ * Opens an existing collection by name.
315
+ */
316
+ collection: <T>(schemaName: string) => Promise<Collection<T>>;
317
+ /**
318
+ * Creates a new collection from a schema definition.
319
+ */
320
+ createCollection: <T>(schema: SchemaDefinition) => Promise<Collection<T>>;
321
+ /**
322
+ * Deletes a collection and its schema record.
323
+ */
324
+ deleteCollection: (schemaName: string) => Promise<boolean>;
325
+ /**
326
+ * Updates an existing collection's schema record.
327
+ */
328
+ updateCollection: (schema: SchemaDefinition) => Promise<boolean>;
329
+ /**
330
+ * Migrates an existing collection's data and schema definition.
331
+ * Processes data in a streaming fashion to avoid loading the full collection
332
+ * into memory.
333
+ */
334
+ migrateCollection: <T>(name: string, opts: CollectionMigrationOptions, batchSize?: number) => Promise<Collection<T>>;
335
+ /**
336
+ * Executes a callback within a TransactionContext.
337
+ * Writes buffered inside the callback are flushed atomically on commit.
338
+ * If the callback throws, the buffer is discarded (no writes are flushed).
339
+ */
340
+ transaction: (callback: (tx: TransactionContext) => Promise<void>) => Promise<void>;
341
+ /**
342
+ * Subscribes to database-level events.
343
+ */
344
+ subscribe: (event: DatabaseEventType | "telemetry", callback: (event: DatabaseEvent | TelemetryEvent) => void) => () => void;
345
+ /**
346
+ * Releases in-memory references and event bus subscriptions.
347
+ * Does not delete any persisted data.
348
+ */
349
+ close: () => void;
350
+ clear: () => Promise<void>;
351
+ /**
352
+ * Ensures a collection exists; creates it if it doesn't. Idempotent.
353
+ */
354
+ ensureCollection: (schema: SchemaDefinition) => Promise<void>;
355
+ /**
356
+ * Ensures multiple collections exist; creates any that don't. Idempotent.
357
+ */
358
+ setupCollections: (schemas: SchemaDefinition[]) => Promise<void>;
359
+ }
360
+ type CollectionMigrationOptions = {
361
+ changes: SchemaChange<any>[];
362
+ description: string;
363
+ rollback?: SchemaChange<any>[];
364
+ transform?: string | DataTransform<any, any>;
365
+ };
366
+ type DatabaseEventType = "collection:create" | "collection:delete" | "collection:update" | "collection:read" | "migrate";
367
+ type DatabaseEvent = {
368
+ type: DatabaseEventType;
369
+ schema?: SchemaDefinition | Partial<SchemaDefinition>;
370
+ timestamp: number;
371
+ };
372
+ type DocumentMetadata = {
373
+ $id?: string;
374
+ $created?: string | Date;
375
+ $updated?: string | Date;
376
+ $version?: number;
377
+ };
378
+ type Document<T> = {
379
+ readonly [K in keyof T]: T[K];
380
+ } & DocumentMetadata & {
381
+ read: () => Promise<boolean>;
382
+ save: (tx?: TransactionContext) => Promise<boolean>;
383
+ update: (props: Partial<T>, tx?: TransactionContext) => Promise<boolean>;
384
+ delete: (tx?: TransactionContext) => Promise<boolean>;
385
+ subscribe: (event: DocumentEventType | TelemetryEventType, callback: (event: DocumentEvent<T> | TelemetryEvent) => void) => () => void;
386
+ state(): T;
387
+ $metadata(): DocumentMetadata;
388
+ };
389
+ type DocumentEventType = "document:create" | "document:write" | "document:update" | "document:delete" | "document:read";
390
+ type DocumentEvent<T> = {
391
+ type: DocumentEventType;
392
+ data?: Partial<T>;
393
+ timestamp: number;
394
+ };
395
+ type TelemetryEventType = "telemetry";
396
+ type TelemetryEvent = {
397
+ type: TelemetryEventType;
398
+ method: string;
399
+ timestamp: number;
400
+ source: any;
401
+ metadata: {
402
+ args: any[];
403
+ performance: {
404
+ durationMs: number;
405
+ };
406
+ source: {
407
+ level: "database" | "collection" | "document";
408
+ collection?: string;
409
+ document?: string;
410
+ };
411
+ result?: {
412
+ type: "array" | string;
413
+ size?: number;
414
+ };
415
+ error: {
416
+ message: string;
417
+ name: string;
418
+ stack?: string;
419
+ } | null;
420
+ };
421
+ };
422
+
423
+ /**
424
+ * Interface defining the shape of the EventBus.
425
+ * @template TEventMap - A record mapping event names to their respective payload types.
426
+ */
427
+ interface EventBus<TEventMap extends Record<string, any>> {
428
+ /**
429
+ * Subscribes to a specific event by name.
430
+ * @param eventName - The name of the event to subscribe to.
431
+ * @param callback - The function to call when the event is emitted.
432
+ * @returns A function to unsubscribe from the event.
433
+ */
434
+ subscribe: <TEventName extends keyof TEventMap>(eventName: TEventName, callback: (payload: TEventMap[TEventName]) => void) => () => void;
435
+ /**
436
+ * Subscribes to an event and automatically unsubscribes after it fires once.
437
+ * @param eventName - The name of the event to subscribe to.
438
+ * @param callback - The function to call when the event is emitted.
439
+ * @returns A function to cancel the one-shot subscription before it fires.
440
+ */
441
+ once: <TEventName extends keyof TEventMap>(eventName: TEventName, callback: (payload: TEventMap[TEventName]) => void) => () => void;
442
+ /**
443
+ * Emits an event with a payload to all subscribed listeners.
444
+ * @param event - An object containing the event name and payload.
445
+ */
446
+ emit: <TEventName extends keyof TEventMap>(event: {
447
+ name: TEventName;
448
+ payload: TEventMap[TEventName];
449
+ }) => void;
450
+ /**
451
+ * Retrieves metrics about event bus usage.
452
+ * @returns An object containing various metrics.
453
+ */
454
+ metrics: () => EventMetrics;
455
+ /**
456
+ * Clears all subscriptions and resets metrics.
457
+ * After calling clear(), the bus is fully reset and can be reused —
458
+ * cross-tab communication is re-established if it was previously enabled.
459
+ */
460
+ clear: () => void;
461
+ }
462
+ /**
463
+ * Interface defining the metrics tracked by the EventBus.
464
+ */
465
+ interface EventMetrics {
466
+ /** Total number of events emitted (both sync and deferred paths). */
467
+ totalEvents: number;
468
+ /** Number of active subscriptions across all event names. */
469
+ activeSubscriptions: number;
470
+ /** Map of event names to their emission counts. */
471
+ eventCounts: Map<string, number>;
472
+ /** Average duration of event dispatch in milliseconds. */
473
+ averageEmitDuration: number;
474
+ }
475
+
476
+ /**
477
+ * Utility type for representing partial updates to the state, allowing deep nesting.
478
+ * It makes all properties optional and applies the same transformation recursively
479
+ * to nested objects and array elements, allowing for selective updates while
480
+ * preserving the original structure. It also includes the original type T and
481
+ * undefined as possibilities for the top level and nested values.
482
+ */
483
+ type DeepPartial<T> = T extends object ? T extends readonly (infer U)[] ? readonly (DeepPartial<U> | undefined)[] | undefined | T : T extends (infer U)[] ? (DeepPartial<U> | undefined)[] | undefined | T : {
484
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined;
485
+ } | undefined | T : T | undefined;
486
+
487
+ /**
488
+ * This file contains the primary domain models, data structures, and command types
489
+ * for the AI Workspace. It acts as the "Source of Truth" for all modules.
490
+ */
491
+
492
+ /** RFC 4122 compliant Universally Unique Identifier. */
493
+ type UUID = string;
494
+ /** ISO-8601 formatted UTC timestamp string. */
495
+ type Timestamp = string;
496
+ /** Uniform Resource Identifier string. */
497
+ type URI = string;
498
+ /** Hexadecimal representation of a SHA-256 hash. */
499
+ type SHA256 = string;
500
+ /** Special marker used to denote a role with no specific instructions or identity. */
501
+ declare const EMPTY_SYSTEM_ROLE = "__system__";
502
+ /**
503
+ * A functional wrapper for operations that can fail.
504
+ * Encourages explicit error handling over try/catch blocks.
505
+ * @template T - The type of the value returned on success.
506
+ * @template E - The type of the error returned on failure.
507
+ */
508
+ type Result<T, E = WorkspaceError> = {
509
+ /** Indicates the operation was successful. */
510
+ ok: true;
511
+ /** The resulting value of the successful operation. */
512
+ value: T;
513
+ } | {
514
+ /** Indicates the operation failed. */
515
+ ok: false;
516
+ /** The error details explaining the failure. */
517
+ error: E;
518
+ };
519
+ /** Occurs when attempting to create a resource with a key that already exists. */
520
+ type DuplicateKeyError = {
521
+ /** Error discriminator code. */
522
+ code: "DUPLICATE_KEY";
523
+ /** The type of resource that caused the collision (e.g., 'role', 'session'). */
524
+ resource: string;
525
+ /** The specific key that duplicated an existing entry. */
526
+ key: string;
527
+ };
528
+ /** Occurs when a requested resource cannot be found by its unique identifier. */
529
+ type NotFoundError = {
530
+ /** Error discriminator code. */
531
+ code: "NOT_FOUND";
532
+ /** The type of resource that was requested. */
533
+ resource: string;
534
+ /** The ID that yielded no results. */
535
+ id: string;
536
+ };
537
+ /** Triggered when a command payload fails validation or is logically inconsistent. */
538
+ type InvalidCommandError = {
539
+ /** Error discriminator code. */
540
+ code: "INVALID_COMMAND";
541
+ /** Detailed explanation of why the command was rejected. */
542
+ reason: string;
543
+ };
544
+ /** Generic wrapper for unexpected infrastructure or downstream service failures. */
545
+ type BackendError = {
546
+ /** Error discriminator code. */
547
+ code: "BACKEND_ERROR";
548
+ /** Description of the underlying system failure. */
549
+ reason: string;
550
+ };
551
+ /** Specific errors related to blob storage, retrieval, or corruption. */
552
+ type BlobError = {
553
+ /** Error discriminator code. */
554
+ code: "BLOB_ERROR";
555
+ /** Description of the blob operation failure. */
556
+ reason: string;
557
+ };
558
+ /** Triggered when the current actor lacks sufficient privileges for a command. */
559
+ type PermissionDeniedError = {
560
+ /** Error discriminator code. */
561
+ code: "PERMISSION_DENIED";
562
+ /** The command that was attempted and subsequently blocked. */
563
+ command: BaseCommand;
564
+ /** Explanation of the missing permissions or blocked action. */
565
+ reason: string;
566
+ };
567
+ /** Union of all possible error types within the Workspace domain. */
568
+ type WorkspaceError = DuplicateKeyError | NotFoundError | InvalidCommandError | BackendError | PermissionDeniedError | BlobError;
569
+ /** Global user preferences and defaults for the workspace. */
570
+ interface Settings {
571
+ /** Default language code used for generic formatting (e.g., 'en-US'). */
572
+ language: string;
573
+ /** The ID or name of the role used when a new session is instantiated without one. */
574
+ defaultRole?: string;
575
+ /** Global system instructions appended to the LLM context across all sessions. */
576
+ prompt?: string;
577
+ }
578
+ /**
579
+ * Represents the project-level metadata container.
580
+ * Allows for extensible metadata fields via the generic Metadata type.
581
+ * @template Metadata - Custom schema for additional project fields.
582
+ */
583
+ type Project<Metadata extends Record<string, any> = Record<string, any>> = Metadata & {
584
+ /** Unique identifier for the project. */
585
+ id: UUID;
586
+ /** Human-readable display name for the project. */
587
+ name: string;
588
+ };
589
+ /** Supported mime-types for image assets. */
590
+ type ImageMediaType = "image/jpeg" | "image/png" | "image/gif" | "image/webp";
591
+ /** Supported mime-types for text-based or structured documents. */
592
+ type DocumentMediaType = "application/pdf" | "application/json" | "text/plain" | "text/html" | "text/markdown" | "text/csv" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
593
+ /** Union of all media types handled by the blob system. */
594
+ type BlobMediaType = ImageMediaType | DocumentMediaType;
595
+ /**
596
+ * A lightweight reference to a blob.
597
+ * Used in content blocks to avoid passing heavy metadata or binary data across boundaries.
598
+ */
599
+ type BlobRef = Pick<BlobRecord, "sha256" | "mediaType" | "sizeBytes" | "filename" | "previewUrl">;
600
+ /**
601
+ * Represents a blob that has been fetched into memory.
602
+ * Can be 'inline' (binary data present) or 'remote' (stored in an external provider).
603
+ */
604
+ type ResolvedBlob = {
605
+ /** Indicates the blob data is available in the local memory space. */
606
+ kind: "inline";
607
+ /** The unique content hash of the blob. */
608
+ sha256: SHA256;
609
+ /** The registered mime-type of the data. */
610
+ mediaType: BlobMediaType;
611
+ /** The raw binary representation of the file. */
612
+ data: Uint8Array;
613
+ } | {
614
+ /** Indicates the blob exists on an external provider and must be referenced by ID. */
615
+ kind: "remote";
616
+ /** The unique content hash of the blob. */
617
+ sha256: SHA256;
618
+ /** The registered mime-type of the data. */
619
+ mediaType: BlobMediaType;
620
+ /** The external provider's unique identifier for this file. */
621
+ fileId: string;
622
+ /** The identifier of the external provider (e.g., 'openai', 'gemini'). */
623
+ providerId: string;
624
+ /** The UTC timestamp when the file was registered with the remote provider. */
625
+ timestamp: Timestamp;
626
+ };
627
+ /**
628
+ * The authoritative registry entry for a file in the system.
629
+ * Includes reference counting for garbage collection and remote mappings.
630
+ */
631
+ interface BlobRecord {
632
+ /** The unique SHA-256 hash representing the blob's binary content. */
633
+ sha256: SHA256;
634
+ /** The recognized MIME type of the blob data. */
635
+ mediaType: BlobMediaType;
636
+ /** The total size of the blob payload in bytes. */
637
+ sizeBytes: number;
638
+ /** The original or user-assigned filename, if available. */
639
+ filename?: string;
640
+ /** A secure, temporary URL for previewing the blob in a UI context, if applicable. */
641
+ previewUrl?: string;
642
+ /** Number of content blocks currently referencing this blob. Prevents premature garbage collection. */
643
+ refCount: number;
644
+ /** Map of external provider IDs to their specific remote file identifiers and upload timestamps. */
645
+ remoteIds: Record<string, {
646
+ /** The external provider's specific file ID. */
647
+ id: string;
648
+ /** The timestamp the mapping was created. */
649
+ timestamp: Timestamp;
650
+ }>;
651
+ /** The UTC timestamp when this blob was first registered in the workspace. */
652
+ createdAt: Timestamp;
653
+ /** The UTC timestamp of the most recent interaction or reference to this blob. */
654
+ lastUsedAt: Timestamp;
655
+ }
656
+ /**
657
+ * Base interface for all content blocks inside a turn.
658
+ * @template BlockType - String literal restricting the block type.
659
+ */
660
+ interface BaseContentBlock<BlockType extends string> {
661
+ /** Unique identifier for the specific content block instance. */
662
+ id: UUID;
663
+ /** Discriminator used to determine the shape and rendering of the block. */
664
+ type: BlockType;
665
+ /** Extensible key-value store for block-specific properties. */
666
+ [key: string]: any;
667
+ }
668
+ /** Standard text content within a turn. */
669
+ interface TextBlock extends BaseContentBlock<"text"> {
670
+ /** The raw markdown or plain text content. */
671
+ text: string;
672
+ }
673
+ /** An image asset within a turn, optionally containing the resolved binary data. */
674
+ interface ImageBlock extends BaseContentBlock<"image"> {
675
+ /** Lightweight pointer to the blob record. */
676
+ ref?: BlobRef;
677
+ /** Fully resolved blob containing actual data or remote pointers. */
678
+ blob?: ResolvedBlob;
679
+ /** Accessible description of the image content. */
680
+ altText?: string;
681
+ }
682
+ /** A document asset within a turn. */
683
+ interface DocumentBlock extends BaseContentBlock<"document"> {
684
+ /** Lightweight pointer to the blob record. */
685
+ ref?: BlobRef;
686
+ /** Fully resolved blob containing actual document data or remote pointers. */
687
+ blob?: ResolvedBlob;
688
+ /** Human-readable title or filename of the document. */
689
+ title?: string;
690
+ }
691
+ /** Captured request from the AI to execute a specific tool. */
692
+ interface ToolUseBlock extends BaseContentBlock<"tool:use"> {
693
+ /** The exact registered name of the tool to be executed. */
694
+ name: string;
695
+ /** The parameter arguments provided by the model for the tool execution. */
696
+ input: Record<string, unknown>;
697
+ }
698
+ /** The resulting output (or error) from a tool execution. */
699
+ interface ToolResultBlock extends BaseContentBlock<"tool:result"> {
700
+ /** The UUID of the original ToolUseBlock that triggered this execution. */
701
+ useId: UUID;
702
+ /** The serialized output of the tool, or a structured JSON response. */
703
+ content: string | Record<string, unknown>;
704
+ /** Flag indicating whether the tool execution resulted in an error state. */
705
+ isError?: boolean;
706
+ }
707
+ /** Internal "Chain of Thought" or reasoning generated by the model. */
708
+ interface ThinkingBlock extends BaseContentBlock<"thinking"> {
709
+ /** The internal reasoning text produced by the model before the final response. */
710
+ thinking: string;
711
+ }
712
+ /** A condensed summary of previous conversation history. */
713
+ interface SummaryBlock extends BaseContentBlock<"summary"> {
714
+ /** The distilled summary text replacing older conversation turns. */
715
+ text: string;
716
+ }
717
+ /** Notates that the session has switched from one Role persona to another. */
718
+ interface RoleTransitionBlock extends BaseContentBlock<"role:transition"> {
719
+ /** The name of the role the session is leaving (undefined if it was a system default). */
720
+ previousRole?: string;
721
+ /** The name of the new role the session is adopting. */
722
+ newRole: string;
723
+ }
724
+ /** Union of all possible content types that can exist within a conversation Turn. */
725
+ type ContentBlock = TextBlock | ImageBlock | DocumentBlock | ToolUseBlock | ToolResultBlock | ThinkingBlock | SummaryBlock | RoleTransitionBlock;
726
+ /** Definition of a tool available to the AI. */
727
+ interface ToolSummary {
728
+ /** The unique, system-level name of the tool (e.g., 'web_search'). */
729
+ name: string;
730
+ /** Human-readable explanation of what the tool does, exposed to the AI model. */
731
+ description: string;
732
+ /** JSON Schema defining the required input arguments and their types. */
221
733
  parameters: {
222
- type: 'object';
734
+ /** Root type of the parameter schema, usually 'object'. */
735
+ type: "object";
736
+ /** Map of property names to their respective sub-schemas. */
223
737
  properties: Record<string, any>;
738
+ /** Array of property names that must be provided to execute the tool. */
224
739
  required: string[];
225
740
  };
226
- /** Semantic tags used to help the model find relevant tools. */
741
+ /** Semantic tags used to help the model dynamically find relevant tools via RAG. */
227
742
  topics: string[];
228
743
  }
229
744
  /** An instance of a tool being called with specific arguments. */
230
745
  interface ToolCall {
746
+ /** The unique execution identifier for this specific call instance. */
231
747
  id: UUID;
748
+ /** The UUID or string identifier of the tool being requested. */
232
749
  tool: UUID;
750
+ /** The fully parsed arguments mapped to the tool's required parameters. */
233
751
  arguments: Record<string, any>;
234
752
  }
235
753
  /** A request for authorization before executing a command or tool. */
236
754
  type AuthRequest = {
237
- type: 'command';
238
- payload: Command;
755
+ /** Discriminator indicating a state mutation authorization request. */
756
+ type: "command";
757
+ /** The specific command attempting to execute. */
758
+ payload: BaseCommand;
239
759
  } | {
240
- type: 'tool';
760
+ /** Discriminator indicating an external tool execution authorization request. */
761
+ type: "tool";
762
+ /** The specific tool call payload attempting to execute. */
241
763
  payload: ToolCall;
242
764
  };
243
765
  /** Identifies whether a turn originated from the user, the AI, a tool, or the system. */
244
- type TurnActor = 'user' | 'assistant' | 'tool' | 'system';
245
- /** * The flat storage format for a conversation turn.
766
+ type SystemActor = "user" | "assistant" | "tool" | "system";
767
+ /**
768
+ * The flat storage format for a conversation turn.
246
769
  * Supports versioning and parent-pointers for branching conversation trees (DAG).
247
770
  */
248
771
  interface Turn {
772
+ /** The unique identifier for this specific turn instance. */
249
773
  id: UUID;
250
- /** Incrementing number for edits to the same turn ID. */
774
+ /** The UUID of the chat session this turn belongs to, used for fast filtering. */
775
+ session: UUID;
776
+ /** Incrementing number representing edits to the same turn ID. */
251
777
  version: number;
252
- actor: TurnActor;
253
- blocks: ContentBlock[];
778
+ /** The entity (user, model, system) that produced this turn's content. */
779
+ actor: SystemActor;
780
+ /** An ordered array of content blocks comprising the payload of this turn. */
781
+ blocks: BaseContentBlock<string>[];
782
+ /** The UTC timestamp when this turn was originally created or received. */
254
783
  timestamp: Timestamp;
255
- /** Name of the role active at the time of this turn. */
784
+ /** Name of the role (persona) active at the exact time this turn occurred. */
256
785
  role?: string;
257
- /** Link to the preceding turn in the conversation tree. */
258
- parent: {
786
+ /** Link to the preceding turn in the conversation tree, defining the DAG graph. */
787
+ parent?: {
788
+ /** The ID of the parent turn. */
259
789
  id: UUID;
790
+ /** The specific version of the parent turn. */
260
791
  version: number;
261
- } | null;
262
- /** Used for fast filtering within a specific chat session. */
263
- sessionId?: UUID;
792
+ };
793
+ /** Local model constraints applied explicitly at the time of this turn. */
794
+ constraints?: ModelConstraintMap;
264
795
  }
796
+ /** Unique composite key used to lookup a specific turn version. */
797
+ type TurnKey = Pick<Turn, "version" | "id" | "session">;
265
798
  /**
266
799
  * An in-memory representation of a turn, including all its versions and children.
267
- * This is used for rendering threaded/branching conversations.
800
+ * This is used for rendering threaded/branching conversations in UI.
268
801
  */
269
802
  interface TurnNode {
803
+ /** The unique root identifier for this turn across all its versions. */
270
804
  id: UUID;
271
- /** Map of version numbers to the Turn data. */
805
+ /** Map of version numbers to the specific Turn data payloads. */
272
806
  versions: Record<number, Turn>;
807
+ /** The version integer currently displayed or active in the primary chat view. */
273
808
  activeVersion: number;
274
- role: TurnActor;
275
- blocks: ContentBlock[];
809
+ /** The entity that produced this turn's root concept. */
810
+ actor: SystemActor;
811
+ /** The content blocks of the *active* version for quick rendering. */
812
+ blocks: BaseContentBlock<string>[];
813
+ /** The UTC timestamp of the original turn creation. */
276
814
  timestamp: Timestamp;
815
+ /** The role name active when this node was created. */
277
816
  roleSnapshot?: string;
278
- parent: {
817
+ /** Reference to the preceding turn in the conversation DAG. */
818
+ parent?: {
819
+ /** Parent turn ID. */
279
820
  id: UUID;
821
+ /** Parent turn version. */
280
822
  version: number;
281
- } | null;
282
- /** Map of version numbers to an array of child turn IDs. */
823
+ };
824
+ /** Map of version numbers to arrays of child turn IDs spawned from that specific version. */
283
825
  children: Record<number, UUID[]>;
284
826
  }
285
827
  /** UI helper for navigating between different versions of a turn (e.g. "2 of 5"). */
286
828
  interface BranchInfo {
829
+ /** Array of all available version numbers for a turn. */
287
830
  versions: number[];
831
+ /** The array index currently being viewed. */
288
832
  currentIndex: number;
833
+ /** The total count of available versions. */
289
834
  total: number;
835
+ /** Indicates if an older version exists to navigate back to. */
290
836
  hasPrev: boolean;
837
+ /** Indicates if a newer version exists to navigate forward to. */
291
838
  hasNext: boolean;
292
839
  }
840
+ /** Unique string identifier for a model (e.g., 'gemini-2.0-flash'). */
841
+ type ModelName = string;
842
+ /** Execution constraints applied to a specific model. */
843
+ interface ModelConstraint {
844
+ /** Sampling temperature. 0.0 = deterministic, higher = more creative. */
845
+ temperature?: number;
846
+ /** Limits and stop boundaries for token generation. */
847
+ tokens: {
848
+ /** Maximum output tokens for this request. Overrides adapter defaults. */
849
+ max?: number;
850
+ /** Stop sequences — generation halts immediately when any of these are produced. */
851
+ stops?: string[];
852
+ /** Thinking/reasoning budget in tokens. (For supported models only). */
853
+ thought?: number;
854
+ };
855
+ }
856
+ /** Map of model names to their explicit, active constraints. */
857
+ type ModelConstraintMap = Record<ModelName, ModelConstraint>;
293
858
  /** A system persona containing specific instructions and associated preferences. */
294
859
  interface Role {
295
- /** Unique identifier name (e.g. "software-architect"). */
860
+ /** Unique identifier name used system-wide (e.g. "software-architect"). */
296
861
  name: string;
297
- /** Human-readable display label. */
862
+ /** Human-readable display label shown in the UI. */
298
863
  label: string;
864
+ /** Optional human-readable description of what this persona is intended for. */
299
865
  description?: string;
300
- /** The core instructions (system prompt) for this persona. */
866
+ /** The core instructions (system prompt base) establishing this persona's behavior. */
301
867
  persona: string;
302
- /** Array of Preference IDs associated with this role. */
868
+ /** Array of Preference UUIDs explicitly bound to this role. */
303
869
  preferences: UUID[];
870
+ /** Array of semantic Topics associated with this role to guide RAG retrieval. */
871
+ topics: string[];
872
+ /** Model constraints natively attached at the role level. */
873
+ constraints?: ModelConstraintMap;
304
874
  }
305
875
  /** A specific user preference or "memory" that informs model behavior. */
306
876
  interface Preference {
877
+ /** Unique identifier for the preference entry. */
307
878
  id: UUID;
879
+ /** The actual text content representing the instruction or fact to remember. */
308
880
  content: string;
309
- /** Topics used for retrieval-augmented generation (RAG). */
881
+ /** Topics used for semantic alignment and retrieval-augmented generation (RAG). */
310
882
  topics: string[];
883
+ /** UTC timestamp of when this preference was established or last updated. */
311
884
  timestamp: Timestamp;
312
885
  }
313
886
  /** Discriminated union of types that can be injected into the AI context. */
314
887
  type ContextContent = {
315
- kind: 'text';
888
+ /** Denotes raw, unstructured text. */
889
+ kind: "text";
890
+ /** The text payload to inject. */
316
891
  value: string;
317
892
  } | {
318
- kind: 'json';
893
+ /** Denotes structured JSON data. */
894
+ kind: "json";
895
+ /** The JSON payload. */
319
896
  value: unknown;
320
897
  } | {
321
- kind: 'blob';
898
+ /** Denotes a reference to a registered blob in the workspace store. */
899
+ kind: "blob";
900
+ /** The hash linking to the full blob record. */
322
901
  sha256: SHA256;
902
+ /** The mime-type of the blob. */
323
903
  mediaType: BlobMediaType;
904
+ /** File size in bytes. */
324
905
  sizeBytes: number;
906
+ /** Human-readable filename. */
325
907
  filename?: string;
326
908
  } | {
327
- kind: 'remote';
909
+ /** Denotes data living at an external HTTP URI. */
910
+ kind: "remote";
911
+ /** The fully qualified URI to the external resource. */
328
912
  uri: URI;
913
+ /** Optional hint for the expected mime-type at the remote destination. */
329
914
  mediaType?: BlobMediaType;
330
915
  };
331
916
  /** A contextual item (file, snippet, or data) attached to a session or prompt. */
332
917
  interface Context {
333
- /** Unique lookup key. */
918
+ /** Unique lookup key for this context entry. */
334
919
  key: string;
920
+ /** Topics linking this context to relevant sessions or roles. */
335
921
  topics: string[];
922
+ /** The actual payload of the context block. */
336
923
  content: ContextContent;
924
+ /** UTC timestamp of when the context was added. */
337
925
  timestamp: Timestamp;
926
+ /** Extensible key-value store for application-specific contextual metadata. */
338
927
  metadata?: Record<string, any>;
339
928
  }
340
929
  /** Metadata for a conversation session, stored in the persistent collection. */
341
- interface SessionMeta {
930
+ interface SessionMetadata {
931
+ /** Unique identifier for the chat session. */
342
932
  id: UUID;
933
+ /** Human-readable title or label for the session. */
343
934
  label: string;
344
- /** The active Role name for this session. */
935
+ /** The active Role (persona) name guiding this specific session. */
345
936
  role: string;
937
+ /** Semantic topics governing what context and tools are active for this session. */
346
938
  topics: string[];
939
+ /** Array of UUIDs pointing to explicitly active preferences for this session. */
347
940
  preferences: UUID[];
941
+ /** Timestamps detailing the session lifecycle. */
348
942
  metadata: {
943
+ /** UTC timestamp of session creation. */
349
944
  created?: Timestamp;
945
+ /** UTC timestamp of the last activity within the session. */
350
946
  updated?: Timestamp;
947
+ /** The current model being use by the session */
948
+ model?: string;
949
+ [key: string]: any;
351
950
  };
352
- /** Tracks how many turns have been persisted to the database. */
353
- flushedTurnCount: number;
354
- /** The current leaf-node of the conversation. */
355
- head: {
951
+ /** The current chronological leaf-node of the conversation DAG. */
952
+ head?: {
953
+ /** The ID of the most recent turn. */
356
954
  id: UUID;
955
+ /** The active version of the most recent turn. */
357
956
  version: number;
358
- } | null;
359
- /** Optional link to a specific Task being worked on. */
360
- task: UUID | null;
361
- }
362
- type TaskStatus = 'todo' | 'active' | 'done' | 'blocked' | 'defered';
363
- /** A single item within a Task's checklist. */
364
- interface TaskStep {
365
- ref: string;
366
- text: string;
367
- completed?: Timestamp;
368
- }
369
- /** A high-level objective with nested steps, used for tracking AI progress. */
370
- interface Task {
371
- id: UUID;
372
- ref?: string;
373
- title: string;
374
- description?: string;
375
- status: TaskStatus;
376
- steps: TaskStep[];
377
- topics: string[];
378
- metadata?: Record<string, any>;
379
- created: Timestamp;
380
- updated: Timestamp;
957
+ };
958
+ /** Overriding execution constraints active at the session level. */
959
+ constraints?: ModelConstraintMap;
381
960
  }
961
+ /** In-memory summary of a Role. */
382
962
  interface RoleSummary {
963
+ /** The unique identifier string for the role. */
383
964
  name: string;
965
+ /** The UI-friendly label for the role. */
384
966
  label: string;
967
+ /** A brief summary of the role's purpose. */
385
968
  description?: string;
969
+ /** Integer count of how many preference records are tied to this role. */
386
970
  preferences: number;
971
+ /** Topics relevant to this role. */
972
+ topics?: string[];
973
+ /** The top-level constraints baked into the role. */
974
+ constraints?: ModelConstraintMap;
387
975
  }
976
+ /** In-memory summary of a Preference. */
388
977
  interface PreferenceSummary {
978
+ /** Unique identifier for the preference. */
389
979
  id: UUID;
980
+ /** The topics linking this preference to the rest of the workspace. */
390
981
  topics: string[];
982
+ /** UTC timestamp of the last update. */
391
983
  timestamp: Timestamp;
984
+ /** A truncated preview string of the preference content. */
392
985
  snippet?: string;
393
986
  }
987
+ /** In-memory summary of a Context entry. */
394
988
  interface ContextSummary {
989
+ /** The unique key for the context item. */
395
990
  key: string;
991
+ /** Associated semantic topics. */
396
992
  topics: string[];
993
+ /** UTC timestamp of addition. */
397
994
  timestamp: Timestamp;
995
+ /** MIME type, if applicable to the content kind. */
398
996
  mime?: string;
997
+ /** File size in bytes, if applicable. */
399
998
  size?: number;
999
+ /** Truncated text preview or URL for visual representation. */
400
1000
  preview?: string;
1001
+ /** Origin or source string indicating where the context came from. */
401
1002
  source?: string;
1003
+ /** Flattened representation of the context's internal metadata. */
402
1004
  metadata?: Record<string, any>;
403
1005
  }
404
- interface TaskSummary {
405
- id: UUID;
406
- ref?: string;
407
- description: string;
408
- title: string;
409
- status: TaskStatus;
410
- steps: {
411
- completed: number;
412
- total: number;
413
- };
414
- topics: string[];
415
- }
416
1006
  /** Maps topics to the various entities that reference them. */
417
1007
  interface TopicIndex {
1008
+ /** The exact string name of the topic. */
418
1009
  topic: string;
1010
+ /** Array of context keys that fall under this topic. */
419
1011
  contextKeys: string[];
1012
+ /** Array of preference UUIDs that fall under this topic. */
420
1013
  preferences: UUID[];
421
- tasks: UUID[];
1014
+ /** Aggregated metadata regarding topic usage. */
422
1015
  metadata?: {
1016
+ /** When the topic was first registered. */
423
1017
  created?: Timestamp;
1018
+ /** When the topic was last updated or applied. */
424
1019
  updated?: Timestamp;
1020
+ /** Total number of workspace items referencing this topic. */
425
1021
  entries?: number;
426
1022
  };
427
1023
  }
428
- /** The complete in-memory read-model of the Workspace state. */
429
- interface Index {
1024
+ type IndexExtensions = Record<string, Record<string, any>>;
1025
+ interface Index<T extends IndexExtensions = IndexExtensions> {
1026
+ /** The complete in-memory read-model of the Workspace state. */
1027
+ /** Lookup dictionary of Roles by their string name. */
430
1028
  roles: Record<string, RoleSummary>;
1029
+ /** Lookup dictionary of Preferences by their UUID. */
431
1030
  preferences: Record<UUID, PreferenceSummary>;
1031
+ /** Lookup dictionary of Context entries by their specific key. */
432
1032
  context: Record<string, ContextSummary>;
433
- sessions: Record<UUID, SessionMeta>;
434
- tasks: Record<UUID, TaskSummary>;
1033
+ /** Lookup dictionary of active Sessions by their UUID. */
1034
+ sessions: Record<UUID, SessionMetadata>;
1035
+ /** Lookup dictionary of semantic Topics by their string name. */
435
1036
  topics: Record<string, TopicIndex>;
1037
+ /** Lookup dictionary of authoritative Blob records by their SHA-256 hash. */
436
1038
  blobs: Record<SHA256, BlobRecord>;
1039
+ /** Lookup dictionary of registered Tool capabilities by their string name. */
437
1040
  tools: Record<string, ToolSummary>;
1041
+ extensions: T;
438
1042
  }
439
1043
  /** The root container for a user's workspace. */
440
- interface Workspace<ProjectMetadata extends Record<string, any> = Record<string, any>> {
1044
+ interface Workspace<ProjectMetadata extends Record<string, any> = Record<string, any>, Extentions extends Record<string, Record<string, any>> = IndexExtensions> {
1045
+ /** Unique identifier for the entire workspace environment. */
441
1046
  id: UUID;
1047
+ /** Global user and systemic settings. */
442
1048
  settings: Settings;
1049
+ /** High-level project metadata. */
443
1050
  project: Project<ProjectMetadata>;
444
- index: Index;
1051
+ /** The in-memory read-projection of all underlying stores. */
1052
+ index: Index<Extentions>;
445
1053
  }
446
- /** * Format used for exporting/importing a complete workspace state,
1054
+ /**
1055
+ * Format used for exporting/importing a complete workspace state,
447
1056
  * including all historical turns and binary records.
448
1057
  */
449
1058
  interface WorkspaceBundle {
450
- format: 'aiworkspace/4.0';
1059
+ /** Schema version identifier for serialization compatibility. */
1060
+ format: "aiworkspace/4.0";
1061
+ /** The core workspace root data. */
451
1062
  workspace: Workspace;
1063
+ /** All exported role definitions. */
452
1064
  roles: Record<string, Role>;
1065
+ /** All exported preference objects. */
453
1066
  preferences: Record<UUID, Preference>;
1067
+ /** All exported context entries. */
454
1068
  context: Record<string, Context>;
455
- sessions: Record<UUID, SessionMeta & {
1069
+ /** All exported sessions, deeply hydrated with their complete turn history. */
1070
+ sessions: Record<UUID, SessionMetadata & {
456
1071
  turns: Turn[];
457
1072
  }>;
458
- tasks: Record<UUID, Task>;
1073
+ /** All exported blob definitions (may contain base64 binary strings or remote mappings). */
459
1074
  blobs: Record<SHA256, BlobRecord>;
460
1075
  }
461
- /** A fully hydrated view of a session, including resolved objects for the prompt builder. */
462
- interface EffectiveSession {
463
- session: SessionMeta;
464
- role: Role;
465
- preferences: Preference[];
466
- context: Context[];
467
- transcript: Turn[];
468
- task: Task | null;
469
- instructions?: string;
470
- }
471
- interface BaseCommand {
472
- /** Discriminator for the command type. */
1076
+ /** Base structure for all state-mutating commands in the system. */
1077
+ interface BaseCommand<T = any> {
1078
+ /** Discriminator for the specific command type. */
473
1079
  type: string;
1080
+ /** UTC timestamp of when the command was issued. */
474
1081
  timestamp: Timestamp;
475
- /** The ID of the user or system component that initiated the command. */
476
- actor?: string;
1082
+ /** The ID of the user, system component, or tool that initiated the command. */
1083
+ actor?: SystemActor;
1084
+ /** An optional, human-readable reason or annotation for the execution. */
477
1085
  description?: string;
1086
+ /** Indicates this command was automatically fired as a side-effect of another command. */
478
1087
  synthetic?: boolean;
1088
+ /** Payload */
1089
+ payload: T;
479
1090
  }
480
1091
  interface CreateWorkspace extends BaseCommand {
481
- type: 'workspace:create';
1092
+ type: "workspace:create";
1093
+ /** Payload detailing initial setup values for the environment. */
482
1094
  payload: {
483
1095
  id: UUID;
484
1096
  settings: Settings;
@@ -486,85 +1098,81 @@ interface CreateWorkspace extends BaseCommand {
486
1098
  };
487
1099
  }
488
1100
  interface AddRole extends BaseCommand {
489
- type: 'role:add';
1101
+ type: "role:add";
1102
+ /** The complete role object to inject into the workspace. */
490
1103
  payload: Role;
491
1104
  }
492
1105
  interface UpdateRole extends BaseCommand {
493
- type: 'role:update';
1106
+ type: "role:update";
1107
+ /** Delta properties to merge into the existing role definition. */
494
1108
  payload: Partial<Role> & {
495
1109
  name: string;
496
1110
  };
497
1111
  }
498
1112
  interface DeleteRole extends BaseCommand {
499
- type: 'role:delete';
1113
+ type: "role:delete";
1114
+ /** Name of the role to destroy. */
500
1115
  payload: {
501
1116
  name: string;
502
1117
  };
503
1118
  }
504
1119
  interface AddPreference extends BaseCommand {
505
- type: 'preference:add';
1120
+ type: "preference:add";
1121
+ /** The complete preference object to register. */
506
1122
  payload: Preference;
507
1123
  }
508
1124
  interface UpdatePreference extends BaseCommand {
509
- type: 'preference:update';
1125
+ type: "preference:update";
1126
+ /** Delta properties to merge into the existing preference record. */
510
1127
  payload: Partial<Preference> & {
511
1128
  id: UUID;
512
1129
  };
513
1130
  }
514
1131
  interface DeletePreference extends BaseCommand {
515
- type: 'preference:delete';
1132
+ type: "preference:delete";
1133
+ /** UUID of the preference to drop. */
516
1134
  payload: {
517
1135
  id: UUID;
518
1136
  };
519
1137
  }
520
1138
  interface CreateSession extends BaseCommand {
521
- type: 'session:create';
1139
+ type: "session:create";
1140
+ /** Initial setup parameters for the new conversation session. */
522
1141
  payload: {
523
1142
  id: UUID;
524
1143
  label: string;
525
1144
  role: string;
526
1145
  topics: string[];
527
- preferences?: UUID[];
1146
+ preferences: UUID[];
1147
+ metadata: {
1148
+ created?: Timestamp;
1149
+ updated?: Timestamp;
1150
+ };
528
1151
  };
529
1152
  }
530
1153
  interface AddContext extends BaseCommand {
531
- type: 'context:add';
1154
+ type: "context:add";
1155
+ /** The new context object to write to the store. */
532
1156
  payload: Context;
533
1157
  }
534
1158
  interface UpdateContext extends BaseCommand {
535
- type: 'context:update';
1159
+ type: "context:update";
1160
+ /** Delta properties to update an existing context record. */
536
1161
  payload: Partial<Context> & {
537
1162
  key: string;
538
1163
  };
539
1164
  }
540
1165
  interface DeleteContext extends BaseCommand {
541
- type: 'context:delete';
1166
+ type: "context:delete";
1167
+ /** Key of the context entry to destroy. */
542
1168
  payload: {
543
1169
  key: string;
544
1170
  };
545
1171
  }
546
- type TaskRef = UUID | string;
547
- interface AddTask extends BaseCommand {
548
- type: 'task:add';
549
- payload: Task;
550
- }
551
- interface UpdateTask extends BaseCommand {
552
- type: 'task:update';
553
- payload: Partial<Task> & ({
554
- id: UUID;
555
- } | {
556
- ref: string;
557
- });
558
- }
559
- interface DeleteTask extends BaseCommand {
560
- type: 'task:delete';
561
- payload: {
562
- id: UUID;
563
- };
564
- }
565
1172
  /** Updates an existing turn record in storage. */
566
- interface SaveTurn extends BaseCommand {
567
- type: 'turn:save';
1173
+ interface UpdateTurn extends BaseCommand {
1174
+ type: "turn:update";
1175
+ /** The session scope and the fully updated turn structure. */
568
1176
  payload: {
569
1177
  sessionId: UUID;
570
1178
  turn: Turn;
@@ -572,7 +1180,8 @@ interface SaveTurn extends BaseCommand {
572
1180
  }
573
1181
  /** Appends a new turn to a session. */
574
1182
  interface AddTurn extends BaseCommand {
575
- type: 'turn:add';
1183
+ type: "turn:add";
1184
+ /** The session scope and the new turn to mount. */
576
1185
  payload: {
577
1186
  sessionId: UUID;
578
1187
  turn: Turn;
@@ -580,7 +1189,8 @@ interface AddTurn extends BaseCommand {
580
1189
  }
581
1190
  /** Creates a new version of an existing turn. */
582
1191
  interface EditTurn extends BaseCommand {
583
- type: 'turn:edit';
1192
+ type: "turn:edit";
1193
+ /** Details for incrementing a specific turn's iteration without losing history. */
584
1194
  payload: {
585
1195
  sessionId: UUID;
586
1196
  turnId: UUID;
@@ -591,42 +1201,51 @@ interface EditTurn extends BaseCommand {
591
1201
  }
592
1202
  /** Creates a new branch in the conversation history from a specific turn. */
593
1203
  interface BranchTurn extends BaseCommand {
594
- type: 'turn:branch';
1204
+ type: "turn:branch";
1205
+ /** The turn object that initiates the new divergent history line. */
595
1206
  payload: {
596
1207
  sessionId: UUID;
597
1208
  turn: Turn;
598
1209
  };
599
1210
  }
1211
+ /** Reference to a specific iteration of a turn. */
600
1212
  interface TurnRef {
1213
+ /** The ID of the referenced turn. */
601
1214
  id: UUID;
1215
+ /** The exact version number of the referenced turn. */
602
1216
  version: number;
603
1217
  }
604
1218
  /** Removes a specific version of a turn and updates the session head if necessary. */
605
1219
  interface DeleteTurn extends BaseCommand {
606
- type: 'turn:delete';
1220
+ type: "turn:delete";
1221
+ /** Identification payload to target the precise turn version for destruction. */
607
1222
  payload: {
608
1223
  sessionId: UUID;
609
1224
  turnId: UUID;
610
1225
  version: number;
611
- newHead: TurnRef | null;
1226
+ /** The fallback position if deleting the current head. */
1227
+ newHead?: TurnRef;
612
1228
  };
613
1229
  }
614
- interface SwitchRole extends BaseCommand {
615
- type: 'session:role:switch';
1230
+ interface SwitchSessionRole extends BaseCommand {
1231
+ type: "session:role:switch";
1232
+ /** Defines the transition of a session from one persona to another. */
616
1233
  payload: {
617
1234
  sessionId: UUID;
618
- role: string;
1235
+ roleName: string;
619
1236
  };
620
1237
  }
621
1238
  interface AddSessionTopics extends BaseCommand {
622
- type: 'session:topics:add';
1239
+ type: "session:topics:add";
1240
+ /** Appends semantic tags to an existing session for RAG alignment. */
623
1241
  payload: {
624
1242
  sessionId: UUID;
625
1243
  topics: string[];
626
1244
  };
627
1245
  }
628
1246
  interface OverrideSessionPreferences extends BaseCommand {
629
- type: 'session:preferences:override';
1247
+ type: "session:preferences:override";
1248
+ /** Replaces the explicit preference list attached to a session. */
630
1249
  payload: {
631
1250
  sessionId: UUID;
632
1251
  preferences: UUID[];
@@ -634,9 +1253,10 @@ interface OverrideSessionPreferences extends BaseCommand {
634
1253
  }
635
1254
  /** Creates a new session starting from the state of an existing one. */
636
1255
  interface ForkSession extends BaseCommand {
637
- type: 'session:fork';
1256
+ type: "session:fork";
1257
+ /** Data defining the divergence point and initial overrides for the new fork. */
638
1258
  payload: {
639
- sourceSessionId: UUID;
1259
+ sessionId: UUID;
640
1260
  newSessionId: UUID;
641
1261
  label: string;
642
1262
  role?: string;
@@ -644,1417 +1264,1070 @@ interface ForkSession extends BaseCommand {
644
1264
  };
645
1265
  }
646
1266
  interface UpdateSession extends BaseCommand {
647
- type: 'session:update';
1267
+ type: "session:update";
1268
+ /** Modifiable metadata fields for an ongoing session. */
648
1269
  payload: {
649
1270
  sessionId: UUID;
650
1271
  label?: string;
651
1272
  role?: string;
652
1273
  topics?: string[];
653
1274
  preferences?: UUID[];
654
- task?: UUID | null;
1275
+ metadata?: SessionMetadata["metadata"];
655
1276
  };
656
1277
  }
657
1278
  interface DeleteSession extends BaseCommand {
658
- type: 'session:delete';
659
- payload: {
660
- sessionId: UUID;
661
- };
662
- }
663
- interface RegisterBlob extends BaseCommand {
664
- type: 'blob:register';
665
- payload: {
666
- data: Uint8Array;
667
- mediaType: BlobMediaType;
668
- filename?: string;
669
- };
670
- }
671
- /** Increases reference count to prevent garbage collection. */
672
- interface RetainBlob extends BaseCommand {
673
- type: 'blob:retain';
674
- payload: {
675
- sha256: SHA256;
676
- };
677
- }
678
- /** Decreases reference count. */
679
- interface ReleaseBlob extends BaseCommand {
680
- type: 'blob:release';
681
- payload: {
682
- sha256: SHA256;
683
- };
684
- }
685
- /** Immediately removes a blob regardless of reference count. */
686
- interface PurgeBlob extends BaseCommand {
687
- type: 'blob:purge';
688
- payload: {
689
- sha256: SHA256;
690
- };
691
- }
692
- /** Maps a local blob to an external provider's file ID. */
693
- interface RecordBlobRemoteId extends BaseCommand {
694
- type: 'blob:record_remote_id';
1279
+ type: "session:delete";
1280
+ /** Identifier of the session to terminate and purge. */
695
1281
  payload: {
696
- sha256: SHA256;
697
- providerId: string;
698
- fileId: string;
699
- timestamp?: Timestamp;
700
- };
701
- }
702
- type BlobCommand = RegisterBlob | RetainBlob | ReleaseBlob | PurgeBlob | RecordBlobRemoteId;
703
- interface CallTool extends BaseCommand {
704
- type: 'tool:call';
705
- payload: ToolCall;
706
- }
707
- /** Union of all possible commands that can be dispatched to the Workspace Manager. */
708
- type Command = CreateWorkspace | AddRole | UpdateRole | DeleteRole | AddPreference | UpdatePreference | DeletePreference | CreateSession | UpdateSession | AddContext | UpdateContext | DeleteContext | AddTask | UpdateTask | DeleteTask | AddTurn | SaveTurn | EditTurn | BranchTurn | DeleteTurn | SwitchRole | AddSessionTopics | OverrideSessionPreferences | ForkSession | DeleteSession | BlobCommand | CallTool;
709
- /** Configuration for token counting and management during prompt generation. */
710
- interface TokenBudget {
711
- total: number;
712
- estimator?: (text: string) => number;
713
- blobTokensPerKB?: number;
714
- }
715
- /** Details regarding why a specific preference was excluded from a prompt. */
716
- interface PreferenceConflict {
717
- topic: string;
718
- kept: UUID;
719
- dropped: UUID;
720
- reason: 'superseded_by_newer';
721
- }
722
- /**
723
- * The final structure sent to an LLM provider.
724
- * Assembled by the PromptAssembler by resolving roles, context, and history.
725
- */
726
- interface Prompt {
727
- /** Information destined for the System Message. */
728
- system: {
729
- instructions?: string;
730
- persona: string;
731
- preferences: Preference[];
732
- context: Context[];
733
- task: Task | null;
734
- };
735
- /** Additional context items injected separately. */
736
- context: Context[];
737
- /** The conversation history. */
738
- transcript: {
739
- turns: Turn[];
740
- };
741
- budget: {
742
- total: number;
743
- used: number;
744
- breakdown: Record<string, number>;
745
- };
746
- /** Statistics on what was removed to fit within the token limit. */
747
- truncated: {
748
- preferences: number;
749
- interactions: number;
750
- context: number;
751
- };
752
- warnings: string[];
753
- conflicts: PreferenceConflict[];
754
- }
755
- /** Typed events emitted by the Workspace when data changes. */
756
- interface WorkspaceEvents {
757
- /** Emitted when the index or core settings change. */
758
- 'workspace:changed': DeepPartial<Workspace>;
759
- /** Emitted when a blob is registered, updated, or removed. */
760
- 'blobs:changed': {
761
- sha256: SHA256;
762
- record: BlobRecord | null;
763
- };
764
- }
765
-
766
- /**
767
- * Handles transcript compression and history management.
768
- * When a conversation exceeds the model's context window, the Summarizer
769
- * condenses older turns into a single summary string to reclaim tokens.
770
- */
771
- interface Summarizer {
772
- /**
773
- * Compresses the provided transcript.
774
- * * @param transcript - The current list of conversation turns.
775
- * @param tokenBudget - The maximum allowed tokens for the history.
776
- * @returns A promise resolving to the summary and the remaining uncompressed turns.
777
- */
778
- summarize(transcript: Turn[], tokenBudget: number): Promise<{
779
- summary: string;
780
- remaining: Turn[];
781
- }>;
782
- }
783
- /**
784
- * Analyzes model outputs for side effects and workspace actions.
785
- * The TurnProcessor scans the assistant's response (Turn) for specific
786
- * triggers, such as file edits, UI updates, or state changes.
787
- */
788
- interface TurnProcessor {
789
- /**
790
- * Scans a turn for actionable blocks and returns workspace commands.
791
- * @param turn - The assistant turn to be processed.
792
- * @param sessionId - The session in which the turn was generated.
793
- * @returns An array of Commands to synchronize the Workspace state.
794
- */
795
- process(turn: Turn, sessionId?: UUID): Command[];
796
- }
797
- /**
798
- * Manages the lifecycle and execution of external tools.
799
- * Acts as a central hub for discovering available capabilities and
800
- * routing tool calls to their respective executors.
801
- */
802
- interface ToolRegistry {
803
- /**
804
- * Subscribes to changes in the tool ecosystem.
805
- * @param callback - Invoked whenever tools are added, removed, or updated.
806
- */
807
- onRegistryChanged(callback: (tools: ToolSummary[]) => void): void;
808
- /**
809
- * Retrieves a list of all currently registered and available tools.
810
- * @returns An array of summaries describing tool capabilities and schemas.
811
- */
812
- list(): ToolSummary[];
813
- /**
814
- * Executes a tool call in a stateless manner.
815
- * * @template T - The expected return type of the tool execution.
816
- * @param call - The specific tool call requested by the model.
817
- * @returns A promise resolving to a Result wrapper containing the tool output.
818
- */
819
- execute<T = any>(call: ToolCall): Promise<Result<T>>;
820
- }
821
- /**
822
- * Enforces security and authorization policies.
823
- * * The PermissionGuard ensures that the current execution context (User/Session)
824
- * has the necessary privileges to perform a requested action or tool call.
825
- */
826
- interface PermissionGuard {
827
- /**
828
- * Validates if the current context has the right to execute the request.
829
- * * @param request - The authentication payload and target action.
830
- * @returns A Result containing the authorized payload or an error.
831
- */
832
- authenticate(request: AuthRequest): Promise<Result<AuthRequest["payload"] | null>>;
833
- }
834
- /**
835
- * Bridge between the internal Workspace types and external LLM APIs.
836
- * This generic adapter allows the system to remain vendor-agnostic by
837
- * centralizing the translation logic for different providers (Google, OpenAI, etc.).
838
- * @template TRequest - The specific request shape expected by the provider SDK.
839
- * @template TRequestParams - Extra parameters for the request (e.g., model name, temperature).
840
- * @template TResponse - The raw response shape returned by the provider SDK.
841
- */
842
- interface LLMAdapter<TRequest, TRequestParams, TResponse> {
843
- /**
844
- * Maps the internal `Prompt` to the vendor-specific request format.
845
- * * @param params - The prompt and provider-specific configuration.
846
- * @returns The formatted request object ready for the SDK.
847
- */
848
- /**
849
- * Prepares the request and identifies necessary side-effects (like uploads).
850
- */
851
- prepare(params: {
852
- prompt: Prompt;
853
- } & TRequestParams): Promise<{
854
- request: TRequest;
855
- effects?: Command[];
856
- }>;
857
- /**
858
- * Maps the vendor-specific response back to an internal `Turn`.
859
- * * @param params - The raw response received from the model API.
860
- * @returns A Result containing standardized Turn object or an error.
861
- */
862
- parse(params: {
863
- response: TResponse;
864
- }): Result<Turn, WorkspaceError>;
865
- }
866
-
867
- /**
868
- * Buffers write operations across one or more stores and commits them atomically.
869
- *
870
- * ## How atomicity works
871
- *
872
- * ### IndexedDB stores (same database)
873
- * At commit time, TransactionContext collects the names of every IDB store that
874
- * received operations, then opens a **single** `IDBTransaction` spanning all of
875
- * them via `ConnectionManager.openTransaction`. Each store's `executeInTransaction`
876
- * receives that shared transaction object and performs its writes against it
877
- * without opening a new transaction of its own. IDB commits or aborts the
878
- * entire multi-store transaction as one unit.
879
- *
880
- * ### MemoryStore
881
- * MemoryStore's `executeInTransaction` receives `null` for the shared transaction.
882
- * It applies ops against an internal staging map and returns. If a later
883
- * participant fails, TransactionContext calls `rollbackMemory` on each
884
- * MemoryStore that already applied its staged ops. MemoryStore restores its
885
- * pre-transaction snapshot.
886
- *
887
- * ### Mixed (IDB + Memory in the same transaction)
888
- * All IDB stores are committed first as a single atomic IDB transaction, then
889
- * each MemoryStore is committed. If a MemoryStore fails after IDB has already
890
- * committed, the IDB side cannot be rolled back — this is an inherent limitation
891
- * of mixing two different storage engines. In practice the schema store is
892
- * always MemoryStore-or-IDB consistently, so mixed transactions should not arise
893
- * in normal usage.
894
- */
895
- declare class TransactionContext {
896
- readonly id: string;
897
- /**
898
- * Flat list of every operation staged so far, in the order they were added.
899
- * We keep the store reference alongside the op so commit() can group them.
900
- */
901
- private staged;
902
- private done;
903
- constructor();
904
- /**
905
- * Stages a single write operation against a store.
906
- * Does NOT touch the store — no I/O happens until commit().
907
- */
908
- addOp<T extends Record<string, any>>(store: Store<T>, type: "put" | "delete" | "add", data: any): Promise<void>;
909
- /**
910
- * Commits all staged operations atomically.
911
- *
912
- * For IDB stores: opens one shared IDBTransaction across all participating
913
- * stores, then dispatches ops to each store's executeInTransaction.
914
- * For MemoryStores: dispatches sequentially; rolls back on failure.
915
- */
916
- commit(): Promise<void>;
917
- /**
918
- * Discards all staged operations. No I/O has occurred so there is nothing
919
- * to undo — we simply clear the buffer.
920
- */
921
- rollback(): void;
922
- /**
923
- * Opens ONE IDBTransaction across all participating IDB stores and lets
924
- * each store execute its ops against the shared transaction handle.
925
- *
926
- * We obtain the IDBDatabase from the first store (they all share the same
927
- * ConnectionManager / database) and open the transaction ourselves so that
928
- * the commit/abort lifecycle belongs entirely to this method.
929
- */
930
- private commitIDB;
931
- /**
932
- * Commits MemoryStore groups sequentially.
933
- * Maintains a list of stores that have already applied their ops; if any
934
- * store throws, all previously-applied stores are rolled back via the
935
- * store-level `_rollbackMemory(snapshot)` escape hatch.
936
- */
937
- private commitMemory;
938
- completed(): boolean;
1282
+ sessionId: UUID;
1283
+ };
939
1284
  }
940
-
941
- interface CursorCallbackResult<T> {
942
- value: T | null;
943
- done: boolean;
944
- offset?: number;
1285
+ interface RegisterBlob extends BaseCommand {
1286
+ type: "blob:register";
1287
+ /** Standard payload for intaking new binary data into the blob system. */
1288
+ payload: {
1289
+ data: Uint8Array;
1290
+ mediaType: BlobMediaType;
1291
+ filename?: string;
1292
+ };
945
1293
  }
946
- /**
947
- * Callback function for cursor iteration over store records.
948
- *
949
- * @template T - The type of records stored.
950
- * @param value - The current record value (cloned, not a live reference).
951
- * @param key - The key (ID) of the current record.
952
- * @param cursor - The underlying cursor object (implementation-specific; may be `null` in memory adapters).
953
- * @returns A promise resolving to an object indicating whether iteration should stop,
954
- * and an optional offset to advance.
955
- */
956
- type CursorCallback<T> = (value: T, key: string | number, cursor: any) => Promise<CursorCallbackResult<T>>;
957
- /**
958
- * A generic representation of a key range, replacing the browser-specific IDBKeyRange.
959
- */
960
- interface StoreKeyRange {
961
- lower?: any;
962
- upper?: any;
963
- lowerOpen?: boolean;
964
- upperOpen?: boolean;
1294
+ /** Increases reference count to prevent garbage collection. */
1295
+ interface RetainBlob extends BaseCommand {
1296
+ type: "blob:retain";
1297
+ /** The hash targeting the specific blob to protect. */
1298
+ payload: {
1299
+ sha256: SHA256;
1300
+ };
1301
+ }
1302
+ /** Decreases reference count. */
1303
+ interface ReleaseBlob extends BaseCommand {
1304
+ type: "blob:release";
1305
+ /** The hash targeting the specific blob to un-protect. */
1306
+ payload: {
1307
+ sha256: SHA256;
1308
+ };
1309
+ }
1310
+ /** Immediately removes a blob regardless of reference count. */
1311
+ interface PurgeBlob extends BaseCommand {
1312
+ type: "blob:purge";
1313
+ /** The hash targeting the specific blob for immediate destruction. */
1314
+ payload: {
1315
+ sha256: SHA256;
1316
+ };
1317
+ }
1318
+ /** Maps a local blob to an external provider's file ID. */
1319
+ interface RecordBlobRemoteId extends BaseCommand {
1320
+ type: "blob:record_remote_id";
1321
+ /** Payload linking local workspace data to an external API's asset registry. */
1322
+ payload: {
1323
+ sha256: SHA256;
1324
+ providerId: string;
1325
+ fileId: string;
1326
+ timestamp?: Timestamp;
1327
+ };
1328
+ }
1329
+ /** Union of all blob management commands. */
1330
+ type BlobCommand = RegisterBlob | RetainBlob | ReleaseBlob | PurgeBlob | RecordBlobRemoteId;
1331
+ /** Entity representing a categorization or grouping mechanism. */
1332
+ interface Topic {
1333
+ /** Core string identifier (e.g., 'machine-learning'). */
1334
+ name: string;
1335
+ /** UI-friendly presentation string. */
1336
+ label?: string;
1337
+ /** Deep description of what the topic encompasses. */
1338
+ description?: string;
1339
+ /** Extensible key-value store for topic-specific attributes. */
1340
+ metadata?: Record<string, any>;
1341
+ /** Timestamp of initial topic creation. */
1342
+ created: Timestamp;
1343
+ /** Timestamp of the most recent modification. */
1344
+ updated: Timestamp;
1345
+ }
1346
+ interface AddTopic extends BaseCommand {
1347
+ type: "topic:add";
1348
+ /** Fully formed topic object to inject. */
1349
+ payload: Topic;
1350
+ }
1351
+ interface UpdateTopic extends BaseCommand {
1352
+ type: "topic:update";
1353
+ /** Delta properties for modifying an existing topic. */
1354
+ payload: Partial<Topic> & {
1355
+ name: string;
1356
+ };
1357
+ }
1358
+ interface DeleteTopic extends BaseCommand {
1359
+ type: "topic:delete";
1360
+ /** Rules for removing a topic, optionally destroying linked resources. */
1361
+ payload: {
1362
+ name: string;
1363
+ cascade?: boolean;
1364
+ };
1365
+ }
1366
+ interface MergeTopics extends BaseCommand {
1367
+ type: "topic:merge";
1368
+ /** Consolidates two separate topics, migrating all relationships to the target. */
1369
+ payload: {
1370
+ source: string;
1371
+ target: string;
1372
+ };
965
1373
  }
1374
+ /** Executes a tool payload securely. */
1375
+ interface ToolCallCommand extends BaseCommand {
1376
+ type: "tool:call";
1377
+ /** Payload detailing the execution request for a registered tool. */
1378
+ payload: ToolCall;
1379
+ }
1380
+ /** Union of all possible commands that can be dispatched to the Workspace Manager. */
1381
+ type Command = CreateWorkspace | AddRole | UpdateRole | DeleteRole | AddPreference | UpdatePreference | DeletePreference | CreateSession | UpdateSession | ForkSession | DeleteSession | SwitchSessionRole | AddSessionTopics | OverrideSessionPreferences | AddContext | UpdateContext | DeleteContext | UpdateTurn | AddTurn | EditTurn | BranchTurn | DeleteTurn | RegisterBlob | RetainBlob | ReleaseBlob | PurgeBlob | RecordBlobRemoteId | AddTopic | UpdateTopic | DeleteTopic | MergeTopics | ToolCallCommand;
966
1382
  /**
967
- * A single buffered operation staged inside a TransactionContext.
968
- * Kept intentionally minimal the context only needs to know what to
969
- * replay against a store during commit.
1383
+ * Standard reducer pattern for updating workspace state.
1384
+ * @template T - Custom contextual additions for the reducer parameters.
1385
+ * @template R - The payload type the reducer expects to process.
970
1386
  */
971
- type BufferedOperation<T> = {
972
- type: "add" | "put";
973
- data: T | T[];
974
- } | {
975
- type: "delete";
976
- data: string | number | (string | number)[];
977
- };
1387
+ type WorkspaceReducer<T = any, R = any> = (
1388
+ /** Combined system context containing current state and active configurations. */
1389
+ ctx: {
1390
+ workspace: Workspace;
1391
+ } & T,
1392
+ /** The payload defining the intended mutation. */
1393
+ payload: R) => Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
978
1394
  /**
979
- * Storage adapter interface for a single object store (collection).
980
- *
981
- * Stores own their indexes. Index lifecycle (create, drop) and index-aware reads
982
- * (findByIndex) are part of this contract so that both MemoryStore and IndexedDBStore
983
- * implement them natively — MemoryStore via in-memory index maps, IndexedDB via its
984
- * native index mechanism.
985
- *
986
- * @template T - The type of objects stored. Must include the key path property.
1395
+ * Middleware wrapper for observing or intercepting command dispatches.
987
1396
  */
988
- interface Store<T extends Record<string, any> = Record<string, any>> {
989
- /**
990
- * Returns the name of this store (the IDB object store / collection name).
991
- * Used by TransactionContext to group operations and open a correctly-scoped
992
- * multi-store IDB transaction at commit time.
993
- */
994
- name(): string;
995
- /**
996
- * Opens the store, ensuring underlying storage structures exist.
997
- */
998
- open(): Promise<void>;
999
- /**
1000
- * Adds one or more records to the store.
1001
- * If a record does not have a value for the store's key path, an automatic
1002
- * key may be assigned. Throws if a record with the same key already exists.
1003
- */
1004
- add(data: T | T[]): Promise<string | number | (string | number)[]>;
1005
- /**
1006
- * Removes all records from the store without destroying index structures.
1007
- */
1008
- clear(): Promise<void>;
1009
- /**
1010
- * Returns the total number of records in the store.
1011
- */
1012
- count(): Promise<number>;
1013
- /**
1014
- * Deletes one or more records by their keys.
1015
- */
1016
- delete(id: string | number | (string | number)[]): Promise<void>;
1017
- /**
1018
- * Retrieves a single record by its primary key.
1019
- */
1020
- getById(id: string | number): Promise<T | undefined>;
1021
- /**
1022
- * Retrieves the first record matching an exact index key (point lookup).
1023
- * Useful for unique indexes — returns the single matching record or undefined.
1024
- *
1025
- * @param indexName - The name of the index to query.
1026
- * @param key - The exact key value to look up.
1027
- */
1028
- getByIndex(indexName: string, key: any): Promise<T | undefined>;
1029
- /**
1030
- * Retrieves all records from a named index, optionally filtered by a key range.
1031
- * Use this for range scans over an index (e.g. all records where age >= 18).
1032
- *
1033
- * @param indexName - The name of the index to query.
1034
- * @param keyRange - Optional range to filter results.
1035
- */
1036
- getByKeyRange(indexName: string, keyRange?: StoreKeyRange): Promise<T[]>;
1037
- /**
1038
- * Retrieves all records from the store without index involvement.
1039
- */
1040
- getAll(): Promise<T[]>;
1041
- /**
1042
- * Inserts or replaces a record. Validates OCC if a record with the same key exists.
1043
- */
1044
- put(data: T): Promise<string | number>;
1045
- /**
1046
- * Iterates over records using a cursor, allowing early termination and skipping.
1047
- *
1048
- * @param callback - Invoked for each record; return `{ done: true }` to stop,
1049
- * `{ offset: n }` to skip ahead n records.
1050
- * @param direction - Iteration order.
1051
- * @param keyRange - Optional range to restrict iteration.
1052
- */
1053
- cursor(callback: CursorCallback<T>, direction?: "forward" | "backward", keyRange?: StoreKeyRange): Promise<T | null>;
1054
- /**
1055
- * Executes a batch of write operations atomically within this store.
1056
- * All operations succeed or fail together.
1057
- *
1058
- * Used for standalone (single-store) atomic writes. For cross-store atomicity,
1059
- * use executeInTransaction instead.
1060
- */
1061
- batch(operations: Array<{
1062
- type: "add" | "put";
1063
- data: T | T[];
1064
- } | {
1065
- type: "delete";
1066
- data: string | number | (string | number)[];
1067
- }>): Promise<void>;
1068
- /**
1069
- * Registers a new index on the store. Idempotent — no-op if the index already exists.
1070
- * For IndexedDB, this triggers a database version upgrade.
1071
- * For MemoryStore, this builds the index map from existing records.
1072
- *
1073
- * @param definition - The full index definition from the schema.
1074
- */
1075
- createIndex(definition: IndexDefinition): Promise<void>;
1076
- /**
1077
- * Removes a named index from the store.
1078
- * For IndexedDB, this triggers a database version upgrade.
1079
- * For MemoryStore, this drops the in-memory index map.
1080
- *
1081
- * @param name - The index name as declared in IndexDefinition.name.
1082
- */
1083
- dropIndex(name: string): Promise<void>;
1084
- /**
1085
- * Returns all records matching an exact index key.
1086
- * Unlike getByIndex (which returns only the first match), this returns all matches —
1087
- * essential for non-unique indexes where multiple records share the same indexed value.
1088
- *
1089
- * @param indexName - The name of the index to query.
1090
- * @param value - The exact value to look up.
1091
- */
1092
- findByIndex(indexName: string, value: any): Promise<T[]>;
1093
- /**
1094
- * Executes a set of buffered operations as part of a cross-store atomic transaction.
1095
- *
1096
- * For IndexedDBStore: `sharedTx` is the single IDBTransaction opened across all
1097
- * participating stores. Operations are applied directly to `sharedTx.objectStore(name)`
1098
- * without opening a new transaction — IDB commits or aborts the whole thing atomically.
1099
- *
1100
- * For MemoryStore: `sharedTx` is null. The store applies ops against its own staging
1101
- * area. The caller (TransactionContext) is responsible for coordinating rollback across
1102
- * all MemoryStores if any participant fails.
1103
- *
1104
- * This method must NOT open, commit, or abort any transaction itself.
1105
- *
1106
- * @param ops - The buffered operations to apply.
1107
- * @param sharedTx - The shared IDBTransaction (IndexedDB only), or null (MemoryStore).
1108
- */
1109
- executeInTransaction(ops: BufferedOperation<T>[], sharedTx: IDBTransaction | null): Promise<void>;
1397
+ type WorkspaceMiddleware = (
1398
+ /** Comprehensive payload including the state, the executing command, and the intended state delta. */
1399
+ ctx: {
1400
+ workspace: Workspace;
1401
+ command: BaseCommand;
1402
+ patch: DeepPartial<Workspace>;
1403
+ } & WorkspaceContext) => Promise<DeepPartial<Workspace>>;
1404
+ /** A fully hydrated and normalized session structure. */
1405
+ interface ResolvedSession {
1406
+ /** The ID of the session. */
1407
+ sessionId: UUID;
1408
+ /** The active, fully resolved persona definition. */
1409
+ role: Role;
1410
+ /** The deduplicated, prioritized array of active preferences. */
1411
+ preferences: Preference[];
1412
+ /** RAG-retrieved context items relevant to the current conversation. */
1413
+ context: Context[];
1414
+ /** The linear conversation sequence flattened from the DAG structure. */
1415
+ transcript: Turn[];
1416
+ /** Dictionary of completely resolved local and remote binary assets. */
1417
+ blobs: Map<SHA256, ResolvedBlob>;
1418
+ /** The global system prompt overlay, if present. */
1419
+ instructions?: string;
1420
+ /** Array of warning strings generated during the resolution process. */
1421
+ warnings: string[];
1110
1422
  }
1111
- interface Collection<T> {
1112
- /**
1113
- * Finds a single document matching the query.
1114
- */
1115
- find: (query: QueryFilter<T>) => Promise<Document<T> | null>;
1116
- /**
1117
- * Lists documents with pagination. Returns an AsyncIterator so consumers can
1118
- * wrap it in their own iteration protocol (e.g. for-await-of via AsyncIterable).
1119
- */
1120
- list: (query: PaginationOptions) => Promise<AsyncIterator<Document<T>[]>>;
1121
- /**
1122
- * Filters all documents matching the query.
1123
- */
1124
- filter: (query: QueryFilter<T>) => Promise<Document<T>[]>;
1423
+ /** Typed events emitted by the Workspace when data changes. */
1424
+ interface WorkspaceEvents {
1425
+ /** Emitted when the index or core settings change. */
1426
+ "workspace:changed": DeepPartial<Workspace>;
1427
+ /** Emitted when a blob is registered, updated, or removed. */
1428
+ "blobs:changed": {
1429
+ /** Hash of the affected blob. */
1430
+ sha256: SHA256;
1431
+ /** The actual modified record, or undefined if deleted. */
1432
+ record?: BlobRecord;
1433
+ };
1434
+ }
1435
+ /** Complete snapshot of the session provided to the PromptBuilder. */
1436
+ interface SessionSnapshot {
1437
+ /** Session identifier. */
1438
+ id: UUID;
1439
+ /** Top-level session definition fields. */
1440
+ meta: SessionMetadata;
1441
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1442
+ model?: string;
1443
+ /** The active role — persona, instructions, role-level constraints. */
1444
+ role: Role;
1445
+ /** Unfiltered, unranked preferences attached strictly to the role or session. */
1446
+ preferences: Preference[];
1447
+ /** All context entries whose topics overlap with the session's active topics. */
1448
+ context: Context[];
1449
+ /** Full active chain from TurnTree — oldest to newest. Untruncated. */
1450
+ transcript: Turn[];
1451
+ /** The session's active semantic topic set. */
1452
+ topics: string[];
1453
+ /** Global workspace instructions from Settings.prompt, if set. */
1454
+ instructions?: string;
1455
+ /** Model constraints structured by their hierarchical application level. */
1456
+ constraints: {
1457
+ /** Broadest constraints explicitly linked to the active role. */
1458
+ role?: ModelConstraintMap;
1459
+ /** Overriding constraints attached to the active session. */
1460
+ session?: ModelConstraintMap;
1461
+ /** The most explicit constraints captured at the last user turn. */
1462
+ turn?: ModelConstraintMap;
1463
+ };
1464
+ }
1465
+
1466
+ /**
1467
+ * Output of PromptBuilder.build(). Input to LLMAdapter.resolve().
1468
+ *
1469
+ * Contains fully ranked and conflict-resolved preferences, context, and a
1470
+ * catalogue of blob references — but is NOT truncated and does NOT contain
1471
+ * resolved binary blob data. The adapter is responsible for:
1472
+ * - Deciding what fits within the model's context window.
1473
+ * - Resolving only the BlobRefs that survive truncation.
1474
+ * - Uploading inline blobs to the provider where required.
1475
+ */
1476
+ interface Prompt {
1477
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1478
+ model?: string;
1479
+ /** Correlates this prompt to its session for logging and evaluation. */
1480
+ session: UUID;
1481
+ /** System-level instructions, context, and preferences. */
1482
+ system: {
1483
+ /** The active role's persona string. */
1484
+ persona: string;
1485
+ /** Global or session-level instructions. */
1486
+ instructions?: string;
1487
+ /** Conflict-resolved, relevance-ordered preferences. */
1488
+ preferences: Preference[];
1489
+ /** Ranked context entries (text and json kinds only). Blob context is
1490
+ * represented as referential blocks in the transcript instead. */
1491
+ context: Context[];
1492
+ };
1493
+ /** Active conversation chain, oldest to newest. May include synthetic turns.
1494
+ * Image and document blocks carry a BlobRef only; the adapter resolves them. */
1495
+ transcript: Turn[];
1125
1496
  /**
1126
- * Creates a new document in the collection.
1127
- *
1128
- * When a TransactionContext is provided the initial store.add is buffered into
1129
- * the transaction rather than written immediately. The document is returned in
1130
- * its fully initialised in-memory state regardless — callers can use it before
1131
- * the transaction commits.
1497
+ * Lightweight catalogue of every blob referenced anywhere in this prompt
1498
+ * (system.context or transcript), keyed by SHA256.
1132
1499
  *
1133
- * @param initial - The initial data for the document.
1134
- * @param tx - Optional transaction to buffer the write into.
1500
+ * Values are BlobRefs metadata only, no binary data. The adapter uses
1501
+ * this catalogue to resolve or upload blobs for whichever turns and context
1502
+ * entries survive its truncation pass.
1135
1503
  */
1136
- create: (initial: T, tx?: TransactionContext) => Promise<Document<T>>;
1137
- /**
1138
- * Subscribes to collection-level events.
1139
- */
1140
- subscribe: (event: CollectionEventType | TelemetryEventType, callback: (event: CollectionEvent<T> | TelemetryEvent) => void) => () => void;
1504
+ blobs: Map<SHA256, BlobRef>;
1505
+ /** The role object — for inspection and adapter use. */
1506
+ role: Role;
1507
+ /** Model constraints to be merged by the adapter (turn > session > role). */
1508
+ constraints: ModelConstraintMap;
1141
1509
  /**
1142
- * Validates data against the collection's schema.
1510
+ * Non-fatal warnings generated during the build phase.
1511
+ * Adapters and callers should surface or log these.
1512
+ * Examples: summarizer failures, unresolvable blob refs.
1143
1513
  */
1144
- validate(data: Record<string, any>): Promise<{
1145
- value?: any;
1146
- issues: Array<{
1147
- message: string;
1148
- path: Array<string>;
1149
- }>;
1514
+ warnings: string[];
1515
+ }
1516
+ /**
1517
+ * Reflects the current state of the LLM adapter (limits, headroom, and readiness).
1518
+ */
1519
+ interface AdapterStatus {
1520
+ /** Provider name (e.g., "google", "anthropic", "openai"). */
1521
+ provider: string;
1522
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1523
+ model: string;
1524
+ /** Whether the adapter is currently able to accept requests. */
1525
+ ready: boolean;
1526
+ /** Token window limits and current usage. */
1527
+ window: {
1528
+ /** Total context window size in tokens. */
1529
+ size: number;
1530
+ /** Maximum output tokens for this model. */
1531
+ out: number;
1532
+ /** Tokens remaining — estimated or as reported by the provider. */
1533
+ free?: number;
1534
+ };
1535
+ /** Capability flags for this model. */
1536
+ feature: {
1537
+ /** Whether the model can process image inputs. */
1538
+ vision: boolean;
1539
+ /** Whether the model supports tool/function calling. */
1540
+ tools: boolean;
1541
+ /** Whether the model supports structured JSON output mode. */
1542
+ json: boolean;
1543
+ /** Whether the provider supports prompt caching. */
1544
+ cache: boolean;
1545
+ /** Whether the adapter supports streaming. */
1546
+ streaming: boolean;
1547
+ /** Whether the model supports extended thinking/reasoning tokens. */
1548
+ thinking: boolean;
1549
+ };
1550
+ /** Pricing tiers for this model. */
1551
+ pricing: Array<{
1552
+ unit: 'token' | 'call' | "image";
1553
+ /** Exponent: price is per 10^scale units. */
1554
+ scale: number;
1555
+ /** Price per unit in USD. */
1556
+ cost: {
1557
+ input: number;
1558
+ output: number;
1559
+ cache?: {
1560
+ read: number;
1561
+ write: number;
1562
+ };
1563
+ };
1150
1564
  }>;
1151
- invalidate(): void;
1565
+ /** Current rate limit state. */
1566
+ rate: {
1567
+ /** Current saturation as a fraction of the most constrained limit (0.0 to 1.0). */
1568
+ load: number;
1569
+ /** Milliseconds until the next request is permitted. */
1570
+ timeout?: number;
1571
+ /** The hard limits enforced by the provider. */
1572
+ capacity: Array<{
1573
+ unit: 'token' | 'call' | string;
1574
+ /** Maximum units allowed per period. */
1575
+ max: number;
1576
+ /** Period length in seconds. */
1577
+ period: number;
1578
+ }>;
1579
+ };
1580
+ /** Adapter-level notes, e.g. model deprecation warnings. */
1581
+ notes?: string[];
1152
1582
  }
1153
1583
  /**
1154
- * Event payload for Collection events.
1584
+ * The result of `PreparedPrompt.execute()`. Contains the turn and derived effects.
1155
1585
  */
1156
- type CollectionEventType = "document:create" | "collection:read" | "migration:start" | "migration:end";
1157
- type CollectionEvent<T> = {
1158
- type: CollectionEventType;
1159
- document?: T;
1160
- model?: string;
1161
- method?: keyof Collection<T>;
1162
- metadata?: Record<string, unknown>;
1163
- timestamp: number;
1164
- };
1165
- interface Database {
1166
- /**
1167
- * Opens an existing collection by name.
1168
- */
1169
- collection: <T>(schemaName: string) => Promise<Collection<T>>;
1170
- /**
1171
- * Creates a new collection from a schema definition.
1172
- */
1173
- createCollection: <T>(schema: SchemaDefinition) => Promise<Collection<T>>;
1174
- /**
1175
- * Deletes a collection and its schema record.
1176
- */
1177
- deleteCollection: (schemaName: string) => Promise<boolean>;
1178
- /**
1179
- * Updates an existing collection's schema record.
1180
- */
1181
- updateCollection: (schema: SchemaDefinition) => Promise<boolean>;
1182
- /**
1183
- * Migrates an existing collection's data and schema definition.
1184
- * Processes data in a streaming fashion to avoid loading the full collection
1185
- * into memory.
1186
- */
1187
- migrateCollection: <T>(name: string, opts: CollectionMigrationOptions, batchSize?: number) => Promise<Collection<T>>;
1586
+ interface ExecuteResult {
1587
+ /** The newly generated assistant turn. */
1588
+ turn: Turn;
1589
+ /** Side-effect commands to dispatch against the workspace. */
1590
+ effects: BaseCommand[];
1591
+ }
1592
+ /**
1593
+ * A single labelled section of the system prompt.
1594
+ * Mirrors PreparedPrompt.system exactly — the assembler's output is stored
1595
+ * there directly, giving callers full inspection without re-parsing the string.
1596
+ */
1597
+ interface PromptSection {
1188
1598
  /**
1189
- * Executes a callback within a TransactionContext.
1190
- * Writes buffered inside the callback are flushed atomically on commit.
1191
- * If the callback throws, the buffer is discarded (no writes are flushed).
1599
+ * Origin label for this section.
1600
+ * Core sections use fixed labels: 'operating-system' | 'persona' |
1601
+ * 'preferences' | 'context' | 'instructions'.
1602
+ * Extensions carry whatever label the injector provides.
1192
1603
  */
1193
- transaction: (callback: (tx: TransactionContext) => Promise<void>) => Promise<void>;
1604
+ label: string;
1605
+ /** Text content exactly as it will be sent to the model. */
1606
+ content: string;
1607
+ /** Optional structured metadata for richer UI display or tooling. */
1608
+ metadata?: Record<string, any>;
1609
+ }
1610
+ /**
1611
+ * The complete, final prompt exactly as the model will receive it.
1612
+ * Generic, provider-agnostic, fully inspectable, and executable.
1613
+ */
1614
+ interface PreparedPrompt {
1615
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1616
+ model: string;
1617
+ /** The complete system instruction broken into labelled sections for inspection. */
1618
+ instructions: Array<PromptSection>;
1619
+ /** Final transcript turns that will be sent after adapter-level truncation. */
1620
+ transcript: Turn[];
1621
+ /** Final context entries included after adapter-level truncation. */
1622
+ context: Context[];
1623
+ /** Final preferences included after adapter-level truncation. */
1624
+ preferences: Preference[];
1625
+ /** The resolved model constraints for this request. */
1626
+ constraints: ModelConstraint;
1627
+ /** Token accounting (estimated or exact). */
1628
+ tokens: {
1629
+ /** Breakdown by section. Keys are adapter-defined. */
1630
+ breakdown: Record<string, number>;
1631
+ /** Total input tokens — estimated or exact. */
1632
+ total: number;
1633
+ /** Whether total is an estimate or exact (provider-supplied). */
1634
+ source: 'estimated' | 'exact';
1635
+ /** Maximum output tokens configured for this request. */
1636
+ output?: number;
1637
+ /** Tokens remaining in the context window after this prompt. */
1638
+ remaining?: number;
1639
+ };
1194
1640
  /**
1195
- * Subscribes to database-level events.
1641
+ * Sends this prompt to the model.
1642
+ * @returns The parsed assistant Turn plus any execution side-effects.
1196
1643
  */
1197
- subscribe: (event: DatabaseEventType | "telemetry", callback: (event: DatabaseEvent | TelemetryEvent) => void) => () => void;
1644
+ execute(): Promise<Result<ExecuteResult, WorkspaceError>>;
1198
1645
  /**
1199
- * Releases in-memory references and event bus subscriptions.
1200
- * Does not delete any persisted data.
1646
+ * Streaming variant of execute(). Yields partial turns as tokens arrive.
1647
+ * Present only if the adapter and model support streaming.
1201
1648
  */
1202
- close: () => void;
1203
- clear: () => Promise<void>;
1649
+ executeStream?(): AsyncIterable<Partial<Turn> | ExecuteResult>;
1650
+ }
1651
+
1652
+ /**
1653
+ * A simple LRU (Least Recently Used) cache implementation.
1654
+ * Used for caching frequently accessed entities in memory.
1655
+ */
1656
+ declare class LRUCache<K, V> {
1657
+ private cache;
1658
+ private readonly maxSize;
1659
+ constructor(maxSize: number);
1204
1660
  /**
1205
- * Ensures a collection exists; creates it if it doesn't. Idempotent.
1661
+ * Retrieves an item from the cache.
1662
+ * Moves the item to the end of the cache (most recently used).
1206
1663
  */
1207
- ensureCollection: (schema: SchemaDefinition) => Promise<void>;
1664
+ get(key: K): V | undefined;
1208
1665
  /**
1209
- * Ensures multiple collections exist; creates any that don't. Idempotent.
1666
+ * Adds or updates an item in the cache.
1667
+ * If the cache exceeds maxSize, the least recently used item is removed.
1210
1668
  */
1211
- setupCollections: (schemas: SchemaDefinition[]) => Promise<void>;
1212
- }
1213
- type CollectionMigrationOptions = {
1214
- changes: SchemaChange<any>[];
1215
- description: string;
1216
- rollback?: SchemaChange<any>[];
1217
- transform?: string | DataTransform<any, any>;
1218
- };
1219
- type DatabaseEventType = "collection:create" | "collection:delete" | "collection:update" | "collection:read" | "migrate";
1220
- type DatabaseEvent = {
1221
- type: DatabaseEventType;
1222
- schema?: SchemaDefinition | Partial<SchemaDefinition>;
1223
- timestamp: number;
1224
- };
1225
- type Document<T> = {
1226
- readonly [K in keyof T]: T[K];
1227
- } & {
1228
- $id?: string;
1229
- $created?: string | Date;
1230
- $updated?: string | Date;
1231
- $version?: number;
1232
- read: () => Promise<boolean>;
1233
- save: (tx?: TransactionContext) => Promise<boolean>;
1234
- update: (props: Partial<T>, tx?: TransactionContext) => Promise<boolean>;
1235
- delete: (tx?: TransactionContext) => Promise<boolean>;
1236
- subscribe: (event: DocumentEventType | TelemetryEventType, callback: (event: DocumentEvent<T> | TelemetryEvent) => void) => () => void;
1237
- state(): T;
1238
- };
1239
- type DocumentEventType = "document:create" | "document:write" | "document:update" | "document:delete" | "document:read";
1240
- type DocumentEvent<T> = {
1241
- type: DocumentEventType;
1242
- data?: Partial<T>;
1243
- timestamp: number;
1244
- };
1245
- type TelemetryEventType = "telemetry";
1246
- type TelemetryEvent = {
1247
- type: TelemetryEventType;
1248
- method: string;
1249
- timestamp: number;
1250
- source: any;
1251
- metadata: {
1252
- args: any[];
1253
- performance: {
1254
- durationMs: number;
1255
- };
1256
- source: {
1257
- level: "database" | "collection" | "document";
1258
- collection?: string;
1259
- document?: string;
1260
- };
1261
- result?: {
1262
- type: "array" | string;
1263
- size?: number;
1264
- };
1265
- error: {
1266
- message: string;
1267
- name: string;
1268
- stack?: string;
1269
- } | null;
1270
- };
1271
- };
1272
-
1273
- interface WorkspaceDatabase {
1669
+ set(key: K, value: V): void;
1274
1670
  /**
1275
- * Open the database. Registers core schemas followed by any extension
1276
- * schemas supplied by the caller (domain plugins).
1277
- *
1278
- * Idempotent — safe to call multiple times; subsequent calls are no-ops
1279
- * if the database is already open.
1671
+ * Checks if a key exists in the cache without refreshing it.
1280
1672
  */
1281
- open(extensionSchemas?: SchemaDefinition[]): Promise<void>;
1673
+ has(key: K): boolean;
1282
1674
  /**
1283
- * Access a collection by schema name.
1284
- * Throws if the schema has not been registered.
1675
+ * Removes an item from the cache.
1285
1676
  */
1286
- collection<T>(schemaName: string): Promise<Collection<T>>;
1677
+ delete(key: K): void;
1287
1678
  /**
1288
- * Close the database connection.
1679
+ * Clears all items from the cache.
1289
1680
  */
1290
- close(): void;
1681
+ clear(): void;
1291
1682
  }
1292
- declare function createWorkspaceDatabase(db: Database): WorkspaceDatabase;
1293
- declare const COLLECTIONS: {
1294
- readonly ROLE: "role";
1295
- readonly PREFERENCE: "preference";
1296
- readonly CONTEXT: "context";
1297
- readonly SESSION: "session";
1298
- readonly TURN: "turn";
1299
- readonly TASK: "task";
1300
- };
1301
- type CollectionName = typeof COLLECTIONS[keyof typeof COLLECTIONS];
1302
-
1303
- declare function del<T>(): T;
1304
- declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
1305
- declare function success<T>(value: T): Result<T, never>;
1306
- declare function error<E = WorkspaceError>(error: E): Result<never, E>;
1307
- declare function omitNullUndefined<T extends Record<string, any>>(obj: T): Partial<T>;
1308
- declare function createProjectWorkspace<ProjectMetadata extends Record<string, any> = Record<string, any>>({ project, language }: {
1309
- language: string;
1310
- project: Omit<Project<ProjectMetadata>, "id">;
1311
- }): Workspace<ProjectMetadata>;
1312
- declare function createSimpleWorkspace({ name, actor, language }: {
1313
- name: string;
1314
- language: string;
1315
- actor: string;
1316
- }): Workspace;
1317
- declare function extractBlobRecord(patch: DeepPartial<Workspace>): BlobRecord | null;
1318
- declare function extractBlobRef(record: BlobRecord): BlobRef;
1319
- declare function computeSHA256(data: Uint8Array): Promise<SHA256>;
1320
- /**
1321
- * Creates a skeleton Role object with empty defaults.
1322
- */
1323
- declare const createEmptyRole: (name: string, label: string) => Role;
1324
- /**
1325
- * Isomorphic Base64 converter (Node.js / browser).
1326
- */
1327
- declare function bufferToBase64(data: ArrayBuffer | Uint8Array | number[]): string;
1328
-
1329
- /**
1330
- * Short, deterministic hash of a string (4 chars in base36).
1331
- * Suitable for AI-friendly reference tokens.
1332
- */
1333
- declare function shortHash(s: string, length?: number): string;
1334
- /**
1335
- * Generates a short, memorable reference for a task.
1336
- * - Returns the proposal's own `ref` if provided.
1337
- * - Otherwise returns a 4‑character hash of the proposal's `id` or `title`.
1338
- */
1339
- declare function generateTaskRef(proposal: TaskProposalBlock): string;
1340
- /**
1341
- * Generates a short step reference.
1342
- * - Returns the step's own `ref` if provided.
1343
- * - Otherwise returns `${taskRef}_${index+1}` (e.g., "a3f9_2").
1344
- *
1345
- * The underscore separator avoids confusion with colons, slashes, or
1346
- * numeric suffixes that could be misinterpreted by LLMs.
1347
- */
1348
- declare function generateTaskStepRef(index: number, proposal: TaskProposalBlock): string;
1349
1683
 
1350
1684
  /**
1351
1685
  * Persistence contract for binary blob content and blob registry records.
1352
1686
  *
1353
- * Two concerns live here together deliberately:
1354
- * 1. Raw bytes stored and retrieved by SHA-256.
1355
- * 2. BlobRecord — the registry entry that tracks ref counts and remote IDs.
1356
- *
1357
- * Keeping them in the same backend ensures atomicity: registering a blob and
1358
- * storing its bytes happen in the same transaction boundary.
1687
+ * This is a hybrid interface because backends (like IndexedDB) need to
1688
+ * ensure atomicity between storing raw bytes and their associated metadata.
1359
1689
  */
1360
1690
  interface BlobStorage {
1361
- /**
1362
- * Store raw bytes for a blob. Idempotent — if the SHA-256 already exists
1363
- * the bytes are not re-written (content-addressed, so they are identical).
1364
- */
1691
+ /** Store raw bytes for a blob. */
1365
1692
  storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
1366
- /** Load raw bytes. Returns null if the blob is not stored locally. */
1693
+ /** Load raw bytes. Returns null if not found locally. */
1367
1694
  loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
1368
1695
  /** Returns true if bytes are stored locally for this SHA-256. */
1369
1696
  hasBytes(sha256: SHA256): Promise<boolean>;
1370
- /**
1371
- * Delete raw bytes. Called by BlobStore when refCount reaches 0 and
1372
- * the blob has been evicted from the local store.
1373
- */
1697
+ /** Delete raw bytes. */
1374
1698
  deleteBytes(sha256: SHA256): Promise<void>;
1375
- /** Persist a BlobRecord (registry metadata, not bytes). */
1699
+ /** Persist a BlobRecord (registry metadata). */
1376
1700
  saveRecord(record: BlobRecord): Promise<void>;
1377
- /** Load a BlobRecord by SHA-256. Returns null if not found. */
1701
+ /** Load a BlobRecord by SHA-256. */
1378
1702
  loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
1379
- /** Delete a BlobRecord. Called when a blob is fully evicted. */
1703
+ /** Delete a BlobRecord. */
1380
1704
  deleteRecord(sha256: SHA256): Promise<void>;
1381
- /** Return all stored BlobRecords. Used for bundle export and GC sweeps. */
1705
+ /** Return all stored BlobRecords. Used for GC and export. */
1382
1706
  listRecords(): Promise<BlobRecord[]>;
1383
- /**
1384
- * Export all bytes as an iterable of [sha256, Uint8Array] pairs.
1385
- * Used for workspace export / migration.
1386
- */
1707
+ /** Export all bytes for migration. */
1387
1708
  exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
1388
- /**
1389
- * Optional atomic operation: store bytes and save record in a single
1390
- * transaction. Backends that support this (e.g. IndexedDB) should
1391
- * implement it to avoid a window where bytes exist without a record.
1392
- * BlobStore will prefer this over calling storeBytes + saveRecord separately.
1393
- */
1709
+ /** Optional atomic operation: store bytes and save record in one transaction. */
1394
1710
  registerBlob?(record: BlobRecord, data: Uint8Array): Promise<void>;
1395
1711
  }
1396
1712
 
1397
- declare class TurnTree {
1398
- private readonly db;
1399
- constructor(db: WorkspaceDatabase);
1400
- private turns;
1401
- private sessions;
1402
- /**
1403
- * Compound filter for a specific (sessionId, id, version) tuple.
1404
- * Uses only declared schema fields — never $id.
1405
- */
1406
- private turnFilter;
1407
- private loadRaw;
1408
- getHead(sessionId: UUID): Promise<TurnRef | null>;
1409
- setHead(sessionId: UUID, head: TurnRef | null): Promise<void>;
1410
- save(sessionId: UUID, turn: Turn, head?: TurnRef | null): Promise<Turn>;
1411
- append(sessionId: UUID, turn: Turn): Promise<Turn>;
1412
- appendBatch(sessionId: UUID, turns: Turn[], finalHead: TurnRef | null): Promise<void>;
1413
- replaceVersion(sessionId: UUID, newTurn: Turn): Promise<void>;
1414
- branch(sessionId: UUID, newTurn: Turn): Promise<void>;
1415
- loadAllTurns(sessionId: UUID): Promise<Turn[]>;
1416
- loadTurnVersions(sessionId: UUID, turnId: UUID): Promise<Turn[]>;
1417
- buildNodes(turns: Turn[], head: TurnRef | null, dirtyBuffer?: readonly Turn[]): Record<UUID, TurnNode>;
1418
- buildNodeGraph(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Record<UUID, TurnNode>>;
1419
- getActiveChain(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Turn[]>;
1420
- buildActiveChain(sessionId: UUID): Promise<TurnNode[]>;
1421
- getTurnSiblings(turnId: UUID, sessionId: UUID): Promise<TurnNode[]>;
1422
- branchInfo(turnId: UUID, sessionId: UUID): Promise<BranchInfo>;
1423
- deleteSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<void>;
1424
- copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
1425
- }
1426
-
1427
- interface BlobStoreConfig {
1428
- /**
1429
- * When true, blobs with refCount === 0 are deleted from the backend
1430
- * immediately on release. When false (default), they are retained until
1431
- * an explicit GC sweep via gc(). Lazy GC is safer for offline-first apps.
1432
- */
1433
- eagerEviction?: boolean;
1434
- }
1713
+ /**
1714
+ * Manages the registry of binary blobs.
1715
+ * Uses a hybrid BlobStorage for bytes and records, ensuring atomicity.
1716
+ */
1435
1717
  declare class BlobStore {
1436
1718
  private readonly storage;
1437
- private readonly config;
1438
- private bus;
1439
- /**
1440
- * In-memory cache of BlobRecords. Kept consistent with the backend on
1441
- * every write. Records are small (no bytes), so we cache all of them.
1442
- */
1443
- private readonly recordCache;
1444
- constructor(backend: BlobStorage, bus: EventBus<WorkspaceEvents>, config?: BlobStoreConfig);
1719
+ private readonly cache;
1720
+ private readonly bus;
1721
+ constructor(storage: BlobStorage, cache: LRUCache<SHA256, BlobRecord>, bus: EventBus<WorkspaceEvents>);
1445
1722
  /**
1446
- * Called after any operation that changes the blob registry.
1447
- * Passes the full BlobRecord (or null on deletion). The integration
1448
- * layer wires this to an Index patch that updates the blob index.
1449
- *
1450
- * BlobRecord is a superset of the former BlobSummary — callers
1451
- * that only need summary fields (sha256, mediaType, sizeBytes, etc.)
1452
- * can read them directly from BlobRecord without a separate type.
1723
+ * Registers a new blob. Uses atomic registerBlob if available.
1453
1724
  */
1454
- subscribe<TEventName extends keyof WorkspaceEvents>(event: TEventName, callback: (payload: WorkspaceEvents[TEventName]) => void): () => void;
1455
- init(): Promise<void>;
1456
1725
  register(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<BlobRef, WorkspaceError>>;
1457
1726
  retain(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1458
1727
  release(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1459
- recordRemoteId(sha256: SHA256, providerId: string, fileId: string): Promise<Result<void, WorkspaceError>>;
1460
- getRemoteId(sha256: SHA256, providerId: string): string | null;
1461
- getRemoteRecord(sha256: SHA256, providerId: string): {
1462
- id: string;
1463
- timestamp: Timestamp;
1464
- } | null;
1465
- resolveRef(ref: BlobRef, providerId: string | null): Promise<Result<ResolvedBlob, WorkspaceError>>;
1466
- resolveRefs(refs: BlobRef[], providerId: string | null): Promise<{
1467
- resolved: Map<SHA256, ResolvedBlob>;
1468
- errors: Array<{
1469
- ref: BlobRef;
1470
- error: WorkspaceError;
1471
- }>;
1472
- }>;
1473
- gc(): Promise<number>;
1474
1728
  purge(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1475
- getRecord(sha256: SHA256): BlobRecord | null;
1729
+ recordRemoteId(sha256: SHA256, providerId: string, fileId: string, timestamp?: string): Promise<Result<void, WorkspaceError>>;
1730
+ getRecord(sha256: SHA256): Promise<BlobRecord | null>;
1476
1731
  /**
1477
- * All records — used to seed Index.blobs on init.
1478
- * Returns BlobRecord directly (BlobSummary has been removed).
1479
- */
1480
- getAllRecords(): Record<SHA256, BlobRecord>;
1481
- }
1482
-
1483
- interface CacheConfig {
1484
- roles?: number;
1485
- preferences?: number;
1486
- context?: number;
1487
- tasks?: number;
1488
- }
1489
- interface ContentStoreConfig {
1490
- cache?: CacheConfig;
1491
- }
1492
- declare class ContentStore {
1493
- private readonly db;
1494
- readonly tree: TurnTree;
1495
- readonly blobs: BlobStore;
1496
- private readonly roleCache;
1497
- private readonly preferenceCache;
1498
- private readonly contextCache;
1499
- private readonly taskCache;
1500
- private bus;
1501
- subscribe<TEventName extends keyof WorkspaceEvents>(event: TEventName, callback: (payload: WorkspaceEvents[TEventName]) => void): () => void;
1502
- private constructor();
1503
- static create(db: WorkspaceDatabase, blobStorage: BlobStorage, eventBus: EventBus<WorkspaceEvents>, config?: ContentStoreConfig): Promise<ContentStore>;
1504
- private init;
1505
- getTurnTree(): TurnTree;
1506
- getRole(name: string): Promise<Result<Role, WorkspaceError>>;
1507
- saveRole(role: Role): Promise<void>;
1508
- deleteRole(name: string): Promise<void>;
1509
- getPreference(id: UUID): Promise<Result<Preference, WorkspaceError>>;
1510
- savePreference(preference: Preference): Promise<void>;
1511
- deletePreference(id: UUID): Promise<void>;
1512
- getContext(key: string): Promise<Result<Context, WorkspaceError>>;
1513
- saveContext(context: Context): Promise<void>;
1514
- deleteContext(key: string): Promise<void>;
1515
- getContextByTopics(indexState: Index, topics: string[]): Promise<Context[]>;
1516
- getTask(id: UUID): Promise<Result<Task, WorkspaceError>>;
1517
- saveTask(task: Task): Promise<void>;
1518
- deleteTask(id: UUID): Promise<void>;
1519
- getTasksByTopics(indexState: Index, topics: string[]): Promise<Task[]>;
1520
- saveSession(meta: SessionMeta): Promise<void>;
1521
- updateSessionMeta(sessionId: UUID, patch: DeepPartial<SessionMeta>): Promise<void>;
1522
- deleteSession(sessionId: UUID): Promise<void>;
1523
- registerBlob(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<BlobRef, WorkspaceError>>;
1524
- retainBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1525
- releaseBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1526
- purgeBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1527
- recordBlobRemoteId(sha256: SHA256, providerId: string, fileId: string): Promise<Result<void, WorkspaceError>>;
1528
- getBlobRecord(sha256: SHA256): BlobRecord | null;
1529
- getAllBlobRecords(): Record<SHA256, BlobRecord>;
1530
- getBlobResolver(): BlobStore['resolveRefs'];
1531
- appendTurn(sessionId: UUID, turn: Turn): Promise<Result<Turn, WorkspaceError>>;
1532
- saveTurn(sessionId: UUID, turn: Turn): Promise<Result<Turn, WorkspaceError>>;
1533
- editTurn(sessionId: UUID, turnId: UUID, newBlocks: ContentBlock[], newVersion: number, roleSnapshot?: string): Promise<Result<void, WorkspaceError>>;
1534
- branchTurn(sessionId: UUID, newTurn: Turn): Promise<Result<void, WorkspaceError>>;
1535
- deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<void, WorkspaceError>>;
1536
- copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
1537
- resolveSession(workspace: Workspace, sessionId: UUID, transcript?: Turn[]): Promise<Result<EffectiveSession, WorkspaceError>>;
1538
- gc(): Promise<number>;
1539
- }
1540
-
1541
- declare class WorkspaceManager {
1542
- private readonly contentStore;
1543
- private readonly permissionGuard?;
1544
- private readonly toolRegistry?;
1545
- private readonly processor;
1546
- private bus;
1547
- constructor(options: {
1548
- contentStore: ContentStore;
1549
- permissionGuard?: PermissionGuard;
1550
- toolRegistry?: ToolRegistry;
1551
- eventBus: EventBus<WorkspaceEvents>;
1552
- turnProcessor?: TurnProcessor;
1553
- });
1554
- store(): ContentStore;
1555
- turnProcessor(): TurnProcessor;
1732
+ * All records — used to seed Index.blobs on init.
1733
+ */
1734
+ getAllRecords(): Promise<Record<SHA256, BlobRecord>>;
1735
+ private reference;
1556
1736
  /**
1557
- * Initializes a Workspace's in-memory Index from environment-static
1558
- * sources (like ToolRegistry). Call this when opening a Workspace.
1737
+ * Resolves a BlobRef to a ResolvedBlob (inline or remote) or null.
1738
+ *
1739
+ * Resolution precedence:
1740
+ * 1. adapter provided and remote mapping exists for that adapter → remote blob (no local fallback)
1741
+ * 2. adapter provided but remote mapping missing → local bytes (if available)
1742
+ * 3. no adapter → local bytes (if available)
1743
+ * 4. otherwise → null (unresolvable)
1559
1744
  */
1560
- initTools(_: Workspace): DeepPartial<Workspace>;
1745
+ resolve(ref: BlobRef, adapter?: string): Promise<Result<ResolvedBlob | null, WorkspaceError>>;
1561
1746
  /**
1562
- * Called after any workspace change
1747
+ * Resolves multiple BlobRefs concurrently.
1748
+ * Uses the same optional adapter for all refs (or none).
1563
1749
  */
1564
- subscribe<TEventName extends keyof WorkspaceEvents>(event: TEventName, callback: (payload: WorkspaceEvents[TEventName]) => void): () => void;
1565
- reduce(workspace: Workspace, command: Command): Result<DeepPartial<Workspace>, WorkspaceError>;
1566
- dispatch(workspace: Workspace, command: Command): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1567
- resolveSession(workspace: Workspace, sessionId: UUID, transcript?: Turn[]): Promise<Result<EffectiveSession, WorkspaceError>>;
1568
- private handleContentSideEffects;
1569
- }
1570
-
1571
- interface ContextRelevanceConfig {
1572
- recentMessageWindow?: number;
1573
- minScore?: number;
1574
- freshnessHalfLifeDays?: number;
1575
- }
1576
- interface ContextRankingInput {
1577
- entries: Context[];
1578
- recentMessages: string[];
1579
- config: ContextRelevanceConfig;
1580
- }
1581
- interface ContextRetriever {
1582
- rank(input: ContextRankingInput): Context[];
1583
- }
1584
- interface PlanningInput {
1585
- systemInstructions?: string;
1586
- persona: string;
1587
- preferences: Preference[];
1588
- context: Context[];
1589
- task: Task | null;
1590
- transcript: Turn[];
1591
- budget?: TokenBudget;
1592
- }
1593
- interface PlanningOutput {
1594
- preferences: Preference[];
1595
- context: Context[];
1596
- task: Task | null;
1597
- transcript: Turn[];
1598
- truncated: {
1599
- preferences: number;
1600
- interactions: number;
1601
- context: number;
1602
- };
1603
- breakdown: Record<string, number>;
1604
- totalUsed: number;
1605
- lastRoleBeforeTruncation: string | null;
1606
- }
1607
- interface TokenPlanner {
1608
- plan(input: PlanningInput): PlanningOutput;
1609
- }
1610
- interface AssemblyInput {
1611
- session: EffectiveSession;
1612
- plan: PlanningOutput;
1613
- resolvedBlobs: Map<SHA256, ResolvedBlob>;
1614
- summaryBlockText: string | null;
1615
- warnings: string[];
1616
- conflicts: PreferenceConflict[];
1617
- budgetTotal: number;
1618
- }
1619
- declare class PromptAssembler {
1620
- assemble(input: AssemblyInput): Prompt;
1621
- private buildReferentialBlock;
1622
- private resolveTurnBlocks;
1623
- }
1624
- declare class PromptBuilder {
1625
- private retriever;
1626
- private planner;
1627
- private assembler;
1628
- private summarizer?;
1629
- private blobResolver;
1630
- constructor(dependencies: {
1631
- blobResolver: BlobStore['resolveRefs'];
1632
- retriever?: ContextRetriever;
1633
- planner?: TokenPlanner;
1634
- assembler?: PromptAssembler;
1635
- summarizer?: Summarizer;
1636
- });
1637
- build(session: EffectiveSession, options?: {
1638
- tokenBudget?: TokenBudget;
1639
- relevanceConfig?: ContextRelevanceConfig;
1640
- providerId?: string;
1641
- }): Promise<Prompt>;
1642
- private collectUsedBlobRefs;
1643
- private deduplicateBlobRefs;
1644
- private extractRecentUserQueries;
1645
- private resolvePreferenceConflicts;
1750
+ resolveMany(refs: BlobRef[], adapter?: string): Promise<Result<Map<SHA256, ResolvedBlob>, WorkspaceError>>;
1646
1751
  }
1647
1752
 
1648
- /**
1649
- * A fluent builder for creating Turn objects.
1650
- * This class helps construct a Turn object by adding various content blocks.
1651
- */
1652
- declare class TurnBuilder {
1653
- private readonly _actor;
1654
- private _turn;
1655
- constructor(_actor: TurnActor, initialTurn?: Turn);
1656
- addText(text: string): TurnBuilder;
1657
- addImage(ref?: BlobRef, altText?: string): TurnBuilder;
1658
- addDocument(ref?: BlobRef, title?: string): TurnBuilder;
1659
- addToolUse(name: string, input: Record<string, unknown>): TurnBuilder;
1660
- addToolResult(useId: UUID, content: string | Record<string, unknown>, isError?: boolean): TurnBuilder;
1661
- addSummary(text: string): TurnBuilder;
1662
- addRoleTransition(previousRole: string | null, newRole: string): TurnBuilder;
1663
- addThinking(thinking: string): TurnBuilder;
1753
+ declare class ContextStore {
1754
+ private readonly collection;
1755
+ private readonly cache;
1756
+ constructor(collection: Collection<Context>, cache: LRUCache<string, Context>);
1757
+ get(key: string): Promise<Context | null>;
1758
+ add(context: Context): Promise<void>;
1759
+ list(): Promise<Context[]>;
1760
+ update(key: string, updates: Partial<Context>): Promise<Context | null>;
1761
+ delete(key: string): Promise<boolean>;
1664
1762
  /**
1665
- * Adds a task proposal block.
1666
- * @param title The task title.
1667
- * @param steps Array of step objects (each with text and optional id/status). Status defaults to 'todo'.
1668
- * @param action The action type ('create', 'update', 'complete'). Defaults to 'create'.
1669
- * @param taskId Optional existing task ID (for update/complete).
1670
- */
1671
- addTaskProposal(title: string, steps: {
1672
- text: string;
1673
- status?: 'todo' | 'done';
1674
- ref?: string;
1675
- }[], action?: 'create' | 'update' | 'complete', id?: string): TurnBuilder;
1676
- addBlock(block: ContentBlock): TurnBuilder;
1677
- deleteBlock(blockId: UUID): TurnBuilder;
1678
- editTextBlock(blockId: UUID, newText: string): TurnBuilder;
1679
- withId(id: UUID): TurnBuilder;
1680
- withVersion(version: number): TurnBuilder;
1681
- withTimestamp(timestamp: Timestamp): TurnBuilder;
1682
- withParent(parent: TurnRef): TurnBuilder;
1683
- withRoleSnapshot(roleSnapshot: string): TurnBuilder;
1684
- build(): Turn;
1763
+ * Retrieves all context items referenced by the given topics using the in-memory index.
1764
+ */
1765
+ getByTopics(index: Index, topics: string[]): Promise<Context[]>;
1685
1766
  }
1686
1767
 
1687
- declare class DefaultTurnProcessor implements TurnProcessor {
1688
- private readonly handlers;
1689
- process(turn: Turn, sessionId?: UUID): Command[];
1768
+ declare class PreferenceStore {
1769
+ private readonly collection;
1770
+ private readonly cache;
1771
+ constructor(collection: Collection<Preference>, cache: LRUCache<UUID, Preference>);
1772
+ get(id: UUID): Promise<Preference | null>;
1773
+ add(preference: Preference): Promise<void>;
1774
+ update(id: UUID, updates: Partial<Preference>): Promise<Preference | null>;
1775
+ delete(id: UUID): Promise<boolean>;
1776
+ load(ids: UUID[]): Promise<Preference[]>;
1777
+ list(): Promise<Preference[]>;
1690
1778
  }
1691
1779
 
1692
- declare class Session {
1693
- private readonly sessionId;
1694
- private readonly tree;
1695
- private readonly manager;
1696
- constructor(sessionId: UUID, tree: TurnTree, manager: WorkspaceManager);
1697
- /** Returns the UUID of this session. */
1698
- id(): UUID;
1699
- /**
1700
- * Retrieves the full metadata record for this session from the workspace index.
1701
- */
1702
- meta(workspace: Workspace): SessionMeta | undefined;
1703
- /** Returns the human-readable label for the session. */
1704
- label(workspace: Workspace): string | undefined;
1705
- /** Returns the name of the role currently assigned to this session. */
1706
- private roleName;
1780
+ /**
1781
+ * Atomic store for Role entities.
1782
+ * Receives a pre-resolved Collection and manages its own LRU cache.
1783
+ */
1784
+ declare class RoleStore {
1785
+ private readonly collection;
1786
+ private readonly cache;
1787
+ constructor(collection: Collection<Role>, cache: LRUCache<string, Role>);
1707
1788
  /**
1708
- * Returns the RoleSummary (label, description, etc.) for the session's active role.
1789
+ * Retrieves a role by its unique name.
1709
1790
  */
1710
- role(workspace: Workspace): RoleSummary | undefined;
1711
- /** Returns the list of topics associated with this session. */
1712
- topics(workspace: Workspace): string[];
1713
- /** Returns the list of preference IDs overriding defaults for this session. */
1714
- preferences(workspace: Workspace): UUID[];
1791
+ get(name: string): Promise<Role | null>;
1715
1792
  /**
1716
- * Returns the current "head" pointer (turnId and version) of the conversation DAG.
1793
+ * Adds a new role to the collection.
1717
1794
  */
1718
- head(workspace: Workspace): TurnRef | null;
1795
+ add(role: Role): Promise<void>;
1719
1796
  /**
1720
- * Returns the full Task object if the session is currently linked to a task.
1797
+ * Updates an existing role.
1721
1798
  */
1722
- task(workspace: Workspace): Promise<Task | undefined>;
1799
+ update(name: string, updates: Partial<Role>): Promise<Role | null>;
1723
1800
  /**
1724
- * Returns the TaskSummary if the session is currently linked to a task.
1801
+ * Deletes a role by name.
1725
1802
  */
1726
- taskSummary(workspace: Workspace): TaskSummary | undefined;
1803
+ delete(name: string): Promise<boolean>;
1727
1804
  /**
1728
- * Checks whether the session is linked to any task.
1805
+ * Lists all roles.
1729
1806
  */
1730
- hasTask(workspace: Workspace): boolean;
1807
+ list(): Promise<Role[]>;
1808
+ }
1809
+
1810
+ declare class SessionStore {
1811
+ private readonly collection;
1812
+ private readonly cache;
1813
+ constructor(collection: Collection<SessionMetadata>, cache: LRUCache<UUID, SessionMetadata>);
1814
+ get(id: UUID): Promise<SessionMetadata | null>;
1815
+ add(session: SessionMetadata): Promise<void>;
1816
+ update(id: UUID, updates: Partial<SessionMetadata>): Promise<SessionMetadata | null>;
1817
+ delete(id: UUID): Promise<boolean>;
1818
+ }
1819
+
1820
+ declare class TopicStore {
1821
+ private readonly collection;
1822
+ private readonly cache;
1823
+ constructor(collection: Collection<Topic>, cache: LRUCache<string, Topic>);
1824
+ get(name: string): Promise<Topic | null>;
1825
+ add(topic: Topic): Promise<void>;
1826
+ update(name: string, updates: Partial<Topic>): Promise<Topic | null>;
1827
+ delete(name: string): Promise<boolean>;
1828
+ getMany(names: string[]): Promise<Topic[]>;
1731
1829
  /**
1732
- * Builds the active conversation chain (the current linear history) as an array
1733
- * of TurnNode objects, following the head pointer and parent links.
1830
+ * Checks if a topic is referenced by any entity in the workspace index.
1734
1831
  */
1735
- turns(): Promise<TurnNode[]>;
1832
+ referencedBy(name: string, index: Index): boolean;
1833
+ }
1834
+
1835
+ declare class TurnStore {
1836
+ private readonly collection;
1837
+ private readonly cache;
1838
+ constructor(collection: Collection<Turn>, cache: LRUCache<string, Document<Turn>>);
1839
+ private key;
1840
+ private find;
1841
+ get(key: {
1842
+ id: UUID;
1843
+ session: UUID;
1844
+ version: number;
1845
+ }): Promise<Turn | null>;
1846
+ add(turn: Turn): Promise<void>;
1847
+ update(key: TurnKey, updates: Partial<Turn>): Promise<Turn | null>;
1848
+ listBySession(sessionId: UUID): Promise<Turn[]>;
1849
+ delete(key: TurnKey): Promise<boolean>;
1850
+ }
1851
+
1852
+ interface WorkspaceDatabase {
1736
1853
  /**
1737
- * Returns all sibling turns of the given turn (other turns that share the same parent).
1854
+ * Open the database. Registers core schemas followed by any extension
1855
+ * schemas supplied by the caller (domain plugins).
1856
+ *
1857
+ * Idempotent — safe to call multiple times; subsequent calls are no-ops
1858
+ * if the database is already open.
1738
1859
  */
1739
- siblings(turnId: UUID): Promise<TurnNode[]>;
1860
+ open(extensionSchemas?: SchemaDefinition[]): Promise<void>;
1740
1861
  /**
1741
- * Returns version‑branching information for a given turn, including available versions,
1742
- * current index, and navigation capabilities.
1862
+ * Access a collection by schema name.
1863
+ * Throws if the schema has not been registered.
1743
1864
  */
1744
- branchInfo(turnId: UUID): Promise<BranchInfo>;
1865
+ collection<T>(schemaName: string): Promise<Collection<T>>;
1745
1866
  /**
1746
- * Retrieves a single turn node by its ID from the session graph.
1867
+ * Close the database connection.
1747
1868
  */
1748
- getTurn(turnId: UUID): Promise<TurnNode | undefined>;
1869
+ close(): void;
1870
+ /** get the underlying database connection. */
1871
+ database(): Database;
1872
+ }
1873
+ declare function createWorkspaceDatabase(db: Database): WorkspaceDatabase;
1874
+ /**
1875
+ * Collection name constants
1876
+ * Defines the names of the collections used in the Workspace database.
1877
+ * Use these instead of raw strings throughout the codebase so a typo is a
1878
+ * compile-time error rather than a silent runtime miss.
1879
+ */
1880
+ declare const COLLECTIONS: {
1881
+ readonly ROLE: "role";
1882
+ readonly PREFERENCE: "preference";
1883
+ readonly CONTEXT: "context";
1884
+ readonly SESSION: "session";
1885
+ readonly TURN: "turn";
1886
+ readonly BLOB: "blob";
1887
+ readonly TOPIC: "topic";
1888
+ };
1889
+ type Collections = typeof COLLECTIONS[keyof typeof COLLECTIONS];
1890
+
1891
+ /**
1892
+ * The full set of stores passed to every reducer and middleware call.
1893
+ * Applications extend this with their own stores (e.g., `interface AppContext extends WorkspaceContext`).
1894
+ */
1895
+ type WorkspaceContext<ProjectMetadata extends Record<string, any> = Record<string, any>, IndexExtentions extends Record<string, Record<string, any>> = Record<string, Record<string, any>>, StoreExtensions = any> = {
1896
+ /** Store for managing system personas and roles. */
1897
+ roles: RoleStore;
1898
+ /** Store for managing global and session-level user preferences. */
1899
+ preferences: PreferenceStore;
1900
+ /** Store for managing RAG-retrievable context entries. */
1901
+ context: ContextStore;
1902
+ /** Store for managing active and archived conversation sessions. */
1903
+ sessions: SessionStore;
1904
+ /** Store for managing topic metadata and indexing. */
1905
+ topics: TopicStore;
1906
+ /** Store for managing blob binary data and references. */
1907
+ blobs: BlobStore;
1908
+ /** Store for managing conversation turns and history. */
1909
+ turns: TurnStore;
1910
+ /** Optional registry for managing available tools. */
1911
+ tools?: ToolRegistry;
1912
+ /** The current state of the workspace. */
1913
+ workspace: Workspace<ProjectMetadata, IndexExtentions>;
1914
+ /** The underlying database used by the workspace */
1915
+ db: WorkspaceDatabase;
1916
+ } & StoreExtensions;
1917
+ /**
1918
+ * Ranks and filters context entries by relevance to the current conversation.
1919
+ * The default implementation uses token overlap and recency weighting, but
1920
+ * applications may substitute embedding-based or hybrid retrieval.
1921
+ */
1922
+ interface ContextRetriever {
1749
1923
  /**
1750
- * Changes the session's display label.
1751
- * @param workspace Current workspace state.
1752
- * @param newLabel New human‑readable label.
1753
- * @returns A patch to merge into the workspace state.
1754
- */
1755
- rename(workspace: Workspace, newLabel: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1924
+ * Ranks context entries by relevance to the current conversation.
1925
+ *
1926
+ * @param input - The payload containing entries to rank and context signals.
1927
+ * @param input.entries - All context entries available for this session.
1928
+ * @param input.recentMessages - Recent user message texts used as the query.
1929
+ * @param input.topics - Topics related to this session.
1930
+ * @param input.config - Optional retriever-specific configuration.
1931
+ * @returns Ranked context entries, most relevant first.
1932
+ */
1933
+ rank(input: {
1934
+ entries: Context[];
1935
+ recentMessages: string[];
1936
+ topics: string[];
1937
+ config?: Record<string, any>;
1938
+ }): Context[];
1939
+ }
1940
+ /**
1941
+ * Configuration options for the PromptBuilder execution.
1942
+ */
1943
+ interface PromptBuilderOptions {
1756
1944
  /**
1757
- * Replaces the session's topic list entirely.
1758
- * @param workspace Current workspace state.
1759
- * @param topics New array of topics (overwrites existing).
1760
- * @returns A patch to merge into the workspace state.
1945
+ * Forwarded to ContextRetriever.rank(). Use to tune retrieval behaviour per-call.
1761
1946
  */
1762
- setTopics(workspace: Workspace, topics: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1947
+ retrieverConfig?: Record<string, any>;
1763
1948
  /**
1764
- * Adds topics to the session (union, no duplicates).
1765
- * @param workspace Current workspace state.
1766
- * @param topics Topics to add.
1767
- * @returns A patch to merge into the workspace state.
1949
+ * When true, PromptBuilder will call the Summarizer to compress old turns before returning the Prompt.
1768
1950
  */
1769
- addTopics(workspace: Workspace, topics: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1951
+ summarize?: boolean;
1952
+ }
1953
+ /**
1954
+ * Transforms a SessionSnapshot into a standardized Prompt.
1955
+ * Extracts messages, ranks context, resolves blob references, and handles preference conflicts.
1956
+ * The produced Prompt contains the full resolved data, delegating token truncation to the LLMAdapter.
1957
+ */
1958
+ interface PromptBuilder {
1770
1959
  /**
1771
- * Replaces the session's preference override list entirely.
1772
- * @param workspace Current workspace state.
1773
- * @param preferenceIds New array of preference IDs.
1774
- * @returns A patch to merge into the workspace state.
1960
+ * Builds a standardized Prompt from a SessionSnapshot.
1961
+ *
1962
+ * @param snapshot - Raw session data assembled by Session.
1963
+ * @param ctx - WorkspaceContext for blob and context store access.
1964
+ * @param options - Optional retriever and summarizer configuration.
1965
+ * @returns A Result containing the fully resolved Prompt or a WorkspaceError.
1775
1966
  */
1776
- setPreferences(workspace: Workspace, preferenceIds: UUID[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1967
+ build(snapshot: SessionSnapshot, ctx: WorkspaceContext, options?: PromptBuilderOptions): Promise<Result<Prompt, WorkspaceError>>;
1968
+ }
1969
+ /**
1970
+ * Bridge between a Prompt and a specific LLM provider's SDK.
1971
+ * Owns all model-specific decisions including truncation, token budgeting, formatting, and serialisation.
1972
+ *
1973
+ * @template TRequestParams - Extra params the caller passes to resolve() (e.g. model name, temperature).
1974
+ */
1975
+ interface LLMAdapter<TRequestParams extends Record<string, any> = {}> {
1777
1976
  /**
1778
- * Links the session to a task, or removes the link if taskId is null.
1779
- * @param workspace Current workspace state.
1780
- * @param taskId ID of the task to link, or null to unlink.
1781
- * @returns A patch to merge into the workspace state.
1977
+ * Returns the current state of the adapter. Callable at any time without a prompt.
1978
+ *
1979
+ * @param model - The model whose params we want to query.
1980
+ * @returns The adapter's status, including context windows and rate limits.
1782
1981
  */
1783
- setActiveTask(workspace: Workspace, taskId: UUID | null): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1982
+ status(model?: string): Promise<AdapterStatus>;
1784
1983
  /**
1785
- * Removes the link between the session and its current task (if any).
1786
- * @param workspace Current workspace state.
1787
- * @returns A patch to merge into the workspace state.
1984
+ * Processes a Prompt into a PreparedPrompt — the complete, final representation of what the model will receive.
1985
+ *
1986
+ * @param params - The input prompt and any additional provider-specific parameters.
1987
+ * @returns The prepared, executable prompt bound to the provider's SDK.
1788
1988
  */
1789
- unsetTask(workspace: Workspace): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1989
+ resolve(params: {
1990
+ prompt: Prompt;
1991
+ } & TRequestParams): Promise<PreparedPrompt>;
1992
+ }
1993
+ interface LLMAdapterStatic<TRequestParams extends Record<string, any> = {}> {
1994
+ /** Lists all model profiles that can be used with this adapter. */
1995
+ models(): ModelProfile[];
1996
+ new (...args: any[]): LLMAdapter<TRequestParams>;
1997
+ }
1998
+ interface ModelProfile {
1999
+ /** Provider identifier, e.g. "google". */
2000
+ provider: string;
2001
+ /** Canonical model string as accepted by the API, e.g. "gemini-2.0-flash". */
2002
+ name: string;
2003
+ /** Context window and output limits. */
2004
+ window: AdapterStatus["window"];
2005
+ /** Capability flags. */
2006
+ feature: AdapterStatus["feature"];
2007
+ /** Pricing tiers. */
2008
+ pricing: AdapterStatus["pricing"];
1790
2009
  /**
1791
- * Creates a new session as a fork (copy) of this one.
1792
- * @param workspace Current workspace state.
1793
- * @param newSessionId Unique ID for the new session.
1794
- * @param label Display label for the new session.
1795
- * @param role Optional role override (defaults to current role).
1796
- * @param topics Optional topic override (defaults to current topics).
1797
- * @returns A patch to merge into the workspace state.
2010
+ * Hard rate limit capacity as enforced by the provider.
2011
+ * Does not include runtime state (load, timeout).
1798
2012
  */
1799
- fork(workspace: Workspace, newSessionId: UUID, label: string, role?: string, topics?: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2013
+ capacity: AdapterStatus["rate"]["capacity"];
2014
+ }
2015
+ interface ModelRegistry {
1800
2016
  /**
1801
- * Permanently deletes this session and all its turns from the workspace.
1802
- * @param workspace Current workspace state.
1803
- * @returns A patch to merge into the workspace state.
2017
+ * Returns the profile for a model, or undefined if the model is unknown.
2018
+ * Callers should treat an undefined return as a configuration error.
1804
2019
  */
1805
- delete(workspace: Workspace): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1806
- dispatch(workspace: Workspace, command: Command): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2020
+ get(model: string): ModelProfile | undefined;
2021
+ /** Lists all registered profiles, optionally filtered by provider. */
2022
+ list(provider?: string): ModelProfile[];
1807
2023
  /**
1808
- * Switches the session to a different role.
1809
- * @param workspace Current workspace state.
1810
- * @param newRole Name of the target role (must exist in the workspace).
1811
- * @returns A patch to merge into the workspace state.
2024
+ * Registers or replaces a model profile. Useful for preview models,
2025
+ * fine-tunes, or updated specs that postdate the bundled defaults.
1812
2026
  */
1813
- switchRole(workspace: Workspace, newRole: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2027
+ register(profile: ModelProfile): void;
2028
+ }
2029
+ /**
2030
+ * Analyzes assistant turn output for workspace side effects.
2031
+ * Implementations scan blocks and emit Commands that the Session dispatches.
2032
+ */
2033
+ interface TurnProcessor {
1814
2034
  /**
1815
- * Returns all available roles in the workspace.
2035
+ * Scans an assistant turn for actionable blocks.
2036
+ *
2037
+ * @param turn - The turn containing blocks to process.
2038
+ * @param session - The UUID of the session the turn belongs to.
2039
+ * @returns Commands to dispatch against the workspace.
1816
2040
  */
1817
- listRoles(workspace: Workspace): RoleSummary[];
2041
+ process(turn: {
2042
+ blocks: BaseContentBlock<string>[];
2043
+ }, session: UUID): BaseCommand[];
2044
+ }
2045
+ /**
2046
+ * Compresses old transcript turns to reclaim token budget.
2047
+ */
2048
+ interface Summarizer {
1818
2049
  /**
1819
- * Returns a specific role by name, or undefined if not found.
2050
+ * Compresses older turns into a summary string.
2051
+ *
2052
+ * @param transcript - The full array of turns to evaluate.
2053
+ * @param tokenBudget - The maximum allowed tokens for the context window.
2054
+ * @returns The generated summary string and the uncompressed remaining turns.
1820
2055
  */
1821
- getRole(workspace: Workspace, name: string): RoleSummary | undefined;
2056
+ summarize(transcript: Turn[], tokenBudget: number): Promise<{
2057
+ summary: string;
2058
+ remaining: Turn[];
2059
+ }>;
2060
+ }
2061
+ /**
2062
+ * Manages the registration, tracking, and execution of AI tools.
2063
+ */
2064
+ interface ToolRegistry {
1822
2065
  /**
1823
- * Creates a new role.
1824
- * @param workspace Current workspace state.
1825
- * @param name Unique identifier for the role (e.g., "software-architect").
1826
- * @param label Human-readable display label.
1827
- * @param persona The system prompt / instructions for this role.
1828
- * @param description Optional description.
1829
- * @param preferenceIds Optional array of preference IDs to associate.
1830
- * @returns A patch to merge into the workspace state.
2066
+ * Subscribes to changes in the tool registry.
2067
+ * @param callback - Triggered with the updated list of tool summaries.
1831
2068
  */
1832
- createRole(workspace: Workspace, name: string, label: string, persona: string, description?: string, preferenceIds?: UUID[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2069
+ onRegistryChanged(callback: (tools: ToolSummary[]) => void): void;
1833
2070
  /**
1834
- * Updates an existing role.
1835
- * @param workspace Current workspace state.
1836
- * @param name Name of the role to update (must exist).
1837
- * @param updates Partial updates (label, description, persona, preferences).
1838
- * @returns A patch to merge into the workspace state.
2071
+ * Retrieves all currently registered tools.
2072
+ * @returns An array of ToolSummary definitions.
1839
2073
  */
1840
- updateRole(workspace: Workspace, name: string, updates: Partial<Pick<Role, 'label' | 'description' | 'persona' | 'preferences'>>): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2074
+ list(): ToolSummary[];
1841
2075
  /**
1842
- * Deletes a role. Fails if the role is still referenced by any session.
1843
- * @param workspace Current workspace state.
1844
- * @param name Name of the role to delete.
1845
- * @returns A patch to merge into the workspace state.
2076
+ * Executes a specific tool call request.
2077
+ * @param call - The tool call payload with arguments.
2078
+ * @returns A Result containing the tool's output.
1846
2079
  */
1847
- deleteRole(workspace: Workspace, name: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2080
+ execute<T = any>(call: ToolCall): Promise<Result<T>>;
2081
+ }
2082
+ /**
2083
+ * Secures commands and tool executions by authenticating requests.
2084
+ */
2085
+ interface PermissionGuard {
1848
2086
  /**
1849
- * Saves a constructed Turn object to the session. The turn's parent is automatically
1850
- * set to the current head of the active chain unless overridden in the turn object.
1851
- * @param workspace Current workspace state.
1852
- * @param turn The Turn object (can be built with startTurn()).
1853
- * @returns A patch to merge into the workspace state.
2087
+ * Authenticates a request before execution.
2088
+ * @param request - The authorization request containing a command or tool payload.
2089
+ * @returns A Result with the authenticated payload or undefined if unhandled.
1854
2090
  */
1855
- addTurn(workspace: Workspace, turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1856
- recordUserTurn(workspace: Workspace, turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1857
- recordAssistantTurn(workspace: Workspace, turn: Turn, recordDenial?: boolean): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1858
- private buildDenialTurn;
1859
- private describeCommand;
2091
+ authenticate(request: AuthRequest): Promise<Result<null>>;
2092
+ }
2093
+ type BlobResolver = (ref: BlobRef, provider?: string) => Promise<Result<ResolvedBlob | null, WorkspaceError>>;
2094
+
2095
+ declare class WorkspaceManager {
2096
+ private registry;
2097
+ private middlewares;
2098
+ private serializer;
2099
+ private bus;
2100
+ private _getWorkspace;
2101
+ private updateWorkspace;
2102
+ private guard?;
2103
+ private readonly _ctx;
2104
+ constructor(params: {
2105
+ ctx: Omit<WorkspaceContext, "workspace">;
2106
+ getWorkspace: () => Workspace;
2107
+ updateWorkspace: (workspace: DeepPartial<Workspace>) => Promise<void>;
2108
+ guard?: PermissionGuard;
2109
+ bus: EventBus<WorkspaceEvents>;
2110
+ });
1860
2111
  /**
1861
- * Creates a new version of an existing turn with updated content.
1862
- * @param workspace Current workspace state.
1863
- * @param turnId ID of the turn to edit.
1864
- * @param newBlocks New content blocks for the turn.
1865
- * @param roleSnapshot Optional role name to record with this version.
1866
- * @returns A patch to merge into the workspace state.
2112
+ * Registers a reducer for a specific command type.
2113
+ * @param reducer The reducer function to handle the command.
2114
+ * @returns The WorkspaceManager instance for chaining.
1867
2115
  */
1868
- editTurn(workspace: Workspace, turnId: UUID, newBlocks: ContentBlock[], roleSnapshot?: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2116
+ register(type: string, reducer: WorkspaceReducer): this;
1869
2117
  /**
1870
- * Creates a new branch from a specific turn (the parent must be set on the turn).
1871
- * @param workspace Current workspace state.
1872
- * @param turn The new turn that continues from an existing parent.
1873
- * @returns A patch to merge into the workspace state.
2118
+ * Registers a middleware function.
2119
+ * @param middleware The middleware function to apply.
2120
+ * @returns The WorkspaceManager instance for chaining.
1874
2121
  */
1875
- branch(workspace: Workspace, turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2122
+ use(middleware: WorkspaceMiddleware): this;
1876
2123
  /**
1877
- * Deletes a specific version of a turn and all its descendants.
1878
- * @param workspace Current workspace state.
1879
- * @param turnId ID of the turn to delete.
1880
- * @param version Version number of the turn to delete.
1881
- * @param newHead Optional new head pointer after deletion.
1882
- * @returns A patch to merge into the workspace state.
2124
+ * Retrieves the current state of the workspace.
2125
+ * @returns The current Workspace state.
1883
2126
  */
1884
- deleteTurn(workspace: Workspace, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2127
+ workspace(): Workspace;
1885
2128
  /**
1886
- * Switch to the previous version of a turn (if available).
1887
- * This changes the active chain head but does not create new data.
1888
- * @param workspace Current workspace state.
1889
- * @param turnId ID of the turn whose version to switch.
1890
- * @returns A patch to merge into the workspace state.
2129
+ * Dispatches a command to modify the workspace state.
2130
+ * It ensures commands are processed sequentially and applies middleware.
2131
+ * @param command The command to dispatch.
2132
+ * @returns A promise resolving to the DeepPartial<Workspace> representing the applied patch.
1891
2133
  */
1892
- switchVersionLeft(workspace: Workspace, turnId: UUID): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2134
+ dispatch(command: BaseCommand): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1893
2135
  /**
1894
- * Switch to the next version of a turn (if available).
1895
- * This changes the active chain head but does not create new data.
1896
- * @param workspace Current workspace state.
1897
- * @param turnId ID of the turn whose version to switch.
1898
- * @returns A patch to merge into the workspace state.
2136
+ * Subscribes to workspace events.
2137
+ * @param event The event name to subscribe to.
2138
+ * @param listener The callback function to execute when the event is emitted.
2139
+ * @returns unsubscribe
1899
2140
  */
1900
- switchVersionRight(workspace: Workspace, turnId: UUID): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1901
- private switchVersion;
1902
- addPreference(workspace: Workspace, content: string, topics: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1903
- listPreferences(workspace: Workspace): Promise<PreferenceSummary[]>;
1904
- addContext(workspace: Workspace, key: string, content: ContextContent, topics: string[], metadata?: Record<string, any>): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1905
- listContextSummaries(workspace: Workspace): Promise<ContextSummary[]>;
1906
- /**
1907
- * Registers a new blob in the workspace and returns its SHA256 and BlobRef.
1908
- * This dispatches a blob:register command and extracts the resulting SHA256
1909
- * from the returned workspace patch.
1910
- */
1911
- registerBlob(workspace: Workspace, data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<{
2141
+ subscribe<K extends keyof WorkspaceEvents>(event: K, listener: (payload: WorkspaceEvents[K]) => void): () => void;
2142
+ ctx(): WorkspaceContext;
2143
+ }
2144
+
2145
+ declare class WorkspaceApi {
2146
+ private readonly manager;
2147
+ constructor(manager: WorkspaceManager);
2148
+ private get workspace();
2149
+ roles(): Promise<Role[]>;
2150
+ role(name: string): Promise<Role | null>;
2151
+ createRole(name: string, label: string, persona: string, description?: string, preferenceIds?: UUID[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2152
+ updateRole(name: string, updates: Partial<Pick<Role, "label" | "description" | "persona" | "preferences">>): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2153
+ deleteRole(name: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2154
+ addPreference(content: string, topics: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2155
+ preferences(): Promise<Preference[]>;
2156
+ addContext(key: string, content: ContextContent, topics: string[], metadata?: Record<string, any>): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2157
+ context(): Promise<Context[]>;
2158
+ registerBlob(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<{
1912
2159
  sha256: SHA256;
1913
2160
  ref: BlobRef;
1914
2161
  }, WorkspaceError>>;
2162
+ }
2163
+
2164
+ declare class Session {
2165
+ private readonly _id;
2166
+ private readonly manager;
2167
+ private readonly processor;
2168
+ private readonly turnRepository;
2169
+ /** Global workspace operations available under session.workspace */
2170
+ readonly workspace: WorkspaceApi;
2171
+ private _role;
2172
+ private _preferences;
2173
+ private tree;
2174
+ private constructor();
2175
+ static create(sessionId: UUID, manager: WorkspaceManager, processor: TurnProcessor): Promise<Session>;
2176
+ private _setRole;
2177
+ private _setPreference;
2178
+ id(): UUID;
2179
+ private ws;
2180
+ meta(): SessionMetadata | undefined;
2181
+ label(): string | undefined;
2182
+ role(): Role | undefined;
2183
+ topics(): string[];
2184
+ preferences(): Preference[];
2185
+ head(): TurnRef | null;
2186
+ turns(): TurnNode[];
2187
+ siblings(turnId: UUID): Promise<TurnNode[]>;
2188
+ branchInfo(turnId: UUID): Promise<BranchInfo>;
2189
+ getTurn(turnId: UUID): Promise<TurnNode | undefined>;
2190
+ rename(newLabel: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2191
+ setTopics(topics: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2192
+ addTopics(topics: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2193
+ setPreferences(preferenceIds: UUID[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2194
+ fork(newSessionId: UUID, label: string, role?: string, topics?: string[]): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2195
+ dispatch(command: BaseCommand): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2196
+ switchRole(newRole: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2197
+ addTurn(turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2198
+ recordUserTurn(turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2199
+ recordAssistantTurn(turn: Turn, recordDenial?: boolean): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2200
+ private buildDenialTurn;
2201
+ private describeCommand;
2202
+ editTurn(turnId: UUID, newBlocks: ContentBlock[], roleSnapshot?: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2203
+ branch(turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2204
+ deleteTurn(turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2205
+ switchVersionLeft(turnId: UUID): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2206
+ switchVersionRight(turnId: UUID): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
2207
+ private switchVersion;
1915
2208
  /**
1916
- * Resolves the session into an EffectiveSession object, which bundles the
1917
- * session metadata, role, preferences, context, transcript, and linked task.
1918
- * @param workspace Current workspace state.
1919
- * @returns The resolved effective session or an error.
2209
+ * Assembles a SessionSnapshot from in-memory state for PromptBuilder.
2210
+ *
2211
+ * This is the handoff point between Session (state management) and
2212
+ * PromptBuilder (prompt preparation). Session's responsibility ends here.
2213
+ *
2214
+ * The only async step is loading context entries by topic from the store.
2215
+ * Role and preferences are already in memory from open().
2216
+ *
2217
+ * Returns undefined if the session no longer exists in the workspace index.
1920
2218
  */
1921
- resolve(workspace: Workspace): Promise<Result<EffectiveSession, WorkspaceError>>;
2219
+ snapshot(): Promise<SessionSnapshot | undefined>;
2220
+ private refreshTurnTree;
1922
2221
  private findSubtreeTip;
1923
2222
  }
1924
2223
 
1925
- interface SessionManagerConfig {
1926
- }
1927
- interface OpenResult {
1928
- session: Session;
1929
- patch: DeepPartial<Workspace>;
1930
- }
1931
2224
  declare class SessionManager {
1932
- private readonly workspaceManager;
1933
- private readonly contentStore;
1934
- constructor(workspaceManager: WorkspaceManager, contentStore: ContentStore);
1935
- /**
1936
- * Returns an array of all session metadata entries in the workspace.
1937
- */
1938
- list(workspace: Workspace): SessionMeta[];
1939
- /**
1940
- * Retrieves the metadata for a specific session without hydrating a Session object.
1941
- */
1942
- meta(workspace: Workspace, sessionId: UUID): SessionMeta | undefined;
1943
- /**
1944
- * Creates a new session and returns a hydrated Session instance.
1945
- * This method dispatches a 'session:create' command which is validated by the
1946
- * reducer (checking for unique IDs and valid roles) and persisted
1947
- * to the content store.
1948
- */
1949
- create(workspace: Workspace, params: {
2225
+ private readonly manager;
2226
+ private readonly processor;
2227
+ private openOnce;
2228
+ constructor(manager: WorkspaceManager, processor: TurnProcessor);
2229
+ open(sessionId: UUID): Promise<Session>;
2230
+ close(sessionId: UUID): void;
2231
+ delete(sessionId: UUID): Promise<Result<undefined, WorkspaceError>>;
2232
+ create(params: {
1950
2233
  label: string;
1951
- role?: string;
1952
- topics?: string[];
2234
+ role: string;
2235
+ topics: string[];
1953
2236
  preferences?: UUID[];
1954
- }): Promise<Result<OpenResult, WorkspaceError>>;
1955
- open(workspace: Workspace, sessionId: UUID): Promise<Result<OpenResult, WorkspaceError>>;
1956
- get workspace(): WorkspaceManager;
1957
- close(_: Session): Promise<void>;
2237
+ }): Promise<Session>;
2238
+ list(): SessionMetadata[];
2239
+ metadata(sessionId: UUID): SessionMetadata | undefined;
1958
2240
  }
1959
2241
 
1960
2242
  /**
1961
- * In-process implementation backed by plain Maps.
1962
- * Suitable for development, testing, and server-side runtimes without
1963
- * access to IndexedDB.
2243
+ * A fluent builder for creating Turn objects.
2244
+ * This class helps construct a Turn object by adding various content blocks.
1964
2245
  */
1965
- declare class MemoryBlobStorage implements BlobStorage {
1966
- private readonly bytes;
1967
- private readonly records;
1968
- storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
1969
- loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
1970
- hasBytes(sha256: SHA256): Promise<boolean>;
1971
- deleteBytes(sha256: SHA256): Promise<void>;
1972
- saveRecord(record: BlobRecord): Promise<void>;
1973
- loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
1974
- deleteRecord(sha256: SHA256): Promise<void>;
1975
- listRecords(): Promise<BlobRecord[]>;
1976
- exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
1977
- /**
1978
- * Atomic register for MemoryBlobStorage — sequential ops are atomic
1979
- * in a single-threaded JS runtime, so this is equivalent to two separate
1980
- * calls, but we implement it for interface consistency.
1981
- */
1982
- registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
2246
+ declare class TurnBuilder {
2247
+ private readonly _actor;
2248
+ private _turn;
2249
+ constructor(_actor: SystemActor, session: string, initialTurn?: Turn);
2250
+ addText(text: string): TurnBuilder;
2251
+ addImage(ref?: BlobRef, altText?: string): TurnBuilder;
2252
+ addDocument(ref?: BlobRef, title?: string): TurnBuilder;
2253
+ addToolUse(name: string, input: Record<string, unknown>): TurnBuilder;
2254
+ addToolResult(useId: UUID, content: string | Record<string, unknown>, isError?: boolean): TurnBuilder;
2255
+ addSummary(text: string): TurnBuilder;
2256
+ addRoleTransition(previousRole: string | undefined, newRole: string): TurnBuilder;
2257
+ addThinking(thinking: string): TurnBuilder;
2258
+ addBlock(block: ContentBlock): TurnBuilder;
2259
+ deleteBlock(blockId: UUID): TurnBuilder;
2260
+ editTextBlock(blockId: UUID, newText: string): TurnBuilder;
2261
+ withId(id: UUID): TurnBuilder;
2262
+ withVersion(version: number): TurnBuilder;
2263
+ withTimestamp(timestamp: Timestamp): TurnBuilder;
2264
+ withParent(parent: TurnRef): TurnBuilder;
2265
+ withRoleSnapshot(roleSnapshot: string): TurnBuilder;
2266
+ build(): Turn;
1983
2267
  }
1984
2268
 
1985
- interface IndexedDBBlobConfig {
1986
- /** Name of the IndexedDB database. Defaults to 'aiworkspace-blobs'. */
1987
- dbName?: string;
2269
+ declare class TurnRepository {
2270
+ private readonly turnStore;
2271
+ private readonly sessionStore;
2272
+ constructor(turnStore: TurnStore, sessionStore: SessionStore);
2273
+ loadAllTurns(sessionId: UUID): Promise<Turn[]>;
2274
+ loadHead(sessionId: UUID): Promise<TurnRef | null>;
2275
+ }
2276
+
2277
+ declare class TurnTree {
2278
+ private readonly nodes;
2279
+ private readonly _head;
2280
+ private constructor();
2281
+ static build(sessionId: UUID, repository: TurnRepository): Promise<TurnTree>;
2282
+ head(): TurnRef | null;
2283
+ chain(): TurnNode[];
2284
+ getTurnSiblings(turnId: UUID): TurnNode[];
2285
+ branchInfo(turnId: UUID): BranchInfo;
2286
+ graph(): Readonly<Record<UUID, TurnNode>>;
1988
2287
  }
2288
+
2289
+ declare function success<T>(value: T): Result<T, never>;
2290
+ declare function ok<T>(value: T): Result<T, never>;
2291
+ declare function error<E extends WorkspaceError>(err: E): Result<never, E>;
2292
+ declare function omitNullUndefined<T extends Record<string, any>>(obj: T): Partial<T>;
2293
+ declare function del<T>(): T;
2294
+ declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
2295
+ declare function computeSHA256(data: Uint8Array): Promise<SHA256>;
1989
2296
  /**
1990
- * IndexedDB-backed blob storage.
1991
- *
1992
- * Bytes are stored as raw Uint8Array IndexedDB handles binary natively,
1993
- * no base64 encoding at rest. This is important for large files.
1994
- *
1995
- * Transaction discipline: never await inside an active transaction.
1996
- * All multi-step operations chain synchronous IDB request handlers
1997
- * inside a single Promise.
2297
+ * Converts a Uint8Array to a Base64 string.
2298
+ * Uses native Buffer in Node.js/Deno, and falls back to a chunked btoa()
2299
+ * implementation for Browsers and Edge environments to avoid stack overflows.
1998
2300
  */
1999
- declare class IndexedDBBlobStorage implements BlobStorage {
2000
- private readonly dbName;
2001
- private db;
2002
- constructor(config?: IndexedDBBlobConfig);
2003
- open(): Promise<void>;
2004
- private createSchema;
2005
- close(): void;
2006
- deleteDatabase(): Promise<void>;
2007
- private getDB;
2008
- private readTx;
2009
- private writeTx;
2010
- storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
2011
- loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
2012
- hasBytes(sha256: SHA256): Promise<boolean>;
2013
- deleteBytes(sha256: SHA256): Promise<void>;
2014
- saveRecord(record: BlobRecord): Promise<void>;
2015
- loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
2016
- deleteRecord(sha256: SHA256): Promise<void>;
2017
- listRecords(): Promise<BlobRecord[]>;
2018
- exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
2019
- /**
2020
- * Atomically stores bytes and saves a record together.
2021
- * Preferred over calling storeBytes + saveRecord separately when both
2022
- * are new — avoids a window where bytes exist without a record.
2023
- */
2024
- registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
2025
- }
2301
+ declare function bufferToBase64(buffer: Uint8Array): string;
2302
+ /**
2303
+ * Short, deterministic hash of a string (4 chars in base36).
2304
+ * Suitable for AI-friendly reference tokens.
2305
+ */
2306
+ declare function shortHash(s: string, length?: number): string;
2307
+ declare function getExtension<K extends string, V>(index: Index, key: K): Record<string, V>;
2026
2308
 
2027
- declare class GoogleGenAIAdapter implements LLMAdapter<{
2028
- model: string;
2029
- }, GenerateContentParameters, GenerateContentResponse> {
2030
- private _;
2031
- constructor(_: GoogleGenAI);
2032
- /**
2033
- * Converts a Prompt into a GenerateContentRequest for @google/genai.
2034
- */
2035
- prepare({ prompt, model }: {
2036
- prompt: Prompt;
2037
- model: string;
2038
- }): Promise<{
2039
- request: {
2040
- model: string;
2041
- contents: _google_genai.Content[];
2042
- config: {
2043
- systemInstruction: _google_genai.Content;
2044
- thinkingConfig: {
2045
- includeThoughts: boolean;
2046
- };
2047
- responseMimeType: string;
2048
- responseSchema: _google_genai.Schema;
2049
- };
2050
- };
2051
- }>;
2052
- /**
2053
- * Parses the GenerateContentResponse into a Turn (assistant turn).
2054
- */
2055
- parse({ response }: {
2056
- response: GenerateContentResponse;
2057
- }): Result<Turn, WorkspaceError>;
2309
+ interface CreateWorkspaceParams {
2310
+ db: Database;
2311
+ blobStorage: BlobStorage;
2312
+ eventBus?: EventBus<WorkspaceEvents>;
2313
+ getWorkspace: () => Workspace;
2314
+ setWorkspace: (workspace: DeepPartial<Workspace>) => Promise<void>;
2315
+ processor: TurnProcessor;
2316
+ guard?: PermissionGuard;
2317
+ toolRegistry?: ToolRegistry;
2318
+ extensionSchemas?: SchemaDefinition[];
2319
+ extensionReducers?: Record<string, WorkspaceReducer<any>>;
2320
+ extensionMiddleware?: WorkspaceMiddleware[];
2321
+ extensionStores?: (ctx: Omit<WorkspaceContext, "workspace">) => Record<string, any>;
2058
2322
  }
2323
+ /**
2324
+ * Boot factory for the Workspace library.
2325
+ * Resolves all collections and initializes entity stores.
2326
+ */
2327
+ declare function createWorkspace(params: CreateWorkspaceParams): Promise<{
2328
+ manager: WorkspaceManager;
2329
+ sessions: SessionManager;
2330
+ ctx: Omit<any, "workspace">;
2331
+ }>;
2059
2332
 
2060
- export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTask, type AddTurn, type AuthRequest, type BackendError, type BaseCommand, type BlobCommand, type BlobError, type BlobMediaType, type BlobRecord, type BlobRef, type BlobStorage, BlobStore, type BlobStoreConfig, type BranchInfo, type BranchTurn, COLLECTIONS, type CallTool, type CollectionName, type Command, type ContentBlock, ContentStore, type Context, type ContextContent, type ContextSummary, type CreateSession, type CreateWorkspace, DefaultTurnProcessor, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTask, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type DuplicateKeyError, EMPTY_SYSTEM_ROLE, type EditTurn, type EffectiveSession, type ForkSession, GoogleGenAIAdapter, type ImageBlock, type ImageMediaType, type Index, type IndexedDBBlobConfig, IndexedDBBlobStorage, type InvalidCommandError, type LLMAdapter, MemoryBlobStorage, type NotFoundError, type OpenResult, type OverrideSessionPreferences, type PermissionDeniedError, type PermissionGuard, type Preference, type PreferenceConflict, type PreferenceSummary, type Project, type Prompt, PromptBuilder, type PurgeBlob, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type Result, type RetainBlob, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, type SaveTurn, Session, SessionManager, type SessionManagerConfig, type SessionMeta, type Settings, type Summarizer, type SummaryBlock, type SwitchRole, type Task, type TaskProposalBlock, type TaskRef, type TaskStatus, type TaskStep, type TaskSummary, type TextBlock, type ThinkingBlock, type Timestamp, type TokenBudget, type ToolCall, type ToolRegistry, type ToolResultBlock, type ToolSummary, type ToolUseBlock, type TopicIndex, type Turn, type TurnActor, TurnBuilder, type TurnNode, type TurnProcessor, type TurnRef, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type UpdateSession, type UpdateTask, type Workspace, type WorkspaceBundle, type WorkspaceDatabase, type WorkspaceError, type WorkspaceEvents, WorkspaceManager, bufferToBase64, computeSHA256, createEmptyRole, createProjectWorkspace, createSimpleWorkspace, createWorkspaceDatabase, del, error, extractBlobRecord, extractBlobRef, generateTaskRef, generateTaskStepRef, merge, omitNullUndefined, shortHash, success };
2333
+ export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTopic, type AddTurn, type AuthRequest, type BackendError, type BaseCommand, type BaseContentBlock, type BlobCommand, type BlobError, type BlobMediaType, type BlobRecord, type BlobRef, type BlobResolver, type BranchInfo, type BranchTurn, COLLECTIONS, type Collections, type Command, type ContentBlock, type Context, type ContextContent, type ContextRetriever, type ContextSummary, type CreateSession, type CreateWorkspace, type CreateWorkspaceParams, type DeepPartial, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTopic, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type DuplicateKeyError, EMPTY_SYSTEM_ROLE, type EditTurn, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type IndexExtensions, type InvalidCommandError, type LLMAdapter, type LLMAdapterStatic, LRUCache, type MergeTopics, type ModelConstraint, type ModelConstraintMap, type ModelName, type ModelProfile, type ModelRegistry, type NotFoundError, type OverrideSessionPreferences, type PermissionDeniedError, type PermissionGuard, type Preference, type PreferenceSummary, type Project, type PromptBuilder, type PromptBuilderOptions, type PurgeBlob, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type ResolvedSession, type Result, type RetainBlob, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, Session, SessionManager, type SessionMetadata, type SessionSnapshot, type Settings, type Summarizer, type SummaryBlock, type SwitchSessionRole, type SystemActor, type TextBlock, type ThinkingBlock, type Timestamp, type ToolCall, type ToolCallCommand, type ToolRegistry, type ToolResultBlock, type ToolSummary, type ToolUseBlock, type Topic, type TopicIndex, type Turn, TurnBuilder, type TurnKey, type TurnNode, type TurnProcessor, type TurnRef, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type UpdateSession, type UpdateTopic, type UpdateTurn, type Workspace, type WorkspaceBundle, type WorkspaceContext, type WorkspaceDatabase, type WorkspaceError, type WorkspaceEvents, WorkspaceManager, type WorkspaceMiddleware, type WorkspaceReducer, bufferToBase64, computeSHA256, createWorkspace, createWorkspaceDatabase, del, error, getExtension, merge, ok, omitNullUndefined, shortHash, success };