@asaidimu/utils-workspace 2.1.1 → 3.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.
package/index.d.ts CHANGED
@@ -1,5 +1,17 @@
1
1
  import { QueryFilter, PaginationOptions } from '@asaidimu/query';
2
2
  import { IndexDefinition, SchemaDefinition, SchemaChange, DataTransform } from '@asaidimu/anansi';
3
+ import { EventBus } from '@asaidimu/events';
4
+
5
+ /**
6
+ * Utility type for representing partial updates to the state, allowing deep nesting.
7
+ * It makes all properties optional and applies the same transformation recursively
8
+ * to nested objects and array elements, allowing for selective updates while
9
+ * preserving the original structure. It also includes the original type T and
10
+ * undefined as possibilities for the top level and nested values.
11
+ */
12
+ 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 : {
13
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined;
14
+ } | undefined | T : T | undefined;
3
15
 
4
16
  type UUID = string;
5
17
  type Timestamp = string;
@@ -12,35 +24,38 @@ type Result<T, E = WorkspaceError> = {
12
24
  ok: false;
13
25
  error: E;
14
26
  };
15
- type WorkspaceError = {
27
+ type DuplicateKeyError = {
16
28
  code: 'DUPLICATE_KEY';
17
29
  resource: string;
18
30
  key: string;
19
- } | {
31
+ };
32
+ type NotFoundError = {
20
33
  code: 'NOT_FOUND';
21
34
  resource: string;
22
35
  id: string;
23
- } | {
36
+ };
37
+ type InvalidCommandError = {
24
38
  code: 'INVALID_COMMAND';
25
39
  reason: string;
26
- } | {
40
+ };
41
+ type BackendError = {
27
42
  code: 'BACKEND_ERROR';
28
43
  reason: string;
29
- } | {
44
+ };
45
+ type BlobError = {
30
46
  code: 'BLOB_ERROR';
31
47
  reason: string;
32
48
  };
49
+ type WorkspaceError = DuplicateKeyError | NotFoundError | InvalidCommandError | BackendError | BlobError;
33
50
  interface Settings {
34
51
  language: string;
35
52
  defaultRole?: string;
36
53
  prompt?: string;
37
54
  }
38
- interface Project {
55
+ type Project<Metadata extends Record<string, any> = Record<string, any>> = Metadata & {
56
+ id: UUID;
39
57
  name: string;
40
- owner: string;
41
- repository?: string;
42
- metadata?: Record<string, any>;
43
- }
58
+ };
44
59
  type ImageMediaType = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp';
45
60
  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';
46
61
  type BlobMediaType = ImageMediaType | DocumentMediaType;
@@ -78,59 +93,104 @@ interface BlobRecord {
78
93
  lastUsedAt: Timestamp;
79
94
  }
80
95
  interface TextBlock {
96
+ id: UUID;
81
97
  type: 'text';
82
98
  text: string;
83
99
  }
84
100
  interface ImageBlock {
101
+ id: UUID;
85
102
  type: 'image';
86
103
  ref?: BlobRef;
87
104
  blob?: ResolvedBlob;
88
105
  altText?: string;
89
106
  }
90
107
  interface DocumentBlock {
108
+ id: UUID;
91
109
  type: 'document';
92
110
  ref?: BlobRef;
93
111
  blob?: ResolvedBlob;
94
112
  title?: string;
95
113
  }
114
+ interface TaskProposalBlock {
115
+ id: UUID;
116
+ taskId?: UUID;
117
+ type: 'task:proposal';
118
+ title: string;
119
+ steps: {
120
+ id?: UUID;
121
+ text: string;
122
+ status: 'todo' | 'done';
123
+ }[];
124
+ action: 'create' | 'update' | 'complete';
125
+ }
96
126
  interface ToolUseBlock {
97
- type: 'tool_use';
98
- toolUseId: string;
127
+ id: UUID;
128
+ type: 'tool:use';
99
129
  name: string;
100
130
  input: Record<string, unknown>;
101
131
  }
102
132
  interface ToolResultBlock {
103
- type: 'tool_result';
104
- toolUseId: string;
133
+ id: UUID;
134
+ type: 'tool:result';
135
+ useId: UUID;
105
136
  content: string | Record<string, unknown>;
106
137
  isError?: boolean;
107
138
  }
108
139
  interface ThinkingBlock {
140
+ id: UUID;
109
141
  type: 'thinking';
110
142
  thinking: string;
111
143
  }
112
144
  interface SummaryBlock {
145
+ id: UUID;
113
146
  type: 'summary';
114
147
  text: string;
115
148
  }
116
149
  interface RoleTransitionBlock {
117
- type: 'role_transition';
150
+ id: UUID;
151
+ type: 'role:transition';
118
152
  previousRole: string | null;
119
153
  newRole: string;
120
154
  }
121
- type ContentBlock = TextBlock | ImageBlock | DocumentBlock | ToolUseBlock | ToolResultBlock | SummaryBlock | RoleTransitionBlock | ThinkingBlock;
155
+ type ContentBlock = TextBlock | ImageBlock | DocumentBlock | ToolUseBlock | ToolResultBlock | SummaryBlock | RoleTransitionBlock | ThinkingBlock | TaskProposalBlock;
156
+ interface ToolSummary {
157
+ name: string;
158
+ description: string;
159
+ parameters: {
160
+ type: 'object';
161
+ properties: Record<string, any>;
162
+ required: string[];
163
+ };
164
+ /**
165
+ * The semantic tags for this tool.
166
+ * Used by the ContextRetriever to filter relevance.
167
+ */
168
+ topics: string[];
169
+ }
170
+ interface ToolCall {
171
+ id: UUID;
172
+ tool: UUID;
173
+ arguments: Record<string, any>;
174
+ }
175
+ type AuthRequest = {
176
+ type: 'command';
177
+ payload: Command;
178
+ } | {
179
+ type: 'tool';
180
+ payload: ToolCall;
181
+ };
122
182
  type TurnRole = 'user' | 'assistant' | 'tool';
123
183
  interface Turn {
124
184
  id: UUID;
125
185
  version: number;
126
- role: TurnRole;
186
+ owner: TurnRole;
127
187
  blocks: ContentBlock[];
128
188
  timestamp: Timestamp;
129
189
  /**
130
190
  * The name of the role active when this turn was recorded.
131
191
  * Snapshot so history is stable even if the role is later renamed.
132
192
  */
133
- roleSnapshot?: string;
193
+ role?: string;
134
194
  /**
135
195
  * Parent pointer. Null for root turns.
136
196
  * This is plain data stored on the document — the DAG is reconstructed
@@ -224,6 +284,24 @@ interface SessionMeta {
224
284
  id: UUID;
225
285
  version: number;
226
286
  } | null;
287
+ task: UUID | null;
288
+ }
289
+ type TaskStatus = 'todo' | 'active' | 'done' | 'blocked' | 'defered';
290
+ interface TaskStep {
291
+ id: UUID;
292
+ text: string;
293
+ completed?: Timestamp;
294
+ }
295
+ interface Task {
296
+ id: UUID;
297
+ title: string;
298
+ description?: string;
299
+ status: TaskStatus;
300
+ steps: TaskStep[];
301
+ topics: string[];
302
+ metadata?: Record<string, any>;
303
+ created: Timestamp;
304
+ updated: Timestamp;
227
305
  }
228
306
  interface RoleSummary {
229
307
  name: string;
@@ -248,10 +326,21 @@ interface ContextSummary {
248
326
  source?: string;
249
327
  metadata?: Record<string, any>;
250
328
  }
329
+ interface TaskSummary {
330
+ id: UUID;
331
+ title: string;
332
+ status: TaskStatus;
333
+ steps: {
334
+ completed: number;
335
+ total: number;
336
+ };
337
+ topics: string[];
338
+ }
251
339
  interface TopicIndex {
252
340
  topic: string;
253
341
  contextKeys: string[];
254
342
  preferences: UUID[];
343
+ tasks: UUID[];
255
344
  metadata?: {
256
345
  created?: Timestamp;
257
346
  updated?: Timestamp;
@@ -263,13 +352,15 @@ interface Index {
263
352
  preferences: Record<UUID, PreferenceSummary>;
264
353
  context: Record<string, ContextSummary>;
265
354
  sessions: Record<UUID, SessionMeta>;
355
+ tasks: Record<UUID, TaskSummary>;
266
356
  topics: Record<string, TopicIndex>;
267
357
  blobs: Record<SHA256, BlobRecord>;
358
+ tools: Record<string, ToolSummary>;
268
359
  }
269
- interface Workspace {
360
+ interface Workspace<ProjectMetadata extends Record<string, any> = Record<string, any>> {
270
361
  id: UUID;
271
362
  settings: Settings;
272
- project: Project;
363
+ project: Project<ProjectMetadata>;
273
364
  index: Index;
274
365
  }
275
366
  interface WorkspaceBundle {
@@ -281,6 +372,7 @@ interface WorkspaceBundle {
281
372
  sessions: Record<UUID, SessionMeta & {
282
373
  turns: Turn[];
283
374
  }>;
375
+ tasks: Record<UUID, Task>;
284
376
  blobs: Record<SHA256, BlobRecord>;
285
377
  }
286
378
  interface EffectiveSession {
@@ -289,12 +381,14 @@ interface EffectiveSession {
289
381
  preferences: Preference[];
290
382
  context: Context[];
291
383
  transcript: Turn[];
384
+ task: Task | null;
292
385
  instructions?: string;
293
386
  }
294
387
  interface CacheConfig {
295
388
  roles?: number;
296
389
  preferences?: number;
297
390
  context?: number;
391
+ tasks?: number;
298
392
  }
299
393
  interface FlushConfig {
300
394
  maxBufferSize: number;
@@ -375,6 +469,29 @@ interface DeleteContext extends BaseCommand {
375
469
  key: string;
376
470
  };
377
471
  }
472
+ interface AddTask extends BaseCommand {
473
+ type: 'task:add';
474
+ payload: Task;
475
+ }
476
+ interface UpdateTask extends BaseCommand {
477
+ type: 'task:update';
478
+ payload: Partial<Task> & {
479
+ id: UUID;
480
+ };
481
+ }
482
+ interface DeleteTask extends BaseCommand {
483
+ type: 'task:delete';
484
+ payload: {
485
+ id: UUID;
486
+ };
487
+ }
488
+ interface SaveTurn extends BaseCommand {
489
+ type: 'turn:save';
490
+ payload: {
491
+ sessionId: UUID;
492
+ turn: Turn;
493
+ };
494
+ }
378
495
  interface AddTurn extends BaseCommand {
379
496
  type: 'turn:add';
380
497
  payload: {
@@ -396,21 +513,20 @@ interface BranchTurn extends BaseCommand {
396
513
  type: 'turn:branch';
397
514
  payload: {
398
515
  sessionId: UUID;
399
- parentTurnId: UUID;
400
- parentVersion: number;
401
- newTurn: Turn;
516
+ turn: Turn;
402
517
  };
403
518
  }
519
+ interface TurnRef {
520
+ id: UUID;
521
+ version: number;
522
+ }
404
523
  interface DeleteTurn extends BaseCommand {
405
524
  type: 'turn:delete';
406
525
  payload: {
407
526
  sessionId: UUID;
408
527
  turnId: UUID;
409
528
  version: number;
410
- newHead: {
411
- id: UUID;
412
- version: number;
413
- } | null;
529
+ newHead: TurnRef | null;
414
530
  };
415
531
  }
416
532
  interface SwitchRole extends BaseCommand {
@@ -485,7 +601,11 @@ interface RecordBlobRemoteId extends BaseCommand {
485
601
  };
486
602
  }
487
603
  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;
604
+ interface CallTool extends BaseCommand {
605
+ type: 'tool:call';
606
+ payload: ToolCall;
607
+ }
608
+ type Command = CreateWorkspace | AddRole | UpdateRole | DeleteRole | AddPreference | UpdatePreference | DeletePreference | CreateSession | AddContext | UpdateContext | DeleteContext | AddTask | UpdateTask | DeleteTask | AddTurn | SaveTurn | EditTurn | BranchTurn | DeleteTurn | SwitchRole | AddSessionTopics | OverrideSessionPreferences | ForkSession | DeleteSession | BlobCommand | CallTool;
489
609
  interface TokenBudget {
490
610
  total: number;
491
611
  estimator?: (text: string) => number;
@@ -514,6 +634,7 @@ interface Prompt {
514
634
  persona: string;
515
635
  preferences: Preference[];
516
636
  context: Context[];
637
+ task: Task | null;
517
638
  };
518
639
  context: Context[];
519
640
  transcript: {
@@ -538,6 +659,13 @@ interface TranscriptWindow {
538
659
  flushedCount: number;
539
660
  hasMore: boolean;
540
661
  }
662
+ interface WorkspaceEvents {
663
+ 'workspace:changed': DeepPartial<Workspace>;
664
+ 'blobs:changed': {
665
+ sha256: SHA256;
666
+ record: BlobRecord | null;
667
+ };
668
+ }
541
669
 
542
670
  /**
543
671
  * Buffers write operations across one or more stores and commits them atomically.
@@ -971,25 +1099,19 @@ declare const COLLECTIONS: {
971
1099
  readonly CONTEXT: "context";
972
1100
  readonly SESSION: "session";
973
1101
  readonly TURN: "turn";
1102
+ readonly TASK: "task";
974
1103
  };
975
1104
  type CollectionName = typeof COLLECTIONS[keyof typeof COLLECTIONS];
976
1105
 
977
- /**
978
- * Utility type for representing partial updates to the state, allowing deep nesting.
979
- * It makes all properties optional and applies the same transformation recursively
980
- * to nested objects and array elements, allowing for selective updates while
981
- * preserving the original structure. It also includes the original type T and
982
- * undefined as possibilities for the top level and nested values.
983
- */
984
- 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 : {
985
- [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined;
986
- } | undefined | T : T | undefined;
987
-
988
1106
  declare function del<T>(): T;
989
1107
  declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
990
1108
  declare function ok<T>(value: T): Result<T, never>;
991
1109
  declare function err<E = WorkspaceError>(error: E): Result<never, E>;
992
1110
  declare function omitNullUndefined<T extends Record<string, any>>(obj: T): Partial<T>;
1111
+ declare function createProjectWorkspace<ProjectMetadata extends Record<string, any> = Record<string, any>>({ project, language }: {
1112
+ language: string;
1113
+ project: Omit<Project<ProjectMetadata>, "id">;
1114
+ }): Workspace<ProjectMetadata>;
993
1115
  declare function createSimpleWorkspace({ name, owner, language }: {
994
1116
  name: string;
995
1117
  language: string;
@@ -1045,10 +1167,6 @@ interface BlobStorage {
1045
1167
  registerBlob?(record: BlobRecord, data: Uint8Array): Promise<void>;
1046
1168
  }
1047
1169
 
1048
- interface TurnRef {
1049
- id: UUID;
1050
- version: number;
1051
- }
1052
1170
  declare class TurnTree {
1053
1171
  private readonly db;
1054
1172
  constructor(db: WorkspaceDatabase);
@@ -1059,15 +1177,22 @@ declare class TurnTree {
1059
1177
  * Uses only declared schema fields — never $id.
1060
1178
  */
1061
1179
  private turnFilter;
1180
+ private loadRaw;
1062
1181
  getHead(sessionId: UUID): Promise<TurnRef | null>;
1063
1182
  setHead(sessionId: UUID, head: TurnRef | null): Promise<void>;
1183
+ save(sessionId: UUID, turn: Turn, head?: TurnRef | null): Promise<Turn>;
1064
1184
  append(sessionId: UUID, turn: Turn): Promise<Turn>;
1065
1185
  appendBatch(sessionId: UUID, turns: Turn[], finalHead: TurnRef | null): Promise<void>;
1066
1186
  replaceVersion(sessionId: UUID, newTurn: Turn): Promise<void>;
1067
1187
  branch(sessionId: UUID, newTurn: Turn): Promise<void>;
1068
1188
  loadAllTurns(sessionId: UUID): Promise<Turn[]>;
1069
- getActiveChain(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Turn[]>;
1189
+ loadTurnVersions(sessionId: UUID, turnId: UUID): Promise<Turn[]>;
1190
+ buildNodes(turns: Turn[], head: TurnRef | null, dirtyBuffer?: readonly Turn[]): Record<UUID, TurnNode>;
1070
1191
  buildNodeGraph(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Record<UUID, TurnNode>>;
1192
+ getActiveChain(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Turn[]>;
1193
+ buildActiveChain(sessionId: UUID): Promise<TurnNode[]>;
1194
+ getTurnSiblings(turnId: UUID, sessionId: UUID): Promise<TurnNode[]>;
1195
+ branchInfo(turnId: UUID, sessionId: UUID): Promise<BranchInfo>;
1071
1196
  deleteSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<void>;
1072
1197
  copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
1073
1198
  }
@@ -1084,11 +1209,13 @@ interface BlobStoreConfig {
1084
1209
  declare class BlobStore {
1085
1210
  private readonly storage;
1086
1211
  private readonly config;
1212
+ private bus;
1087
1213
  /**
1088
1214
  * In-memory cache of BlobRecords. Kept consistent with the backend on
1089
1215
  * every write. Records are small (no bytes), so we cache all of them.
1090
1216
  */
1091
1217
  private readonly recordCache;
1218
+ constructor(backend: BlobStorage, bus: EventBus<WorkspaceEvents>, config?: BlobStoreConfig);
1092
1219
  /**
1093
1220
  * Called after any operation that changes the blob registry.
1094
1221
  * Passes the full BlobRecord (or null on deletion). The integration
@@ -1098,8 +1225,7 @@ declare class BlobStore {
1098
1225
  * that only need summary fields (sha256, mediaType, sizeBytes, etc.)
1099
1226
  * can read them directly from BlobRecord without a separate type.
1100
1227
  */
1101
- onRegistryChanged?: (sha256: SHA256, record: BlobRecord | null) => void;
1102
- constructor(backend: BlobStorage, config?: BlobStoreConfig);
1228
+ subscribe<TEventName extends keyof WorkspaceEvents>(event: TEventName, callback: (payload: WorkspaceEvents[TEventName]) => void): () => void;
1103
1229
  init(): Promise<void>;
1104
1230
  register(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<BlobRef, WorkspaceError>>;
1105
1231
  retain(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
@@ -1115,7 +1241,6 @@ declare class BlobStore {
1115
1241
  }>;
1116
1242
  }>;
1117
1243
  gc(): Promise<number>;
1118
- gcFull(): Promise<number>;
1119
1244
  purge(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1120
1245
  getRecord(sha256: SHA256): BlobRecord | null;
1121
1246
  /**
@@ -1132,17 +1257,11 @@ declare class ContentStore {
1132
1257
  private readonly roleCache;
1133
1258
  private readonly preferenceCache;
1134
1259
  private readonly contextCache;
1135
- /**
1136
- * Called after any blob registry change with the sha256 and updated
1137
- * BlobRecord (null on deletion). Wire this to your state manager to
1138
- * keep Index.blobs current.
1139
- *
1140
- * ContentStore sets this on BlobStore.onRegistryChanged internally.
1141
- * Consumers set this property to receive the forwarded notifications.
1142
- */
1143
- onBlobRegistryChanged?: (sha256: SHA256, record: BlobRecord | null) => void;
1260
+ private readonly taskCache;
1261
+ private bus;
1262
+ subscribe<TEventName extends keyof WorkspaceEvents>(event: TEventName, callback: (payload: WorkspaceEvents[TEventName]) => void): () => void;
1144
1263
  private constructor();
1145
- static create(db: WorkspaceDatabase, blobStorage: BlobStorage, config?: ContentStoreConfig): Promise<ContentStore>;
1264
+ static create(db: WorkspaceDatabase, blobStorage: BlobStorage, eventBus: EventBus<WorkspaceEvents>, config?: ContentStoreConfig): Promise<ContentStore>;
1146
1265
  private init;
1147
1266
  getTurnTree(): TurnTree;
1148
1267
  getRole(name: string): Promise<Result<Role, WorkspaceError>>;
@@ -1155,6 +1274,10 @@ declare class ContentStore {
1155
1274
  saveContext(context: Context): Promise<void>;
1156
1275
  deleteContext(key: string): Promise<void>;
1157
1276
  getContextByTopics(indexState: Index, topics: string[]): Promise<Context[]>;
1277
+ getTask(id: UUID): Promise<Result<Task, WorkspaceError>>;
1278
+ saveTask(task: Task): Promise<void>;
1279
+ deleteTask(id: UUID): Promise<void>;
1280
+ getTasksByTopics(indexState: Index, topics: string[]): Promise<Task[]>;
1158
1281
  saveSession(meta: SessionMeta): Promise<void>;
1159
1282
  updateSessionMeta(sessionId: UUID, patch: DeepPartial<SessionMeta>): Promise<void>;
1160
1283
  deleteSession(sessionId: UUID): Promise<void>;
@@ -1165,43 +1288,75 @@ declare class ContentStore {
1165
1288
  recordBlobRemoteId(sha256: SHA256, providerId: string, fileId: string): Promise<Result<void, WorkspaceError>>;
1166
1289
  getBlobRecord(sha256: SHA256): BlobRecord | null;
1167
1290
  getAllBlobRecords(): Record<SHA256, BlobRecord>;
1168
- /**
1169
- * Returns the blob resolver function expected by PromptBuilder.
1170
- * Closes over the internal BlobStore — no BlobStore reference leaks out.
1171
- */
1172
1291
  getBlobResolver(): BlobStore['resolveRefs'];
1173
- recordTurn(sessionId: UUID, turn: Turn): Promise<Result<void, WorkspaceError>>;
1292
+ appendTurn(sessionId: UUID, turn: Turn): Promise<Result<Turn, WorkspaceError>>;
1293
+ saveTurn(sessionId: UUID, turn: Turn): Promise<Result<Turn, WorkspaceError>>;
1174
1294
  editTurn(sessionId: UUID, turnId: UUID, newBlocks: ContentBlock[], newVersion: number, roleSnapshot?: string): Promise<Result<void, WorkspaceError>>;
1175
1295
  branchTurn(sessionId: UUID, newTurn: Turn): Promise<Result<void, WorkspaceError>>;
1176
1296
  deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<void, WorkspaceError>>;
1177
1297
  copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
1178
1298
  resolveSession(workspace: Workspace, sessionId: UUID, transcript?: Turn[]): Promise<Result<EffectiveSession, WorkspaceError>>;
1299
+ gc(): Promise<number>;
1179
1300
  }
1180
1301
 
1181
1302
  declare function workspaceReducer({ index: state }: Workspace, command: Command): Result<DeepPartial<Workspace>, WorkspaceError>;
1182
1303
 
1304
+ interface Summarizer {
1305
+ summarize(transcript: Turn[], tokenBudget: number): Promise<{
1306
+ summary: string;
1307
+ remaining: Turn[];
1308
+ }>;
1309
+ }
1310
+ interface ToolRegistry {
1311
+ /**
1312
+ * Subscribe to tool registry changes.
1313
+ * The callback is executed whenever the set of available tools changes.
1314
+ */
1315
+ onRegistryChanged(callback: (tools: ToolSummary[]) => void): void;
1316
+ /**
1317
+ * Returns all tools currently available in the environment.
1318
+ */
1319
+ list(): ToolSummary[];
1320
+ /**
1321
+ * The stateless executor.
1322
+ * Takes the call, returns the raw result.
1323
+ */
1324
+ execute<T = any>(call: ToolCall): Promise<Result<T>>;
1325
+ }
1326
+ interface PermissionGuard {
1327
+ /**
1328
+ * An async predicate that determines if the current context
1329
+ * (user, session, project) has the right to execute the request.
1330
+ */
1331
+ authenticate(request: AuthRequest): Promise<Result<null>>;
1332
+ }
1333
+
1183
1334
  declare class WorkspaceManager {
1184
1335
  private readonly contentStore;
1336
+ private readonly permissionGuard?;
1337
+ private readonly toolRegistry?;
1338
+ private bus;
1185
1339
  /**
1186
- * Called when BlobStore triggers a registry change outside of a dispatch()
1187
- * call — e.g. eagerEviction deleting a blob on release. The caller should
1188
- * merge this patch into their Workspace.
1340
+ * Called after any workspace change
1189
1341
  */
1190
- onWorkspacePatch?: (patch: DeepPartial<Workspace>) => void;
1191
- constructor(contentStore: ContentStore);
1342
+ subscribe<TEventName extends keyof WorkspaceEvents>(event: TEventName, callback: (payload: WorkspaceEvents[TEventName]) => void): () => void;
1343
+ constructor(options: {
1344
+ contentStore: ContentStore;
1345
+ permissionGuard?: PermissionGuard;
1346
+ toolRegistry?: ToolRegistry;
1347
+ eventBus: EventBus<WorkspaceEvents>;
1348
+ });
1349
+ /**
1350
+ * Initializes a Workspace's in-memory Index from environment-static
1351
+ * sources (like ToolRegistry). Call this when opening a Workspace.
1352
+ */
1353
+ init(_: Workspace): DeepPartial<Workspace>;
1192
1354
  reduce(workspace: Workspace, command: Command): Result<DeepPartial<Workspace>, WorkspaceError>;
1193
1355
  dispatch(workspace: Workspace, command: Command): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1194
- resolveSession(workspace: Workspace, sessionId: UUID): Promise<Result<EffectiveSession, WorkspaceError>>;
1356
+ resolveSession(workspace: Workspace, sessionId: UUID, transcript?: Turn[]): Promise<Result<EffectiveSession, WorkspaceError>>;
1195
1357
  private handleContentSideEffects;
1196
1358
  }
1197
1359
 
1198
- interface Summarizer {
1199
- summarize(transcript: Turn[], tokenBudget: number): Promise<{
1200
- summary: string;
1201
- remaining: Turn[];
1202
- }>;
1203
- }
1204
-
1205
1360
  interface ContextRankingInput {
1206
1361
  entries: Context[];
1207
1362
  recentMessages: string[];
@@ -1215,12 +1370,14 @@ interface PlanningInput {
1215
1370
  persona: string;
1216
1371
  preferences: Preference[];
1217
1372
  context: Context[];
1373
+ task: Task | null;
1218
1374
  transcript: Turn[];
1219
1375
  budget?: TokenBudget;
1220
1376
  }
1221
1377
  interface PlanningOutput {
1222
1378
  preferences: Preference[];
1223
1379
  context: Context[];
1380
+ task: Task | null;
1224
1381
  transcript: Turn[];
1225
1382
  truncated: {
1226
1383
  preferences: number;
@@ -1272,49 +1429,87 @@ declare class PromptBuilder {
1272
1429
  private resolvePreferenceConflicts;
1273
1430
  }
1274
1431
 
1432
+ /**
1433
+ * A fluent builder for creating Turn objects.
1434
+ * This class helps construct a Turn object by adding various content blocks.
1435
+ */
1436
+ declare class TurnBuilder {
1437
+ private readonly _owner;
1438
+ private _turn;
1439
+ constructor(_owner: TurnRole, initialTurn?: Turn);
1440
+ addText(text: string): TurnBuilder;
1441
+ addImage(ref?: BlobRef, altText?: string): TurnBuilder;
1442
+ addDocument(ref?: BlobRef, title?: string): TurnBuilder;
1443
+ addToolUse(name: string, input: Record<string, unknown>): TurnBuilder;
1444
+ addToolResult(useId: UUID, content: string | Record<string, unknown>, isError?: boolean): TurnBuilder;
1445
+ addSummary(text: string): TurnBuilder;
1446
+ addRoleTransition(previousRole: string | null, newRole: string): TurnBuilder;
1447
+ addThinking(thinking: string): TurnBuilder;
1448
+ /**
1449
+ * Adds a task proposal block.
1450
+ * @param title The task title.
1451
+ * @param steps Array of step objects (each with text and optional id/status). Status defaults to 'todo'.
1452
+ * @param action The action type ('create', 'update', 'complete'). Defaults to 'create'.
1453
+ * @param taskId Optional existing task ID (for update/complete).
1454
+ */
1455
+ addTaskProposal(title: string, steps: {
1456
+ text: string;
1457
+ status?: 'todo' | 'done';
1458
+ id?: UUID;
1459
+ }[], action?: 'create' | 'update' | 'complete', taskId?: UUID): TurnBuilder;
1460
+ addBlock(block: ContentBlock): TurnBuilder;
1461
+ deleteBlock(blockId: UUID): TurnBuilder;
1462
+ editTextBlock(blockId: UUID, newText: string): TurnBuilder;
1463
+ withId(id: UUID): TurnBuilder;
1464
+ withVersion(version: number): TurnBuilder;
1465
+ withTimestamp(timestamp: Timestamp): TurnBuilder;
1466
+ withParent(parent: TurnRef): TurnBuilder;
1467
+ withRoleSnapshot(roleSnapshot: string): TurnBuilder;
1468
+ build(): Turn;
1469
+ }
1470
+
1275
1471
  declare class Session {
1276
- /** The session ID this object manages. */
1277
- readonly sessionId: UUID;
1472
+ private readonly sessionId;
1473
+ private readonly tree;
1474
+ private readonly manager;
1475
+ constructor(sessionId: UUID, tree: TurnTree, manager: WorkspaceManager);
1476
+ turns(): Promise<TurnNode[]>;
1477
+ siblings(turnId: UUID): Promise<TurnNode[]>;
1478
+ branchInfo(turnId: UUID): Promise<BranchInfo>;
1479
+ id(): string;
1278
1480
  /**
1279
- * The turn DAG. Keys are turn IDs. Mutated in-place on every write.
1280
- * Callers read this directly for rendering no copy is made.
1481
+ * Creates a new fluent TurnBuilder for constructing a Turn object.
1482
+ * @param owner The role of the owner of the turn (e.g., 'user', 'assistant', 'tool').
1483
+ * @returns A new TurnBuilder instance.
1281
1484
  */
1282
- readonly nodes: Record<UUID, TurnNode>;
1485
+ startTurn(owner: TurnRole): TurnBuilder;
1283
1486
  /**
1284
- * Current head of the active branch. Mirrors what is in
1285
- * workspace.index.sessions[sessionId].head after each patch is applied.
1286
- * Session keeps its own copy so reads don't require workspace.
1487
+ * Saves a constructed Turn object to the session. This method handles setting the session ID
1488
+ * and automatically determines the parent turn if not explicitly provided in the Turn object.
1489
+ * @param workspace The current workspace state.
1490
+ * @param turn The Turn object to save. It can be constructed using the TurnBuilder.
1491
+ * @param parentRef Optional TurnRef to explicitly set the parent of the turn. If not provided,
1492
+ * the current head of the active chain will be used as the parent.
1493
+ * @returns A promise resolving to a Result containing a DeepPartial<Workspace> on success,
1494
+ * or a WorkspaceError on failure.
1287
1495
  */
1288
- private head;
1289
- /** Turns not yet flushed to storage. */
1290
- private readonly dirtyBuffer;
1291
- private flushTimer;
1292
- private flushChain;
1293
- private readonly flushConfig;
1294
- private readonly tree;
1295
- private readonly contentStore;
1296
- constructor(sessionId: UUID, nodes: Record<UUID, TurnNode>, head: TurnRef | null, tree: TurnTree, contentStore: ContentStore, flushConfig?: FlushConfig);
1297
- activeChain(): TurnNode[];
1298
- siblings(turnId: UUID): TurnNode[];
1299
- branchInfo(turnId: UUID): BranchInfo;
1300
1496
  addTurn(workspace: Workspace, turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1497
+ /**
1498
+ * Updates an existing turn in the session using a fully constructed Turn object.
1499
+ * This method will dispatch a 'turn:edit' command.
1500
+ * @param workspace The current workspace state.
1501
+ * @param updatedTurn The Turn object containing the updated blocks and other properties.
1502
+ * @returns A promise resolving to a Result containing a DeepPartial<Workspace> on success,
1503
+ * or a WorkspaceError on failure.
1504
+ */
1301
1505
  editTurn(workspace: Workspace, turnId: UUID, newBlocks: ContentBlock[], roleSnapshot?: string): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1302
- branchFrom(workspace: Workspace, newTurn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1506
+ branch(workspace: Workspace, turn: Turn): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1303
1507
  deleteTurn(workspace: Workspace, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1304
- switchVersionLeft(_: Workspace, turnId: UUID): Result<DeepPartial<Workspace>, WorkspaceError>;
1305
- switchVersionRight(_: Workspace, turnId: UUID): Result<DeepPartial<Workspace>, WorkspaceError>;
1508
+ switchVersionLeft(workspace: Workspace, turnId: UUID): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1509
+ switchVersionRight(workspace: Workspace, turnId: UUID): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
1306
1510
  private switchVersion;
1307
1511
  resolve(workspace: Workspace): Promise<Result<EffectiveSession, WorkspaceError>>;
1308
- flush(): Promise<void>;
1309
- dispose(): Promise<void>;
1310
- private findSubtreeTipForVersion;
1311
- private collectSubtreeIds;
1312
- private upsertNode;
1313
- private scheduleFlush;
1314
- private cancelFlushTimer;
1315
- private doFlush;
1316
- }
1317
- declare function buildTurnNode(turn: Turn, children?: UUID[]): TurnNode;
1512
+ }
1318
1513
 
1319
1514
  interface SessionManagerConfig {
1320
1515
  flush?: Partial<FlushConfig>;
@@ -1326,11 +1521,10 @@ interface OpenResult {
1326
1521
  declare class SessionManager {
1327
1522
  private readonly workspaceManager;
1328
1523
  private readonly contentStore;
1329
- private readonly flushConfig;
1330
- constructor(workspaceManager: WorkspaceManager, contentStore: ContentStore, config?: SessionManagerConfig);
1524
+ constructor(workspaceManager: WorkspaceManager, contentStore: ContentStore);
1331
1525
  open(workspace: Workspace, sessionId: UUID): Promise<Result<OpenResult, WorkspaceError>>;
1332
- close(session: Session): Promise<void>;
1333
1526
  get workspace(): WorkspaceManager;
1527
+ close(_: Session): Promise<void>;
1334
1528
  }
1335
1529
 
1336
1530
  /**
@@ -1400,4 +1594,4 @@ declare class IndexedDBBlobStorage implements BlobStorage {
1400
1594
  registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
1401
1595
  }
1402
1596
 
1403
- 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 };
1597
+ 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 CacheConfig, type CallTool, 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 DeleteTask, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type DuplicateKeyError, type EditTurn, type EffectiveSession, type FlushConfig, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type IndexedDBBlobConfig, IndexedDBBlobStorage, type InvalidCommandError, MemoryBlobStorage, type NotFoundError, 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, type SaveTurn, Session, SessionManager, type SessionManagerConfig, type SessionMeta, type Settings, type SummaryBlock, type SwitchRole, type Task, type TaskProposalBlock, type TaskStatus, type TaskStep, type TaskSummary, type TextBlock, type ThinkingBlock, type Timestamp, type TokenBudget, type ToolCall, type ToolResultBlock, type ToolSummary, 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 UpdateTask, type Workspace, type WorkspaceBundle, type WorkspaceDatabase, type WorkspaceError, type WorkspaceEvents, WorkspaceManager, computeSHA256, createProjectWorkspace, createSimpleWorkspace, createWorkspaceDatabase, del, err, extractBlobRecord, extractBlobRef, merge, ok, omitNullUndefined, workspaceReducer };