@genesislcap/ai-assistant 14.494.0 → 14.496.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 (46) hide show
  1. package/dist/ai-assistant.api.json +588 -214
  2. package/dist/ai-assistant.d.ts +157 -6
  3. package/dist/chat-driver.cjs +5608 -0
  4. package/dist/chat-driver.cjs.map +7 -0
  5. package/dist/chat-driver.mjs +5566 -0
  6. package/dist/chat-driver.mjs.map +7 -0
  7. package/dist/custom-elements.json +713 -333
  8. package/dist/dts/channel/ai-activity-bus.d.ts +36 -0
  9. package/dist/dts/channel/ai-activity-bus.d.ts.map +1 -1
  10. package/dist/dts/channel/ai-activity-channel.d.ts +10 -1
  11. package/dist/dts/channel/ai-activity-channel.d.ts.map +1 -1
  12. package/dist/dts/chat-driver-node.d.ts +28 -0
  13. package/dist/dts/chat-driver-node.d.ts.map +1 -0
  14. package/dist/dts/components/chat-driver/chat-driver.d.ts +66 -5
  15. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  16. package/dist/dts/components/chat-driver/chat-driver.test.d.ts.map +1 -1
  17. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +3 -0
  18. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
  19. package/dist/dts/config/config.d.ts +37 -2
  20. package/dist/dts/config/config.d.ts.map +1 -1
  21. package/dist/dts/index.d.ts +1 -0
  22. package/dist/dts/index.d.ts.map +1 -1
  23. package/dist/dts/main/main.d.ts.map +1 -1
  24. package/dist/dts/state/debug-event-log.d.ts +8 -12
  25. package/dist/dts/state/debug-event-log.d.ts.map +1 -1
  26. package/dist/esm/channel/ai-activity-bus.js +48 -12
  27. package/dist/esm/chat-driver-node.js +33 -0
  28. package/dist/esm/components/chat-driver/chat-driver.js +77 -25
  29. package/dist/esm/components/chat-driver/chat-driver.test.js +160 -36
  30. package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +7 -1
  31. package/dist/esm/main/main.js +8 -1
  32. package/dist/esm/main/popout-interaction-gate.test.js +6 -10
  33. package/dist/tsconfig.tsbuildinfo +1 -1
  34. package/package.json +29 -19
  35. package/scripts/build-chat-driver-node.mjs +42 -0
  36. package/src/channel/ai-activity-bus.ts +64 -10
  37. package/src/channel/ai-activity-channel.ts +9 -1
  38. package/src/chat-driver-node.ts +54 -0
  39. package/src/components/chat-driver/chat-driver.test.ts +237 -50
  40. package/src/components/chat-driver/chat-driver.ts +151 -39
  41. package/src/components/orchestrating-driver/orchestrating-driver.ts +10 -11
  42. package/src/config/config.ts +40 -1
  43. package/src/index.ts +1 -0
  44. package/src/main/main.ts +8 -11
  45. package/src/main/popout-interaction-gate.test.ts +6 -11
  46. package/src/state/debug-event-log.ts +9 -18
@@ -6,6 +6,7 @@ import type { CachePolicy } from '@genesislcap/foundation-ai';
6
6
  import type { ChatAttachment } from '@genesislcap/foundation-ai';
7
7
  import type { ChatConfig } from '@genesislcap/foundation-ai';
8
8
  import type { ChatDriverResult } from '@genesislcap/foundation-ai';
9
+ import type { ChatFallback } from '@genesislcap/foundation-ai';
9
10
  import type { ChatInputDuringExecutionMode } from '@genesislcap/foundation-ai';
10
11
  import type { ChatMessage } from '@genesislcap/foundation-ai';
11
12
  import type { ChatToolChoice } from '@genesislcap/foundation-ai';
@@ -18,8 +19,21 @@ import { InterfaceSymbol } from '@microsoft/fast-foundation';
18
19
  import type { Modal } from '@genesislcap/rapid-design-system';
