@genesislcap/ai-assistant 14.434.0 → 14.435.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/ai-assistant.api.json +1513 -70
  2. package/dist/ai-assistant.d.ts +367 -7
  3. package/dist/dts/components/ai-driver/ai-driver.d.ts +8 -0
  4. package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
  5. package/dist/dts/components/chat-driver/chat-driver.d.ts +79 -3
  6. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  7. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +23 -0
  8. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
  9. package/dist/dts/config/config.d.ts +106 -2
  10. package/dist/dts/config/config.d.ts.map +1 -1
  11. package/dist/dts/config/define-stateful-agent.d.ts +115 -0
  12. package/dist/dts/config/define-stateful-agent.d.ts.map +1 -0
  13. package/dist/dts/index.d.ts +1 -0
  14. package/dist/dts/index.d.ts.map +1 -1
  15. package/dist/dts/main/main.d.ts +36 -4
  16. package/dist/dts/main/main.d.ts.map +1 -1
  17. package/dist/dts/main/main.template.d.ts.map +1 -1
  18. package/dist/esm/components/chat-driver/chat-driver.js +126 -11
  19. package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +192 -33
  20. package/dist/esm/config/define-stateful-agent.js +174 -0
  21. package/dist/esm/index.js +1 -0
  22. package/dist/esm/main/main.js +164 -21
  23. package/dist/esm/main/main.template.js +2 -11
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +16 -16
  26. package/src/components/ai-driver/ai-driver.ts +9 -0
  27. package/src/components/chat-driver/chat-driver.ts +178 -8
  28. package/src/components/orchestrating-driver/orchestrating-driver.ts +191 -17
  29. package/src/config/config.ts +112 -2
  30. package/src/config/define-stateful-agent.ts +293 -0
  31. package/src/index.ts +1 -0
  32. package/src/main/main.template.ts +2 -9
  33. package/src/main/main.ts +167 -14
@@ -129,6 +129,22 @@ export declare interface AgenticActivityEvents {
129
129
  'chat-popin': undefined;
130
130
  }
131
131
 
132
+ /**
133
+ * Context passed to `onActivate` / `onDeactivate` lifecycle hooks on an agent.
134
+ *
135
+ * @beta
136
+ */
137
+ export declare interface AgentLifecycleContext {
138
+ /** The agent the hook is firing for. */
139
+ agentName: string;
140
+ /** The assistant session key — stable across reloads, unique per assistant instance. */
141
+ sessionKey: string;
142
+ /** The agent that was active immediately before this one, if any. Only set on `onActivate`. */
143
+ previousAgentName?: string;
144
+ /** Aborted if the session disconnects mid-activation. */
145
+ signal: AbortSignal;
146
+ }
147
+
132
148
  /**
133
149
  * User-facing agent picker rendered above the chat input.
134
150
  *
@@ -317,6 +333,13 @@ export declare interface AiDriver extends EventTarget {
317
333
  * Get query suggestions from the AI.
318
334
  */
319
335
  getSuggestions(history: ChatMessage[], prompt: string, count: number, allAgentInfo?: AllAgentSummary[]): Promise<string[]>;
336
+ /**
337
+ * Per-LLM-call snapshots — what the model saw each turn (prompt, tools,
338
+ * agent state). Used by the host's debug-log exporter. Optional because the
339
+ * interface is implemented by both leaf and orchestrating drivers; the
340
+ * orchestrator just delegates to its inner `ChatDriver`.
341
+ */
342
+ getTurnSnapshots?(): ReadonlyArray<TurnSnapshot>;
320
343
  }
321
344
 
322
345
  /**
@@ -357,12 +380,21 @@ declare interface BaseAgentConfig {
357
380
  name: string;
358
381
  /**
359
382
  * System prompt injected into every conversation turn for this agent.
383
+ *
384
+ * Either a string (resolved once) or a function resolved each tool-loop
385
+ * iteration — pick the function form when the prompt depends on per-turn state
386
+ * (e.g. a state machine's current step). See {@link SystemPromptInput}.
360
387
  */
361
- systemPrompt?: string;
388
+ systemPrompt?: SystemPromptInput;
362
389
  /**
363
390
  * Tool definitions (JSON Schema) passed to the AI provider for this agent.
391
+ *
392
+ * Either a static array or a function resolved each tool-loop iteration —
393
+ * pick the function form to narrow the tool surface per turn (e.g. expose
394
+ * only the tools valid in the current state of a state machine).
395
+ * See {@link ToolDefinitionsInput}.
364
396
  */
365
- toolDefinitions?: ChatToolDefinition[];
397
+ toolDefinitions?: ToolDefinitionsInput;
366
398
  /**
367
399
  * Tool handler implementations for this agent.
368
400
  */
