@asaidimu/utils-workspace 1.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +274 -322
- package/index.d.mts +938 -426
- package/index.d.ts +938 -426
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +5 -1
package/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { QueryFilter, PaginationOptions } from '@asaidimu/query';
|
|
2
|
+
import { SchemaDefinition, SchemaChange, DataTransform } from '@asaidimu/anansi';
|
|
3
|
+
|
|
1
4
|
type UUID = string;
|
|
2
5
|
type Timestamp = string;
|
|
3
6
|
type URI = string;
|
|
@@ -9,8 +12,6 @@ type Result<T, E = WorkspaceError> = {
|
|
|
9
12
|
ok: false;
|
|
10
13
|
error: E;
|
|
11
14
|
};
|
|
12
|
-
declare function ok<T>(value: T): Result<T, never>;
|
|
13
|
-
declare function err<E = WorkspaceError>(error: E): Result<never, E>;
|
|
14
15
|
type WorkspaceError = {
|
|
15
16
|
code: 'DUPLICATE_KEY';
|
|
16
17
|
resource: string;
|
|
@@ -31,7 +32,7 @@ type WorkspaceError = {
|
|
|
31
32
|
};
|
|
32
33
|
interface Settings {
|
|
33
34
|
language: string;
|
|
34
|
-
defaultRole
|
|
35
|
+
defaultRole?: string;
|
|
35
36
|
prompt?: string;
|
|
36
37
|
}
|
|
37
38
|
interface Project {
|
|
@@ -43,13 +44,12 @@ interface Project {
|
|
|
43
44
|
type ImageMediaType = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp';
|
|
44
45
|
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';
|
|
45
46
|
type BlobMediaType = ImageMediaType | DocumentMediaType;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
47
|
+
/**
|
|
48
|
+
* Lightweight pointer to a blob — the subset of BlobRecord that content
|
|
49
|
+
* blocks and context entries carry. Use this at call sites that only need
|
|
50
|
+
* to reference a blob, not inspect its registry metadata.
|
|
51
|
+
*/
|
|
52
|
+
type BlobRef = Pick<BlobRecord, 'sha256' | 'mediaType' | 'sizeBytes' | 'filename' | 'previewUrl'>;
|
|
53
53
|
type ResolvedBlob = {
|
|
54
54
|
kind: 'inline';
|
|
55
55
|
sha256: SHA256;
|
|
@@ -62,37 +62,35 @@ type ResolvedBlob = {
|
|
|
62
62
|
fileId: string;
|
|
63
63
|
providerId: string;
|
|
64
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* Full registry entry for a blob. BlobRef is a Pick of this type, so
|
|
67
|
+
* a BlobRecord is always assignable to BlobRef.
|
|
68
|
+
*/
|
|
65
69
|
interface BlobRecord {
|
|
66
70
|
sha256: SHA256;
|
|
67
71
|
mediaType: BlobMediaType;
|
|
68
72
|
sizeBytes: number;
|
|
69
73
|
filename?: string;
|
|
74
|
+
previewUrl?: string;
|
|
70
75
|
refCount: number;
|
|
71
76
|
remoteIds: Record<string, string>;
|
|
72
77
|
createdAt: Timestamp;
|
|
73
78
|
lastUsedAt: Timestamp;
|
|
74
79
|
}
|
|
75
|
-
interface BlobSummary {
|
|
76
|
-
sha256: SHA256;
|
|
77
|
-
mediaType: BlobMediaType;
|
|
78
|
-
sizeBytes: number;
|
|
79
|
-
filename?: string;
|
|
80
|
-
refCount: number;
|
|
81
|
-
createdAt: Timestamp;
|
|
82
|
-
lastUsedAt: Timestamp;
|
|
83
|
-
}
|
|
84
80
|
interface TextBlock {
|
|
85
81
|
type: 'text';
|
|
86
82
|
text: string;
|
|
87
83
|
}
|
|
88
84
|
interface ImageBlock {
|
|
89
85
|
type: 'image';
|
|
90
|
-
|
|
86
|
+
ref?: BlobRef;
|
|
87
|
+
blob?: ResolvedBlob;
|
|
91
88
|
altText?: string;
|
|
92
89
|
}
|
|
93
90
|
interface DocumentBlock {
|
|
94
91
|
type: 'document';
|
|
95
|
-
|
|
92
|
+
ref?: BlobRef;
|
|
93
|
+
blob?: ResolvedBlob;
|
|
96
94
|
title?: string;
|
|
97
95
|
}
|
|
98
96
|
interface ToolUseBlock {
|
|
@@ -111,7 +109,16 @@ interface ThinkingBlock {
|
|
|
111
109
|
type: 'thinking';
|
|
112
110
|
thinking: string;
|
|
113
111
|
}
|
|
114
|
-
|
|
112
|
+
interface SummaryBlock {
|
|
113
|
+
type: 'summary';
|
|
114
|
+
text: string;
|
|
115
|
+
}
|
|
116
|
+
interface RoleTransitionBlock {
|
|
117
|
+
type: 'role_transition';
|
|
118
|
+
previousRole: string | null;
|
|
119
|
+
newRole: string;
|
|
120
|
+
}
|
|
121
|
+
type ContentBlock = TextBlock | ImageBlock | DocumentBlock | ToolUseBlock | ToolResultBlock | SummaryBlock | RoleTransitionBlock | ThinkingBlock;
|
|
115
122
|
type TurnRole = 'user' | 'assistant' | 'tool';
|
|
116
123
|
interface Turn {
|
|
117
124
|
id: UUID;
|
|
@@ -119,75 +126,89 @@ interface Turn {
|
|
|
119
126
|
role: TurnRole;
|
|
120
127
|
blocks: ContentBlock[];
|
|
121
128
|
timestamp: Timestamp;
|
|
129
|
+
/**
|
|
130
|
+
* The name of the role active when this turn was recorded.
|
|
131
|
+
* Snapshot so history is stable even if the role is later renamed.
|
|
132
|
+
*/
|
|
122
133
|
roleSnapshot?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Parent pointer. Null for root turns.
|
|
136
|
+
* This is plain data stored on the document — the DAG is reconstructed
|
|
137
|
+
* in memory by TurnTree.buildNodeGraph() at session open time.
|
|
138
|
+
*/
|
|
123
139
|
parent: {
|
|
124
140
|
id: UUID;
|
|
125
141
|
version: number;
|
|
126
142
|
} | null;
|
|
143
|
+
/**
|
|
144
|
+
* Partition key. Stored on the Turn document so Collection.filter
|
|
145
|
+
* can retrieve all turns for a session in a single query.
|
|
146
|
+
* Not present on Turn objects used purely in memory (e.g. dirty buffer).
|
|
147
|
+
*/
|
|
148
|
+
sessionId?: UUID;
|
|
127
149
|
}
|
|
128
|
-
interface
|
|
150
|
+
interface TurnNode {
|
|
129
151
|
id: UUID;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
152
|
+
versions: Record<number, Turn>;
|
|
153
|
+
activeVersion: number;
|
|
154
|
+
role: TurnRole;
|
|
155
|
+
blocks: ContentBlock[];
|
|
156
|
+
timestamp: Timestamp;
|
|
157
|
+
roleSnapshot?: string;
|
|
158
|
+
parent: {
|
|
159
|
+
id: UUID;
|
|
160
|
+
version: number;
|
|
161
|
+
} | null;
|
|
162
|
+
children: Record<number, UUID[]>;
|
|
136
163
|
}
|
|
137
|
-
interface
|
|
164
|
+
interface BranchInfo {
|
|
165
|
+
versions: number[];
|
|
166
|
+
currentIndex: number;
|
|
167
|
+
total: number;
|
|
168
|
+
hasPrev: boolean;
|
|
169
|
+
hasNext: boolean;
|
|
170
|
+
}
|
|
171
|
+
interface Role {
|
|
138
172
|
name: string;
|
|
139
173
|
label: string;
|
|
140
174
|
description?: string;
|
|
141
|
-
|
|
175
|
+
persona: string;
|
|
176
|
+
preferences: UUID[];
|
|
142
177
|
}
|
|
143
|
-
interface
|
|
178
|
+
interface Preference {
|
|
144
179
|
id: UUID;
|
|
180
|
+
content: string;
|
|
145
181
|
topics: string[];
|
|
146
182
|
timestamp: Timestamp;
|
|
147
|
-
snippet?: string;
|
|
148
183
|
}
|
|
149
|
-
|
|
184
|
+
type ContextContent = {
|
|
185
|
+
kind: 'text';
|
|
186
|
+
value: string;
|
|
187
|
+
} | {
|
|
188
|
+
kind: 'json';
|
|
189
|
+
value: unknown;
|
|
190
|
+
} | {
|
|
191
|
+
kind: 'blob';
|
|
192
|
+
sha256: SHA256;
|
|
193
|
+
mediaType: BlobMediaType;
|
|
194
|
+
sizeBytes: number;
|
|
195
|
+
filename?: string;
|
|
196
|
+
} | {
|
|
197
|
+
kind: 'remote';
|
|
198
|
+
uri: URI;
|
|
199
|
+
mediaType?: BlobMediaType;
|
|
200
|
+
};
|
|
201
|
+
interface Context {
|
|
150
202
|
key: string;
|
|
151
203
|
topics: string[];
|
|
204
|
+
content: ContextContent;
|
|
152
205
|
timestamp: Timestamp;
|
|
153
|
-
mime?: string;
|
|
154
|
-
size?: number;
|
|
155
|
-
preview?: string;
|
|
156
|
-
source?: string;
|
|
157
206
|
metadata?: Record<string, any>;
|
|
158
207
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
metadata?: {
|
|
164
|
-
created?: Timestamp;
|
|
165
|
-
updated?: Timestamp;
|
|
166
|
-
entries?: number;
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
interface Indexes {
|
|
170
|
-
sessions: Record<UUID, SessionSummary>;
|
|
171
|
-
roles: Record<string, RoleSummary>;
|
|
172
|
-
preferences: Record<UUID, PreferenceSummary>;
|
|
173
|
-
context: Record<string, ContextSummary>;
|
|
174
|
-
topics: Record<string, TopicIndex>;
|
|
175
|
-
}
|
|
176
|
-
interface Workspace {
|
|
177
|
-
id: UUID;
|
|
178
|
-
settings: Settings;
|
|
179
|
-
project: Project;
|
|
180
|
-
indexes: Indexes;
|
|
181
|
-
}
|
|
182
|
-
interface IndexState {
|
|
183
|
-
format: string;
|
|
184
|
-
workspace: Workspace;
|
|
185
|
-
roles: Record<string, RoleSummary>;
|
|
186
|
-
preferences: Record<UUID, PreferenceSummary>;
|
|
187
|
-
context: Record<string, ContextSummary>;
|
|
188
|
-
sessions: Record<UUID, SessionMeta>;
|
|
189
|
-
blobs: Record<SHA256, BlobSummary>;
|
|
190
|
-
}
|
|
208
|
+
/**
|
|
209
|
+
* SessionMeta is stored as a document in the 'session' collection.
|
|
210
|
+
* The head pointer lives here — no separate session_heads store needed.
|
|
211
|
+
*/
|
|
191
212
|
interface SessionMeta {
|
|
192
213
|
id: UUID;
|
|
193
214
|
label: string;
|
|
@@ -204,68 +225,76 @@ interface SessionMeta {
|
|
|
204
225
|
version: number;
|
|
205
226
|
} | null;
|
|
206
227
|
}
|
|
207
|
-
interface
|
|
208
|
-
id: UUID;
|
|
228
|
+
interface RoleSummary {
|
|
209
229
|
name: string;
|
|
210
230
|
label: string;
|
|
211
|
-
persona: string;
|
|
212
231
|
description?: string;
|
|
213
|
-
|
|
232
|
+
/** Number of preference IDs listed on the role. */
|
|
233
|
+
preferences: number;
|
|
214
234
|
}
|
|
215
|
-
interface
|
|
235
|
+
interface PreferenceSummary {
|
|
216
236
|
id: UUID;
|
|
217
|
-
content: string;
|
|
218
237
|
topics: string[];
|
|
219
238
|
timestamp: Timestamp;
|
|
239
|
+
snippet?: string;
|
|
220
240
|
}
|
|
221
|
-
interface
|
|
241
|
+
interface ContextSummary {
|
|
222
242
|
key: string;
|
|
223
|
-
content: string | object | URI;
|
|
224
243
|
topics: string[];
|
|
225
244
|
timestamp: Timestamp;
|
|
245
|
+
mime?: string;
|
|
246
|
+
size?: number;
|
|
247
|
+
preview?: string;
|
|
248
|
+
source?: string;
|
|
226
249
|
metadata?: Record<string, any>;
|
|
227
|
-
attachments?: BlobRef[];
|
|
228
250
|
}
|
|
229
|
-
interface
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
role: string;
|
|
233
|
-
topics: string[];
|
|
251
|
+
interface TopicIndex {
|
|
252
|
+
topic: string;
|
|
253
|
+
contextKeys: string[];
|
|
234
254
|
preferences: UUID[];
|
|
235
|
-
|
|
236
|
-
metadata: {
|
|
255
|
+
metadata?: {
|
|
237
256
|
created?: Timestamp;
|
|
238
257
|
updated?: Timestamp;
|
|
258
|
+
entries?: number;
|
|
239
259
|
};
|
|
240
260
|
}
|
|
261
|
+
interface Index {
|
|
262
|
+
roles: Record<string, RoleSummary>;
|
|
263
|
+
preferences: Record<UUID, PreferenceSummary>;
|
|
264
|
+
context: Record<string, ContextSummary>;
|
|
265
|
+
sessions: Record<UUID, SessionMeta>;
|
|
266
|
+
topics: Record<string, TopicIndex>;
|
|
267
|
+
blobs: Record<SHA256, BlobRecord>;
|
|
268
|
+
}
|
|
269
|
+
interface Workspace {
|
|
270
|
+
id: UUID;
|
|
271
|
+
settings: Settings;
|
|
272
|
+
project: Project;
|
|
273
|
+
index: Index;
|
|
274
|
+
}
|
|
241
275
|
interface WorkspaceBundle {
|
|
242
276
|
format: 'aiworkspace/4.0';
|
|
243
277
|
workspace: Workspace;
|
|
244
278
|
roles: Record<string, Role>;
|
|
245
279
|
preferences: Record<UUID, Preference>;
|
|
246
280
|
context: Record<string, Context>;
|
|
247
|
-
sessions: Record<UUID,
|
|
281
|
+
sessions: Record<UUID, SessionMeta & {
|
|
282
|
+
turns: Turn[];
|
|
283
|
+
}>;
|
|
248
284
|
blobs: Record<SHA256, BlobRecord>;
|
|
249
285
|
}
|
|
250
|
-
interface TranscriptWindow {
|
|
251
|
-
sessionId: UUID;
|
|
252
|
-
turns: Turn[];
|
|
253
|
-
flushedCount: number;
|
|
254
|
-
hasMore: boolean;
|
|
255
|
-
}
|
|
256
286
|
interface EffectiveSession {
|
|
257
287
|
session: SessionMeta;
|
|
258
288
|
role: Role;
|
|
259
289
|
preferences: Preference[];
|
|
260
290
|
context: Context[];
|
|
261
291
|
transcript: Turn[];
|
|
262
|
-
|
|
292
|
+
instructions?: string;
|
|
263
293
|
}
|
|
264
294
|
interface CacheConfig {
|
|
265
295
|
roles?: number;
|
|
266
296
|
preferences?: number;
|
|
267
|
-
|
|
268
|
-
transcriptWindows?: number;
|
|
297
|
+
context?: number;
|
|
269
298
|
}
|
|
270
299
|
interface FlushConfig {
|
|
271
300
|
maxBufferSize: number;
|
|
@@ -274,7 +303,6 @@ interface FlushConfig {
|
|
|
274
303
|
interface ContentStoreConfig {
|
|
275
304
|
cache?: CacheConfig;
|
|
276
305
|
flush?: FlushConfig;
|
|
277
|
-
transcriptWindowSize?: number;
|
|
278
306
|
}
|
|
279
307
|
interface BaseCommand {
|
|
280
308
|
type: string;
|
|
@@ -385,13 +413,6 @@ interface DeleteTurn extends BaseCommand {
|
|
|
385
413
|
} | null;
|
|
386
414
|
};
|
|
387
415
|
}
|
|
388
|
-
interface AddInteraction extends BaseCommand {
|
|
389
|
-
type: 'turn:add';
|
|
390
|
-
payload: {
|
|
391
|
-
sessionId: UUID;
|
|
392
|
-
turn: Turn;
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
416
|
interface SwitchRole extends BaseCommand {
|
|
396
417
|
type: 'session:role:switch';
|
|
397
418
|
payload: {
|
|
@@ -431,14 +452,16 @@ interface DeleteSession extends BaseCommand {
|
|
|
431
452
|
}
|
|
432
453
|
interface RegisterBlob extends BaseCommand {
|
|
433
454
|
type: 'blob:register';
|
|
434
|
-
payload:
|
|
455
|
+
payload: {
|
|
456
|
+
data: Uint8Array;
|
|
457
|
+
mediaType: BlobMediaType;
|
|
458
|
+
filename?: string;
|
|
459
|
+
};
|
|
435
460
|
}
|
|
436
|
-
interface
|
|
437
|
-
type: 'blob:
|
|
461
|
+
interface RetainBlob extends BaseCommand {
|
|
462
|
+
type: 'blob:retain';
|
|
438
463
|
payload: {
|
|
439
464
|
sha256: SHA256;
|
|
440
|
-
providerId: string;
|
|
441
|
-
fileId: string;
|
|
442
465
|
};
|
|
443
466
|
}
|
|
444
467
|
interface ReleaseBlob extends BaseCommand {
|
|
@@ -447,7 +470,22 @@ interface ReleaseBlob extends BaseCommand {
|
|
|
447
470
|
sha256: SHA256;
|
|
448
471
|
};
|
|
449
472
|
}
|
|
450
|
-
|
|
473
|
+
interface PurgeBlob extends BaseCommand {
|
|
474
|
+
type: 'blob:purge';
|
|
475
|
+
payload: {
|
|
476
|
+
sha256: SHA256;
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
interface RecordBlobRemoteId extends BaseCommand {
|
|
480
|
+
type: 'blob:record_remote_id';
|
|
481
|
+
payload: {
|
|
482
|
+
sha256: SHA256;
|
|
483
|
+
providerId: string;
|
|
484
|
+
fileId: string;
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
type BlobCommand = RegisterBlob | RetainBlob | ReleaseBlob | PurgeBlob | RecordBlobRemoteId;
|
|
488
|
+
type Command = CreateWorkspace | AddRole | UpdateRole | DeleteRole | AddPreference | UpdatePreference | DeletePreference | CreateSession | AddContext | UpdateContext | DeleteContext | AddTurn | EditTurn | BranchTurn | DeleteTurn | SwitchRole | AddSessionTopics | OverrideSessionPreferences | ForkSession | DeleteSession | BlobCommand;
|
|
451
489
|
interface TokenBudget {
|
|
452
490
|
total: number;
|
|
453
491
|
estimator?: (text: string) => number;
|
|
@@ -464,170 +502,524 @@ interface ContextRelevanceConfig {
|
|
|
464
502
|
minScore?: number;
|
|
465
503
|
freshnessHalfLifeDays?: number;
|
|
466
504
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
505
|
+
/**
|
|
506
|
+
* Prompt.transcript.turns is Turn[].
|
|
507
|
+
* Synthetic turns produced by PromptAssembler (summary blocks, truncation
|
|
508
|
+
* notices, referential attachments) carry generated UUIDs and version 0,
|
|
509
|
+
* with parent: null. They are ephemeral — never stored, never patched.
|
|
510
|
+
*/
|
|
471
511
|
interface Prompt {
|
|
472
|
-
system:
|
|
473
|
-
|
|
474
|
-
|
|
512
|
+
system: {
|
|
513
|
+
instructions?: string;
|
|
514
|
+
persona: string;
|
|
515
|
+
preferences: Preference[];
|
|
516
|
+
context: Context[];
|
|
517
|
+
};
|
|
518
|
+
context: Context[];
|
|
519
|
+
transcript: {
|
|
520
|
+
turns: Turn[];
|
|
521
|
+
};
|
|
522
|
+
budget: {
|
|
523
|
+
total: number;
|
|
524
|
+
used: number;
|
|
525
|
+
breakdown: Record<string, number>;
|
|
526
|
+
};
|
|
475
527
|
truncated: {
|
|
476
528
|
preferences: number;
|
|
477
529
|
interactions: number;
|
|
478
|
-
|
|
530
|
+
context: number;
|
|
479
531
|
};
|
|
480
|
-
conflicts: PreferenceConflict[];
|
|
481
532
|
warnings: string[];
|
|
533
|
+
conflicts: PreferenceConflict[];
|
|
482
534
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
savePreference(preference: Preference): Promise<void>;
|
|
489
|
-
loadPreference(id: UUID): Promise<Preference | null>;
|
|
490
|
-
deletePreference(id: UUID): Promise<void>;
|
|
491
|
-
saveContext(context: Context): Promise<void>;
|
|
492
|
-
loadContext(key: string): Promise<Context | null>;
|
|
493
|
-
deleteContext(key: string): Promise<void>;
|
|
494
|
-
saveTurn(sessionId: UUID, turn: Turn): Promise<void>;
|
|
495
|
-
loadTurn(sessionId: UUID, turnId: UUID, version: number): Promise<Turn | null>;
|
|
496
|
-
loadAllTurns(sessionId: UUID, limit?: number): Promise<Turn[]>;
|
|
497
|
-
setSessionHead(sessionId: UUID, head: {
|
|
498
|
-
id: UUID;
|
|
499
|
-
version: number;
|
|
500
|
-
} | null): Promise<void>;
|
|
501
|
-
getSessionHead(sessionId: UUID): Promise<{
|
|
502
|
-
id: UUID;
|
|
503
|
-
version: number;
|
|
504
|
-
} | null>;
|
|
505
|
-
deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number): Promise<void>;
|
|
506
|
-
getActiveChain(sessionId: UUID): Promise<Turn[]>;
|
|
507
|
-
countChainedTurns(sessionId: UUID): Promise<number>;
|
|
508
|
-
copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
|
|
535
|
+
interface TranscriptWindow {
|
|
536
|
+
sessionId: UUID;
|
|
537
|
+
turns: Turn[];
|
|
538
|
+
flushedCount: number;
|
|
539
|
+
hasMore: boolean;
|
|
509
540
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
private
|
|
514
|
-
private
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
savePreference(preference: Preference): Promise<void>;
|
|
520
|
-
loadPreference(id: UUID): Promise<Preference | null>;
|
|
521
|
-
deletePreference(id: UUID): Promise<void>;
|
|
522
|
-
saveContext(context: Context): Promise<void>;
|
|
523
|
-
loadContext(key: string): Promise<Context | null>;
|
|
524
|
-
deleteContext(key: string): Promise<void>;
|
|
525
|
-
saveTurn(sessionId: UUID, turn: Turn): Promise<void>;
|
|
526
|
-
loadTurn(sessionId: UUID, turnId: UUID, version: number): Promise<Turn | null>;
|
|
527
|
-
loadAllTurns(sessionId: UUID, limit?: number): Promise<Turn[]>;
|
|
528
|
-
setSessionHead(sessionId: UUID, head: {
|
|
529
|
-
id: UUID;
|
|
530
|
-
version: number;
|
|
531
|
-
} | null): Promise<void>;
|
|
532
|
-
getSessionHead(sessionId: UUID): Promise<{
|
|
533
|
-
id: UUID;
|
|
534
|
-
version: number;
|
|
535
|
-
} | null>;
|
|
536
|
-
getActiveChain(sessionId: UUID): Promise<Turn[]>;
|
|
537
|
-
deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number): Promise<void>;
|
|
538
|
-
countChainedTurns(sessionId: UUID): Promise<number>;
|
|
539
|
-
copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
|
|
540
|
-
static fromBundle(bundle: WorkspaceBundle): {
|
|
541
|
-
backend: MemoryStorage;
|
|
542
|
-
indexState: IndexState;
|
|
543
|
-
};
|
|
541
|
+
|
|
542
|
+
declare class TransactionContext {
|
|
543
|
+
readonly id: string;
|
|
544
|
+
private buffer;
|
|
545
|
+
private committed;
|
|
546
|
+
constructor();
|
|
547
|
+
addOp(store: Store<any>, type: "put" | "delete", data: any): void;
|
|
548
|
+
commit(): Promise<void>;
|
|
549
|
+
rollback(): void;
|
|
544
550
|
}
|
|
545
551
|
|
|
552
|
+
interface CursorCallbackResult<T> {
|
|
553
|
+
value: T | null;
|
|
554
|
+
done: boolean;
|
|
555
|
+
offset?: number;
|
|
556
|
+
}
|
|
546
557
|
/**
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
558
|
+
* Callback function for cursor iteration over store records.
|
|
559
|
+
*
|
|
560
|
+
* @template T - The type of records stored.
|
|
561
|
+
* @param value - The current record value (cloned, not a live reference).
|
|
562
|
+
* @param key - The key (ID) of the current record.
|
|
563
|
+
* @param cursor - The underlying cursor object (implementation‑specific; may be `null` in memory adapters).
|
|
564
|
+
* @returns A promise that resolves to an object indicating whether iteration should stop, and an optional offset to advance.
|
|
552
565
|
*/
|
|
553
|
-
type
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
declare class IndexedDBStorage implements ContentStorage {
|
|
564
|
-
private readonly dbName;
|
|
565
|
-
private db;
|
|
566
|
-
constructor(config?: IndexedDBConfig);
|
|
567
|
-
open(): Promise<void>;
|
|
568
|
-
private createSchema;
|
|
569
|
-
close(): void;
|
|
570
|
-
deleteDatabase(): Promise<void>;
|
|
571
|
-
private getDB;
|
|
572
|
-
private readTx;
|
|
573
|
-
private writeTx;
|
|
574
|
-
saveRole(role: Role): Promise<void>;
|
|
575
|
-
loadRole(name: string): Promise<Role | null>;
|
|
576
|
-
deleteRole(name: string): Promise<void>;
|
|
577
|
-
savePreference(preference: Preference): Promise<void>;
|
|
578
|
-
loadPreference(id: UUID): Promise<Preference | null>;
|
|
579
|
-
deletePreference(id: UUID): Promise<void>;
|
|
580
|
-
saveContext(context: Context): Promise<void>;
|
|
581
|
-
loadContext(key: string): Promise<Context | null>;
|
|
582
|
-
deleteContext(key: string): Promise<void>;
|
|
583
|
-
saveTurn(sessionId: UUID, turn: Turn): Promise<void>;
|
|
584
|
-
loadAllTurns(sessionId: UUID, limit?: number): Promise<Turn[]>;
|
|
585
|
-
countChainedTurns(sessionId: UUID): Promise<number>;
|
|
586
|
-
loadTurn(sessionId: UUID, turnId: UUID, version: number): Promise<Turn | null>;
|
|
587
|
-
setSessionHead(sessionId: UUID, head: {
|
|
588
|
-
id: UUID;
|
|
589
|
-
version: number;
|
|
590
|
-
} | null): Promise<void>;
|
|
591
|
-
getSessionHead(sessionId: UUID): Promise<{
|
|
592
|
-
id: UUID;
|
|
593
|
-
version: number;
|
|
594
|
-
} | null>;
|
|
595
|
-
getActiveChain(sessionId: UUID): Promise<Turn[]>;
|
|
596
|
-
deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number): Promise<void>;
|
|
597
|
-
copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
|
|
598
|
-
saveIndexState(state: IndexState): Promise<void>;
|
|
599
|
-
loadIndexState(): Promise<IndexState | null>;
|
|
600
|
-
exportBundle(): Promise<{
|
|
601
|
-
roles: Record<string, Role>;
|
|
602
|
-
preferences: Record<UUID, Preference>;
|
|
603
|
-
context: Record<string, Context>;
|
|
604
|
-
transcripts: Record<UUID, Turn[]>;
|
|
605
|
-
indexState: IndexState | null;
|
|
606
|
-
}>;
|
|
607
|
-
importBundle(data: {
|
|
608
|
-
roles: Record<string, Role>;
|
|
609
|
-
preferences: Record<UUID, Preference>;
|
|
610
|
-
context: Record<string, Context>;
|
|
611
|
-
transcripts: Record<UUID, Turn[]>;
|
|
612
|
-
indexState?: IndexState;
|
|
613
|
-
}): Promise<void>;
|
|
614
|
-
private getAllFromStore;
|
|
566
|
+
type CursorCallback<T> = (value: T, key: string | number, cursor: any) => Promise<CursorCallbackResult<T>>;
|
|
567
|
+
/**
|
|
568
|
+
* A generic representation of a key range, replacing the browser-specific IDBKeyRange.
|
|
569
|
+
*/
|
|
570
|
+
interface StoreKeyRange {
|
|
571
|
+
lower?: any;
|
|
572
|
+
upper?: any;
|
|
573
|
+
lowerOpen?: boolean;
|
|
574
|
+
upperOpen?: boolean;
|
|
615
575
|
}
|
|
616
|
-
|
|
617
576
|
/**
|
|
618
|
-
*
|
|
577
|
+
* Storage adapter interface for a single object store (collection).
|
|
619
578
|
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
579
|
+
* This interface abstracts all low‑level persistence operations, allowing
|
|
580
|
+
* different backends (IndexedDB, memory, remote, etc.) to be used interchangeably.
|
|
581
|
+
* All methods return promises and operate on clones of data to prevent
|
|
582
|
+
* unintended mutations.
|
|
623
583
|
*
|
|
624
|
-
*
|
|
625
|
-
* storing its bytes happen in the same transaction boundary.
|
|
584
|
+
* @template T - The type of objects stored in this store. Must include the key path property.
|
|
626
585
|
*/
|
|
627
|
-
interface
|
|
586
|
+
interface Store<T = any> {
|
|
628
587
|
/**
|
|
629
|
-
*
|
|
630
|
-
*
|
|
588
|
+
* Adds one or more records to the store.
|
|
589
|
+
*
|
|
590
|
+
* If a record does not have a value for the store's key path, an automatic
|
|
591
|
+
* key (e.g., auto‑incremented number) may be assigned. The store's key path
|
|
592
|
+
* property is then updated on the added record(s).
|
|
593
|
+
*
|
|
594
|
+
* @param data - A single record or an array of records to add.
|
|
595
|
+
* @returns A promise that resolves to:
|
|
596
|
+
* - the key(s) of the added record(s) – a single key if `data` was a single record,
|
|
597
|
+
* or an array of keys if `data` was an array.
|
|
598
|
+
* @throws {Error} If any record lacks the key path property and auto‑keying is not supported,
|
|
599
|
+
* or if a record with the same key already exists.
|
|
600
|
+
*/
|
|
601
|
+
add(data: T | T[]): Promise<string | number | (string | number)[]>;
|
|
602
|
+
/**
|
|
603
|
+
* Removes all records from the store.
|
|
604
|
+
*
|
|
605
|
+
* @returns A promise that resolves when the store is cleared.
|
|
606
|
+
* @throws {Error} If the operation fails (e.g., store is closed).
|
|
607
|
+
*/
|
|
608
|
+
clear(): Promise<void>;
|
|
609
|
+
/**
|
|
610
|
+
* Returns the total number of records in the store.
|
|
611
|
+
*
|
|
612
|
+
* @returns A promise that resolves to the record count.
|
|
613
|
+
* @throws {Error} If the operation fails.
|
|
614
|
+
*/
|
|
615
|
+
count(): Promise<number>;
|
|
616
|
+
/**
|
|
617
|
+
* Deletes one or more records by their keys.
|
|
618
|
+
*
|
|
619
|
+
* @param id - A single key or an array of keys to delete.
|
|
620
|
+
* @returns A promise that resolves when the records are deleted.
|
|
621
|
+
* @throws {Error} If any key is `undefined` or the operation fails.
|
|
622
|
+
*/
|
|
623
|
+
delete(id: string | number | (string | number)[]): Promise<void>;
|
|
624
|
+
/**
|
|
625
|
+
* Retrieves a single record by its primary key.
|
|
626
|
+
*
|
|
627
|
+
* @param id - The key of the record to retrieve.
|
|
628
|
+
* @returns A promise that resolves to the record (cloned) if found, otherwise `undefined`.
|
|
629
|
+
* @throws {Error} If the key is `undefined` or the operation fails.
|
|
630
|
+
*/
|
|
631
|
+
getById(id: string | number): Promise<T | undefined>;
|
|
632
|
+
/**
|
|
633
|
+
* Retrieves a single record by an index and index key.
|
|
634
|
+
*
|
|
635
|
+
* @param index - The name of the index to query.
|
|
636
|
+
* @param key - The exact key value to look up in the index.
|
|
637
|
+
* @returns A promise that resolves to the first matching record (cloned), or `undefined` if none.
|
|
638
|
+
* @throws {Error} If the index does not exist, the key is `undefined`, or the operation fails.
|
|
639
|
+
*/
|
|
640
|
+
getByIndex(index: string, key: any): Promise<T | undefined>;
|
|
641
|
+
/**
|
|
642
|
+
* Retrieves multiple records from an index, optionally within a key range.
|
|
643
|
+
*
|
|
644
|
+
* @param index - The name of the index to query.
|
|
645
|
+
* @param keyRange - Optional `StoreKeyRange` to filter results. If omitted, all records are returned.
|
|
646
|
+
* @returns A promise that resolves to an array of matching records (each cloned).
|
|
647
|
+
* @throws {Error} If the index does not exist or the operation fails.
|
|
648
|
+
*/
|
|
649
|
+
getByKeyRange(index: string, keyRange?: StoreKeyRange): Promise<T[]>;
|
|
650
|
+
/**
|
|
651
|
+
* Retrieves all records from the store.
|
|
652
|
+
*
|
|
653
|
+
* @returns A promise that resolves to an array of all records (each cloned).
|
|
654
|
+
* @throws {Error} If the operation fails.
|
|
655
|
+
*/
|
|
656
|
+
getAll(): Promise<T[]>;
|
|
657
|
+
/**
|
|
658
|
+
* Inserts or replaces a record.
|
|
659
|
+
*
|
|
660
|
+
* If a record with the same key already exists, it is replaced.
|
|
661
|
+
* The record must contain the store's key path property.
|
|
662
|
+
*
|
|
663
|
+
* @param data - The record to store.
|
|
664
|
+
* @returns A promise that resolves to the key of the stored record.
|
|
665
|
+
* @throws {Error} If the record lacks the key path property or the operation fails.
|
|
666
|
+
*/
|
|
667
|
+
put(data: T): Promise<string | number>;
|
|
668
|
+
/**
|
|
669
|
+
* Iterates over records using a cursor, allowing early termination and skipping.
|
|
670
|
+
*
|
|
671
|
+
* The callback is invoked for each record in iteration order. The callback
|
|
672
|
+
* can control the iteration by returning `{ done: true }` to stop, or
|
|
673
|
+
* `{ offset: n }` to skip ahead `n` records.
|
|
674
|
+
*
|
|
675
|
+
* @param callback - Function called for each record.
|
|
676
|
+
* @param direction - Iteration direction: `"forward"` (ascending keys) or `"backward"` (descending keys).
|
|
677
|
+
* @param keyRange - An optional StoreKeyRange to start from specific points.
|
|
678
|
+
* @returns A promise that resolves to the last record processed (or `null` if none).
|
|
679
|
+
* @throws {Error} If the callback throws or the operation fails.
|
|
680
|
+
*/
|
|
681
|
+
cursor(callback: CursorCallback<T>, direction?: "forward" | "backward", keyRange?: StoreKeyRange): Promise<T | null>;
|
|
682
|
+
/**
|
|
683
|
+
* Executes a batch of write operations atomically.
|
|
684
|
+
*
|
|
685
|
+
* All operations in the batch succeed or fail together. This is useful for
|
|
686
|
+
* maintaining consistency when multiple writes are required.
|
|
687
|
+
*
|
|
688
|
+
* @param operations - An array of operations. Each operation can be:
|
|
689
|
+
* - `{ type: "add" | "put", data: T | T[] }`
|
|
690
|
+
* - `{ type: "delete", data: string | number | (string | number)[] }`
|
|
691
|
+
* @returns A promise that resolves when the batch is committed.
|
|
692
|
+
* @throws {Error} If any operation fails or the batch cannot be completed.
|
|
693
|
+
*/
|
|
694
|
+
batch(operations: Array<{
|
|
695
|
+
type: "add" | "put";
|
|
696
|
+
data: T | T[];
|
|
697
|
+
} | {
|
|
698
|
+
type: "delete";
|
|
699
|
+
data: string | number | (string | number)[];
|
|
700
|
+
}>): Promise<void>;
|
|
701
|
+
open(): Promise<void>;
|
|
702
|
+
}
|
|
703
|
+
interface Collection<T> {
|
|
704
|
+
/**
|
|
705
|
+
* Finds a single document matching the query.
|
|
706
|
+
* @param query - The query to execute.
|
|
707
|
+
* @returns A promise resolving to the matching document or `null` if not found.
|
|
708
|
+
*/
|
|
709
|
+
find: (query: QueryFilter<T>) => Promise<Document<T> | null>;
|
|
710
|
+
/**
|
|
711
|
+
* Lists documents based on the provided query.
|
|
712
|
+
* @param query - The query to list documents (supports pagination and sorting).
|
|
713
|
+
* @returns A promise resolving to an array of documents.
|
|
714
|
+
*/
|
|
715
|
+
list: (query: PaginationOptions) => Promise<AsyncIterator<Document<T>[]>>;
|
|
716
|
+
/**
|
|
717
|
+
* Filters documents based on the provided query.
|
|
718
|
+
* @param query - The query to filter documents.
|
|
719
|
+
* @returns A promise resolving to an array of matching documents.
|
|
720
|
+
*/
|
|
721
|
+
filter: (query: QueryFilter<T>) => Promise<Document<T>[]>;
|
|
722
|
+
/**
|
|
723
|
+
* Creates a new document in the schema.
|
|
724
|
+
* @param initial - The initial data for the document.
|
|
725
|
+
* @returns A promise resolving to the created document.
|
|
726
|
+
*/
|
|
727
|
+
create: (initial: T) => Promise<Document<T>>;
|
|
728
|
+
/**
|
|
729
|
+
* Subscribes to schema-level events (e.g., "create", "update", "delete", "access").
|
|
730
|
+
* @param event - The event type to subscribe to.
|
|
731
|
+
* @param callback - The function to call when the event occurs.
|
|
732
|
+
* @returns A promise resolving to an unsubscribe function.
|
|
733
|
+
*/
|
|
734
|
+
subscribe: (event: CollectionEventType | TelemetryEventType, callback: (event: CollectionEvent<T> | TelemetryEvent) => void) => Promise<() => void>;
|
|
735
|
+
/**
|
|
736
|
+
* Validate data
|
|
737
|
+
* @param data - The data to validate
|
|
738
|
+
* @returns An object containing validation results
|
|
739
|
+
*/
|
|
740
|
+
validate(data: Record<string, any>): Promise<{
|
|
741
|
+
value?: any;
|
|
742
|
+
issues: Array<{
|
|
743
|
+
message: string;
|
|
744
|
+
path: Array<string>;
|
|
745
|
+
}>;
|
|
746
|
+
}>;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Event payload for DocumentCursor events.
|
|
750
|
+
*/
|
|
751
|
+
type CollectionEventType = "document:create" | "collection:read" | "migration:start" | "migration:end";
|
|
752
|
+
type CollectionEvent<T> = {
|
|
753
|
+
type: CollectionEventType;
|
|
754
|
+
document?: T;
|
|
755
|
+
model?: string;
|
|
756
|
+
method?: keyof Collection<T>;
|
|
757
|
+
metadata?: Record<string, unknown>;
|
|
758
|
+
timestamp: number;
|
|
759
|
+
};
|
|
760
|
+
interface Database {
|
|
761
|
+
/**
|
|
762
|
+
* Accesses a schema model by name.
|
|
763
|
+
* @param schemaName - The name of the schema to access.
|
|
764
|
+
* @returns A promise resolving to the schema's DocumentCursor.
|
|
765
|
+
* @throws DatabaseError
|
|
766
|
+
*/
|
|
767
|
+
collection: <T>(schemaName: string) => Promise<Collection<T>>;
|
|
768
|
+
/**
|
|
769
|
+
* Creates a new schema model.
|
|
770
|
+
* @param schema - The schema definition.
|
|
771
|
+
* @returns A promise resolving to the created schema's DocumentCursor.
|
|
772
|
+
* @throws DatabaseError
|
|
773
|
+
*/
|
|
774
|
+
createCollection: <T>(schema: SchemaDefinition) => Promise<Collection<T>>;
|
|
775
|
+
/**
|
|
776
|
+
* Deletes a schema by name.
|
|
777
|
+
* @param schemaName - The name of the schema to delete.
|
|
778
|
+
* @returns A promise resolving to `true` if successful, or `false` if an error occurs.
|
|
779
|
+
* @throws DatabaseError
|
|
780
|
+
*/
|
|
781
|
+
deleteCollection: (schemaName: string) => Promise<boolean>;
|
|
782
|
+
/**
|
|
783
|
+
* Updates an existing schema.
|
|
784
|
+
* @param schema - The updated schema definition.
|
|
785
|
+
* @returns A promise resolving to `true` if successful, or `false` if an error occurs.
|
|
786
|
+
* @throws DatabaseError
|
|
787
|
+
*/
|
|
788
|
+
updateCollection: (schema: SchemaDefinition) => Promise<boolean>;
|
|
789
|
+
/**
|
|
790
|
+
* Migrates an existing collection's data and updates its schema definition metadata.
|
|
791
|
+
* This function processes data in a streaming fashion to prevent loading
|
|
792
|
+
* the entire collection into memory.
|
|
793
|
+
*
|
|
794
|
+
* It will:
|
|
795
|
+
* 1. Verify the target collection exists.
|
|
796
|
+
* 2. Retrieve the collection's current schema definition from a metadata store ($index).
|
|
797
|
+
* 3. Initialize a `MigrationEngine` with this schema.
|
|
798
|
+
* 4. Allow a callback to define specific data transformations using the `MigrationEngine`.
|
|
799
|
+
* 5. **Crucially, it uses `migrationEngine.dryRun()` to get the `newSchema` that results**
|
|
800
|
+
* **from the transformations defined in the callback.**
|
|
801
|
+
* 6. Execute these transformations by streaming data from the collection,
|
|
802
|
+
* through the `MigrationEngine`, and back into the same collection.
|
|
803
|
+
* 7. Finally, update the schema definition for the collection in the `$index` metadata store
|
|
804
|
+
* to reflect this `newSchema`.
|
|
805
|
+
* All these steps for data and metadata updates happen within a single atomic IndexedDB transaction.
|
|
806
|
+
*
|
|
807
|
+
* Note: This function focuses solely on *data transformation* and *metadata updates*.
|
|
808
|
+
* It does NOT handle structural IndexedDB changes like adding/removing physical indexes or object stores,
|
|
809
|
+
* which still require an `onupgradeneeded` event (i.e., a database version upgrade).
|
|
810
|
+
*
|
|
811
|
+
* @param name - The name of the collection (IndexedDB object store) to migrate.
|
|
812
|
+
* @param {Object} opts - Options for the new migration
|
|
813
|
+
* @param {SchemaChange<any>[]} opts.changes - Array of schema changes
|
|
814
|
+
* @param {string} opts.description - Description of the migration
|
|
815
|
+
* @param {SchemaChange<any>[]} [opts.rollback] - Optional rollback changes
|
|
816
|
+
* @param {DataTransform<any, any>} [opts.transform] - Optional data transform
|
|
817
|
+
* @returns A Promise resolving to `true` if the migration completes successfully,
|
|
818
|
+
* @throws {DatabaseError} If the collection does not exist, its schema metadata is missing,
|
|
819
|
+
* or any IndexedDB operation/streaming fails critically.
|
|
820
|
+
*/
|
|
821
|
+
migrateCollection: (name: string, opts: CollectionMigrationOptions, batchSize?: number) => Promise<boolean>;
|
|
822
|
+
/**
|
|
823
|
+
* Subscribes to database-level events (e.g., "schemaAdded", "schemaDeleted", "schemaAccessed", "migrate").
|
|
824
|
+
* @param event - The event type to subscribe to.
|
|
825
|
+
* @param callback - The function to call when the event occurs.
|
|
826
|
+
* @returns A promise resolving to an unsubscribe function.
|
|
827
|
+
*/
|
|
828
|
+
subscribe: (event: DatabaseEventType | "telemetry", callback: (event: DatabaseEvent | TelemetryEvent) => void) => Promise<() => void>;
|
|
829
|
+
/**
|
|
830
|
+
* Closes the connection to the database
|
|
831
|
+
*/
|
|
832
|
+
close: () => void;
|
|
833
|
+
/**
|
|
834
|
+
* Ensures a collection exists; creates it if it doesn't.
|
|
835
|
+
* Idempotent – safe to call multiple times.
|
|
836
|
+
* @param schema - The schema definition for the collection.
|
|
837
|
+
* @returns A promise that resolves when the collection exists.
|
|
838
|
+
* @throws {DatabaseError} If validation fails or an unexpected error occurs.
|
|
839
|
+
*/
|
|
840
|
+
ensureCollection: (schema: SchemaDefinition) => Promise<void>;
|
|
841
|
+
/**
|
|
842
|
+
* Ensures multiple collections exist; creates any that don't.
|
|
843
|
+
* Idempotent – safe to call multiple times.
|
|
844
|
+
* @param schemas - An array of schema definitions.
|
|
845
|
+
* @returns A promise that resolves when all collections exist.
|
|
846
|
+
* @throws {DatabaseError} If any schema validation fails or an unexpected error occurs.
|
|
847
|
+
*/
|
|
848
|
+
setupCollections: (schemas: SchemaDefinition[]) => Promise<void>;
|
|
849
|
+
}
|
|
850
|
+
type CollectionMigrationOptions = {
|
|
851
|
+
changes: SchemaChange<any>[];
|
|
852
|
+
description: string;
|
|
853
|
+
rollback?: SchemaChange<any>[];
|
|
854
|
+
transform?: string | DataTransform<any, any>;
|
|
855
|
+
};
|
|
856
|
+
/**
|
|
857
|
+
* Event payload for Database events.
|
|
858
|
+
*/
|
|
859
|
+
type DatabaseEventType = "collection:create" | "collection:delete" | "collection:update" | "collection:read" | "migrate";
|
|
860
|
+
type DatabaseEvent = {
|
|
861
|
+
type: DatabaseEventType;
|
|
862
|
+
schema?: SchemaDefinition | Partial<SchemaDefinition>;
|
|
863
|
+
timestamp: number;
|
|
864
|
+
};
|
|
865
|
+
type Document<T> = {
|
|
866
|
+
readonly [K in keyof T]: T[K];
|
|
867
|
+
} & {
|
|
868
|
+
/**
|
|
869
|
+
* Unique identifier for the document (assigned automatically if not provided).
|
|
870
|
+
*/
|
|
871
|
+
$id?: string;
|
|
872
|
+
/**
|
|
873
|
+
* Timestamp of document creation (ISO string or Date).
|
|
874
|
+
*/
|
|
875
|
+
$created?: string | Date;
|
|
876
|
+
/**
|
|
877
|
+
* Timestamp of last document update (ISO string or Date).
|
|
878
|
+
*/
|
|
879
|
+
$updated?: string | Date;
|
|
880
|
+
/**
|
|
881
|
+
* Version number incremented on each change (used for optimistic concurrency control).
|
|
882
|
+
*/
|
|
883
|
+
$version?: number;
|
|
884
|
+
/**
|
|
885
|
+
* Fetches the latest data from the database and updates the document instance.
|
|
886
|
+
* @returns A promise resolving to `true` if successful, or `false` if an error occurs.
|
|
887
|
+
*/
|
|
888
|
+
read: () => Promise<boolean>;
|
|
889
|
+
/**
|
|
890
|
+
* Saves the current document state to the database.
|
|
891
|
+
* Normally called automatically by `update()` or `delete()`, but can be used manually.
|
|
892
|
+
* @returns A promise resolving to `true` if successful, or `false` if an error occurs.
|
|
893
|
+
*/
|
|
894
|
+
save: (tx?: TransactionContext) => Promise<boolean>;
|
|
895
|
+
/**
|
|
896
|
+
* Updates the document with the provided properties.
|
|
897
|
+
* @param props - Partial object containing the fields to update.
|
|
898
|
+
* @returns A promise resolving to `true` if successful, or `false` if an error occurs.
|
|
899
|
+
*/
|
|
900
|
+
update: (props: Partial<T>) => Promise<boolean>;
|
|
901
|
+
/**
|
|
902
|
+
* Deletes the document from the database.
|
|
903
|
+
* @returns A promise resolving to `true` if successful, or `false` if an error occurs.
|
|
904
|
+
*/
|
|
905
|
+
delete: () => Promise<boolean>;
|
|
906
|
+
/**
|
|
907
|
+
* Subscribes to document events (e.g., "update", "delete", "access").
|
|
908
|
+
* @param event - The event type to subscribe to.
|
|
909
|
+
* @param callback - The function to call when the event occurs.
|
|
910
|
+
* @returns An unsubscribe function.
|
|
911
|
+
*/
|
|
912
|
+
subscribe: (event: DocumentEventType | TelemetryEventType, callback: (event: DocumentEvent<T> | TelemetryEvent) => void) => () => void;
|
|
913
|
+
/**
|
|
914
|
+
* Returns a plain object containing only the user-defined data (without system fields like $id, $version, etc.).
|
|
915
|
+
* @returns The current user data.
|
|
916
|
+
*/
|
|
917
|
+
state(): T;
|
|
918
|
+
};
|
|
919
|
+
/**
|
|
920
|
+
* Event payload for DocumentModel events.
|
|
921
|
+
*/
|
|
922
|
+
type DocumentEventType = "document:create" | "document:write" | "document:update" | "document:delete" | "document:read";
|
|
923
|
+
type DocumentEvent<T> = {
|
|
924
|
+
type: DocumentEventType;
|
|
925
|
+
data?: Partial<T>;
|
|
926
|
+
timestamp: number;
|
|
927
|
+
};
|
|
928
|
+
type TelemetryEventType = "telemetry";
|
|
929
|
+
type TelemetryEvent = {
|
|
930
|
+
type: TelemetryEventType;
|
|
931
|
+
method: string;
|
|
932
|
+
timestamp: number;
|
|
933
|
+
source: any;
|
|
934
|
+
metadata: {
|
|
935
|
+
args: any[];
|
|
936
|
+
performance: {
|
|
937
|
+
durationMs: number;
|
|
938
|
+
};
|
|
939
|
+
source: {
|
|
940
|
+
level: "database" | "collection" | "document";
|
|
941
|
+
collection?: string;
|
|
942
|
+
document?: string;
|
|
943
|
+
};
|
|
944
|
+
result?: {
|
|
945
|
+
type: 'array' | string;
|
|
946
|
+
size?: number;
|
|
947
|
+
};
|
|
948
|
+
error: {
|
|
949
|
+
message: string;
|
|
950
|
+
name: string;
|
|
951
|
+
stack?: string;
|
|
952
|
+
} | null;
|
|
953
|
+
};
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
interface WorkspaceDatabase {
|
|
957
|
+
/**
|
|
958
|
+
* Open the database. Registers core schemas followed by any extension
|
|
959
|
+
* schemas supplied by the caller (domain plugins).
|
|
960
|
+
*
|
|
961
|
+
* Idempotent — safe to call multiple times; subsequent calls are no-ops
|
|
962
|
+
* if the database is already open.
|
|
963
|
+
*/
|
|
964
|
+
open(extensionSchemas?: SchemaDefinition[]): Promise<void>;
|
|
965
|
+
/**
|
|
966
|
+
* Access a collection by schema name.
|
|
967
|
+
* Throws if the schema has not been registered.
|
|
968
|
+
*/
|
|
969
|
+
collection<T>(schemaName: string): Promise<Collection<T>>;
|
|
970
|
+
/**
|
|
971
|
+
* Close the database connection.
|
|
972
|
+
*/
|
|
973
|
+
close(): void;
|
|
974
|
+
}
|
|
975
|
+
declare function createWorkspaceDatabase(db: Database): WorkspaceDatabase;
|
|
976
|
+
declare const COLLECTIONS: {
|
|
977
|
+
readonly ROLE: "role";
|
|
978
|
+
readonly PREFERENCE: "preference";
|
|
979
|
+
readonly CONTEXT: "context";
|
|
980
|
+
readonly SESSION: "session";
|
|
981
|
+
readonly TURN: "turn";
|
|
982
|
+
};
|
|
983
|
+
type CollectionName = typeof COLLECTIONS[keyof typeof COLLECTIONS];
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Utility type for representing partial updates to the state, allowing deep nesting.
|
|
987
|
+
* It makes all properties optional and applies the same transformation recursively
|
|
988
|
+
* to nested objects and array elements, allowing for selective updates while
|
|
989
|
+
* preserving the original structure. It also includes the original type T and
|
|
990
|
+
* undefined as possibilities for the top level and nested values.
|
|
991
|
+
*/
|
|
992
|
+
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 : {
|
|
993
|
+
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined;
|
|
994
|
+
} | undefined | T : T | undefined;
|
|
995
|
+
|
|
996
|
+
declare function del<T>(): T;
|
|
997
|
+
declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
|
|
998
|
+
declare function ok<T>(value: T): Result<T, never>;
|
|
999
|
+
declare function err<E = WorkspaceError>(error: E): Result<never, E>;
|
|
1000
|
+
declare function omitNullUndefined<T extends Record<string, any>>(obj: T): Partial<T>;
|
|
1001
|
+
declare function createSimpleWorkspace({ name, owner, language }: {
|
|
1002
|
+
name: string;
|
|
1003
|
+
language: string;
|
|
1004
|
+
owner: string;
|
|
1005
|
+
}): Workspace;
|
|
1006
|
+
declare function extractBlobRecord(patch: DeepPartial<Workspace>): BlobRecord | null;
|
|
1007
|
+
declare function extractBlobRef(record: BlobRecord): BlobRef;
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* Persistence contract for binary blob content and blob registry records.
|
|
1011
|
+
*
|
|
1012
|
+
* Two concerns live here together deliberately:
|
|
1013
|
+
* 1. Raw bytes — stored and retrieved by SHA-256.
|
|
1014
|
+
* 2. BlobRecord — the registry entry that tracks ref counts and remote IDs.
|
|
1015
|
+
*
|
|
1016
|
+
* Keeping them in the same backend ensures atomicity: registering a blob and
|
|
1017
|
+
* storing its bytes happen in the same transaction boundary.
|
|
1018
|
+
*/
|
|
1019
|
+
interface BlobStorage {
|
|
1020
|
+
/**
|
|
1021
|
+
* Store raw bytes for a blob. Idempotent — if the SHA-256 already exists
|
|
1022
|
+
* the bytes are not re-written (content-addressed, so they are identical).
|
|
631
1023
|
*/
|
|
632
1024
|
storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
|
|
633
1025
|
/** Load raw bytes. Returns null if the blob is not stored locally. */
|
|
@@ -652,65 +1044,40 @@ interface BlobStorage {
|
|
|
652
1044
|
* Used for workspace export / migration.
|
|
653
1045
|
*/
|
|
654
1046
|
exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
|
|
1047
|
+
/**
|
|
1048
|
+
* Optional atomic operation: store bytes and save record in a single
|
|
1049
|
+
* transaction. Backends that support this (e.g. IndexedDB) should
|
|
1050
|
+
* implement it to avoid a window where bytes exist without a record.
|
|
1051
|
+
* BlobStore will prefer this over calling storeBytes + saveRecord separately.
|
|
1052
|
+
*/
|
|
1053
|
+
registerBlob?(record: BlobRecord, data: Uint8Array): Promise<void>;
|
|
655
1054
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
*/
|
|
661
|
-
declare class MemoryBlobStorage implements BlobStorage {
|
|
662
|
-
private readonly bytes;
|
|
663
|
-
private readonly records;
|
|
664
|
-
storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
|
|
665
|
-
loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
|
|
666
|
-
hasBytes(sha256: SHA256): Promise<boolean>;
|
|
667
|
-
deleteBytes(sha256: SHA256): Promise<void>;
|
|
668
|
-
saveRecord(record: BlobRecord): Promise<void>;
|
|
669
|
-
loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
|
|
670
|
-
deleteRecord(sha256: SHA256): Promise<void>;
|
|
671
|
-
listRecords(): Promise<BlobRecord[]>;
|
|
672
|
-
exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
|
|
673
|
-
}
|
|
674
|
-
interface IndexedDBBlobConfig {
|
|
675
|
-
/** Name of the IndexedDB database. Defaults to 'aiworkspace-blobs'. */
|
|
676
|
-
dbName?: string;
|
|
1055
|
+
|
|
1056
|
+
interface TurnRef {
|
|
1057
|
+
id: UUID;
|
|
1058
|
+
version: number;
|
|
677
1059
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
*
|
|
684
|
-
* Transaction discipline matches IndexedDBBlobStorage: never await inside an
|
|
685
|
-
* active transaction. All multi-step operations chain synchronous IDB
|
|
686
|
-
* request handlers inside a single Promise.
|
|
687
|
-
*/
|
|
688
|
-
declare class IndexedDBBlobStorage implements BlobStorage {
|
|
689
|
-
private readonly dbName;
|
|
690
|
-
private db;
|
|
691
|
-
constructor(config?: IndexedDBBlobConfig);
|
|
692
|
-
open(): Promise<void>;
|
|
693
|
-
private createSchema;
|
|
694
|
-
close(): void;
|
|
695
|
-
deleteDatabase(): Promise<void>;
|
|
696
|
-
private getDB;
|
|
697
|
-
private readTx;
|
|
698
|
-
private writeTx;
|
|
699
|
-
storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
|
|
700
|
-
loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
|
|
701
|
-
hasBytes(sha256: SHA256): Promise<boolean>;
|
|
702
|
-
deleteBytes(sha256: SHA256): Promise<void>;
|
|
703
|
-
saveRecord(record: BlobRecord): Promise<void>;
|
|
704
|
-
loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
|
|
705
|
-
deleteRecord(sha256: SHA256): Promise<void>;
|
|
706
|
-
listRecords(): Promise<BlobRecord[]>;
|
|
707
|
-
exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
|
|
1060
|
+
declare class TurnTree {
|
|
1061
|
+
private readonly db;
|
|
1062
|
+
constructor(db: WorkspaceDatabase);
|
|
1063
|
+
private turns;
|
|
1064
|
+
private sessions;
|
|
708
1065
|
/**
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
* are new — avoids a window where bytes exist without a record.
|
|
1066
|
+
* Compound filter for a specific (sessionId, id, version) tuple.
|
|
1067
|
+
* Uses only declared schema fields — never $id.
|
|
712
1068
|
*/
|
|
713
|
-
|
|
1069
|
+
private turnFilter;
|
|
1070
|
+
getHead(sessionId: UUID): Promise<TurnRef | null>;
|
|
1071
|
+
setHead(sessionId: UUID, head: TurnRef | null): Promise<void>;
|
|
1072
|
+
append(sessionId: UUID, turn: Turn): Promise<Turn>;
|
|
1073
|
+
appendBatch(sessionId: UUID, turns: Turn[], finalHead: TurnRef | null): Promise<void>;
|
|
1074
|
+
replaceVersion(sessionId: UUID, newTurn: Turn): Promise<void>;
|
|
1075
|
+
branch(sessionId: UUID, newTurn: Turn): Promise<void>;
|
|
1076
|
+
loadAllTurns(sessionId: UUID): Promise<Turn[]>;
|
|
1077
|
+
getActiveChain(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Turn[]>;
|
|
1078
|
+
buildNodeGraph(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Record<UUID, TurnNode>>;
|
|
1079
|
+
deleteSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<void>;
|
|
1080
|
+
copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
|
|
714
1081
|
}
|
|
715
1082
|
|
|
716
1083
|
declare function computeSHA256(data: Uint8Array): Promise<SHA256>;
|
|
@@ -718,13 +1085,12 @@ interface BlobStoreConfig {
|
|
|
718
1085
|
/**
|
|
719
1086
|
* When true, blobs with refCount === 0 are deleted from the backend
|
|
720
1087
|
* immediately on release. When false (default), they are retained until
|
|
721
|
-
* an explicit GC sweep via gc(). Lazy GC is safer for offline-first apps
|
|
722
|
-
* that may need blobs for re-upload after a crash.
|
|
1088
|
+
* an explicit GC sweep via gc(). Lazy GC is safer for offline-first apps.
|
|
723
1089
|
*/
|
|
724
1090
|
eagerEviction?: boolean;
|
|
725
1091
|
}
|
|
726
1092
|
declare class BlobStore {
|
|
727
|
-
private readonly
|
|
1093
|
+
private readonly storage;
|
|
728
1094
|
private readonly config;
|
|
729
1095
|
/**
|
|
730
1096
|
* In-memory cache of BlobRecords. Kept consistent with the backend on
|
|
@@ -733,61 +1099,22 @@ declare class BlobStore {
|
|
|
733
1099
|
private readonly recordCache;
|
|
734
1100
|
/**
|
|
735
1101
|
* Called after any operation that changes the blob registry.
|
|
736
|
-
*
|
|
737
|
-
*
|
|
1102
|
+
* Passes the full BlobRecord (or null on deletion). The integration
|
|
1103
|
+
* layer wires this to an Index patch that updates the blob index.
|
|
1104
|
+
*
|
|
1105
|
+
* BlobRecord is a superset of the former BlobSummary — callers
|
|
1106
|
+
* that only need summary fields (sha256, mediaType, sizeBytes, etc.)
|
|
1107
|
+
* can read them directly from BlobRecord without a separate type.
|
|
738
1108
|
*/
|
|
739
|
-
onRegistryChanged?: (sha256: SHA256,
|
|
1109
|
+
onRegistryChanged?: (sha256: SHA256, record: BlobRecord | null) => void;
|
|
740
1110
|
constructor(backend: BlobStorage, config?: BlobStoreConfig);
|
|
741
1111
|
init(): Promise<void>;
|
|
742
|
-
/**
|
|
743
|
-
* Register a binary blob and return a BlobRef.
|
|
744
|
-
*
|
|
745
|
-
* If the same bytes have been registered before (same SHA-256), only the
|
|
746
|
-
* ref count is incremented — bytes are not written again.
|
|
747
|
-
*
|
|
748
|
-
* @param data Raw binary content.
|
|
749
|
-
* @param mediaType MIME type of the content.
|
|
750
|
-
* @param filename Optional original filename for UI display.
|
|
751
|
-
*/
|
|
752
1112
|
register(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<BlobRef, WorkspaceError>>;
|
|
753
|
-
/**
|
|
754
|
-
* Increment the ref count for a blob that is being referenced by a new
|
|
755
|
-
* turn or context entry. Safe to call multiple times for the same sha256.
|
|
756
|
-
*/
|
|
757
1113
|
retain(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
|
|
758
|
-
/**
|
|
759
|
-
* Decrement the ref count. When it reaches 0, the blob is eligible for
|
|
760
|
-
* eviction. With eagerEviction=true, bytes are deleted immediately.
|
|
761
|
-
* With eagerEviction=false, bytes are retained until gc() is called.
|
|
762
|
-
*/
|
|
763
1114
|
release(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
|
|
764
|
-
/**
|
|
765
|
-
* Record that a blob has been uploaded to a provider and assigned a file ID.
|
|
766
|
-
* Idempotent — calling with the same providerId + fileId has no effect.
|
|
767
|
-
*/
|
|
768
1115
|
recordRemoteId(sha256: SHA256, providerId: string, fileId: string): Promise<Result<void, WorkspaceError>>;
|
|
769
|
-
/**
|
|
770
|
-
* Get the remote file ID for a blob on a specific provider, if known.
|
|
771
|
-
*/
|
|
772
1116
|
getRemoteId(sha256: SHA256, providerId: string): string | null;
|
|
773
|
-
/**
|
|
774
|
-
* Resolve a BlobRef to a ResolvedBlob.
|
|
775
|
-
*
|
|
776
|
-
* If a remote file ID is known for the given providerId, returns
|
|
777
|
-
* { kind: 'remote' } — no bytes transferred to the model call.
|
|
778
|
-
* Otherwise loads bytes from the backend and returns { kind: 'inline' }.
|
|
779
|
-
*
|
|
780
|
-
* @param ref The BlobRef to resolve.
|
|
781
|
-
* @param providerId The provider the resolved blob will be sent to
|
|
782
|
-
* (e.g. 'anthropic', 'openai'). Used to look up
|
|
783
|
-
* known remote file IDs. Pass null for local-only use.
|
|
784
|
-
*/
|
|
785
1117
|
resolveRef(ref: BlobRef, providerId: string | null): Promise<Result<ResolvedBlob, WorkspaceError>>;
|
|
786
|
-
/**
|
|
787
|
-
* Resolve multiple BlobRefs, collecting all results.
|
|
788
|
-
* Returns a map of sha256 → ResolvedBlob for successes and a list of
|
|
789
|
-
* errors for failures, so partial failures don't block the whole build.
|
|
790
|
-
*/
|
|
791
1118
|
resolveRefs(refs: BlobRef[], providerId: string | null): Promise<{
|
|
792
1119
|
resolved: Map<SHA256, ResolvedBlob>;
|
|
793
1120
|
errors: Array<{
|
|
@@ -795,74 +1122,84 @@ declare class BlobStore {
|
|
|
795
1122
|
error: WorkspaceError;
|
|
796
1123
|
}>;
|
|
797
1124
|
}>;
|
|
798
|
-
/**
|
|
799
|
-
* Delete bytes for all blobs with refCount === 0.
|
|
800
|
-
* Records are kept so re-registration is cheap (no re-hash needed).
|
|
801
|
-
* Call this periodically or on app startup to reclaim storage.
|
|
802
|
-
*
|
|
803
|
-
* Returns the number of blobs whose bytes were evicted.
|
|
804
|
-
*/
|
|
805
1125
|
gc(): Promise<number>;
|
|
806
|
-
|
|
807
|
-
* Fully purge a blob — delete both bytes and record regardless of refCount.
|
|
808
|
-
* Only use this for explicit user-initiated deletion or during workspace
|
|
809
|
-
* destruction. In normal operation, use release() and let GC handle it.
|
|
810
|
-
*/
|
|
1126
|
+
gcFull(): Promise<number>;
|
|
811
1127
|
purge(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
|
|
812
1128
|
getRecord(sha256: SHA256): BlobRecord | null;
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
1129
|
+
/**
|
|
1130
|
+
* All records — used to seed Index.blobs on init.
|
|
1131
|
+
* Returns BlobRecord directly (BlobSummary has been removed).
|
|
1132
|
+
*/
|
|
1133
|
+
getAllRecords(): Record<SHA256, BlobRecord>;
|
|
816
1134
|
}
|
|
817
1135
|
|
|
818
1136
|
declare class ContentStore {
|
|
819
|
-
private readonly
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
private
|
|
823
|
-
private
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1137
|
+
private readonly db;
|
|
1138
|
+
readonly tree: TurnTree;
|
|
1139
|
+
readonly blobs: BlobStore;
|
|
1140
|
+
private readonly roleCache;
|
|
1141
|
+
private readonly preferenceCache;
|
|
1142
|
+
private readonly contextCache;
|
|
1143
|
+
/**
|
|
1144
|
+
* Called after any blob registry change with the sha256 and updated
|
|
1145
|
+
* BlobRecord (null on deletion). Wire this to your state manager to
|
|
1146
|
+
* keep Index.blobs current.
|
|
1147
|
+
*
|
|
1148
|
+
* ContentStore sets this on BlobStore.onRegistryChanged internally.
|
|
1149
|
+
* Consumers set this property to receive the forwarded notifications.
|
|
1150
|
+
*/
|
|
1151
|
+
onBlobRegistryChanged?: (sha256: SHA256, record: BlobRecord | null) => void;
|
|
1152
|
+
private constructor();
|
|
1153
|
+
static create(db: WorkspaceDatabase, blobStorage: BlobStorage, config?: ContentStoreConfig): Promise<ContentStore>;
|
|
1154
|
+
private init;
|
|
1155
|
+
getTurnTree(): TurnTree;
|
|
828
1156
|
getRole(name: string): Promise<Result<Role, WorkspaceError>>;
|
|
829
|
-
getPreference(id: UUID): Promise<Result<Preference, WorkspaceError>>;
|
|
830
|
-
getContext(key: string): Promise<Result<Context, WorkspaceError>>;
|
|
831
|
-
getContextByTopics(indexState: IndexState, topics: string[]): Promise<Context[]>;
|
|
832
|
-
getTranscriptWindow(sessionId: UUID, windowSize?: number): Promise<TranscriptWindow>;
|
|
833
1157
|
saveRole(role: Role): Promise<void>;
|
|
834
|
-
savePreference(preference: Preference): Promise<void>;
|
|
835
|
-
saveContext(context: Context): Promise<void>;
|
|
836
|
-
copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
|
|
837
1158
|
deleteRole(name: string): Promise<void>;
|
|
1159
|
+
getPreference(id: UUID): Promise<Result<Preference, WorkspaceError>>;
|
|
1160
|
+
savePreference(preference: Preference): Promise<void>;
|
|
838
1161
|
deletePreference(id: UUID): Promise<void>;
|
|
1162
|
+
getContext(key: string): Promise<Result<Context, WorkspaceError>>;
|
|
1163
|
+
saveContext(context: Context): Promise<void>;
|
|
839
1164
|
deleteContext(key: string): Promise<void>;
|
|
1165
|
+
getContextByTopics(indexState: Index, topics: string[]): Promise<Context[]>;
|
|
1166
|
+
saveSession(meta: SessionMeta): Promise<void>;
|
|
1167
|
+
updateSessionMeta(sessionId: UUID, patch: DeepPartial<SessionMeta>): Promise<void>;
|
|
1168
|
+
deleteSession(sessionId: UUID): Promise<void>;
|
|
1169
|
+
registerBlob(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<BlobRef, WorkspaceError>>;
|
|
1170
|
+
retainBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
|
|
1171
|
+
releaseBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
|
|
1172
|
+
purgeBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
|
|
1173
|
+
recordBlobRemoteId(sha256: SHA256, providerId: string, fileId: string): Promise<Result<void, WorkspaceError>>;
|
|
1174
|
+
getBlobRecord(sha256: SHA256): BlobRecord | null;
|
|
1175
|
+
getAllBlobRecords(): Record<SHA256, BlobRecord>;
|
|
1176
|
+
/**
|
|
1177
|
+
* Returns the blob resolver function expected by PromptBuilder.
|
|
1178
|
+
* Closes over the internal BlobStore — no BlobStore reference leaks out.
|
|
1179
|
+
*/
|
|
1180
|
+
getBlobResolver(): BlobStore['resolveRefs'];
|
|
840
1181
|
recordTurn(sessionId: UUID, turn: Turn): Promise<Result<void, WorkspaceError>>;
|
|
841
1182
|
editTurn(sessionId: UUID, turnId: UUID, newBlocks: ContentBlock[], newVersion: number, roleSnapshot?: string): Promise<Result<void, WorkspaceError>>;
|
|
842
1183
|
branchTurn(sessionId: UUID, newTurn: Turn): Promise<Result<void, WorkspaceError>>;
|
|
843
|
-
deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number, newHead:
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
} | null): Promise<Result<void, WorkspaceError>>;
|
|
847
|
-
activateSession(meta: SessionMeta): Promise<Result<void, WorkspaceError>>;
|
|
848
|
-
deactivateSession(meta?: SessionMeta): Promise<void>;
|
|
849
|
-
resolveSession(indexState: IndexState, sessionId: UUID): Promise<Result<EffectiveSession, WorkspaceError>>;
|
|
850
|
-
flush(): Promise<void>;
|
|
851
|
-
dispose(): Promise<void>;
|
|
1184
|
+
deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<void, WorkspaceError>>;
|
|
1185
|
+
copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
|
|
1186
|
+
resolveSession(workspace: Workspace, sessionId: UUID, transcript?: Turn[]): Promise<Result<EffectiveSession, WorkspaceError>>;
|
|
852
1187
|
}
|
|
853
1188
|
|
|
854
|
-
declare function workspaceReducer(state:
|
|
1189
|
+
declare function workspaceReducer({ index: state }: Workspace, command: Command): Result<DeepPartial<Workspace>, WorkspaceError>;
|
|
855
1190
|
|
|
856
1191
|
declare class WorkspaceManager {
|
|
857
1192
|
private readonly contentStore;
|
|
1193
|
+
/**
|
|
1194
|
+
* Called when BlobStore triggers a registry change outside of a dispatch()
|
|
1195
|
+
* call — e.g. eagerEviction deleting a blob on release. The caller should
|
|
1196
|
+
* merge this patch into their Workspace.
|
|
1197
|
+
*/
|
|
1198
|
+
onWorkspacePatch?: (patch: DeepPartial<Workspace>) => void;
|
|
858
1199
|
constructor(contentStore: ContentStore);
|
|
859
|
-
reduce(
|
|
860
|
-
dispatch(
|
|
861
|
-
resolveSession(
|
|
862
|
-
activateSession(indexState: IndexState, sessionId: UUID): Promise<Result<void, WorkspaceError>>;
|
|
863
|
-
deactivateSession(indexState?: IndexState): Promise<void>;
|
|
864
|
-
flush(): Promise<void>;
|
|
865
|
-
dispose(): Promise<void>;
|
|
1200
|
+
reduce(workspace: Workspace, command: Command): Result<DeepPartial<Workspace>, WorkspaceError>;
|
|
1201
|
+
dispatch(workspace: Workspace, command: Command): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
|
|
1202
|
+
resolveSession(workspace: Workspace, sessionId: UUID): Promise<Result<EffectiveSession, WorkspaceError>>;
|
|
866
1203
|
private handleContentSideEffects;
|
|
867
1204
|
}
|
|
868
1205
|
|
|
@@ -873,27 +1210,202 @@ interface Summarizer {
|
|
|
873
1210
|
}>;
|
|
874
1211
|
}
|
|
875
1212
|
|
|
1213
|
+
interface ContextRankingInput {
|
|
1214
|
+
entries: Context[];
|
|
1215
|
+
recentMessages: string[];
|
|
1216
|
+
config: ContextRelevanceConfig;
|
|
1217
|
+
}
|
|
1218
|
+
interface ContextRetriever {
|
|
1219
|
+
rank(input: ContextRankingInput): Context[];
|
|
1220
|
+
}
|
|
1221
|
+
interface PlanningInput {
|
|
1222
|
+
systemInstructions?: string;
|
|
1223
|
+
persona: string;
|
|
1224
|
+
preferences: Preference[];
|
|
1225
|
+
context: Context[];
|
|
1226
|
+
transcript: Turn[];
|
|
1227
|
+
budget?: TokenBudget;
|
|
1228
|
+
}
|
|
1229
|
+
interface PlanningOutput {
|
|
1230
|
+
preferences: Preference[];
|
|
1231
|
+
context: Context[];
|
|
1232
|
+
transcript: Turn[];
|
|
1233
|
+
truncated: {
|
|
1234
|
+
preferences: number;
|
|
1235
|
+
interactions: number;
|
|
1236
|
+
context: number;
|
|
1237
|
+
};
|
|
1238
|
+
breakdown: Record<string, number>;
|
|
1239
|
+
totalUsed: number;
|
|
1240
|
+
lastRoleBeforeTruncation: string | null;
|
|
1241
|
+
}
|
|
1242
|
+
interface TokenPlanner {
|
|
1243
|
+
plan(input: PlanningInput): PlanningOutput;
|
|
1244
|
+
}
|
|
1245
|
+
interface AssemblyInput {
|
|
1246
|
+
session: EffectiveSession;
|
|
1247
|
+
plan: PlanningOutput;
|
|
1248
|
+
resolvedBlobs: Map<SHA256, ResolvedBlob>;
|
|
1249
|
+
summaryBlockText: string | null;
|
|
1250
|
+
warnings: string[];
|
|
1251
|
+
conflicts: PreferenceConflict[];
|
|
1252
|
+
budgetTotal: number;
|
|
1253
|
+
}
|
|
1254
|
+
declare class PromptAssembler {
|
|
1255
|
+
assemble(input: AssemblyInput): Prompt;
|
|
1256
|
+
private buildReferentialBlock;
|
|
1257
|
+
private resolveTurnBlocks;
|
|
1258
|
+
}
|
|
876
1259
|
declare class PromptBuilder {
|
|
877
|
-
private
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
* @param options.relevanceConfig Optional context ranking config.
|
|
891
|
-
*/
|
|
892
|
-
build(effectiveSession: EffectiveSession, options?: {
|
|
893
|
-
resolvedBlobs?: Map<SHA256, ResolvedBlob>;
|
|
1260
|
+
private retriever;
|
|
1261
|
+
private planner;
|
|
1262
|
+
private assembler;
|
|
1263
|
+
private summarizer?;
|
|
1264
|
+
private blobResolver;
|
|
1265
|
+
constructor(dependencies: {
|
|
1266
|
+
blobResolver: BlobStore['resolveRefs'];
|
|
1267
|
+
retriever?: ContextRetriever;
|
|
1268
|
+
planner?: TokenPlanner;
|
|
1269
|
+
assembler?: PromptAssembler;
|
|
1270
|
+
summarizer?: Summarizer;
|
|
1271
|
+
});
|
|
1272
|
+
build(session: EffectiveSession, options?: {
|
|
894
1273
|
tokenBudget?: TokenBudget;
|
|
895
1274
|
relevanceConfig?: ContextRelevanceConfig;
|
|
1275
|
+
providerId?: string;
|
|
896
1276
|
}): Promise<Prompt>;
|
|
1277
|
+
private collectUsedBlobRefs;
|
|
1278
|
+
private deduplicateBlobRefs;
|
|
1279
|
+
private extractRecentUserQueries;
|
|
1280
|
+
private resolvePreferenceConflicts;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
declare class Session {
|
|
1284
|
+
/** The session ID this object manages. */
|
|
1285
|
+
readonly sessionId: UUID;
|
|
1286
|
+
/**
|
|
1287
|
+
* The turn DAG. Keys are turn IDs. Mutated in-place on every write.
|
|
1288
|
+
* Callers read this directly for rendering — no copy is made.
|
|
1289
|
+
*/
|
|
1290
|
+
readonly nodes: Record<UUID, TurnNode>;
|
|
1291
|
+
/**
|
|
1292
|
+
* Current head of the active branch. Mirrors what is in
|
|
1293
|
+
* workspace.index.sessions[sessionId].head after each patch is applied.
|
|
1294
|
+
* Session keeps its own copy so reads don't require workspace.
|
|
1295
|
+
*/
|
|
1296
|
+
private head;
|
|
1297
|
+
/** Turns not yet flushed to storage. */
|
|
1298
|
+
private readonly dirtyBuffer;
|
|
1299
|
+
private flushTimer;
|
|
1300
|
+
private flushChain;
|
|
1301
|
+
private readonly flushConfig;
|
|
1302
|
+
private readonly tree;
|
|
1303
|
+
private readonly contentStore;
|
|
1304
|
+
constructor(sessionId: UUID, nodes: Record<UUID, TurnNode>, head: TurnRef | null, tree: TurnTree, contentStore: ContentStore, flushConfig?: FlushConfig);
|
|
1305
|
+
activeChain(): TurnNode[];
|
|
1306
|
+
siblings(turnId: UUID): TurnNode[];
|
|
1307
|
+
branchInfo(turnId: UUID): BranchInfo;
|
|
1308
|
+
addTurn(workspace: Workspace, turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
|
|
1309
|
+
editTurn(workspace: Workspace, turnId: UUID, newBlocks: ContentBlock[], roleSnapshot?: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
|
|
1310
|
+
branchFrom(workspace: Workspace, newTurn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
|
|
1311
|
+
deleteTurn(workspace: Workspace, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
|
|
1312
|
+
switchVersionLeft(_: Workspace, turnId: UUID): Result<DeepPartial<Workspace>, WorkspaceError>;
|
|
1313
|
+
switchVersionRight(_: Workspace, turnId: UUID): Result<DeepPartial<Workspace>, WorkspaceError>;
|
|
1314
|
+
private switchVersion;
|
|
1315
|
+
resolve(workspace: Workspace): Promise<Result<EffectiveSession, WorkspaceError>>;
|
|
1316
|
+
flush(): Promise<void>;
|
|
1317
|
+
dispose(): Promise<void>;
|
|
1318
|
+
private findSubtreeTipForVersion;
|
|
1319
|
+
private collectSubtreeIds;
|
|
1320
|
+
private upsertNode;
|
|
1321
|
+
private scheduleFlush;
|
|
1322
|
+
private cancelFlushTimer;
|
|
1323
|
+
private doFlush;
|
|
1324
|
+
}
|
|
1325
|
+
declare function buildTurnNode(turn: Turn, children?: UUID[]): TurnNode;
|
|
1326
|
+
|
|
1327
|
+
interface SessionManagerConfig {
|
|
1328
|
+
flush?: Partial<FlushConfig>;
|
|
1329
|
+
}
|
|
1330
|
+
interface OpenResult {
|
|
1331
|
+
session: Session;
|
|
1332
|
+
patch: DeepPartial<Workspace>;
|
|
1333
|
+
}
|
|
1334
|
+
declare class SessionManager {
|
|
1335
|
+
private readonly workspaceManager;
|
|
1336
|
+
private readonly contentStore;
|
|
1337
|
+
private readonly flushConfig;
|
|
1338
|
+
constructor(workspaceManager: WorkspaceManager, contentStore: ContentStore, config?: SessionManagerConfig);
|
|
1339
|
+
open(workspace: Workspace, sessionId: UUID): Promise<Result<OpenResult, WorkspaceError>>;
|
|
1340
|
+
close(session: Session): Promise<void>;
|
|
1341
|
+
get workspace(): WorkspaceManager;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* In-process implementation backed by plain Maps.
|
|
1346
|
+
* Suitable for development, testing, and server-side runtimes without
|
|
1347
|
+
* access to IndexedDB.
|
|
1348
|
+
*/
|
|
1349
|
+
declare class MemoryBlobStorage implements BlobStorage {
|
|
1350
|
+
private readonly bytes;
|
|
1351
|
+
private readonly records;
|
|
1352
|
+
storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
|
|
1353
|
+
loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
|
|
1354
|
+
hasBytes(sha256: SHA256): Promise<boolean>;
|
|
1355
|
+
deleteBytes(sha256: SHA256): Promise<void>;
|
|
1356
|
+
saveRecord(record: BlobRecord): Promise<void>;
|
|
1357
|
+
loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
|
|
1358
|
+
deleteRecord(sha256: SHA256): Promise<void>;
|
|
1359
|
+
listRecords(): Promise<BlobRecord[]>;
|
|
1360
|
+
exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
|
|
1361
|
+
/**
|
|
1362
|
+
* Atomic register for MemoryBlobStorage — sequential ops are atomic
|
|
1363
|
+
* in a single-threaded JS runtime, so this is equivalent to two separate
|
|
1364
|
+
* calls, but we implement it for interface consistency.
|
|
1365
|
+
*/
|
|
1366
|
+
registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
interface IndexedDBBlobConfig {
|
|
1370
|
+
/** Name of the IndexedDB database. Defaults to 'aiworkspace-blobs'. */
|
|
1371
|
+
dbName?: string;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* IndexedDB-backed blob storage.
|
|
1375
|
+
*
|
|
1376
|
+
* Bytes are stored as raw Uint8Array — IndexedDB handles binary natively,
|
|
1377
|
+
* no base64 encoding at rest. This is important for large files.
|
|
1378
|
+
*
|
|
1379
|
+
* Transaction discipline: never await inside an active transaction.
|
|
1380
|
+
* All multi-step operations chain synchronous IDB request handlers
|
|
1381
|
+
* inside a single Promise.
|
|
1382
|
+
*/
|
|
1383
|
+
declare class IndexedDBBlobStorage implements BlobStorage {
|
|
1384
|
+
private readonly dbName;
|
|
1385
|
+
private db;
|
|
1386
|
+
constructor(config?: IndexedDBBlobConfig);
|
|
1387
|
+
open(): Promise<void>;
|
|
1388
|
+
private createSchema;
|
|
1389
|
+
close(): void;
|
|
1390
|
+
deleteDatabase(): Promise<void>;
|
|
1391
|
+
private getDB;
|
|
1392
|
+
private readTx;
|
|
1393
|
+
private writeTx;
|
|
1394
|
+
storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
|
|
1395
|
+
loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
|
|
1396
|
+
hasBytes(sha256: SHA256): Promise<boolean>;
|
|
1397
|
+
deleteBytes(sha256: SHA256): Promise<void>;
|
|
1398
|
+
saveRecord(record: BlobRecord): Promise<void>;
|
|
1399
|
+
loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
|
|
1400
|
+
deleteRecord(sha256: SHA256): Promise<void>;
|
|
1401
|
+
listRecords(): Promise<BlobRecord[]>;
|
|
1402
|
+
exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
|
|
1403
|
+
/**
|
|
1404
|
+
* Atomically stores bytes and saves a record together.
|
|
1405
|
+
* Preferred over calling storeBytes + saveRecord separately when both
|
|
1406
|
+
* are new — avoids a window where bytes exist without a record.
|
|
1407
|
+
*/
|
|
1408
|
+
registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
|
|
897
1409
|
}
|
|
898
1410
|
|
|
899
|
-
export { type AddContext, type
|
|
1411
|
+
export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTurn, type BaseCommand, type BlobCommand, type BlobMediaType, type BlobRecord, type BlobRef, type BlobStorage, BlobStore, type BlobStoreConfig, type BranchInfo, type BranchTurn, COLLECTIONS, type CacheConfig, type CollectionName, type Command, type ContentBlock, ContentStore, type ContentStoreConfig, type Context, type ContextContent, type ContextRelevanceConfig, type ContextSummary, type CreateSession, type CreateWorkspace, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type EditTurn, type EffectiveSession, type FlushConfig, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type IndexedDBBlobConfig, IndexedDBBlobStorage, MemoryBlobStorage, type OpenResult, type OverrideSessionPreferences, 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, Session, SessionManager, type SessionManagerConfig, type SessionMeta, type Settings, type SummaryBlock, type SwitchRole, type TextBlock, type ThinkingBlock, type Timestamp, type TokenBudget, type ToolResultBlock, type ToolUseBlock, type TopicIndex, type TranscriptWindow, type Turn, type TurnNode, type TurnRef, type TurnRole, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type Workspace, type WorkspaceBundle, type WorkspaceDatabase, type WorkspaceError, WorkspaceManager, buildTurnNode, computeSHA256, createSimpleWorkspace, createWorkspaceDatabase, del, err, extractBlobRecord, extractBlobRef, merge, ok, omitNullUndefined, workspaceReducer };
|