19
20
  import { ModelTagAppearance } from '@genesislcap/foundation-ai';
20
21
  import type { SubAgentFailureReason } from '@genesislcap/foundation-ai';
22
+ import type { TurnFailureReason } from '@genesislcap/foundation-ai';
21
23
  import { ViewTemplate } from '@genesislcap/web-core';
22
24
 
25
+ /**
26
+ * Minimal activity-bus surface the drivers depend on. `ChatDriver`/`OrchestratingDriver`
27
+ * only ever *publish* — accepting this narrow interface (rather than importing the module
28
+ * singleton) lets a headless/server or unit-test host omit the bus entirely, so no live
29
+ * `BroadcastChannel` is ever opened on that path. See {@link NOOP_ACTIVITY_BUS}.
30
+ *
31
+ * @beta
32
+ */
33
+ export declare interface ActivityBus {
34
+ publish<K extends keyof AgenticActivityEvents>(type: K, detail: AgenticActivityEvents[K]): void;
35
+ }
36
+
23
37
  /** Sentinel value used by the segmented control / select to represent "Auto". */
24
38
  export declare const AGENT_PICKER_AUTO_VALUE = "__auto__";
25
39
 
@@ -50,12 +64,23 @@ export declare type AgentConfig = SpecialistAgentConfig | FallbackAgentConfig;
50
64
  export declare class AgenticActivityBus {
51
65
  private readonly subscribers;
52
66
  private readonly crossTabEvents;
67
+ private readonly channelNameFactory?;
53
68
  private channel?;
69
+ private channelInitialised;
54
70
  /**
55
71
  * @param config - Optional configuration. Omit to create an in-memory-only bus.
56
72
  * @beta
57
73
  */
58
74
  constructor(config?: AgenticActivityBusConfig);
75
+ /**
76
+ * Lazily open the cross-tab `BroadcastChannel` on first use. Deferred (rather than
77
+ * created in the constructor) so that importing this module, or constructing the bus
78
+ * off-browser (Node, tests, headless server), never opens a live channel or reads
79
+ * `sessionStorage` — both would keep a Node event loop alive and hang the process.
80
+ * Cross-tab forwarding is inherently browser-only, so channel creation is gated on a
81
+ * browser environment; elsewhere the bus stays purely in-process.
82
+ */
83
+ private ensureChannel;
59
84
  /**
60
85
  * Subscribe to an event. Returns an unsubscribe function — call it in
61
86
  * `disconnectedCallback` to avoid memory leaks.
@@ -114,6 +139,13 @@ export declare interface AgenticActivityBusConfig {
114
139
  crossTabEvents?: (keyof AgenticActivityEvents)[];
115
140
  /** BroadcastChannel name. Only used when crossTabEvents is non-empty. */
116
141
  channelName?: string;
142
+ /**
143
+ * Lazy alternative to {@link AgenticActivityBusConfig.channelName}: called the first
144
+ * time a cross-tab channel is actually needed, in a browser only. Deferring the name
145
+ * computation keeps side effects (e.g. `sessionStorage` reads) out of module-eval and
146
+ * off the non-browser path. Ignored if `channelName` is also set.
147
+ */
148
+ channelNameFactory?: () => string;
117
149
  }
118
150
 
119
151
  /**
@@ -179,8 +211,16 @@ export declare interface AgenticActivityEvents {
179
211
  * spinner animation lifecycle (which can flap mid-turn as tool calls resolve), whereas
180
212
  * this event is a one-shot per turn boundary. Use this for hooks tied to a turn ending
181
213
  * (telemetry flushes, post-turn workspace transitions, deferred state recomputation).
214
+ *
215
+ * The detail carries the turn's outcome (PTC-0): on a failure it is `{ failureReason }`
216
+ * with the typed `TurnFailureReason`; on a clean completion, a user cancel, a
217
+ * driver dispose, and an agent handoff the detail is `undefined` — the historical shape,
218
+ * kept byte-identical so subscribers that only care about the boundary can keep ignoring
219
+ * it. Structured-cloneable so it survives the cross-tab BroadcastChannel hop.
182
220
  */