@@ -387,6 +419,40 @@ declare interface BaseAgentConfig {
387
419
  * disabled. See {@link ManualSelectionConfig}.
388
420
  */
389
421
  manualSelection?: ManualSelectionConfig;
422
+ /**
423
+ * Fires when this agent becomes the active specialist (including being pinned).
424
+ * Use to instantiate per-agent state that should outlive a single turn — e.g.
425
+ * a state machine the agent owns across the conversation. Awaited before the
426
+ * agent's first turn runs.
427
+ *
428
+ * Capture dependencies (services, redux store refs, etc.) via closure on the
429
+ * host element rather than expecting them on the context.
430
+ *
431
+ * @beta
432
+ */
433
+ onActivate?: (ctx: AgentLifecycleContext) => void | Promise<void>;
434
+ /**
435
+ * Fires when this agent is being deactivated (the user switches to another
436
+ * agent, the session is torn down, or the agent is unpinned and replaced).
437
+ * Use to dispose per-agent state created in `onActivate`. Awaited before the
438
+ * incoming agent's `onActivate` runs.
439
+ *
440
+ * @beta
441
+ */
442
+ onDeactivate?: (ctx: AgentLifecycleContext) => void | Promise<void>;
443
+ /**
444
+ * Returns an agent-supplied debug payload for the export log. Called once per
445
+ * LLM call by the driver (alongside the resolved prompt and tool list) and
446
+ * once at log-export time for the latest snapshot. Stateful agents should
447
+ * return their machine state and captured context so the exported timeline
448
+ * captures what drove each turn.
449
+ *
450
+ * Return value must be JSON-serializable. {@link defineStatefulAgent} wires a
451
+ * sensible default that snapshots any machine-shaped state automatically.
452
+ *
453
+ * @beta
454
+ */
455
+ getDebugSnapshot?: () => unknown;
390
456
  }
391
457
 
392
458
  /**
@@ -406,7 +472,19 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
406
472
  private busy;
407
473
  private pendingInteractions;
408
474
  private systemPrompt?;
475
+ /**
476
+ * Resolved tool definitions visible to the LLM. Folds mutate this in place
477
+ * (push/pop on open/close). When `toolDefinitionsFactory` is set, this is
478
+ * overwritten each tool-loop iteration with the factory's output.
479
+ */
409
480
  private toolDefinitions;
481
+ /**
482
+ * Optional dynamic-tools source. When set, called each tool-loop iteration
483
+ * to recompute `toolDefinitions` before the LLM call. `defineStatefulAgent`
484
+ * forbids folds when this is set, so the fold-mutation path is unreachable
485
+ * in that case.
486
+ */
487
+ private toolDefinitionsFactory?;
410
488
  private toolHandlers;
411
489
  private primerHistory?;
412
490
  private activeAgentName?;
@@ -438,7 +516,28 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
438
516
  * `undefined` means the loop has not been stopped early.
439
517
  */
440
518
  private subAgentCompletion;
441
- constructor(aiProvider: AIProvider, toolHandlers?: ChatToolHandlers, toolDefinitions?: ChatToolDefinition[], systemPrompt?: string, primerHistory?: ChatMessage[], maxToolIterations?: number, maxFoldOperations?: number);
519
+ /**
520
+ * Set by `releaseAgent` inside a top-level tool handler — typically a stateful
521
+ * agent's terminal-state handler signalling that its flow is complete and the
522
+ * auto-pin lock can release. Checked by the orchestrator after `sendMessage`
523
+ * returns; the orchestrator fires `onDeactivate` and clears the pin.
524
+ *
525
+ * Reset at the start of each `sendMessage` so a release from a previous turn
526
+ * doesn't leak forward.
527
+ */
528
+ private agentReleaseRequested;
529
+ /**
530
+ * Ring buffer of per-LLM-call snapshots. Cap is configurable via
531
+ * `chatConfig.agent.maxTurnSnapshots`; older entries drop off as new ones
532
+ * arrive. See {@link TurnSnapshot} for the captured shape.
533
+ */
534
+ private turnSnapshots;
535
+ /** Monotonic counter that survives agent swaps — useful for cross-referencing with history. */
536
+ private globalTurnIndex;
537
+ /** Captured from `applyAgent` so we don't store the whole `AgentConfig`. */
538
+ private debugSnapshotter?;
539
+ private readonly maxTurnSnapshots;
540
+ constructor(aiProvider: AIProvider, toolHandlers?: ChatToolHandlers, toolDefinitions?: ToolDefinitionsInput, systemPrompt?: SystemPromptInput, primerHistory?: ChatMessage[], maxToolIterations?: number, maxFoldOperations?: number, maxTurnSnapshots?: number);
442
541
  /**
443
542
  * Swap in a new agent's configuration. Called by OrchestratingDriver before
444
543
  * each specialist turn so the shared driver runs with the right tools and prompt.
@@ -451,6 +550,25 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
451
550
  getSubAgentCompletion(): {
452
551
  result: unknown;
453
552
  } | undefined;
553
+ /**
554
+ * Returns true if `releaseAgent` was called during the most recent turn.
555
+ * Consumed by the orchestrator to trigger the auto-pin release path.
556
+ */
557
+ getAgentReleaseRequested(): boolean;
558
+ /**
559
+ * Return the per-turn snapshots captured so far. Used by the host's debug
560
+ * log exporter to show what the LLM saw on each turn — system prompt, tool
561
+ * surface, and agent-supplied state (e.g. a machine snapshot).
562
+ *
563
+ * Ring-buffered at `MAX_TURN_SNAPSHOTS`; older entries are dropped.
564
+ */
565
+ getTurnSnapshots(): ReadonlyArray<TurnSnapshot>;
566
+ /**
567
+ * Push one snapshot to the ring buffer. Called inside `runToolLoop` just
568
+ * before each LLM call — that's the latest point where the prompt, tool
569
+ * surface, and agent state line up with what the model is about to see.
570
+ */
571
+ private recordTurnSnapshot;
454
572
  /**
455
573
  * Optional transform applied to conversation history immediately before each LLM request.
456
574
  * Cleared when `undefined`. Does not alter stored history.
@@ -631,6 +749,33 @@ export declare function createToolFold(config: {
631
749
  */
