@lmthing/repl 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1691 @@
1
+ import { ReactElement } from 'react';
2
+ import { EventEmitter } from 'node:events';
3
+ import { z } from 'zod';
4
+ import vm from 'node:vm';
5
+ import ts from 'typescript';
6
+
7
+ interface AgentSpawnOptions {
8
+ context: "empty" | "branch";
9
+ }
10
+ interface AgentSpawnConfig {
11
+ spaceDir: string;
12
+ spaceName: string;
13
+ agentSlug: string;
14
+ actionId: string;
15
+ request: string;
16
+ params: Record<string, any>;
17
+ options: AgentSpawnOptions;
18
+ /** Internal: links spawn to registry entry for Phase 1e child-to-parent questions. */
19
+ _originPromise?: unknown;
20
+ }
21
+ interface AgentSpawnResult {
22
+ scope: Record<string, any>;
23
+ result: any;
24
+ keyFiles?: string[];
25
+ issues?: string[];
26
+ }
27
+ interface SerializedValue {
28
+ value: unknown;
29
+ display: string;
30
+ }
31
+ interface StopPayload {
32
+ [argNameOrExpression: string]: SerializedValue;
33
+ }
34
+ interface ErrorPayload {
35
+ type: string;
36
+ message: string;
37
+ line: number;
38
+ source: string;
39
+ }
40
+ interface AsyncCancellation {
41
+ cancelled: true;
42
+ message: string;
43
+ }
44
+ interface AskCancellation {
45
+ _cancelled: true;
46
+ }
47
+ interface ClassMethodInfo {
48
+ name: string;
49
+ description: string;
50
+ signature: string;
51
+ }
52
+ interface TaskDefinition {
53
+ id: string;
54
+ instructions: string;
55
+ outputSchema: Record<string, {
56
+ type: string;
57
+ }>;
58
+ dependsOn?: string[];
59
+ condition?: string;
60
+ optional?: boolean;
61
+ }
62
+ interface Tasklist {
63
+ tasklistId: string;
64
+ description: string;
65
+ tasks: TaskDefinition[];
66
+ }
67
+ interface TaskCompletion {
68
+ output: Record<string, any>;
69
+ timestamp: number;
70
+ status: 'completed' | 'failed' | 'skipped';
71
+ error?: string;
72
+ duration?: number;
73
+ }
74
+ interface TasklistState {
75
+ plan: Tasklist;
76
+ completed: Map<string, TaskCompletion>;
77
+ readyTasks: Set<string>;
78
+ runningTasks: Set<string>;
79
+ outputs: Map<string, Record<string, any>>;
80
+ progressMessages: Map<string, {
81
+ message: string;
82
+ percent?: number;
83
+ }>;
84
+ retryCount: Map<string, number>;
85
+ }
86
+ interface TasklistsState {
87
+ tasklists: Map<string, TasklistState>;
88
+ }
89
+ type AgentStatus = 'running' | 'waiting' | 'resolved' | 'failed';
90
+ interface AgentPromiseEntry {
91
+ varName: string;
92
+ label: string;
93
+ status: AgentStatus;
94
+ promise: Promise<unknown>;
95
+ childSession: Session | null;
96
+ resolvedValue?: unknown;
97
+ error?: string;
98
+ registeredAt: number;
99
+ completedAt?: number;
100
+ registeredTurn: number;
101
+ pendingQuestion?: {
102
+ message: string;
103
+ schema: Record<string, unknown>;
104
+ } | null;
105
+ }
106
+ interface AgentSnapshot {
107
+ varName: string;
108
+ label: string;
109
+ status: AgentStatus;
110
+ tasklistsState: TasklistsState | null;
111
+ pendingQuestion: {
112
+ message: string;
113
+ schema: Record<string, unknown>;
114
+ } | null;
115
+ error?: string;
116
+ valueIncluded?: boolean;
117
+ }
118
+ interface ScopeEntry {
119
+ name: string;
120
+ type: string;
121
+ value: string;
122
+ }
123
+ type ASTPattern = {
124
+ type: string;
125
+ [property: string]: unknown;
126
+ } | {
127
+ oneOf: ASTPattern[];
128
+ } | {
129
+ type: string;
130
+ not: ASTPattern;
131
+ };
132
+ interface HookMatch {
133
+ node: unknown;
134
+ source: string;
135
+ captures: Record<string, unknown>;
136
+ }
137
+ interface HookContext {
138
+ lineNumber: number;
139
+ sessionId: string;
140
+ scope: ScopeEntry[];
141
+ }
142
+ type HookAction = {
143
+ type: 'continue';
144
+ } | {
145
+ type: 'side_effect';
146
+ fn: () => void | Promise<void>;
147
+ } | {
148
+ type: 'transform';
149
+ newSource: string;
150
+ } | {
151
+ type: 'interrupt';
152
+ message: string;
153
+ } | {
154
+ type: 'skip';
155
+ reason?: string;
156
+ };
157
+ interface Hook {
158
+ id: string;
159
+ label: string;
160
+ pattern: ASTPattern;
161
+ phase: 'before' | 'after';
162
+ handler: (match: HookMatch, ctx: HookContext) => HookAction | Promise<HookAction>;
163
+ }
164
+ type SessionStatus = 'idle' | 'executing' | 'waiting_for_input' | 'paused' | 'complete' | 'error';
165
+ interface StreamPauseController {
166
+ pause(): void;
167
+ resume(): void;
168
+ isPaused(): boolean;
169
+ }
170
+ interface StatementExecutor {
171
+ execute(code: string, lineNumber: number): Promise<LineResult>;
172
+ getScope(): ScopeEntry[];
173
+ getScopeValue(name: string): unknown;
174
+ }
175
+ interface LineResult {
176
+ ok: boolean;
177
+ result?: unknown;
178
+ error?: ErrorPayload;
179
+ }
180
+ interface RenderSurface {
181
+ append(id: string, element: ReactElement): void;
182
+ renderForm(id: string, element: ReactElement): Promise<Record<string, unknown>>;
183
+ cancelForm(id: string): void;
184
+ appendTasklistProgress?(tasklistId: string, state: TasklistState): void;
185
+ updateTasklistProgress?(tasklistId: string, state: TasklistState): void;
186
+ updateTaskProgress?(tasklistId: string, taskId: string, message: string, percent?: number): void;
187
+ }
188
+ type SessionEvent = {
189
+ type: 'code';
190
+ lines: string;
191
+ blockId: string;
192
+ } | {
193
+ type: 'code_complete';
194
+ blockId: string;
195
+ lineCount: number;
196
+ } | {
197
+ type: 'read';
198
+ payload: Record<string, unknown>;
199
+ blockId: string;
200
+ } | {
201
+ type: 'error';
202
+ error: ErrorPayload;
203
+ blockId: string;
204
+ } | {
205
+ type: 'hook';
206
+ hookId: string;
207
+ action: string;
208
+ detail: string;
209
+ blockId: string;
210
+ } | {
211
+ type: 'display';
212
+ componentId: string;
213
+ jsx: SerializedJSX;
214
+ } | {
215
+ type: 'ask_start';
216
+ formId: string;
217
+ jsx: SerializedJSX;
218
+ } | {
219
+ type: 'ask_end';
220
+ formId: string;
221
+ } | {
222
+ type: 'async_start';
223
+ taskId: string;
224
+ label: string;
225
+ } | {
226
+ type: 'async_progress';
227
+ taskId: string;
228
+ elapsed: number;
229
+ } | {
230
+ type: 'async_complete';
231
+ taskId: string;
232
+ elapsed: number;
233
+ } | {
234
+ type: 'async_failed';
235
+ taskId: string;
236
+ error: string;
237
+ } | {
238
+ type: 'async_cancelled';
239
+ taskId: string;
240
+ } | {
241
+ type: 'tasklist_declared';
242
+ tasklistId: string;
243
+ plan: Tasklist;
244
+ } | {
245
+ type: 'task_complete';
246
+ tasklistId: string;
247
+ id: string;
248
+ output: Record<string, any>;
249
+ } | {
250
+ type: 'task_complete_continue';
251
+ tasklistId: string;
252
+ completedTaskId: string;
253
+ readyTasks: Array<{
254
+ id: string;
255
+ instructions: string;
256
+ outputSchema: Record<string, {
257
+ type: string;
258
+ }>;
259
+ }>;
260
+ } | {
261
+ type: 'tasklist_reminder';
262
+ tasklistId: string;
263
+ ready: string[];
264
+ blocked: string[];
265
+ failed: string[];
266
+ } | {
267
+ type: 'task_failed';
268
+ tasklistId: string;
269
+ id: string;
270
+ error: string;
271
+ } | {
272
+ type: 'task_retried';
273
+ tasklistId: string;
274
+ id: string;
275
+ } | {
276
+ type: 'task_skipped';
277
+ tasklistId: string;
278
+ id: string;
279
+ reason: string;
280
+ } | {
281
+ type: 'task_progress';
282
+ tasklistId: string;
283
+ id: string;
284
+ message: string;
285
+ percent?: number;
286
+ } | {
287
+ type: 'task_async_start';
288
+ tasklistId: string;
289
+ id: string;
290
+ } | {
291
+ type: 'task_async_complete';
292
+ tasklistId: string;
293
+ id: string;
294
+ output: Record<string, any>;
295
+ } | {
296
+ type: 'task_async_failed';
297
+ tasklistId: string;
298
+ id: string;
299
+ error: string;
300
+ } | {
301
+ type: 'task_order_violation';
302
+ tasklistId: string;
303
+ attemptedTaskId: string;
304
+ readyTasks: Array<{
305
+ id: string;
306
+ instructions: string;
307
+ outputSchema: Record<string, {
308
+ type: string;
309
+ }>;
310
+ }>;
311
+ } | {
312
+ type: 'knowledge_loaded';
313
+ domains: string[];
314
+ } | {
315
+ type: 'class_loaded';
316
+ className: string;
317
+ methods: string[];
318
+ } | {
319
+ type: 'spawn_start';
320
+ childId: string;
321
+ context: string;
322
+ directive: string;
323
+ } | {
324
+ type: 'spawn_complete';
325
+ childId: string;
326
+ turns: number;
327
+ duration: number;
328
+ } | {
329
+ type: 'spawn_error';
330
+ childId: string;
331
+ error: string;
332
+ } | {
333
+ type: 'agent_spawn_start';
334
+ spaceName: string;
335
+ agentSlug: string;
336
+ actionId: string;
337
+ } | {
338
+ type: 'agent_spawn_complete';
339
+ spaceName: string;
340
+ agentSlug: string;
341
+ actionId: string;
342
+ result: AgentSpawnResult;
343
+ } | {
344
+ type: 'agent_spawn_failed';
345
+ spaceName: string;
346
+ agentSlug: string;
347
+ actionId: string;
348
+ error: string;
349
+ } | {
350
+ type: 'agent_registered';
351
+ varName: string;
352
+ label: string;
353
+ } | {
354
+ type: 'agent_resolved';
355
+ varName: string;
356
+ } | {
357
+ type: 'agent_failed';
358
+ varName: string;
359
+ error: string;
360
+ } | {
361
+ type: 'agent_question_asked';
362
+ varName: string;
363
+ question: {
364
+ message: string;
365
+ schema: Record<string, unknown>;
366
+ };
367
+ } | {
368
+ type: 'agent_question_answered';
369
+ varName: string;
370
+ } | {
371
+ type: 'knowledge_saved';
372
+ domain: string;
373
+ field: string;
374
+ option: string;
375
+ } | {
376
+ type: 'knowledge_removed';
377
+ domain: string;
378
+ field: string;
379
+ option: string;
380
+ } | {
381
+ type: 'status';
382
+ status: SessionStatus;
383
+ } | {
384
+ type: 'scope';
385
+ entries: ScopeEntry[];
386
+ };
387
+ interface SerializedJSX {
388
+ component: string;
389
+ props: Record<string, unknown>;
390
+ children?: (SerializedJSX | string)[];
391
+ }
392
+ interface SessionSnapshot {
393
+ status: SessionStatus;
394
+ blocks: Array<{
395
+ type: string;
396
+ id: string;
397
+ data: unknown;
398
+ }>;
399
+ scope: ScopeEntry[];
400
+ asyncTasks: Array<{
401
+ id: string;
402
+ label: string;
403
+ status: string;
404
+ elapsed: number;
405
+ }>;
406
+ activeFormId: string | null;
407
+ tasklistsState: TasklistsState;
408
+ agentEntries: Array<{
409
+ varName: string;
410
+ label: string;
411
+ status: AgentStatus;
412
+ error?: string;
413
+ }>;
414
+ }
415
+
416
+ /**
417
+ * Represents a knowledge domain (top-level folder in knowledge/).
418
+ */
419
+ interface KnowledgeDomain {
420
+ slug: string;
421
+ label: string;
422
+ description: string;
423
+ icon: string;
424
+ color: string;
425
+ fields: KnowledgeField[];
426
+ }
427
+ /**
428
+ * Represents a field within a knowledge domain.
429
+ */
430
+ interface KnowledgeField {
431
+ slug: string;
432
+ label: string;
433
+ description: string;
434
+ fieldType: 'select' | 'multiSelect' | 'text' | 'number';
435
+ required: boolean;
436
+ default?: string;
437
+ variableName: string;
438
+ options: KnowledgeOption[];
439
+ }
440
+ /**
441
+ * Represents a selectable option within a field (parsed from .md frontmatter).
442
+ */
443
+ interface KnowledgeOption {
444
+ slug: string;
445
+ title: string;
446
+ description: string;
447
+ order: number;
448
+ }
449
+ /**
450
+ * The full knowledge tree for a space — used to show the agent what's available.
451
+ */
452
+ interface KnowledgeTree {
453
+ /** Space name (directory basename), used for grouping in the prompt */
454
+ name?: string;
455
+ domains: KnowledgeDomain[];
456
+ }
457
+ /**
458
+ * Flat selector (no space names): { domainSlug: { fieldSlug: { optionSlug: true } } }
459
+ */
460
+ type FlatKnowledgeSelector = Record<string, Record<string, Record<string, true>>>;
461
+ /**
462
+ * Selector object the agent passes to loadKnowledge().
463
+ *
464
+ * With named spaces: { spaceName: { domainSlug: { fieldSlug: { optionSlug: true } } } }
465
+ * Without spaces: { domainSlug: { fieldSlug: { optionSlug: true } } }
466
+ *
467
+ * The loader auto-detects the format based on whether space names are configured.
468
+ */
469
+ type KnowledgeSelector = Record<string, any>;
470
+ /**
471
+ * Flat content (no space names): { domainSlug: { fieldSlug: { optionSlug: markdownString } } }
472
+ */
473
+ type FlatKnowledgeContent = Record<string, Record<string, Record<string, string>>>;
474
+ /**
475
+ * Loaded knowledge content returned to the agent.
476
+ * Same shape as the selector but with markdown content instead of `true`.
477
+ */
478
+ type KnowledgeContent = Record<string, any>;
479
+
480
+ interface SessionConfig {
481
+ functionTimeout: number;
482
+ askTimeout: number;
483
+ sessionTimeout: number;
484
+ maxStopCalls: number;
485
+ maxAsyncTasks: number;
486
+ maxTasklistReminders: number;
487
+ maxTaskRetries: number;
488
+ maxTasksPerTasklist: number;
489
+ taskAsyncTimeout: number;
490
+ sleepMaxSeconds: number;
491
+ maxContextTokens: number;
492
+ serializationLimits: {
493
+ maxStringLength: number;
494
+ maxArrayElements: number;
495
+ maxObjectKeys: number;
496
+ maxDepth: number;
497
+ };
498
+ workspace: {
499
+ maxScopeVariables: number;
500
+ maxScopeValueWidth: number;
501
+ maxScopeTokens: number;
502
+ };
503
+ contextWindow: {
504
+ codeWindowLines: number;
505
+ stopDecayTiers: {
506
+ full: number;
507
+ keysOnly: number;
508
+ summary: number;
509
+ };
510
+ neverTruncateInterventions: boolean;
511
+ };
512
+ }
513
+ declare function createDefaultConfig(): SessionConfig;
514
+ declare const sessionConfigSchema: z.ZodObject<{
515
+ functionTimeout: z.ZodOptional<z.ZodNumber>;
516
+ askTimeout: z.ZodOptional<z.ZodNumber>;
517
+ sessionTimeout: z.ZodOptional<z.ZodNumber>;
518
+ maxStopCalls: z.ZodOptional<z.ZodNumber>;
519
+ maxAsyncTasks: z.ZodOptional<z.ZodNumber>;
520
+ maxTasklistReminders: z.ZodOptional<z.ZodNumber>;
521
+ maxTaskRetries: z.ZodOptional<z.ZodNumber>;
522
+ maxTasksPerTasklist: z.ZodOptional<z.ZodNumber>;
523
+ taskAsyncTimeout: z.ZodOptional<z.ZodNumber>;
524
+ sleepMaxSeconds: z.ZodOptional<z.ZodNumber>;
525
+ maxContextTokens: z.ZodOptional<z.ZodNumber>;
526
+ serializationLimits: z.ZodOptional<z.ZodObject<{
527
+ maxStringLength: z.ZodOptional<z.ZodNumber>;
528
+ maxArrayElements: z.ZodOptional<z.ZodNumber>;
529
+ maxObjectKeys: z.ZodOptional<z.ZodNumber>;
530
+ maxDepth: z.ZodOptional<z.ZodNumber>;
531
+ }, z.core.$strip>>;
532
+ workspace: z.ZodOptional<z.ZodObject<{
533
+ maxScopeVariables: z.ZodOptional<z.ZodNumber>;
534
+ maxScopeValueWidth: z.ZodOptional<z.ZodNumber>;
535
+ maxScopeTokens: z.ZodOptional<z.ZodNumber>;
536
+ }, z.core.$strip>>;
537
+ contextWindow: z.ZodOptional<z.ZodObject<{
538
+ codeWindowLines: z.ZodOptional<z.ZodNumber>;
539
+ stopDecayTiers: z.ZodOptional<z.ZodObject<{
540
+ full: z.ZodOptional<z.ZodNumber>;
541
+ keysOnly: z.ZodOptional<z.ZodNumber>;
542
+ summary: z.ZodOptional<z.ZodNumber>;
543
+ }, z.core.$strip>>;
544
+ neverTruncateInterventions: z.ZodOptional<z.ZodBoolean>;
545
+ }, z.core.$strip>>;
546
+ }, z.core.$strip>;
547
+ type PartialSessionConfig = z.infer<typeof sessionConfigSchema>;
548
+ declare function validateConfig(input: unknown): {
549
+ valid: true;
550
+ config: PartialSessionConfig;
551
+ } | {
552
+ valid: false;
553
+ errors: string[];
554
+ };
555
+ declare function mergeConfig(overrides: PartialSessionConfig): SessionConfig;
556
+
557
+ interface AgentRegistryConfig {
558
+ onRegistered?: (varName: string, label: string) => void;
559
+ onResolved?: (varName: string) => void;
560
+ onFailed?: (varName: string, error: string) => void;
561
+ onQuestionAsked?: (varName: string, question: {
562
+ message: string;
563
+ schema: Record<string, unknown>;
564
+ }) => void;
565
+ onQuestionAnswered?: (varName: string) => void;
566
+ }
567
+ declare class AgentRegistry {
568
+ private entries;
569
+ private questionResolvers;
570
+ private currentTurn;
571
+ private config;
572
+ constructor(config?: AgentRegistryConfig);
573
+ register(varName: string, promise: Promise<unknown>, label: string, childSession: Session | null): void;
574
+ resolve(varName: string, value: unknown): void;
575
+ fail(varName: string, error: string): void;
576
+ getAll(): AgentPromiseEntry[];
577
+ getPending(): AgentPromiseEntry[];
578
+ getSnapshot(varName: string): AgentSnapshot | null;
579
+ getAllSnapshots(): AgentSnapshot[];
580
+ findByPromise(promise: unknown): AgentPromiseEntry | null;
581
+ advanceTurn(): void;
582
+ getCurrentTurn(): number;
583
+ hasEntries(): boolean;
584
+ hasVisibleEntries(): boolean;
585
+ /**
586
+ * Low-level setter — updates entry status and question fields.
587
+ * Prefer askQuestion() for the full flow (sets question + returns Promise).
588
+ */
589
+ setPendingQuestion(varName: string, question: {
590
+ message: string;
591
+ schema: Record<string, unknown>;
592
+ }): void;
593
+ /**
594
+ * Ask a question on behalf of a child agent. Sets status to 'waiting',
595
+ * stores the question, and returns a Promise that resolves when the
596
+ * parent calls respond().
597
+ */
598
+ askQuestion(varName: string, question: {
599
+ message: string;
600
+ schema: Record<string, unknown>;
601
+ }): Promise<Record<string, unknown>>;
602
+ /**
603
+ * Deliver structured input to a child agent's pending askParent() call.
604
+ * Resolves the Promise returned by askQuestion(), clears the pending
605
+ * question, and sets the agent back to 'running'.
606
+ */
607
+ respond(varName: string, data: Record<string, unknown>): void;
608
+ destroy(): void;
609
+ }
610
+
611
+ type TurnBoundary = {
612
+ type: 'stop';
613
+ payload: Record<string, {
614
+ display: string;
615
+ type: string;
616
+ }>;
617
+ } | {
618
+ type: 'error';
619
+ error: {
620
+ type: string;
621
+ message: string;
622
+ line: number;
623
+ source: string;
624
+ };
625
+ } | {
626
+ type: 'intervention';
627
+ text: string;
628
+ } | {
629
+ type: 'hook_interrupt';
630
+ hookId: string;
631
+ message: string;
632
+ } | {
633
+ type: 'tasklist_reminder';
634
+ tasklistId: string;
635
+ ready: string[];
636
+ blocked: string[];
637
+ failed: string[];
638
+ } | {
639
+ type: 'completion';
640
+ };
641
+ interface ScopeDelta {
642
+ added: ScopeEntry[];
643
+ changed: Array<ScopeEntry & {
644
+ previousValue: string;
645
+ previousType: string;
646
+ }>;
647
+ removed: string[];
648
+ }
649
+ type TurnEvent = {
650
+ type: 'display';
651
+ componentId: string;
652
+ } | {
653
+ type: 'ask_start';
654
+ formId: string;
655
+ } | {
656
+ type: 'ask_end';
657
+ formId: string;
658
+ } | {
659
+ type: 'async_start';
660
+ taskId: string;
661
+ label: string;
662
+ } | {
663
+ type: 'async_complete';
664
+ taskId: string;
665
+ } | {
666
+ type: 'async_failed';
667
+ taskId: string;
668
+ error: string;
669
+ } | {
670
+ type: 'async_cancelled';
671
+ taskId: string;
672
+ } | {
673
+ type: 'tasklist_declared';
674
+ tasklistId: string;
675
+ description: string;
676
+ taskCount: number;
677
+ } | {
678
+ type: 'task_complete';
679
+ tasklistId: string;
680
+ taskId: string;
681
+ } | {
682
+ type: 'task_failed';
683
+ tasklistId: string;
684
+ taskId: string;
685
+ error: string;
686
+ } | {
687
+ type: 'task_retried';
688
+ tasklistId: string;
689
+ taskId: string;
690
+ } | {
691
+ type: 'task_skipped';
692
+ tasklistId: string;
693
+ taskId: string;
694
+ reason: string;
695
+ } | {
696
+ type: 'task_progress';
697
+ tasklistId: string;
698
+ taskId: string;
699
+ message: string;
700
+ percent?: number;
701
+ } | {
702
+ type: 'knowledge_loaded';
703
+ domains: string[];
704
+ } | {
705
+ type: 'class_loaded';
706
+ className: string;
707
+ methods: string[];
708
+ } | {
709
+ type: 'hook';
710
+ hookId: string;
711
+ action: string;
712
+ } | {
713
+ type: 'agent_registered';
714
+ varName: string;
715
+ label: string;
716
+ } | {
717
+ type: 'agent_resolved';
718
+ varName: string;
719
+ } | {
720
+ type: 'agent_failed';
721
+ varName: string;
722
+ error: string;
723
+ };
724
+ interface ConversationTurn {
725
+ /** Monotonically increasing turn index (0-based) */
726
+ index: number;
727
+ /** Timestamp when the turn started */
728
+ startedAt: number;
729
+ /** Timestamp when the turn boundary was hit */
730
+ endedAt: number;
731
+ /** Role of this turn */
732
+ role: 'assistant' | 'user' | 'system';
733
+ /** For assistant turns: the code lines written */
734
+ code: string[] | null;
735
+ /** For user turns: the message text */
736
+ message: string | null;
737
+ /** What caused this turn to end (null for user turns) */
738
+ boundary: TurnBoundary | null;
739
+ /** Scope snapshot after this turn */
740
+ scopeSnapshot: ScopeEntry[];
741
+ /** Scope delta compared to the previous turn */
742
+ scopeDelta: ScopeDelta | null;
743
+ /** Events that occurred during this turn */
744
+ events: TurnEvent[];
745
+ }
746
+ interface SerializedTaskCompletion {
747
+ output: Record<string, any>;
748
+ timestamp: number;
749
+ status: 'completed' | 'failed' | 'skipped';
750
+ error?: string;
751
+ duration?: number;
752
+ }
753
+ interface SerializedTasklistState {
754
+ plan: {
755
+ tasklistId: string;
756
+ description: string;
757
+ tasks: TaskDefinition[];
758
+ };
759
+ completed: Record<string, SerializedTaskCompletion>;
760
+ readyTasks: string[];
761
+ runningTasks: string[];
762
+ outputs: Record<string, Record<string, any>>;
763
+ progressMessages: Record<string, {
764
+ message: string;
765
+ percent?: number;
766
+ }>;
767
+ retryCount: Record<string, number>;
768
+ }
769
+ interface SerializedTasklistsState {
770
+ tasklists: Record<string, SerializedTasklistState>;
771
+ }
772
+ interface ConversationState {
773
+ /** Session start timestamp */
774
+ startedAt: number;
775
+ /** All turns in chronological order */
776
+ turns: ConversationTurn[];
777
+ /** Current tasklist state (serializable) */
778
+ tasklists: SerializedTasklistsState;
779
+ /** Total stop calls so far */
780
+ stopCount: number;
781
+ /** Current session status */
782
+ status: SessionStatus;
783
+ }
784
+ /**
785
+ * Compute what changed in scope between two snapshots.
786
+ */
787
+ declare function computeScopeDelta(previous: ScopeEntry[], current: ScopeEntry[]): ScopeDelta;
788
+ /**
789
+ * Convert TasklistsState (Map/Set) to a plain JSON-serializable object.
790
+ */
791
+ declare function serializeTasklistsState(state: TasklistsState): SerializedTasklistsState;
792
+ /**
793
+ * Builds a serializable ConversationState incrementally at each turn boundary.
794
+ */
795
+ declare class ConversationRecorder {
796
+ private state;
797
+ private previousScope;
798
+ private pendingEvents;
799
+ private currentTurnStartedAt;
800
+ constructor();
801
+ /** Record an assistant turn ending at a stop boundary. */
802
+ recordStop(code: string[], payload: StopPayload, scope: ScopeEntry[], tasklists: TasklistsState): void;
803
+ /** Record an assistant turn ending at an error boundary. */
804
+ recordError(code: string[], error: ErrorPayload, scope: ScopeEntry[]): void;
805
+ /** Record an assistant turn ending at an intervention boundary. */
806
+ recordIntervention(code: string[], text: string, scope: ScopeEntry[]): void;
807
+ /** Record an assistant turn ending at a tasklist reminder boundary. */
808
+ recordTasklistReminder(code: string[], tasklistId: string, ready: string[], blocked: string[], failed: string[], scope: ScopeEntry[], tasklists: TasklistsState): void;
809
+ /** Record session completion. */
810
+ recordCompletion(code: string[], scope: ScopeEntry[], tasklists: TasklistsState, status: SessionStatus): void;
811
+ /** Record a user message turn. */
812
+ recordUserMessage(text: string, scope: ScopeEntry[]): void;
813
+ /** Accumulate a session event (filtered to TurnEvent subset). */
814
+ recordEvent(event: SessionEvent): void;
815
+ /** Update session status. */
816
+ updateStatus(status: SessionStatus): void;
817
+ /** Get the current full conversation state (returns a shallow copy). */
818
+ getState(): ConversationState;
819
+ private pushTurn;
820
+ }
821
+
822
+ interface SessionOptions {
823
+ config?: Partial<SessionConfig>;
824
+ hooks?: Hook[];
825
+ globals?: Record<string, unknown>;
826
+ knowledgeLoader?: (selector: KnowledgeSelector) => KnowledgeContent;
827
+ /** Return class info without side effects (validation only). */
828
+ getClassInfo?: (className: string) => {
829
+ methods: ClassMethodInfo[];
830
+ } | null;
831
+ /** Load a class: instantiate, bind methods, inject into sandbox. */
832
+ loadClass?: (className: string, session: Session) => void;
833
+ /** Agent namespace globals to inject into the sandbox. */
834
+ agentNamespaces?: Record<string, unknown>;
835
+ /** Spawn a child agent session. Used by agent namespace globals. */
836
+ onSpawn?: (config: AgentSpawnConfig) => Promise<AgentSpawnResult>;
837
+ /** Route child agent's askParent() to parent. Set for tracked child sessions. */
838
+ onAskParent?: (question: {
839
+ message: string;
840
+ schema: Record<string, unknown>;
841
+ }) => Promise<Record<string, unknown>>;
842
+ /** Whether this is a fire-and-forget child (untracked). askParent resolves immediately. */
843
+ isFireAndForget?: boolean;
844
+ /** Knowledge namespace global (built-in, always available if configured). */
845
+ knowledgeNamespace?: Record<string, unknown>;
846
+ }
847
+ declare class Session extends EventEmitter {
848
+ private status;
849
+ private config;
850
+ private sandbox;
851
+ private asyncManager;
852
+ private hookRegistry;
853
+ private streamController;
854
+ private globalsApi;
855
+ private blocks;
856
+ private codeLines;
857
+ private messages;
858
+ private activeFormId;
859
+ private stopCount;
860
+ private tasklistReminderCount;
861
+ private agentRegistry;
862
+ private recorder;
863
+ private turnCodeStart;
864
+ private onSpawn?;
865
+ constructor(options?: SessionOptions);
866
+ private executeStatement;
867
+ private handleStop;
868
+ private handleError;
869
+ /**
870
+ * Handle a user message.
871
+ */
872
+ handleUserMessage(text: string): Promise<void>;
873
+ /**
874
+ * Feed tokens from the LLM stream.
875
+ */
876
+ feedToken(token: string): Promise<void>;
877
+ /**
878
+ * Finalize the LLM stream.
879
+ * Returns 'complete' if done, or 'tasklist_incomplete' if tasks remain.
880
+ */
881
+ finalize(): Promise<'complete' | 'tasklist_incomplete'>;
882
+ /**
883
+ * Resolve a pending stop() call, allowing sandbox to continue.
884
+ * Called by the runner after injecting the stop payload as a user message.
885
+ */
886
+ resolveStop(): void;
887
+ /**
888
+ * Inject a value into the sandbox as a global.
889
+ * Used to inject class namespace objects after loadClass().
890
+ */
891
+ injectGlobal(name: string, value: unknown): void;
892
+ /**
893
+ * Resolve a pending ask() form.
894
+ */
895
+ resolveAsk(formId: string, data: Record<string, unknown>): void;
896
+ /**
897
+ * Cancel a pending ask() form.
898
+ */
899
+ cancelAsk(formId: string): void;
900
+ /**
901
+ * Cancel an async task.
902
+ */
903
+ cancelAsyncTask(taskId: string, message?: string): void;
904
+ /**
905
+ * Pause the session.
906
+ */
907
+ pause(): void;
908
+ /**
909
+ * Resume the session.
910
+ */
911
+ resume(): void;
912
+ /**
913
+ * Handle user intervention (message while agent is running).
914
+ */
915
+ handleIntervention(text: string): void;
916
+ /**
917
+ * Get a snapshot of the current session state.
918
+ */
919
+ snapshot(): SessionSnapshot;
920
+ /**
921
+ * Get the full serializable conversation state.
922
+ */
923
+ getConversationState(): ConversationState;
924
+ /**
925
+ * Get the current status.
926
+ */
927
+ getStatus(): SessionStatus;
928
+ /**
929
+ * Get messages for context.
930
+ */
931
+ getMessages(): Array<{
932
+ role: string;
933
+ content: string;
934
+ }>;
935
+ /**
936
+ * Get the public globals object (for passing to setup functions).
937
+ */
938
+ getGlobals(): Record<string, Function>;
939
+ /**
940
+ * Get the agent registry.
941
+ */
942
+ getAgentRegistry(): AgentRegistry;
943
+ /**
944
+ * Get scope table as string.
945
+ */
946
+ getScopeTable(): string;
947
+ private setStatus;
948
+ private emitEvent;
949
+ /**
950
+ * Destroy the session and clean up resources.
951
+ */
952
+ destroy(): void;
953
+ }
954
+
955
+ interface SandboxOptions {
956
+ timeout?: number;
957
+ globals?: Record<string, unknown>;
958
+ }
959
+ /**
960
+ * The REPL sandbox — manages a persistent vm.Context for line-by-line execution.
961
+ */
962
+ declare class Sandbox {
963
+ private context;
964
+ private declaredNames;
965
+ private lineCount;
966
+ private timeout;
967
+ constructor(options?: SandboxOptions);
968
+ /**
969
+ * Execute a line of TypeScript in the sandbox.
970
+ */
971
+ execute(code: string): Promise<LineResult>;
972
+ /**
973
+ * Inject a value into the sandbox's global scope.
974
+ */
975
+ inject(name: string, value: unknown): void;
976
+ /**
977
+ * Get a value from the sandbox scope.
978
+ */
979
+ getValue(name: string): unknown;
980
+ /**
981
+ * Get all user-declared variable names.
982
+ */
983
+ getDeclaredNames(): string[];
984
+ /**
985
+ * Get the current scope as ScopeEntry[].
986
+ */
987
+ getScope(): ScopeEntry[];
988
+ /**
989
+ * Get the line count.
990
+ */
991
+ getLineCount(): number;
992
+ /**
993
+ * Get the raw vm.Context (for advanced use).
994
+ */
995
+ getContext(): vm.Context;
996
+ /**
997
+ * Destroy the sandbox.
998
+ */
999
+ destroy(): void;
1000
+ }
1001
+
1002
+ /**
1003
+ * Transpile a TypeScript statement to JavaScript.
1004
+ * Uses transpile-only mode (no type checking).
1005
+ */
1006
+ declare function transpile(code: string): string;
1007
+
1008
+ /**
1009
+ * Execute a single line of TypeScript in the given sandbox context.
1010
+ * Handles both declarations (which must persist in scope) and expressions.
1011
+ */
1012
+ declare function executeLine(code: string, lineNumber: number, context: vm.Context, timeout?: number): Promise<LineResult>;
1013
+
1014
+ interface AsyncTask {
1015
+ id: string;
1016
+ label: string;
1017
+ abortController: AbortController;
1018
+ promise: Promise<void>;
1019
+ status: 'running' | 'completed' | 'failed' | 'cancelled';
1020
+ startTime: number;
1021
+ result?: unknown;
1022
+ error?: string;
1023
+ }
1024
+ /**
1025
+ * Manages background async tasks spawned by async() calls.
1026
+ */
1027
+ declare class AsyncManager {
1028
+ private tasks;
1029
+ private results;
1030
+ private counter;
1031
+ private maxTasks;
1032
+ constructor(maxTasks?: number);
1033
+ /**
1034
+ * Register a new background task.
1035
+ */
1036
+ register(fn: (signal: AbortSignal) => Promise<void>, label?: string): string;
1037
+ /**
1038
+ * Cancel a task by ID.
1039
+ */
1040
+ cancel(taskId: string, message?: string): boolean;
1041
+ /**
1042
+ * Store a result from a task's scoped stop() call.
1043
+ */
1044
+ setResult(taskId: string, value: unknown): void;
1045
+ /**
1046
+ * Drain all accumulated results and clear the results map.
1047
+ */
1048
+ drainResults(): Map<string, unknown>;
1049
+ /**
1050
+ * Get a task by ID.
1051
+ */
1052
+ getTask(taskId: string): AsyncTask | undefined;
1053
+ /**
1054
+ * Get all tasks.
1055
+ */
1056
+ getAllTasks(): AsyncTask[];
1057
+ /**
1058
+ * Get count of currently running tasks.
1059
+ */
1060
+ getRunningCount(): number;
1061
+ /**
1062
+ * Build the async portion of a stop payload.
1063
+ * Running tasks show "pending", completed ones show their results.
1064
+ */
1065
+ buildStopPayload(): Record<string, unknown>;
1066
+ /**
1067
+ * Wait for all running tasks to complete, with timeout.
1068
+ */
1069
+ drain(timeoutMs?: number): Promise<void>;
1070
+ /**
1071
+ * Cancel all running tasks.
1072
+ */
1073
+ cancelAll(): void;
1074
+ }
1075
+
1076
+ interface GlobalsConfig {
1077
+ pauseController: StreamPauseController;
1078
+ renderSurface: RenderSurface;
1079
+ asyncManager: AsyncManager;
1080
+ serializationLimits?: {
1081
+ maxStringLength?: number;
1082
+ maxArrayElements?: number;
1083
+ maxObjectKeys?: number;
1084
+ maxDepth?: number;
1085
+ };
1086
+ askTimeout?: number;
1087
+ onStop?: (payload: StopPayload, source: string) => void;
1088
+ onDisplay?: (id: string) => void;
1089
+ onAsyncStart?: (taskId: string, label: string) => void;
1090
+ onTasklistDeclared?: (tasklistId: string, plan: Tasklist) => void;
1091
+ onTaskComplete?: (tasklistId: string, id: string, output: Record<string, any>) => void;
1092
+ onTaskFailed?: (tasklistId: string, id: string, error: string) => void;
1093
+ onTaskRetried?: (tasklistId: string, id: string) => void;
1094
+ onTaskSkipped?: (tasklistId: string, id: string, reason: string) => void;
1095
+ onTaskProgress?: (tasklistId: string, id: string, message: string, percent?: number) => void;
1096
+ onTaskAsyncStart?: (tasklistId: string, id: string) => void;
1097
+ onTaskAsyncComplete?: (tasklistId: string, id: string, output: Record<string, any>) => void;
1098
+ onTaskAsyncFailed?: (tasklistId: string, id: string, error: string) => void;
1099
+ onTaskOrderViolation?: (tasklistId: string, attemptedTaskId: string, readyTasks: Array<{
1100
+ id: string;
1101
+ instructions: string;
1102
+ outputSchema: Record<string, {
1103
+ type: string;
1104
+ }>;
1105
+ }>) => void;
1106
+ onTaskCompleteContinue?: (tasklistId: string, completedTaskId: string, readyTasks: Array<{
1107
+ id: string;
1108
+ instructions: string;
1109
+ outputSchema: Record<string, {
1110
+ type: string;
1111
+ }>;
1112
+ }>) => void;
1113
+ maxTaskRetries?: number;
1114
+ maxTasksPerTasklist?: number;
1115
+ sleepMaxSeconds?: number;
1116
+ onLoadKnowledge?: (selector: KnowledgeSelector) => KnowledgeContent;
1117
+ /** Validate a class name and return its methods (no side effects). */
1118
+ getClassInfo?: (className: string) => {
1119
+ methods: ClassMethodInfo[];
1120
+ } | null;
1121
+ /** Signal that loadClass was called — emits events, injects bindings. Called after pause. */
1122
+ onLoadClass?: (className: string) => void;
1123
+ /** Spawn a child agent session. Used by agent namespace globals. */
1124
+ onSpawn?: (config: AgentSpawnConfig) => Promise<AgentSpawnResult>;
1125
+ /** Route child agent's askParent() to parent. Set only for tracked child sessions. */
1126
+ onAskParent?: (question: {
1127
+ message: string;
1128
+ schema: Record<string, unknown>;
1129
+ }) => Promise<Record<string, unknown>>;
1130
+ /** Whether this is a fire-and-forget child (untracked). askParent resolves immediately. */
1131
+ isFireAndForget?: boolean;
1132
+ /** Deliver structured input to a child agent's pending askParent(). */
1133
+ onRespond?: (promise: unknown, data: Record<string, unknown>) => void;
1134
+ }
1135
+ /**
1136
+ * Create the twelve global functions: stop, display, ask, async, tasklist, completeTask, completeTaskAsync, taskProgress, failTask, retryTask, sleep, loadKnowledge.
1137
+ * These use callback interfaces, never importing stream-controller or session directly.
1138
+ */
1139
+ declare function createGlobals(config: GlobalsConfig): {
1140
+ stop: (...values: unknown[]) => Promise<void>;
1141
+ display: (element: unknown) => void;
1142
+ ask: (element: unknown) => Promise<Record<string, unknown>>;
1143
+ async: (fn: () => Promise<void>, label?: string) => void;
1144
+ tasklist: (tasklistId: string, description: string, tasks: Tasklist["tasks"]) => void;
1145
+ completeTask: (tasklistId: string, id: string, output: Record<string, any>) => void;
1146
+ completeTaskAsync: (tasklistId: string, taskId: string, fn: () => Promise<Record<string, any>>) => void;
1147
+ taskProgress: (tasklistId: string, taskId: string, message: string, percent?: number) => void;
1148
+ failTask: (tasklistId: string, taskId: string, error: string) => void;
1149
+ retryTask: (tasklistId: string, taskId: string) => void;
1150
+ sleep: (seconds: number) => Promise<void>;
1151
+ loadKnowledge: (selector: KnowledgeSelector) => KnowledgeContent;
1152
+ loadClass: (className: string) => void;
1153
+ askParent: (message: string, schema?: Record<string, unknown>) => Promise<Record<string, unknown>>;
1154
+ respond: (promise: unknown, data: Record<string, unknown>) => void;
1155
+ setCurrentSource: (source: string) => void;
1156
+ resolveStop: () => void;
1157
+ getTasklistsState: () => TasklistsState;
1158
+ };
1159
+
1160
+ declare class HookRegistry {
1161
+ private hooks;
1162
+ private failureCounts;
1163
+ private disabledHooks;
1164
+ private maxConsecutiveFailures;
1165
+ constructor(maxConsecutiveFailures?: number);
1166
+ register(hook: Hook): void;
1167
+ unregister(id: string): boolean;
1168
+ get(id: string): Hook | undefined;
1169
+ /**
1170
+ * List hooks by phase, excluding disabled hooks.
1171
+ */
1172
+ listByPhase(phase: 'before' | 'after'): Hook[];
1173
+ /**
1174
+ * Record a failure for a hook. After maxConsecutiveFailures, disable it.
1175
+ */
1176
+ recordFailure(id: string): void;
1177
+ /**
1178
+ * Record a success for a hook (resets failure count).
1179
+ */
1180
+ recordSuccess(id: string): void;
1181
+ isDisabled(id: string): boolean;
1182
+ getAll(): Hook[];
1183
+ clear(): void;
1184
+ }
1185
+
1186
+ interface StreamControllerOptions {
1187
+ onStatement: (source: string) => Promise<LineResult>;
1188
+ onStop: (payload: StopPayload, source: string) => void;
1189
+ onError: (error: ErrorPayload) => void;
1190
+ onEvent: (event: SessionEvent) => void;
1191
+ onCodeLine: (line: string) => void;
1192
+ hookRegistry: HookRegistry;
1193
+ hookContext: () => HookContext;
1194
+ }
1195
+ declare class StreamController implements StreamPauseController {
1196
+ private accumulator;
1197
+ private paused;
1198
+ private pauseResolve;
1199
+ private options;
1200
+ private lineCount;
1201
+ private currentBlockId;
1202
+ constructor(options: StreamControllerOptions);
1203
+ /**
1204
+ * Feed tokens from the LLM stream.
1205
+ */
1206
+ feedToken(token: string): Promise<void>;
1207
+ /**
1208
+ * Called when the LLM stream ends. Flush remaining buffer.
1209
+ */
1210
+ finalize(): Promise<void>;
1211
+ private processStatement;
1212
+ pause(): void;
1213
+ resume(): void;
1214
+ isPaused(): boolean;
1215
+ private waitForResume;
1216
+ /**
1217
+ * Clear the line accumulator (e.g., on intervention).
1218
+ */
1219
+ clearBuffer(): void;
1220
+ /**
1221
+ * Set the current block ID for events.
1222
+ */
1223
+ setBlockId(id: string): void;
1224
+ private newBlockId;
1225
+ }
1226
+
1227
+ interface SerializationLimits {
1228
+ maxStringLength: number;
1229
+ maxArrayElements: number;
1230
+ maxObjectKeys: number;
1231
+ maxDepth: number;
1232
+ }
1233
+ /**
1234
+ * Serialize a value to a human-readable string for injection into the LLM context.
1235
+ * Handles truncation, circular references, and depth limiting.
1236
+ */
1237
+ declare function serialize(value: unknown, limits?: Partial<SerializationLimits>): string;
1238
+
1239
+ interface BracketState {
1240
+ round: number;
1241
+ curly: number;
1242
+ square: number;
1243
+ inString: false | "'" | '"' | '`';
1244
+ inLineComment: boolean;
1245
+ inBlockComment: boolean;
1246
+ templateDepth: number;
1247
+ /** JSX nesting depth — tracks open/close tag pairs */
1248
+ jsxDepth: number;
1249
+ /**
1250
+ * JSX tag parsing state:
1251
+ * - 'none': not inside a JSX tag
1252
+ * - 'pending_open': saw '<', waiting for next char to classify
1253
+ * - 'open': inside an opening tag <Component ...
1254
+ * - 'close': inside a closing tag </Component...
1255
+ * - 'selfclose_pending': saw '/' inside opening tag, waiting for '>'
1256
+ */
1257
+ jsxTagState: 'none' | 'pending_open' | 'open' | 'close' | 'selfclose_pending';
1258
+ }
1259
+ declare function createBracketState(): BracketState;
1260
+ /**
1261
+ * Feed a chunk of text into the bracket tracker, updating state character by character.
1262
+ * Returns the updated state (mutates and returns the same object for performance).
1263
+ */
1264
+ declare function feedChunk(state: BracketState, chunk: string): BracketState;
1265
+ /**
1266
+ * Returns true if all brackets are balanced and we're not inside a string/comment.
1267
+ */
1268
+ declare function isBalanced(state: BracketState): boolean;
1269
+ /**
1270
+ * Reset the bracket state.
1271
+ */
1272
+ declare function resetBracketState(state: BracketState): void;
1273
+
1274
+ interface LineAccumulator {
1275
+ buffer: string;
1276
+ bracketState: BracketState;
1277
+ }
1278
+ declare function createLineAccumulator(): LineAccumulator;
1279
+ interface FeedResult {
1280
+ /** Complete statements that were flushed */
1281
+ statements: string[];
1282
+ /** Whether there's still content in the buffer */
1283
+ hasRemaining: boolean;
1284
+ }
1285
+ /**
1286
+ * Feed a token (chunk of text) into the accumulator.
1287
+ * Returns any complete statements that were detected.
1288
+ */
1289
+ declare function feed(acc: LineAccumulator, token: string): FeedResult;
1290
+ /**
1291
+ * Flush any remaining content in the buffer as a statement.
1292
+ * Called when the LLM stream ends.
1293
+ */
1294
+ declare function flush(acc: LineAccumulator): string | null;
1295
+ /**
1296
+ * Clear the accumulator without returning any content.
1297
+ */
1298
+ declare function clear(acc: LineAccumulator): void;
1299
+
1300
+ /**
1301
+ * Determines if a buffered string is a complete TypeScript statement.
1302
+ * Uses bracket depth, JSX depth, and string context tracking as a heuristic.
1303
+ */
1304
+ declare function isCompleteStatement(buffer: string): boolean;
1305
+
1306
+ /**
1307
+ * Detects if a source line is a call to one of the six globals.
1308
+ * Handles both `stop(...)` and `await stop(...)` patterns.
1309
+ */
1310
+ type GlobalName = 'stop' | 'display' | 'ask' | 'async' | 'tasklist' | 'completeTask' | 'loadKnowledge';
1311
+ declare function detectGlobalCall(source: string): GlobalName | null;
1312
+
1313
+ /**
1314
+ * Parse a single TypeScript statement into an AST node.
1315
+ */
1316
+ declare function parseStatement(source: string): ts.Node | null;
1317
+ /**
1318
+ * Extract declared variable names from a statement.
1319
+ * Handles const/let/var and destructuring patterns.
1320
+ */
1321
+ declare function extractDeclarations(source: string): string[];
1322
+ /**
1323
+ * Recover argument names from a stop(...) or similar call expression.
1324
+ * Given `stop(user.name, x, getX())`, returns:
1325
+ * ["user.name", "x", "arg_2"]
1326
+ */
1327
+ declare function recoverArgumentNames(source: string): string[];
1328
+ /**
1329
+ * Extract all variable names referenced in a source string.
1330
+ */
1331
+ declare function extractVariableNames(source: string): string[];
1332
+
1333
+ interface ScopeGeneratorOptions {
1334
+ maxVariables?: number;
1335
+ maxValueWidth?: number;
1336
+ }
1337
+ /**
1338
+ * Generate a SCOPE table string from scope entries.
1339
+ */
1340
+ declare function generateScopeTable(entries: ScopeEntry[], options?: ScopeGeneratorOptions): string;
1341
+ /**
1342
+ * Describe the type of a value for the scope table.
1343
+ */
1344
+ declare function describeType(val: unknown): string;
1345
+ /**
1346
+ * Truncate a value for display in the scope table.
1347
+ */
1348
+ declare function truncateValue(val: unknown, maxLen?: number): string;
1349
+
1350
+ interface CodeTurn {
1351
+ lines: string[];
1352
+ declarations: string[];
1353
+ turnIndex: number;
1354
+ }
1355
+ /**
1356
+ * Compress code turns beyond the sliding window.
1357
+ * Keeps the most recent N lines verbatim; older code replaced with summaries.
1358
+ */
1359
+ declare function compressCodeWindow(turns: CodeTurn[], maxLines: number): string[];
1360
+ /**
1361
+ * Build a summary comment for a compressed code section.
1362
+ */
1363
+ declare function buildSummaryComment(startLine: number, endLine: number, declarations: string[]): string;
1364
+
1365
+ interface DecayTiers {
1366
+ full: number;
1367
+ keysOnly: number;
1368
+ summary: number;
1369
+ }
1370
+ type DecayLevel = 'full' | 'keys' | 'count' | 'removed';
1371
+ /**
1372
+ * Determine decay level based on distance from current turn.
1373
+ */
1374
+ declare function getDecayLevel(distance: number, tiers?: DecayTiers): DecayLevel;
1375
+ /**
1376
+ * Apply decay to a stop payload string based on distance.
1377
+ */
1378
+ declare function decayStopPayload(payload: StopPayload, distance: number, tiers?: DecayTiers): string | null;
1379
+ /**
1380
+ * Apply decay to an error payload message.
1381
+ */
1382
+ declare function decayErrorMessage(errorMsg: string, distance: number, tiers?: DecayTiers): string | null;
1383
+
1384
+ /**
1385
+ * Build the system prompt by replacing slot markers with content.
1386
+ */
1387
+ declare function buildSystemPrompt(template: string, slots: Record<string, string>): string;
1388
+ /**
1389
+ * Update just the {{SCOPE}} slot in an existing system prompt.
1390
+ */
1391
+ declare function updateScopeInPrompt(systemPrompt: string, scopeTable: string): string;
1392
+
1393
+ /**
1394
+ * Progressive decay for knowledge content in stop payloads.
1395
+ *
1396
+ * When the agent loads knowledge via loadKnowledge() and reads it via stop(),
1397
+ * the markdown content can be very large. As turns progress, older knowledge
1398
+ * stop messages are progressively truncated to conserve context window space.
1399
+ *
1400
+ * Decay tiers (by distance in turns from current):
1401
+ * 0 → full content (as serialized)
1402
+ * 1 → truncated: first ~300 chars per file + "...(truncated)"
1403
+ * 2 → headers: just markdown headings from each file
1404
+ * 3+ → names: just the loaded file paths
1405
+ */
1406
+
1407
+ /** Symbol used to tag objects returned by loadKnowledge(). */
1408
+ declare const KNOWLEDGE_TAG: unique symbol;
1409
+ interface KnowledgeDecayTiers {
1410
+ /** Distance 0..full: show full content */
1411
+ full: number;
1412
+ /** Distance full+1..truncated: show truncated content */
1413
+ truncated: number;
1414
+ /** Distance truncated+1..headers: show headers only */
1415
+ headers: number;
1416
+ }
1417
+ type KnowledgeDecayLevel = 'full' | 'truncated' | 'headers' | 'names';
1418
+ declare function getKnowledgeDecayLevel(distance: number, tiers?: KnowledgeDecayTiers): KnowledgeDecayLevel;
1419
+ /**
1420
+ * Check if a value was returned by loadKnowledge() (has the knowledge tag).
1421
+ */
1422
+ declare function isKnowledgeContent(value: unknown): value is KnowledgeContent;
1423
+ /**
1424
+ * Tag an object as knowledge content (called by the loadKnowledge global).
1425
+ */
1426
+ declare function tagAsKnowledge<T extends object>(obj: T): T;
1427
+ /**
1428
+ * Produce a decayed serialization of knowledge content for a stop message.
1429
+ */
1430
+ declare function decayKnowledgeValue(content: KnowledgeContent, distance: number, tiers?: KnowledgeDecayTiers): string;
1431
+
1432
+ /**
1433
+ * Build a user message for a stop() injection.
1434
+ * Format: ← stop { key: value, ... }
1435
+ */
1436
+ declare function buildStopMessage(payload: StopPayload): string;
1437
+ /**
1438
+ * Build a user message for an error injection.
1439
+ * Format: ← error [Type] message (line N)
1440
+ */
1441
+ declare function buildErrorMessage(error: ErrorPayload): string;
1442
+ /**
1443
+ * Build a user message for a human intervention.
1444
+ * No prefix — raw text.
1445
+ */
1446
+ declare function buildInterventionMessage(text: string): string;
1447
+ /**
1448
+ * Build a user message for a hook interrupt.
1449
+ * Format: ⚠ [hook:id] message
1450
+ */
1451
+ declare function buildHookInterruptMessage(hookId: string, message: string): string;
1452
+ /**
1453
+ * Build a user message for an incomplete tasklist reminder.
1454
+ * Format: ⚠ [system] Tasklist "tasklistId" incomplete. Remaining: id1, id2. Continue from where you left off.
1455
+ */
1456
+ declare function buildTasklistReminderMessage(tasklistId: string, ready: string[], blocked: string[], failed: string[]): string;
1457
+ /**
1458
+ * Compute the symbol and detail string for a single task, given the tasklist state.
1459
+ * Reused by generateTasksBlock and agents-block.ts.
1460
+ */
1461
+ declare function renderTaskLine(task: TaskDefinition, state: TasklistState): {
1462
+ symbol: string;
1463
+ detail: string;
1464
+ };
1465
+ /**
1466
+ * Build a user message after a task completion when there are remaining tasks.
1467
+ * Guides the agent to the next ready task with its instructions.
1468
+ */
1469
+ declare function buildTaskContinueMessage(tasklistId: string, completedTaskId: string, readyTasks: Array<{
1470
+ id: string;
1471
+ instructions: string;
1472
+ outputSchema: Record<string, {
1473
+ type: string;
1474
+ }>;
1475
+ }>, tasklistsState: TasklistsState): string;
1476
+ /**
1477
+ * Build a user message for a task order violation.
1478
+ * Stops the stream and guides the agent to the correct next task.
1479
+ */
1480
+ declare function buildTaskOrderViolationMessage(tasklistId: string, attemptedTaskId: string, readyTasks: Array<{
1481
+ id: string;
1482
+ instructions: string;
1483
+ outputSchema: Record<string, {
1484
+ type: string;
1485
+ }>;
1486
+ }>, tasklistsState: TasklistsState): string;
1487
+ /**
1488
+ * Generate a {{CURRENT_TASK}} block showing instructions for the next ready task(s).
1489
+ * Appended to stop messages alongside {{TASKS}} when tasklists are active.
1490
+ */
1491
+ declare function generateCurrentTaskBlock(tasklistsState: TasklistsState): string | null;
1492
+ /**
1493
+ * Generate the {{TASKS}} block showing current state of all active tasklists.
1494
+ * Appended to stop messages when tasklists are active.
1495
+ */
1496
+ declare function generateTasksBlock(tasklistsState: TasklistsState): string | null;
1497
+
1498
+ /**
1499
+ * Generate the {{AGENTS}} block showing the state of all tracked agent promises.
1500
+ * Returns null if no entries are visible.
1501
+ */
1502
+ declare function generateAgentsBlock(registry: AgentRegistry, resolvedInThisStop: Set<string>): string | null;
1503
+
1504
+ /**
1505
+ * Match an AST pattern against a TypeScript AST node.
1506
+ */
1507
+ declare function matchPattern(node: ts.Node, pattern: ASTPattern, sourceFile: ts.SourceFile): HookMatch | null;
1508
+ /**
1509
+ * Find all matching nodes in a source file for a pattern.
1510
+ */
1511
+ declare function findMatches(sourceFile: ts.SourceFile, pattern: ASTPattern): HookMatch[];
1512
+
1513
+ interface HookExecutionResult {
1514
+ action: 'execute' | 'skip' | 'interrupt';
1515
+ source: string;
1516
+ interruptMessage?: string;
1517
+ sideEffects: Array<() => void | Promise<void>>;
1518
+ matchedHooks: Array<{
1519
+ hookId: string;
1520
+ action: string;
1521
+ }>;
1522
+ }
1523
+ /**
1524
+ * Run matching hooks for a statement.
1525
+ * Returns the final action: execute (possibly with transformed source), skip, or interrupt.
1526
+ */
1527
+ declare function executeHooks(source: string, phase: 'before' | 'after', registry: HookRegistry, context: HookContext): Promise<HookExecutionResult>;
1528
+
1529
+ interface RegistryOptions {
1530
+ timeout?: number;
1531
+ rateLimit?: {
1532
+ maxCalls: number;
1533
+ windowMs: number;
1534
+ };
1535
+ onCall?: (name: string, args: unknown[], duration: number) => void;
1536
+ }
1537
+ /**
1538
+ * Wrap a function with timeout, logging, and rate limiting.
1539
+ */
1540
+ declare function wrapFunction<T extends (...args: any[]) => any>(name: string, fn: T, options?: RegistryOptions): T;
1541
+ /**
1542
+ * Create a function registry that wraps all registered functions.
1543
+ */
1544
+ declare class FunctionRegistry {
1545
+ private functions;
1546
+ private options;
1547
+ constructor(options?: RegistryOptions);
1548
+ register(name: string, fn: (...args: any[]) => any): void;
1549
+ get(name: string): Function | undefined;
1550
+ getAll(): Record<string, Function>;
1551
+ has(name: string): boolean;
1552
+ names(): string[];
1553
+ }
1554
+
1555
+ interface SanitizationError {
1556
+ path: string;
1557
+ message: string;
1558
+ }
1559
+ /**
1560
+ * Validate a serialized JSX tree for security concerns.
1561
+ * Returns an array of errors (empty if safe).
1562
+ */
1563
+ declare function sanitizeJSX(jsx: SerializedJSX, path?: string): SanitizationError[];
1564
+ /**
1565
+ * Check if a JSX tree is safe to render.
1566
+ */
1567
+ declare function isJSXSafe(jsx: SerializedJSX): boolean;
1568
+ /**
1569
+ * Validate that an ask() form only contains registered input components.
1570
+ */
1571
+ declare function validateFormComponents(jsx: SerializedJSX, allowedComponents: Set<string>, path?: string): SanitizationError[];
1572
+
1573
+ interface CatalogFunction {
1574
+ /** Function name — becomes a global in the sandbox */
1575
+ name: string;
1576
+ /** Human-readable description — injected into system prompt */
1577
+ description: string;
1578
+ /** TypeScript signature string for the system prompt */
1579
+ signature: string;
1580
+ /** The actual implementation */
1581
+ fn: (...args: unknown[]) => unknown;
1582
+ }
1583
+ interface CatalogModule {
1584
+ /** Module name (e.g., "fs", "fetch") */
1585
+ id: string;
1586
+ /** One-line description */
1587
+ description: string;
1588
+ /** Functions provided by this module */
1589
+ functions: CatalogFunction[];
1590
+ }
1591
+
1592
+ /**
1593
+ * Load catalog modules by their IDs.
1594
+ * If 'all' is passed, loads all available modules.
1595
+ */
1596
+ declare function loadCatalog(moduleIds: string[] | 'all'): Promise<CatalogModule[]>;
1597
+ /**
1598
+ * Merge multiple catalogs into a flat list of functions.
1599
+ */
1600
+ declare function mergeCatalogs(modules: CatalogModule[]): CatalogFunction[];
1601
+ /**
1602
+ * Get a specific module by ID from a loaded catalog list.
1603
+ */
1604
+ declare function getCatalogModule(modules: CatalogModule[], id: string): CatalogModule | undefined;
1605
+ /**
1606
+ * Generate the system prompt block for catalog functions.
1607
+ */
1608
+ declare function formatCatalogForPrompt(modules: CatalogModule[]): string;
1609
+
1610
+ /**
1611
+ * Knowledge tree builder and file loader for spaces.
1612
+ *
1613
+ * Reads a space's knowledge/ directory, builds a tree of domains/fields/options,
1614
+ * and provides a loader function that reads selected markdown files on demand.
1615
+ */
1616
+
1617
+ /**
1618
+ * Merge multiple KnowledgeTrees into one. Domains with the same slug are
1619
+ * combined (fields are merged); distinct domains are concatenated.
1620
+ */
1621
+ declare function mergeKnowledgeTrees(trees: KnowledgeTree[]): KnowledgeTree;
1622
+ /**
1623
+ * Build a KnowledgeTree from a space's knowledge/ directory.
1624
+ */
1625
+ declare function buildKnowledgeTree(knowledgeDir: string): KnowledgeTree;
1626
+ /**
1627
+ * Load knowledge file contents based on a selector object.
1628
+ *
1629
+ * The selector mirrors the knowledge tree structure:
1630
+ * { domainSlug: { fieldSlug: { optionSlug: true } } }
1631
+ *
1632
+ * Returns the same structure with markdown content:
1633
+ * { domainSlug: { fieldSlug: { optionSlug: "# Title\n..." } } }
1634
+ */
1635
+ declare function loadKnowledgeFiles(knowledgeDir: string, selector: FlatKnowledgeSelector): FlatKnowledgeContent;
1636
+ /**
1637
+ * Format knowledge trees as an XML representation for the system prompt.
1638
+ *
1639
+ * Accepts a single tree or an array of named trees.
1640
+ *
1641
+ * ```xml
1642
+ * <knowledge>
1643
+ * <space name="cooking">
1644
+ * <domain name="cuisine" icon="🌍" label="Cuisine">
1645
+ * <field name="type" type="select" var="cuisineType">
1646
+ * <option name="italian">Italian — Mediterranean cooking</option>
1647
+ * <option name="japanese">Japanese — East Asian cuisine</option>
1648
+ * </field>
1649
+ * </domain>
1650
+ * </space>
1651
+ * </knowledge>
1652
+ * ```
1653
+ */
1654
+ declare function formatKnowledgeTreeForPrompt(treeOrTrees: KnowledgeTree | KnowledgeTree[]): string;
1655
+
1656
+ /**
1657
+ * Knowledge writer — creates, updates, and deletes knowledge files on disk.
1658
+ *
1659
+ * Used by the built-in `knowledge` agent namespace to persist memories
1660
+ * and manage knowledge entries. Files follow the same domain/field/option
1661
+ * structure as regular knowledge.
1662
+ */
1663
+ /**
1664
+ * Save a knowledge file to disk.
1665
+ *
1666
+ * Creates domain/field directories and config.json files if they don't exist.
1667
+ * Writes the option as a markdown file with frontmatter.
1668
+ */
1669
+ declare function saveKnowledgeFile(knowledgeDir: string, domain: string, field: string, option: string, content: string): void;
1670
+ /**
1671
+ * Delete a knowledge option file.
1672
+ */
1673
+ declare function deleteKnowledgeFile(knowledgeDir: string, domain: string, field: string, option: string): boolean;
1674
+ /**
1675
+ * Ensure the memory domain exists in a knowledge directory.
1676
+ *
1677
+ * Creates the `memory/` domain with `user`, `project`, `feedback`,
1678
+ * and `reference` field directories plus their config.json files.
1679
+ * Idempotent — skips already-existing entries.
1680
+ */
1681
+ declare function ensureMemoryDomain(knowledgeDir: string): void;
1682
+ /**
1683
+ * Parse a "domain/field" path from the writer's `field` param.
1684
+ * Supports both "domain/field" and plain "field" (defaults to memory domain).
1685
+ */
1686
+ declare function parseFieldPath(fieldParam: string): {
1687
+ domain: string;
1688
+ field: string;
1689
+ };
1690
+
1691
+ export { type ASTPattern, type AgentPromiseEntry, AgentRegistry, type AgentRegistryConfig, type AgentSnapshot, type AgentSpawnConfig, type AgentSpawnResult, type AgentStatus, type AskCancellation, type AsyncCancellation, AsyncManager, type CatalogFunction, type CatalogModule, type ClassMethodInfo, ConversationRecorder, type ConversationState, type ConversationTurn, type ErrorPayload, type FlatKnowledgeContent, type FlatKnowledgeSelector, FunctionRegistry, type GlobalName, type GlobalsConfig, type Hook, type HookAction, type HookContext, type HookExecutionResult, type HookMatch, HookRegistry, KNOWLEDGE_TAG, type KnowledgeContent, type KnowledgeDecayLevel, type KnowledgeDecayTiers, type KnowledgeDomain, type KnowledgeField, type KnowledgeOption, type KnowledgeSelector, type KnowledgeTree, type LineResult, type PartialSessionConfig, type RegistryOptions, type RenderSurface, Sandbox, type SandboxOptions, type ScopeDelta, type ScopeEntry, type SerializationLimits, type SerializedJSX, type SerializedTaskCompletion, type SerializedTasklistState, type SerializedTasklistsState, type SerializedValue, Session, type SessionConfig, type SessionEvent, type SessionOptions, type SessionSnapshot, type SessionStatus, type StatementExecutor, type StopPayload, StreamController, type StreamControllerOptions, type StreamPauseController, type TaskCompletion, type TaskDefinition, type Tasklist, type TasklistsState, type TurnBoundary, type TurnEvent, buildErrorMessage, buildHookInterruptMessage, buildInterventionMessage, buildKnowledgeTree, buildStopMessage, buildSummaryComment, buildSystemPrompt, buildTaskContinueMessage, buildTaskOrderViolationMessage, buildTasklistReminderMessage, clear, compressCodeWindow, computeScopeDelta, createBracketState, createDefaultConfig, createGlobals, createLineAccumulator, decayErrorMessage, decayKnowledgeValue, decayStopPayload, deleteKnowledgeFile, describeType, detectGlobalCall, ensureMemoryDomain, executeHooks, executeLine, extractDeclarations, extractVariableNames, feed, feedChunk, findMatches, flush, formatCatalogForPrompt, formatKnowledgeTreeForPrompt, generateAgentsBlock, generateCurrentTaskBlock, generateScopeTable, generateTasksBlock, getCatalogModule, getDecayLevel, getKnowledgeDecayLevel, isBalanced, isCompleteStatement, isJSXSafe, isKnowledgeContent, loadCatalog, loadKnowledgeFiles, matchPattern, mergeCatalogs, mergeConfig, mergeKnowledgeTrees, parseFieldPath, parseStatement, recoverArgumentNames, renderTaskLine, resetBracketState, sanitizeJSX, saveKnowledgeFile, serialize, serializeTasklistsState, tagAsKnowledge, transpile, truncateValue, updateScopeInPrompt, validateConfig, validateFormComponents, wrapFunction };