183
- 'tool-loop-end': undefined;
221
+ 'tool-loop-end': {
222
+ failureReason?: TurnFailureReason;
223
+ } | undefined;
184
224
  /**
185
225
  * Fired when a tool handler hands a widget to the user mid-loop and parks awaiting it
186
226
  * (`requestInteraction`) — the turn is suspended between provider calls, with no request
@@ -826,6 +866,25 @@ declare interface BaseAgentConfig {
826
866
  * @beta
827
867
  */
828
868
  tailContext?: TailContextInput;
869
+ /**
870
+ * Structured-output schema for this agent. When resolved to a schema on a turn, the model's
871
+ * final (non-tool) answer is constrained to it instead of free text. Composes with `tools`;
872
+ * resolved per turn like {@link BaseAgentConfig.cachePolicy}, so returning `undefined` on
873
+ * working turns and the schema on the finalize turn gives finalize-turn enforcement for free.
874
+ * See {@link ResponseSchemaInput}.
875
+ *
876
+ * @beta
877
+ */
878
+ responseSchema?: ResponseSchemaInput;
879
+ /**
880
+ * Refusal-fallback chain for this agent (provider-neutral). If the model declines a turn
881
+ * (`stop_reason: 'refusal'` — e.g. Fable 5 safety classifiers), the provider re-runs it on the
882
+ * next listed model. Typical use: a Fable 5 agent with `[{ model: 'claude-opus-4-8' }]`. Static
883
+ * (not per-turn); providers that support it apply it server-side, others ignore it.
884
+ *
885
+ * @beta
886
+ */
887
+ fallbacks?: ChatFallback[];
829
888
  /**
830
889
  * Optional hook consulted when the model calls a tool the driver cannot
831
890
  * dispatch — either a *stale* tool (advertised earlier this activation but
@@ -955,9 +1014,6 @@ export declare type CachePolicyInput = CachePolicy | ((ctx: SystemPromptContext)
955
1014
  */