632
750
  export declare function defineAgent<const T extends AgentConfig>(config: T): T;
633
751
 
752
+ /**
753
+ * Build an `AgentConfig` whose `systemPrompt`, `toolDefinitions`, and tool
754
+ * handlers all close over a long-lived state object created on activation.
755
+ *
756
+ * The framework wires the lifecycle: `init` on `onActivate`, `dispose` on
757
+ * `onDeactivate`. State is held inside the helper's closure — never exposed on
758
+ * the resulting `AgentConfig` — so the redux serializer doesn't see it.
759
+ *
760
+ * @example
761
+ * ```ts
762
+ * const guidedBooking = defineStatefulAgent<{ machine: GuidedBookingMachine }>({
763
+ * name: 'Guided Booking',
764
+ * description: 'Books a trade via a guided wizard.',
765
+ * excludeFromClassifier: true,
766
+ * manualSelection: { enabled: true, hint: 'Step-by-step trade booking' },
767
+ * init: () => ({ machine: new GuidedBookingMachine() }),
768
+ * dispose: ({ state }) => state.machine.stop(),
769
+ * systemPrompt: ({ state }) => composeFromMachine(state.machine),
770
+ * toolDefinitions: ({ state }) => toolsForState(state.machine.state),
771
+ * toolHandlers: ({ machine }) => ({ ... }),
772
+ * });
773
+ * ```
774
+ *
775
+ * @beta
776
+ */
777
+ export declare function defineStatefulAgent<S>(opts: StatefulAgentInit<S>): AgentConfig;
778
+
634
779
  /**
635
780
  * Expands a flat list of tool definitions into a nested tree by resolving fold
636
781
  * metadata from the corresponding handlers. Use this for debug output so the
@@ -830,6 +975,14 @@ export declare class FoundationAiAssistant extends GenesisElement {
830
975
  * current agent configuration. Does not wire event listeners or register in
831
976
  * the driver registry.
832
977
  */
978
+ /**
979
+ * Warn at config time if any stateful agent (one with lifecycle hooks) is
980
+ * configured in a way that makes it unreachable: `excludeFromClassifier`
981
+ * removes the classifier path, so the only entry left is manual pinning —
982
+ * which requires both `manualSelection.enabled` on the agent and the picker
983
+ * itself being enabled at the assistant level.
984
+ */
985
+ private warnUnreachableStatefulAgents;
833
986
  private createDriver;
834
987
  /**
835
988
  * Attaches event listeners to the current driver. Stores a cleanup function
@@ -888,6 +1041,21 @@ export declare class FoundationAiAssistant extends GenesisElement {
888
1041
  get agentPickerEnabled(): boolean;
889
1042
  /** Hint text for the currently pinned agent, if any. Used in the toggle button tooltip. */
890
1043
  get pinnedAgentHint(): string | undefined;