956
1015
  export declare class ChatDriver extends EventTarget implements AiDriver {
957
1016
  private readonly providerRegistry;
958
- private readonly maxToolIterations;
959
- /** Session identity used to file meta events onto the shared debug-log timeline. */
960
- private readonly sessionKey;
961
1017
  private history;
962
1018
  private busy;
963
1019
  /** Epoch ms when the current turn loop began — drives the `turn.end` duration. */
@@ -1185,6 +1241,16 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1185
1241
  * the resolved string in a `<system-reminder>` marker and injects it at the message tail.
1186
1242
  */
1187
1243
  private activeTailContextInput?;
1244
+ /**
1245
+ * Active agent's structured-output schema selector (static value or per-turn resolver).
1246
+ * When it resolves to a schema, the model's final answer is constrained to it this turn.
1247
+ */
1248
+ private activeResponseSchemaInput?;
1249
+ /**
1250
+ * Active agent's refusal-fallback chain (static). Passed through to the provider so a refused
1251
+ * turn (e.g. Fable 5) is re-run on the next model server-side.
1252
+ */
1253
+ private activeFallbacks?;
1188
1254
  /**
1189
1255
  * Active agent's unresolved-tool hook, captured from `applyAgent`. Consulted
1190
1256
  * only when a tool call cannot be dispatched (a stale or hallucinated name);
@@ -1229,9 +1295,13 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1229
1295
  * teardown in `runSubAgent`.
1230
1296
  */
1231
1297
  private unsubscribeRegistry?;
1232
- constructor(providerRegistry: AIProviderRegistry, toolHandlers?: ToolHandlersInput, toolDefinitions?: ToolDefinitionsInput, systemPrompt?: SystemPromptInput, primerHistory?: ChatMessage[], maxToolIterations?: number, maxFoldOperations?: number, maxTurnSnapshots?: number,
1298
+ /** Hard cap on tool-loop iterations. */
1299
+ private readonly maxToolIterations;
1233
1300
  /** Session identity used to file meta events onto the shared debug-log timeline. */
1234
- sessionKey?: string);
1301
+ private readonly sessionKey;
1302
+ /** Injected activity bus; defaults to a no-op off-browser (Node/tests/headless). */
1303
+ private readonly activityBus;
1304
+ constructor(providerRegistry: AIProviderRegistry, config?: ChatDriverConfig);
1235
1305
  /**
1236
1306
  * Tear down the driver: aborts the lifecycle signal so any in-flight provider
1237
1307
  * request (and prompt/tool factories awaiting it) cancels instead of running
@@ -1268,6 +1338,23 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1268
1338
  * cached history would otherwise gain a stray marker on remount).
1269
1339
  */
1270
1340
  private completeAbortedTurn;
1341
+ /**
1342
+ * Build the `done` loop result, carrying the typed failure reason when the turn
1343
+ * bailed (PTC-0). The discriminant stays `'done'` either way — the same value a
1344
+ * clean turn returns — so consumers matching on `reason === 'done'` are unchanged;
1345
+ * `failureReason` is simply present on a failure and absent on success. Omitted
1346
+ * (rather than set to `undefined`) so a happy-path result stays byte-identical to
1347
+ * the historical `{ reason: 'done' }`.
1348
+ */
1349
+ private turnDone;
1350
+ /** The typed failure reason on a loop result, or `undefined` for a clean turn / handoff. */
1351
+ private static failureReasonOf;
1352
+ /**
1353
+ * Build the `tool-loop-end` event detail for a turn's result. A failure carries a
1354
+ * `{ failureReason }` detail; a clean turn emits `undefined` — the historical shape,
1355
+ * kept byte-identical so subscribers see exactly what they always have.
1356
+ */
1357
+ private static loopEndDetail;
1271
1358
  /**
1272
1359
  * Swap in a new agent's configuration. Called by OrchestratingDriver before
1273
1360
  * each specialist turn so the shared driver runs with the right tools and prompt.
@@ -1516,6 +1603,41 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1516
1603
  private appendToHistory;
1517
1604
  }
1518
1605
 
1606
+ /**
1607
+ * Construction-time configuration for {@link ChatDriver}. Everything except the provider
1608
+ * registry is optional — most fields are also settable per-agent via `applyAgent`, so a
1609
+ * bare `new ChatDriver(registry)` is valid. Mirrors the `(registry, options)` shape of
1610
+ * `OrchestratingDriver`.
1611
+ *
1612
+ * @beta
1613
+ */
1614
+ export declare interface ChatDriverConfig {
1615
+ /** Initial tool handlers (static map or per-turn factory). Default `{}`. */
1616
+ toolHandlers?: ToolHandlersInput;
1617
+ /** Initial tool definitions (static array or per-turn factory). Default `[]`. */
1618
+ toolDefinitions?: ToolDefinitionsInput;
1619
+ /** Initial system prompt (string or per-turn resolver). */
1620
+ systemPrompt?: SystemPromptInput;
1621
+ /** Primer history prepended to the conversation. */
1622
+ primerHistory?: ChatMessage[];
1623
+ /** Hard cap on tool-loop iterations. Default `50`. */
1624
+ maxToolIterations?: number;
1625
+ /** Hard cap on fold operations. Default `5`. */
1626
+ maxFoldOperations?: number;
1627
+ /** Ring-buffer size for per-turn snapshots. Default `400`. */
1628
+ maxTurnSnapshots?: number;
1629
+ /** Session identity used to file meta events onto the shared debug-log timeline. */
1630
+ sessionKey?: string;
1631
+ /**
1632
+ * Activity bus for lifecycle/halo/tool-loop events. Injected by the browser host
1633
+ * (the shared cross-tab singleton); omitted off-browser (Node, tests, headless), where
1634
+ * it defaults to {@link NOOP_ACTIVITY_BUS} so no `BroadcastChannel` is ever opened.
1635
+ */
1636
+ activityBus?: ActivityBus;
1637
+ }
1638
+
1639
+ export { ChatFallback }
1640
+
1519
1641
  /**
1520
1642
  * `detail` of the `AiAssistantEvent.ChatHeaderMouseDown` event.
1521
1643
  *
@@ -2860,6 +2982,14 @@ export declare interface ManualSelectionConfig {
2860
2982
 
2861
2983
  export { ModelTagAppearance }
2862
2984
 
2985
+ /**
2986
+ * No-op {@link ActivityBus}. The default when no bus is injected (Node, tests, headless
2987
+ * server use) — publishing goes nowhere and nothing is left open to tear down.
2988
+ *
2989
+ * @beta
2990
+ */
2991
+ export declare const NOOP_ACTIVITY_BUS: ActivityBus;
2992
+
2863
2993
  /**
2864
2994
  * Orchestrates multiple specialist agents. Sits between `FoundationAiAssistant`
2865
2995
  * and `ChatDriver`, classifying each user message and routing it to the right
@@ -2919,6 +3049,8 @@ export declare class OrchestratingDriver extends EventTarget implements AiDriver
2919
3049
  maxToolIterations?: number;
2920
3050
  maxFoldOperations?: number;
2921
3051
  maxTurnSnapshots?: number;
3052
+ /** Activity bus passed through to the inner ChatDriver (browser host injects the singleton). */
3053
+ activityBus?: ActivityBus;
2922
3054
  });
2923
3055
  resolveInteraction(interactionId: string, result: unknown): void;
2924
3056
  getInteractionContext(interactionId: string): InteractionContext | undefined;
@@ -3103,6 +3235,23 @@ declare interface ResolvedCostHistoryConfig {
3103
3235
  badgeLabel: string;
3104
3236
  }
3105
3237
 
3238
+ /**
3239
+ * Structured-output schema for an agent. When set, the model's final (non-tool) answer is
3240
+ * constrained to this JSON Schema instead of free text. Either a static schema or a function
3241
+ * resolved each tool-loop iteration — return the schema on the turn(s) it should apply and
3242
+ * `undefined` otherwise, so "whole-loop" vs "finalize-turn" enforcement is just what the
3243
+ * resolver returns (e.g. `({ state }) => state.machine.matches('finalizing') ? schema : undefined`).
3244
+ *
3245
+ * Orthogonal to {@link ToolChoiceInput}: an agent can carry both `tools` and a `responseSchema`.
3246
+ * Each provider applies it natively where possible (Anthropic `output_config.format`, Gemini
3247
+ * JSON mode) and degrades gracefully otherwise. The schema is a plain JSON Schema object; keep to
3248
+ * the portable subset providers share (`additionalProperties: false`, explicit `required`, enums,
3249
+ * `anyOf` for nullables — no numeric/string constraints or recursion).
3250
+ *
3251
+ * @beta
3252
+ */
3253
+ export declare type ResponseSchemaInput = object | ((ctx: SystemPromptContext) => object | undefined | Promise<object | undefined>);
3254
+
3106
3255
  /**
3107
3256
  * Restore a foundation-state-machine instance from a snapshot produced by the
3108
3257
  * default serializer (or `machine.getPersistedSnapshot()`). Call inside a
@@ -3698,6 +3847,8 @@ export declare interface ToolTreeNode extends ChatToolDefinition {
3698
3847
  tools?: ToolTreeNode[];
3699
3848
  }
3700
3849
 
3850
+ export { TurnFailureReason }
3851
+
3701
3852
  /**
3702
3853
  * One captured frame of what the LLM saw on a single tool-loop iteration.
3703
3854
  * The driver records these as a ring buffer (cap: configurable via