1044
+ /**
1045
+ * The pin is locked when a stateful agent (one with lifecycle hooks) is
1046
+ * *actively running* — i.e. its `onActivate` has fired and it owns live
1047
+ * state. Until the user sends their first message, a freshly pinned stateful
1048
+ * agent is not yet active and the picker should remain free; the user might
1049
+ * change their mind and unpin without anything to clean up.
1050
+ *
1051
+ * We derive from `activeAgent` (set by the orchestrator after `onActivate`
1052
+ * completes) rather than `pinnedAgentName` (set immediately on picker
1053
+ * click). The serialized `activeAgent` strips lifecycle hooks, so we look
1054
+ * up the live config from `this.agents` to check for them.
1055
+ */
1056
+ get pinLocked(): boolean;
1057
+ /** Tooltip shown on the picker toggle button. */
1058
+ get agentToggleTitle(): string;
891
1059
  /**
892
1060
  * Tint applied to the pin icon when an agent is pinned. Picked from the
893
1061
  * brand palette by agent position (modulo the palette length), so each agent
@@ -912,23 +1080,30 @@ export declare class FoundationAiAssistant extends GenesisElement {
912
1080
  timestamp: string;
913
1081
  host: string;
914
1082
  agentSummary: ({
915
- toolDefinitions: ToolTreeNode[];
1083
+ toolDefinitions: string | ToolTreeNode[];
916
1084
  toolHandlers: any;
1085
+ onActivate: any;
1086
+ onDeactivate: any;
1087
+ getDebugSnapshot: any;
917
1088
  description: string;
918
1089
  fallback?: never;
1090
+ excludeFromClassifier?: boolean;
919
1091
  name: string;
920
- systemPrompt?: string;
1092
+ systemPrompt?: SystemPromptInput;
921
1093
  primerHistory?: ChatMessage[];
922
1094
  subAgents?: AgentConfig[];
923
1095
  chatInputDuringExecution?: ChatInputDuringExecutionMode;
924
1096
  manualSelection?: ManualSelectionConfig;
925
1097
  } | {
926
- toolDefinitions: ToolTreeNode[];
1098
+ toolDefinitions: string | ToolTreeNode[];
927
1099
  toolHandlers: any;
1100
+ onActivate: any;
1101
+ onDeactivate: any;
1102
+ getDebugSnapshot: any;
928
1103
  fallback: true;
929
1104
  description?: never;
930
1105
  name: string;
931
- systemPrompt?: string;
1106
+ systemPrompt?: SystemPromptInput;
932
1107
  primerHistory?: ChatMessage[];
933
1108
  subAgents?: AgentConfig[];
934
1109
  chatInputDuringExecution?: ChatInputDuringExecutionMode;
@@ -937,6 +1112,8 @@ export declare class FoundationAiAssistant extends GenesisElement {
937
1112
  activeSystemPrompt: string;
938
1113
  activePrimerHistory: ChatMessage[];
939
1114
  activeFoldStack: string[];
1115
+ activeDebugSnapshot: unknown;
1116
+ turnSnapshots: readonly TurnSnapshot[];
940
1117
  debug: unknown;
941
1118
  };
942
1119
  };
@@ -1056,14 +1233,22 @@ export declare class OrchestratingDriver extends EventTarget implements AiDriver
1056
1233
  private readonly maxHandoffs;
1057
1234
  private readonly classifierHistoryLength;
1058
1235
  private readonly classifierRetries;
1236
+ private readonly sessionKey;
1237
+ /**
1238
+ * Aborted on driver disposal. Threaded into `AgentLifecycleContext.signal`
1239
+ * so long-running `onActivate` work can bail if the session disconnects.
1240
+ */
1241
+ private readonly lifecycleAbortController;
1059
1242
  private pinnedAgentName;
1060
1243
  activeAgent?: AgentConfig;
1061
1244
  constructor(aiProvider: AIProvider, agents: AgentConfig[], options?: {
1245
+ sessionKey?: string;
1062
1246
  maxHandoffs?: number;
1063
1247
  classifierHistoryLength?: number;
1064
1248
  classifierRetries?: number;
1065
1249
  maxToolIterations?: number;
1066
1250
  maxFoldOperations?: number;
1251
+ maxTurnSnapshots?: number;
1067
1252
  });
1068
1253
  resolveInteraction(interactionId: string, result: unknown): void;
1069
1254
  isBusy(): boolean;
@@ -1076,10 +1261,24 @@ export declare class OrchestratingDriver extends EventTarget implements AiDriver
1076
1261
  setPinnedAgent(name: string | null): void;
1077
1262
  loadHistory(messages: ChatMessage[]): void;
1078
1263
  getRawHistory(): readonly ChatMessage[];
1264
+ /** Delegates to the inner {@link ChatDriver} — turns are captured there. */
1265
+ getTurnSnapshots(): ReadonlyArray<TurnSnapshot>;
1079
1266
  getSuggestions(history: ChatMessage[], prompt: string, count: number, allAgentInfo?: AllAgentSummary[]): Promise<string[]>;
1080
1267
  sendMessage(input: string, attachments?: ChatAttachment[]): Promise<ChatDriverResult>;
1081
1268
  continueFromHistory(transientPrimer?: ChatMessage[]): Promise<ChatDriverResult>;
1082
1269
  private applyAgent;
1270
+ /**
1271
+ * Release the current stateful agent: fire `onDeactivate`, clear the pin,
1272
+ * dispatch events so the host (and Redux) reflect the unpinned state. Called
1273
+ * automatically when a tool handler invokes `context.releaseAgent`.
1274
+ */
1275
+ private releaseActiveAgent;
1276
+ /**
1277
+ * Fire `onDeactivate` on the current active agent and abort any pending
1278
+ * lifecycle work. Called by the host on session teardown so machines can
1279
+ * release resources cleanly.
1280
+ */
1281
+ dispose(): Promise<void>;
1083
1282
  private classify;
1084
1283
  /**
1085
1284
  * Returns the pinned agent if `pinnedAgentName` matches a known specialist or
@@ -1118,6 +1317,106 @@ export declare interface SpecialistAgentConfig extends BaseAgentConfig {
1118
1317
  */
1119
1318
  description: string;
1120
1319
  fallback?: never;
1320
+ /**
1321
+ * When `true`, the classifier never auto-routes to this agent. The user can
1322
+ * still select it manually via the picker, provided both prerequisites are
1323
+ * met: this agent has `manualSelection.enabled` set to `true`, *and* the
1324
+ * assistant has the picker enabled via `chatConfig.picker.mode`.
1325
+ *
1326
+ * Use this for agents that overlap heavily with a sibling (e.g. a guided
1327
+ * wizard sitting next to a free-form agent in the same domain) and should
1328
+ * only be reached intentionally rather than via classifier routing.
1329
+ *
1330
+ * @beta
1331
+ */
1332
+ excludeFromClassifier?: boolean;
1333
+ }
1334
+
1335
+ /**
1336
+ * Init options for {@link defineStatefulAgent}. Generic over the state shape `S`
1337
+ * the agent owns (a state machine, an observable controller, anything).
1338
+ *
1339
+ * The helper threads `state` through `systemPrompt`, `toolDefinitions`, and the
1340
+ * `toolHandlers` factory so consumer code never has to reach for a closure or
1341
+ * a module-level mutable.
1342
+ *
1343
+ * @beta
1344
+ */
1345
+ export declare interface StatefulAgentInit<S> {
1346
+ /** Display name — must be unique within the agents array. */
1347
+ name: string;
1348
+ /** Plain-language description used by the classifier. Required: stateful agents are always specialists. */
1349
+ description: string;
1350
+ /**
1351
+ * Hide this agent from the classifier — only reachable via manual pinning.
1352
+ * Stateful agents are always specialists; they cannot be the fallback (a
1353
+ * fallback is a leaf invoked when no specialist matches, with no flow to
1354
+ * own state for).
1355
+ */
1356
+ excludeFromClassifier?: boolean;
1357
+ /** Static primer history prepended to every call (not visible to the user). */
1358
+ primerHistory?: ChatMessage[];
1359
+ /** Sub-agents available to this agent's tool handlers via `requestSubAgent`. */
1360
+ subAgents?: AgentConfig[];
1361
+ /** Opt this agent in to manual picker selection. */
1362
+ manualSelection?: ManualSelectionConfig;
1363
+ /** How the main chat input behaves while this agent is executing. */
1364
+ chatInputDuringExecution?: ChatInputDuringExecutionMode;
1365
+ /**
1366
+ * Construct the agent-scoped state. Called by the framework when this agent
1367
+ * becomes active (`onActivate`). Awaited before the agent's first turn runs.
1368
+ */
1369
+ init: (ctx: AgentLifecycleContext) => S | Promise<S>;
1370
+ /**
1371
+ * Tear down the agent-scoped state. Called when the agent is being replaced.
1372
+ * Awaited before the incoming agent's `init` runs.
1373
+ */
1374
+ dispose?: (ctx: AgentLifecycleContext & {
1375
+ state: S;
1376
+ }) => void | Promise<void>;
1377
+ /**
1378
+ * System prompt composed from current state. Resolved each tool-loop
1379
+ * iteration. Use this to feed the LLM whatever the current state implies
1380
+ * (e.g. a state machine's `meta.systemPrompt` plus captured context).
1381
+ */
1382
+ systemPrompt?: (ctx: SystemPromptContext & {
1383
+ state: S;
1384
+ }) => string | Promise<string>;
1385
+ /**
1386
+ * Tool definitions the LLM sees. Either a static array (resolved once) or a
1387
+ * function resolved each tool-loop iteration. The function form is how a
1388
+ * machine-driven agent narrows the surface per state.
1389
+ *
1390
+ * **Constraint:** the resolved handlers (returned from {@link StatefulAgentInit.toolHandlers})
1391
+ * must not include fold facades. Folds are an LLM-driven UX optimisation
1392
+ * that competes with the machine for control of the tool view; one of them
1393
+ * has to be in charge. Helper throws at init time if a fold-tagged handler
1394
+ * is detected.
1395
+ */
1396
+ toolDefinitions?: ChatToolDefinition[] | ((ctx: SystemPromptContext & {
1397
+ state: S;
1398
+ }) => ChatToolDefinition[] | Promise<ChatToolDefinition[]>);
1399
+ /**
1400
+ * Factory returning the tool handler map. Called with the live `state` at
1401
+ * `onActivate` time; the handlers it returns are cached for the lifetime of
1402
+ * this activation. Each handler closes over `state` and any other deps you
1403
+ * captured.
1404
+ *
1405
+ * The handler set returned must be the **union** of every tool name your
1406
+ * agent might advertise across all states — `toolDefinitions` filters which
1407
+ * are visible to the LLM per turn, but every name still needs an entry here.
1408
+ */
1409
+ toolHandlers?: (state: S) => ChatToolHandlers;
1410
+ /**
1411
+ * Optional getter for the debug-log snapshot. Defaults to auto-snapshotting
1412
+ * any property on `state` that looks like a foundation-state-machine
1413
+ * instance (has `state`, `context`, and `complete` fields). Override when
1414
+ * the default doesn't capture what you need — e.g. multiple machines, or
1415
+ * non-machine state worth recording.
1416
+ *
1417
+ * Return value must be JSON-serializable.
1418
+ */
1419
+ getDebugSnapshot?: (state: S) => unknown;
1121
1420
  }
1122
1421
 
1123
1422
  /**
@@ -1161,6 +1460,32 @@ export declare type SuggestionsState = {
1161
1460
  message: string;
1162
1461
  };
1163
1462
 
1463
+ /**
1464
+ * Context passed to the function form of `systemPrompt` / `toolDefinitions`.
1465
+ * Resolved each tool-loop iteration so the agent can vary what the LLM sees per turn.
1466
+ *
1467
+ * @beta
1468
+ */
1469
+ export declare interface SystemPromptContext {
1470
+ /** The active agent's name. */
1471
+ agentName: string;
1472
+ /** Full conversation history up to (but not including) the message being processed. */
1473
+ history: ReadonlyArray<ChatMessage>;
1474
+ /** 0 = first LLM call this turn; > 0 = retry or subsequent tool-loop iteration. */
1475
+ turnIndex: number;
1476
+ /** Aborted if the turn is cancelled. */
1477
+ signal: AbortSignal;
1478
+ }
1479
+
1480
+ /**
1481
+ * System prompt for an agent. Either a static string (resolved once) or a function
1482
+ * resolved each tool-loop iteration. The function form lets the agent compute the
1483
+ * prompt from external state — e.g. a state machine's current step.
1484
+ *
1485
+ * @beta
1486
+ */
1487
+ export declare type SystemPromptInput = string | ((ctx: SystemPromptContext) => string | Promise<string>);
1488
+
1164
1489
  /**
1165
1490
  * Symbol used to attach ToolFold metadata to a facade handler function.
1166
1491
  * The ChatDriver inspects this to detect fold facades at runtime.
@@ -1169,6 +1494,16 @@ export declare type SuggestionsState = {
1169
1494
  */
1170
1495
  export declare const TOOL_FOLD_SYMBOL: unique symbol;
1171
1496
 
1497
+ /**
1498
+ * Tool definitions for an agent. Either a static array (the conventional shape) or
1499
+ * a function resolved each tool-loop iteration. The function form lets the agent
1500
+ * narrow the tool surface per turn — e.g. expose only the tools valid in the
1501
+ * current state of a state machine.
1502
+ *
1503
+ * @beta
1504
+ */
1505
+ export declare type ToolDefinitionsInput = ChatToolDefinition[] | ((ctx: SystemPromptContext) => ChatToolDefinition[] | Promise<ChatToolDefinition[]>);
1506
+
1172
1507
  /**
1173
1508
  * Internal metadata for a tool fold. Attached to the facade handler via TOOL_FOLD_SYMBOL.
1174
1509
  *
@@ -1224,4 +1559,29 @@ export declare interface ToolTreeNode extends ChatToolDefinition {
1224
1559
  tools?: ToolTreeNode[];
1225
1560
  }
1226
1561
 
1562
+ /**
1563
+ * One captured frame of what the LLM saw on a single tool-loop iteration.
1564
+ * The driver records these as a ring buffer (cap: configurable via
1565
+ * `chatConfig.agent.maxTurnSnapshots`, default 40) so the export log can show,
1566
+ * per turn: which agent was active, the resolved system prompt, the tool names
1567
+ * visible to the LLM, and any agent-supplied debug snapshot (e.g. machine
1568
+ * state for stateful agents).
1569
+ *
1570
+ * @beta
1571
+ */
1572
+ export declare interface TurnSnapshot {
1573
+ /** Monotonic counter across the driver's lifetime (does not reset on agent swap). */
1574
+ turnIndex: number;
1575
+ /** ISO timestamp captured just before the LLM call. */
1576
+ timestamp: string;
1577
+ /** Name of the agent active when this LLM call ran. */
1578
+ agentName?: string;
1579
+ /** Final system prompt sent to the LLM (post-fold-suffix, post-retry hint). */
1580
+ systemPrompt?: string;
1581
+ /** Tool names sent to the LLM, in order — definitions are static per name so names alone suffice. */
1582
+ toolNames: string[];
1583
+ /** Agent-supplied snapshot — machine state/context for stateful agents, undefined otherwise. */
1584
+ agentSnapshot?: unknown;
1585
+ }
1586
+
1227
1587
  export { }
@@ -1,4 +1,5 @@
1
1
  import type { ChatAttachment, ChatDriverResult, ChatMessage, ChatToolDefinition } from '@genesislcap/foundation-ai';
2
+ import type { TurnSnapshot } from '../chat-driver/chat-driver';
2
3
  /** @internal */
3
4
  export interface AllAgentSummary {
4
5
  name: string;
@@ -48,5 +49,12 @@ export interface AiDriver extends EventTarget {
48
49
  * Get query suggestions from the AI.
49
50
  */
50
51
  getSuggestions(history: ChatMessage[], prompt: string, count: number, allAgentInfo?: AllAgentSummary[]): Promise<string[]>;
52
+ /**
53
+ * Per-LLM-call snapshots — what the model saw each turn (prompt, tools,
54
+ * agent state). Used by the host's debug-log exporter. Optional because the
55
+ * interface is implemented by both leaf and orchestrating drivers; the
56
+ * orchestrator just delegates to its inner `ChatDriver`.
57
+ */
58
+ getTurnSnapshots?(): ReadonlyArray<TurnSnapshot>;
51
59
  }
52
60
  //# sourceMappingURL=ai-driver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-driver.d.ts","sourceRoot":"","sources":["../../../../src/components/ai-driver/ai-driver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAEpC,gBAAgB;AAChB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC3C;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEtF;;;;;OAKG;IACH,mBAAmB,CAAC,eAAe,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEhF;;OAEG;IACH,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAEjE;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAE3C;;OAEG;IACH,aAAa,CAAC,IAAI,SAAS,WAAW,EAAE,CAAC;IAEzC;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC;IAElB;;OAEG;IACH,cAAc,CACZ,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,eAAe,EAAE,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACtB"}
1
+ {"version":3,"file":"ai-driver.d.ts","sourceRoot":"","sources":["../../../../src/components/ai-driver/ai-driver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,gBAAgB;AAChB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC3C;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEtF;;;;;OAKG;IACH,mBAAmB,CAAC,eAAe,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEhF;;OAEG;IACH,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAEjE;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAE3C;;OAEG;IACH,aAAa,CAAC,IAAI,SAAS,WAAW,EAAE,CAAC;IAEzC;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC;IAElB;;OAEG;IACH,cAAc,CACZ,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,eAAe,EAAE,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAErB;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,aAAa,CAAC,YAAY,CAAC,CAAC;CAClD"}
@@ -1,5 +1,5 @@
1
- import type { AIProvider, ChatAttachment, ChatDriverResult, ChatMessage, ChatToolDefinition, ChatToolHandlers } from '@genesislcap/foundation-ai';
2
- import type { AgentConfig } from '../../config/config';
1
+ import type { AIProvider, ChatAttachment, ChatDriverResult, ChatMessage, ChatToolHandlers } from '@genesislcap/foundation-ai';
2
+ import type { AgentConfig, SystemPromptInput, ToolDefinitionsInput } from '../../config/config';
3
3
  import type { AiDriver, AllAgentSummary } from '../ai-driver/ai-driver';
4
4
  /** Name reserved for the cross-agent handoff tool — injected by OrchestratingDriver. */
5
5
  export declare const REQUEST_CONTINUATION_TOOL = "request_continuation";
@@ -9,6 +9,30 @@ export declare const REQUEST_CONTINUATION_TOOL = "request_continuation";
9
9
  * @beta
10
10
  */
11
11
  export type ChatHistoryUpdatedEvent = CustomEvent<ReadonlyArray<ChatMessage>>;
12
+ /**
13
+ * One captured frame of what the LLM saw on a single tool-loop iteration.
14
+ * The driver records these as a ring buffer (cap: configurable via
15
+ * `chatConfig.agent.maxTurnSnapshots`, default 40) so the export log can show,
16
+ * per turn: which agent was active, the resolved system prompt, the tool names
17
+ * visible to the LLM, and any agent-supplied debug snapshot (e.g. machine
18
+ * state for stateful agents).
19
+ *
20
+ * @beta
21
+ */
22
+ export interface TurnSnapshot {
23
+ /** Monotonic counter across the driver's lifetime (does not reset on agent swap). */
24
+ turnIndex: number;
25
+ /** ISO timestamp captured just before the LLM call. */
26
+ timestamp: string;
27
+ /** Name of the agent active when this LLM call ran. */
28
+ agentName?: string;
29
+ /** Final system prompt sent to the LLM (post-fold-suffix, post-retry hint). */
30
+ systemPrompt?: string;
31
+ /** Tool names sent to the LLM, in order — definitions are static per name so names alone suffice. */
32
+ toolNames: string[];
33
+ /** Agent-supplied snapshot — machine state/context for stateful agents, undefined otherwise. */
34
+ agentSnapshot?: unknown;
35
+ }
12
36
  /**
13
37
  * Plain TS class that drives a multi-turn chat conversation, including the tool-call loop.
14
38
  * Owned by `FoundationAiAssistant` — created in `connectedCallback`, torn down in `disconnectedCallback`.
@@ -26,7 +50,19 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
26
50
  private busy;
27
51
  private pendingInteractions;
28
52
  private systemPrompt?;
53
+ /**
54
+ * Resolved tool definitions visible to the LLM. Folds mutate this in place
55
+ * (push/pop on open/close). When `toolDefinitionsFactory` is set, this is
56
+ * overwritten each tool-loop iteration with the factory's output.
57
+ */
29
58
  private toolDefinitions;
59
+ /**
60
+ * Optional dynamic-tools source. When set, called each tool-loop iteration
61
+ * to recompute `toolDefinitions` before the LLM call. `defineStatefulAgent`
62
+ * forbids folds when this is set, so the fold-mutation path is unreachable
63
+ * in that case.
64
+ */
65
+ private toolDefinitionsFactory?;
30
66
  private toolHandlers;
31
67
  private primerHistory?;
32
68
  private activeAgentName?;
@@ -58,7 +94,28 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
58
94
  * `undefined` means the loop has not been stopped early.
59
95
  */
60
96
  private subAgentCompletion;
61
- constructor(aiProvider: AIProvider, toolHandlers?: ChatToolHandlers, toolDefinitions?: ChatToolDefinition[], systemPrompt?: string, primerHistory?: ChatMessage[], maxToolIterations?: number, maxFoldOperations?: number);
97
+ /**
98
+ * Set by `releaseAgent` inside a top-level tool handler — typically a stateful
99
+ * agent's terminal-state handler signalling that its flow is complete and the
100
+ * auto-pin lock can release. Checked by the orchestrator after `sendMessage`
101
+ * returns; the orchestrator fires `onDeactivate` and clears the pin.
102
+ *
103
+ * Reset at the start of each `sendMessage` so a release from a previous turn
104
+ * doesn't leak forward.
105
+ */
106
+ private agentReleaseRequested;
107
+ /**
108
+ * Ring buffer of per-LLM-call snapshots. Cap is configurable via
109
+ * `chatConfig.agent.maxTurnSnapshots`; older entries drop off as new ones
110
+ * arrive. See {@link TurnSnapshot} for the captured shape.
111
+ */
112
+ private turnSnapshots;
113
+ /** Monotonic counter that survives agent swaps — useful for cross-referencing with history. */
114
+ private globalTurnIndex;
115
+ /** Captured from `applyAgent` so we don't store the whole `AgentConfig`. */
116
+ private debugSnapshotter?;
117
+ private readonly maxTurnSnapshots;
118
+ constructor(aiProvider: AIProvider, toolHandlers?: ChatToolHandlers, toolDefinitions?: ToolDefinitionsInput, systemPrompt?: SystemPromptInput, primerHistory?: ChatMessage[], maxToolIterations?: number, maxFoldOperations?: number, maxTurnSnapshots?: number);
62
119
  /**
63
120
  * Swap in a new agent's configuration. Called by OrchestratingDriver before
64
121
  * each specialist turn so the shared driver runs with the right tools and prompt.
@@ -71,6 +128,25 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
71
128
  getSubAgentCompletion(): {
72
129
  result: unknown;
73
130
  } | undefined;
131
+ /**
132
+ * Returns true if `releaseAgent` was called during the most recent turn.
133
+ * Consumed by the orchestrator to trigger the auto-pin release path.
134
+ */
135
+ getAgentReleaseRequested(): boolean;
136
+ /**
137
+ * Return the per-turn snapshots captured so far. Used by the host's debug
138
+ * log exporter to show what the LLM saw on each turn — system prompt, tool
139
+ * surface, and agent-supplied state (e.g. a machine snapshot).
140
+ *
141
+ * Ring-buffered at `MAX_TURN_SNAPSHOTS`; older entries are dropped.
142
+ */
143
+ getTurnSnapshots(): ReadonlyArray<TurnSnapshot>;
144
+ /**
145
+ * Push one snapshot to the ring buffer. Called inside `runToolLoop` just
146
+ * before each LLM call — that's the latest point where the prompt, tool
147
+ * surface, and agent state line up with what the model is about to see.
148
+ */
149
+ private recordTurnSnapshot;
74
150
  /**
75
151
  * Optional transform applied to conversation history immediately before each LLM request.
76
152
  * Cleared when `undefined`. Does not alter stored history.