@genesislcap/ai-assistant 15.26.0 → 15.27.0-agent-log-submit.3

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 (52) hide show
  1. package/dist/ai-assistant.api.json +1014 -110
  2. package/dist/ai-assistant.d.ts +236 -99
  3. package/dist/chat-driver.cjs +460 -373
  4. package/dist/chat-driver.cjs.map +4 -4
  5. package/dist/chat-driver.mjs +460 -373
  6. package/dist/chat-driver.mjs.map +4 -4
  7. package/dist/custom-elements.json +1171 -248
  8. package/dist/dts/components/chat-driver/chat-driver.d.ts +28 -200
  9. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  10. package/dist/dts/components/chat-driver/interaction-controller.d.ts +99 -0
  11. package/dist/dts/components/chat-driver/interaction-controller.d.ts.map +1 -0
  12. package/dist/dts/components/chat-driver/turn-recorder.d.ts +191 -0
  13. package/dist/dts/components/chat-driver/turn-recorder.d.ts.map +1 -0
  14. package/dist/dts/components/settings-modal/settings-modal.d.ts.map +1 -1
  15. package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
  16. package/dist/dts/components/settings-modal/settings-modal.template.d.ts +28 -0
  17. package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
  18. package/dist/dts/index.d.ts +1 -0
  19. package/dist/dts/index.d.ts.map +1 -1
  20. package/dist/dts/main/main.d.ts +180 -1
  21. package/dist/dts/main/main.d.ts.map +1 -1
  22. package/dist/dts/main/main.styles.d.ts.map +1 -1
  23. package/dist/dts/main/main.template.d.ts +19 -0
  24. package/dist/dts/main/main.template.d.ts.map +1 -1
  25. package/dist/dts/state/ai-assistant-slice.d.ts +7 -1
  26. package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
  27. package/dist/dts/state/persistence/session-persistence-provider.d.ts +5 -0
  28. package/dist/dts/state/persistence/session-persistence-provider.d.ts.map +1 -1
  29. package/dist/dts/state/session-store.d.ts +1 -0
  30. package/dist/dts/state/session-store.d.ts.map +1 -1
  31. package/dist/dts/utils/format-message-timestamp.d.ts +77 -0
  32. package/dist/dts/utils/format-message-timestamp.d.ts.map +1 -0
  33. package/dist/dts/utils/resolve-debug-log-note.d.ts +25 -0
  34. package/dist/dts/utils/resolve-debug-log-note.d.ts.map +1 -0
  35. package/dist/dts/utils/resolve-preference-baseline.d.ts +18 -1
  36. package/dist/dts/utils/resolve-preference-baseline.d.ts.map +1 -1
  37. package/dist/esm/components/chat-driver/chat-driver.js +68 -404
  38. package/dist/esm/components/chat-driver/interaction-controller.js +235 -0
  39. package/dist/esm/components/chat-driver/turn-recorder.js +206 -0
  40. package/dist/esm/components/settings-modal/settings-modal.js +1 -0
  41. package/dist/esm/components/settings-modal/settings-modal.styles.js +85 -5
  42. package/dist/esm/components/settings-modal/settings-modal.template.js +220 -25
  43. package/dist/esm/main/main.js +510 -23
  44. package/dist/esm/main/main.styles.js +75 -0
  45. package/dist/esm/main/main.template.js +43 -2
  46. package/dist/esm/state/ai-assistant-slice.js +5 -0
  47. package/dist/esm/utils/format-message-timestamp.js +126 -0
  48. package/dist/esm/utils/resolve-debug-log-note.js +37 -0
  49. package/dist/esm/utils/resolve-preference-baseline.js +54 -2
  50. package/package.json +16 -16
  51. package/sandbox/README.md +45 -2
  52. package/sandbox/sandbox.ts +95 -3
@@ -23,6 +23,7 @@ import { InterfaceSymbol } from '@microsoft/fast-foundation';
23
23
  import type { Modal } from '@genesislcap/rapid-design-system';
24
24
  import { ModelTagAppearance } from '@genesislcap/foundation-ai';
25
25
  import type { SubAgentFailureReason } from '@genesislcap/foundation-ai';
26
+ import type { TimestampDisplay } from '@genesislcap/foundation-ai';
26
27
  import type { TurnFailureReason } from '@genesislcap/foundation-ai';
27
28
  import { ViewTemplate } from '@genesislcap/web-core';
28
29
 
@@ -1463,17 +1464,8 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1463
1464
  private busy;
1464
1465
  /** Epoch ms when the current turn loop began — drives the `turn.end` duration. */
1465
1466
  private turnStartedAt;
1466
- private pendingInteractions;
1467
- /**
1468
- * Live per-interaction contexts (GENC-1390), keyed by interactionId. Created in
1469
- * `requestInteraction` alongside the pending entry, disposed + removed in
1470
- * `resolveInteraction`. Non-serialisable (sockets, timers, subscriber sets), so
1471
- * they live here on the driver — not on the DOM, not in the persisted store — and
1472
- * therefore survive the element remounts (layout reflow/drag, transcript
1473
- * re-render) that this feature exists to make harmless. At most one is live at a
1474
- * time (see the one-interaction-at-a-time guard in `requestInteraction`).
1475
- */
1476
- private interactionContexts;
1467
+ /** Custom UI interactions: the pending call, its live context, and any host to delegate to. */
1468
+ private readonly interactions;
1477
1469
  private systemPrompt?;
1478
1470
  /**
1479
1471
  * Preamble cost of the most recent request, set at the request-build site.
@@ -1518,13 +1510,6 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1518
1510
  */
1519
1511
  private activeAgentLabel?;
1520
1512
  private displayName?;
1521
- /**
1522
- * When set, `requestInteraction` delegates to this callback instead of using
1523
- * this driver's own pending map. Wired by `invokeSubAgent` so a sub-agent's
1524
- * widget renders in — and resolves through — the parent (ultimately the
1525
- * root) driver, where the main UI is listening.
1526
- */
1527
- private hostInteractionRequester?;
1528
1513
  /**
1529
1514
  * When set (e.g. by OrchestratingDriver), applied only to the conversation slice
1530
1515
  * sent to the model — stored `history` stays unchanged for UI and logging.
@@ -1637,33 +1622,10 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1637
1622
  */
1638
1623
  private agentReleaseRequested;
1639
1624
  /**
1640
- * Ring buffer of per-LLM-call snapshots. Cap is configurable via
1641
- * `chatConfig.agent.maxTurnSnapshots`; older entries drop off as new ones
1642
- * arrive. See {@link TurnSnapshot} for the captured shape.
1643
- */
1644
- private turnSnapshots;
1645
- /**
1646
- * `turn` + `message` diagnostic-log entries harvested from an out-of-band source (a resolved
1647
- * interaction whose widget returned `InteractionResult.diagnostics` — e.g. a server-side
1648
- * ChatDriver's debug log). `event` entries are NOT kept here — they're folded into the session's
1649
- * meta-event registry via `mergeMetaEvents` (see `resolveInteraction`) so they inherit fresh host
1650
- * indices, and reach the log through `getMetaEvents`. Append-only; the host folds these into its
1651
- * debug log alongside this driver's own timeline. Not cleared here — it lives with the driver
1652
- * instance, like `turnSnapshots`, so a new chat (fresh driver) starts empty while a compaction
1653
- * (same instance) keeps it. (GENC-1461.)
1625
+ * Per-turn snapshots, forwarded sub-agent snapshots, and harvested external diagnostics —
1626
+ * everything the exported debug log draws from this driver.
1654
1627
  */
1655
- private readonly externalDiagnostics;
1656
- /**
1657
- * Monotonic count of external-diagnostics batches harvested this driver-lifetime. Namespaces each
1658
- * batch's re-keyed `turn` entries so distinct server generations in one chat session can't collide
1659
- * on `turnIndex` in the forward-capture persister (which dedups turns by that key). (GENC-1461.)
1660
- */
1661
- private externalDiagnosticsBatches;
1662
- /** Monotonic counter that survives agent swaps — useful for cross-referencing with history. */
1663
- private globalTurnIndex;
1664
- /** Captured from `applyAgent` so we don't store the whole `AgentConfig`. */
1665
- private debugSnapshotter?;
1666
- private readonly maxTurnSnapshots;
1628
+ private readonly turnRecorder;
1667
1629
  /**
1668
1630
  * Aborted by `dispose()` on driver teardown (e.g. an agent-config swap).
1669
1631
  * Threaded into every provider call as `ChatRequestOptions.signal`, so a
@@ -1855,7 +1817,7 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
1855
1817
  * on to completion or the transport timeout. Called by the host on driver
1856
1818
  * swap and by `OrchestratingDriver.dispose()`. Idempotent.
1857
1819
  *
1858
- * Deliberately does NOT settle `pendingInteractions` here: dispose is never
1820
+ * Deliberately does NOT settle pending interactions here: dispose is never
1859
1821
  * reached while one is pending. The only host-level dispose is the agent-swap
1860
1822
  * rebuild, which is guarded by `isBusy()` — a pending interaction keeps the
1861
1823
  * tool loop suspended (`busy === true`), so the swap is deferred until the
@@ -2096,7 +2058,7 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
2096
2058
  * log exporter to show what the LLM saw on each turn — system prompt, tool
2097
2059
  * surface, and agent-supplied state (e.g. a machine snapshot).
2098
2060
  *
2099
- * Ring-buffered at `MAX_TURN_SNAPSHOTS`; older entries are dropped.
2061
+ * Ring-buffered at `maxTurnSnapshots`; older entries are dropped.
2100
2062
  */
2101
2063
  getTurnSnapshots(): ReadonlyArray<TurnSnapshot>;
2102
2064
  /**
@@ -2104,37 +2066,10 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
2104
2066
  * `InteractionResult.diagnostics` (e.g. a server-side ChatDriver's collated debug log). The host
2105
2067
  * concatenates these into its own debug log so `downloadDebugLog`/the persisted diagnostics stream
2106
2068
  * include external-engine logs; `event` entries are excluded here because they're merged into the
2107
- * session's meta-event registry instead (see `resolveInteraction`) and reach the log via
2108
- * `getMetaEvents`. Opaque, chronologically sorted by the host at assemble time. (GENC-1461.)
2069
+ * session's meta-event registry instead and reach the log via `getMetaEvents`. Opaque,
2070
+ * chronologically sorted by the host at assemble time. (GENC-1461.)
2109
2071
  */
2110
2072
  getExternalDiagnostics(): ReadonlyArray<DiagnosticEntry>;
2111
- /**
2112
- * Merge a sub-agent's turn snapshots into this driver's buffer so they surface
2113
- * as `kind:'turn'` entries in the exported debug log. The child runs as a
2114
- * separate, discarded driver, so its snapshots would otherwise be lost. Each is
2115
- * re-labelled under the parent turn that activated the sub-agent: the child's
2116
- * own (numeric) turns become `"<parentTurn>-1"`, `"-2"`, … (1-based, in order);
2117
- * any already-forwarded grand-child labels (strings) have their leading segment
2118
- * remapped the same way, so nesting composes (`"5-2"` → `"5-2-1"`).
2119
- *
2120
- * Note: two sub-agents invoked in the *same* parent turn share the prefix, so
2121
- * their labels can repeat — `agentName` on each snapshot disambiguates them.
2122
- */
2123
- private forwardSubAgentSnapshots;
2124
- /**
2125
- * Push one snapshot to the ring buffer. Called inside `runToolLoop` just
2126
- * before each LLM call — that's the latest point where the prompt, tool
2127
- * surface, and agent state line up with what the model is about to see.
2128
- *
2129
- * Returns the pushed object so the caller can back-fill what only the response
2130
- * knows (`usage`). Mutating it after the fact is safe whether or not the ring
2131
- * buffer has since evicted it — an evicted snapshot is simply no longer exported.
2132
- */
2133
- private recordTurnSnapshot;
2134
- /**
2135
- * Optional transform applied to conversation history immediately before each LLM request.
2136
- * Cleared when `undefined`. Does not alter stored history.
2137
- */
2138
2073
  /**
2139
2074
  * Mid-loop context guard policy (GENC-1567). `undefined` disables the guard.
2140
2075
  *
@@ -2168,6 +2103,10 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
2168
2103
  * far is not lost.
2169
2104
  */
2170
2105
  private contextExhausted;
2106
+ /**
2107
+ * Optional transform applied to conversation history immediately before each LLM request.
2108
+ * Cleared when `undefined`. Does not alter stored history.
2109
+ */
2171
2110
  setProviderHistoryTransform(transform?: (history: ChatMessage[]) => ChatMessage[]): void;
2172
2111
  getHistory(): ReadonlyArray<ChatMessage>;
2173
2112
  getRawHistory(): readonly ChatMessage[];
@@ -2253,21 +2192,12 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
2253
2192
  */
2254
2193
  requestInteraction<T>(componentName: string, data: any, options?: InteractionRequestOptions): Promise<T>;
2255
2194
  /**
2256
- * Add external (non-LLM) spend to an interaction's message AFTER it has resolved.
2257
- *
2258
- * **Why this exists separately from `resolveInteraction`.** A widget's spend reaches the session
2259
- * total only through `InteractionResult.costUsd`, which is read exactly once — `resolveInteraction`
2260
- * does its whole job inside `if (interaction)` and then deletes the entry from
2261
- * `pendingInteractions`. That is correct for the resolution itself, but it assumes a widget stops
2262
- * costing money when it resolves, and several deliberately do not: a widget that resolves EARLY so
2263
- * the assistant stops waiting (options shown, a preview rendered) may stay interactive for minutes
2264
- * afterwards and do more paid work on the user's behalf. Re-emitting `interaction-completed` does
2265
- * not help — with the interaction gone from the map the call is a silent no-op — so that spend had
2266
- * nowhere to go and was simply missing from the figure shown to the user.
2195
+ * Add external (non-LLM) spend to an interaction's message AFTER it has resolved — for a widget
2196
+ * that resolves early so the assistant stops waiting, then keeps doing paid work on the user's
2197
+ * behalf. `InteractionController.recordExternalCost` explains why the resolution path cannot
2198
+ * carry this.
2267
2199
  *
2268
- * Additive by design: the caller reports a DELTA, not a running total, so repeated calls sum. It
2269
- * touches only `externalCostUsd`; the recorded `interaction.resolved` payload is left exactly as
2270
- * the resolution wrote it, because this is not a second resolution and must not read like one.
2200
+ * Additive by design: the caller reports a DELTA, not a running total, so repeated calls sum.
2271
2201
  *
2272
2202
  * Deliberately does NOT require the interaction to be pending, does not resurrect it, and has no
2273
2203
  * loading/turn side effects — this is bookkeeping about a turn that already happened.
@@ -2277,8 +2207,8 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
2277
2207
  * @returns `true` when the spend was recorded; `false` when it was not — either the value was
2278
2208
  * not a positive finite amount, or the message is no longer in history (trimmed or condensed
2279
2209
  * away). A real outcome a caller may want to log rather than a failure to throw on; every
2280
- * `false` also records an `interaction.external-cost-dropped` meta event here, so money can
2281
- * never disappear without a trace.
2210
+ * `false` also records an `interaction.external-cost-dropped` meta event, so money can never
2211
+ * disappear without a trace.
2282
2212
  * @beta
2283
2213
  */
2284
2214
  recordExternalCost(interactionId: string, costUsd: number): boolean;
@@ -2294,14 +2224,10 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
2294
2224
  */
2295
2225
  getInteractionContext(interactionId: string): InteractionContext | undefined;
2296
2226
  /**
2297
- * Resolve every in-flight interaction with a `'timeout'` result, closing its
2298
- * widget read-only. Used when a sub-agent that owns the open widget times out:
2299
- * the widget is parked in *this* driver's map (interactions resolve on the
2300
- * host, not the child), so cancelling it here unblocks the sub-agent handler
2301
- * awaiting it. The "one interaction at a time" invariant means there is at
2302
- * most one.
2227
+ * Replace the history message owning `interactionId`. `false` when it is no longer in history.
2228
+ * Does not announce the change — the interaction paths differ on whether they should.
2303
2229
  */
2304
- private cancelPendingInteractions;
2230
+ private patchInteractionMessage;
2305
2231
  /**
2306
2232
  * Seeds the driver with a prior conversation history so a new component instance
2307
2233
  * can continue an existing conversation. Call this before the first user message.
@@ -2364,6 +2290,8 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
2364
2290
  */
2365
2291
  private appendDriverNotice;
2366
2292
  private appendToHistory;
2293
+ /** Announce the current history to the host. */
2294
+ private notifyHistoryUpdated;
2367
2295
  }
2368
2296
 
2369
2297
  /**
@@ -3218,6 +3146,37 @@ export declare class FoundationAiAssistant extends GenesisElement {
3218
3146
  /** Current user-facing toggle state for agent switch indicator visibility. */
3219
3147
  get showAgentSwitchIndicator(): boolean;
3220
3148
  set showAgentSwitchIndicator(value: boolean);
3149
+ /**
3150
+ * When each message shows its timestamp — `'off'`, `'hover'` (default) or `'always'`.
3151
+ *
3152
+ * Falls back to `DEFAULT_TIMESTAMP_DISPLAY` rather than `'off'` when there is no
3153
+ * store yet: this preference defaults ON, so the pre-store render must match the state
3154
+ * the baseline is about to resolve to, or timestamps would visibly pop in on connect.
3155
+ */
3156
+ get timestampDisplay(): TimestampDisplay;
3157
+ set timestampDisplay(value: TimestampDisplay);
3158
+ /**
3159
+ * Epoch ms the transcript's relative timestamps are measured against.
3160
+ *
3161
+ * A relative label is only correct at the instant it renders: FAST evaluates the
3162
+ * binding once, and an idle conversation never re-renders, so "2 minutes ago" would
3163
+ * still read "2 minutes ago" an hour later. Making the formatter read this observable
3164
+ * instead of `Date.now()` gives every row one shared, invalidatable clock — a tick
3165
+ * re-evaluates them all.
3166
+ */
3167
+ timestampClock: number;
3168
+ /** Handle for the `TIMESTAMP_CLOCK_INTERVAL_MS` ticker; undefined while stopped. */
3169
+ private _timestampClockTimer?;
3170
+ /**
3171
+ * Start or stop the timestamp clock to match the current mode and connection state.
3172
+ *
3173
+ * Idempotent, and safe to call from either lifecycle end — it is driven from
3174
+ * `connectedCallback`, `disconnectedCallback` and the `timestampDisplay` setter, which
3175
+ * can fire in any order. Nothing runs while the mode is `'off'` (no binding reads the
3176
+ * clock) or while disconnected (a timer outliving its element is a leak, and a
3177
+ * popped-out view disconnects without the session ending).
3178
+ */
3179
+ private syncTimestampClock;
3221
3180
  /** Currently enabled animations. */
3222
3181
  get enabledAnimations(): AiAssistantAnimation[];
3223
3182
  set enabledAnimations(value: AiAssistantAnimation[]);
@@ -3651,6 +3610,38 @@ export declare class FoundationAiAssistant extends GenesisElement {
3651
3610
  * element has its own settings modal.
3652
3611
  */
3653
3612
  downloadingDebugLog: boolean;
3613
+ /**
3614
+ * True while `submitDebugLog` is building and handing off the log. Same role as
3615
+ * `downloadingDebugLog` for the Send button: the lifetime-stitch and the host's
3616
+ * `send` callback are async, so the button needs a visible in-flight state.
3617
+ */
3618
+ submittingDebugLog: boolean;
3619
+ /**
3620
+ * Outcome of the last log submission, shown briefly on the button ('Sent' /
3621
+ * 'Failed — retry') then cleared by `setDebugLogSubmitResult`'s timer. `null` when idle.
3622
+ */
3623
+ debugLogSubmitResult: 'sent' | 'error' | null;
3624
+ /** Timer that clears `debugLogSubmitResult` back to idle. */
3625
+ private debugLogSubmitResultTimer?;
3626
+ /**
3627
+ * Whether the agent-log compose box (note + Send/Cancel) is open. Opened by the row's
3628
+ * Send button when `debugLogSubmit.note` is not `false`; closed by Cancel or a
3629
+ * successful send. Stays open after a failure so the typed note is not lost.
3630
+ */
3631
+ debugLogComposeOpen: boolean;
3632
+ /** The note typed in the compose box, raw (trimmed only at submit time). */
3633
+ debugLogNote: string;
3634
+ /** Bound to the compose box's text-area via the template ref, for focus on open. */
3635
+ debugLogNoteEl?: HTMLElement;
3636
+ /** How long 'Sent' shows before idle. Overridable so tests need not wait 4 seconds. */
3637
+ debugLogSubmitResultFlashMs: number;
3638
+ /**
3639
+ * Bumped by `resetDebugLogSubmitState`. An in-flight `submitDebugLog` captures it and
3640
+ * drops its continuation when a reset (disconnect, session switch, Clear) happened
3641
+ * while it awaited — otherwise the stale submission would write state, arm a timer on
3642
+ * a torn-down element, or report 'Sent' into a session it never belonged to.
3643
+ */
3644
+ private debugLogSubmitGeneration;
3654
3645
  /** Active tab inside the settings modal. */
3655
3646
  get settingsModalTab(): SettingsModalTab;
3656
3647
  set settingsModalTab(value: SettingsModalTab);
@@ -4302,6 +4293,65 @@ export declare class FoundationAiAssistant extends GenesisElement {
4302
4293
  get settingsCostTabVisible(): boolean;
4303
4294
  /** Whether session token usage should render on the Usage tab. */
4304
4295
  get settingsSessionTokensVisible(): boolean;
4296
+ /**
4297
+ * Whether the settings "Agent log" section renders — shown when either action is
4298
+ * enabled: the download button (`allowDebugDownload`) or the host-transport Send
4299
+ * button (`debugLogSubmit`). Each button is additionally gated on its own flag
4300
+ * inside the section, so a host can enable one without the other.
4301
+ */
4302
+ get settingsAgentLogSectionVisible(): boolean;
4303
+ /**
4304
+ * The resolved compose-box settings for the agent-log Send button, or `null` when the
4305
+ * host opted out (`debugLogSubmit.note: false`) and the button sends on first click.
4306
+ */
4307
+ get debugLogNoteConfig(): ResolvedDebugLogNoteConfig | null;
4308
+ /**
4309
+ * Whether the typed note counts as empty — the ONE emptiness rule, shared by the
4310
+ * compose box's disabled state and its "required" hint so the two cannot drift apart.
4311
+ */
4312
+ get debugLogNoteMissing(): boolean;
4313
+ /** The Send button's idle label, as the host configured it. */
4314
+ get debugLogSubmitLabel(): string;
4315
+ /**
4316
+ * Label on the agent-log row's Send button. While the compose box is open the row
4317
+ * button is just the (disabled) trigger, so it keeps its idle label; otherwise it
4318
+ * reflects the in-flight / flashed outcome of the last submission.
4319
+ */
4320
+ get debugLogSubmitButtonLabel(): string;
4321
+ /**
4322
+ * The compose box's footer hint: a failure first, then the "required" nudge, else the
4323
+ * live counter. Visual only — the same information reaches assistive technology via
4324
+ * `debugLogNoteAriaLabel` (counter, required) and `debugLogSubmitAnnouncement` (outcome),
4325
+ * because IDREF attributes such as `aria-describedby` cannot point across the
4326
+ * design-system text-area's shadow boundary.
4327
+ */
4328
+ get debugLogComposeHint(): string;
4329
+ /**
4330
+ * Accessible name for the note. Deliberately STATIC apart from "(required)": a name
4331
+ * that changed per keystroke would be re-read in full by NVDA on every key and never
4332
+ * updated by JAWS. The running count reaches AT through `debugLogSubmitAnnouncement`
4333
+ * at the thresholds where it matters.
4334
+ */
4335
+ get debugLogNoteAriaLabel(): string;
4336
+ /**
4337
+ * Text for the always-present live region beside the agent-log row, so the outcome of
4338
+ * a submission is announced even when the compose box is closed or opted out
4339
+ * (`note: false`), where the only visible change is the button label.
4340
+ */
4341
+ get debugLogSubmitAnnouncement(): string;
4342
+ /**
4343
+ * The agent-log row's description, phrased for whichever actions the host enabled.
4344
+ * Send is called out as transmitting: Download keeps the log on the user's machine,
4345
+ * Send hands the full conversation to wherever the host's transport delivers it.
4346
+ */
4347
+ get debugLogRowDescription(): string;
4348
+ /**
4349
+ * Whether the compose box's Send button is inert: a send is already in flight, or the
4350
+ * host made the note required and it is still blank.
4351
+ */
4352
+ get debugLogSendDisabled(): boolean;
4353
+ /** Live "typed / max" counter for the compose box. */
4354
+ get debugLogNoteCounter(): string;
4305
4355
  /** Whether the chat header (and settings cog) should render. */
4306
4356
  get settingsCogVisible(): boolean;
4307
4357
  openSettingsModal(): void;
@@ -4372,6 +4422,62 @@ export declare class FoundationAiAssistant extends GenesisElement {
4372
4422
  */
4373
4423
  private buildMetaSnapshot;
4374
4424
  downloadDebugLog(): Promise<void>;
4425
+ /**
4426
+ * Hand the agent log to the host's `ui.debugLogSubmit.send` callback — the Send
4427
+ * button next to Download. Reuses `buildDownloadLog`, so the submitted log is
4428
+ * byte-identical to what Download saves (lifetime-stitched when the provider
4429
+ * persists diagnostics). The assistant is vendor-agnostic: the callback owns the
4430
+ * transport (Sentry feedback, a support API, an upload endpoint). Outcome lands in
4431
+ * `debugLogSubmitResult` so the button can flash 'Sent'/'Failed'; failures also go
4432
+ * to the logger with the cause.
4433
+ */
4434
+ submitDebugLog(): Promise<void>;
4435
+ /** The agent name stamped on the log: the active agent, else the header title. */
4436
+ private get debugLogAgentName();
4437
+ /**
4438
+ * Filename for the agent log — the ONE derivation Download saves under and Send hands
4439
+ * to the host, so `ChatDebugLogSubmission.filename`'s "same stem as the download"
4440
+ * promise is enforced rather than relying on two copies agreeing.
4441
+ */
4442
+ private debugLogFilename;
4443
+ /**
4444
+ * Back to idle: nothing in flight, no flash, no open compose box, no note. Called on
4445
+ * disconnect and on a session switch / Clear (a note typed against one conversation
4446
+ * must not caption the next one's log). On disconnect — the
4447
+ * flash timer would otherwise fire against a torn-down element, and clearing ONLY the
4448
+ * timer would strand `debugLogSubmitResult` at 'sent'/'error' for good on a pop-out /
4449
+ * pop-in (nothing else resets it), with the box remounting open on a stale note.
4450
+ */
4451
+ private resetDebugLogSubmitState;
4452
+ /**
4453
+ * The row's Send button. With a compose box configured (the default) it opens the box
4454
+ * and focuses the note so the user can caption the log; with `note: false` it sends
4455
+ * straight away, as before.
4456
+ */
4457
+ openDebugLogCompose(): void;
4458
+ /** The note's `@input`: track the text, and let typing dismiss a standing failure. */
4459
+ noteDebugLogInput(value: string): void;
4460
+ /** Close the compose box and discard the typed note. */
4461
+ cancelDebugLogCompose(): void;
4462
+ /**
4463
+ * Closing the compose box unmounts the focused text-area, which drops focus to the
4464
+ * document body and strands keyboard and screen-reader users. Hand it back to the row's
4465
+ * Send button — next frame, once the `when` block has torn down and the button, disabled
4466
+ * while the box was open, is interactive again.
4467
+ */
4468
+ private restoreDebugLogTriggerFocus;
4469
+ /**
4470
+ * After a FAILED send the controls come back but the element that started the send
4471
+ * was disabled meanwhile, so focus has already dropped to the document body. Put it
4472
+ * where the retry happens: the note when the box is open, else the row trigger.
4473
+ */
4474
+ private restoreDebugLogRetryFocus;
4475
+ /**
4476
+ * Record the submit outcome. 'sent' flashes and falls back to idle; 'error' PERSISTS
4477
+ * until the user acts (types, reopens the box, cancels, or retries) — a failure that
4478
+ * silently reverted to the counter after four seconds left no trace it had happened.
4479
+ */
4480
+ private setDebugLogSubmitResult;
4375
4481
  /**
4376
4482
  * The log to download (GENC-1351 §5.8). When the provider persists diagnostics,
4377
4483
  * stitch the **whole lifetime** stream (every page load) rather than just the
@@ -4794,6 +4900,25 @@ export declare interface ManualSelectionConfig {
4794
4900
  hint?: string;
4795
4901
  }
4796
4902
 
4903
+ /**
4904
+ * The timestamp shown beside the sender name (GENC-1257).
4905
+ *
4906
+ * Two strings, not one. A screen reader announces a `<time>` element's TEXT — it has no
4907
+ * implicit ARIA role, and the `datetime` attribute is never surfaced to the user — so the
4908
+ * relative text is hidden from assistive tech and paired with a visually-hidden absolute
4909
+ * string. Otherwise AT would hear "5 minutes ago" with nothing to anchor it, and in
4910
+ * `'hover'` mode would hear it for a timestamp sighted users never asked to see.
4911
+ * `datetime` stays because it is correct HTML and useful to tooling, not for a11y.
4912
+ *
4913
+ * Only the VISUAL reveal is hover-gated, in CSS — see `.message-timestamp`. `opacity: 0`
4914
+ * leaves the element in the accessibility tree, so AT gets a time in both visible modes;
4915
+ * `'off'` is the only mode that removes it.
4916
+ *
4917
+ * Reads `timestampClock` rather than `Date.now()` so every row shares one invalidatable
4918
+ * clock and a tick re-evaluates them all; see `FoundationAiAssistant.timestampClock`.
4919
+ */
4920
+ export declare const messageTimestampTemplate: ViewTemplate<ChatMessage, FoundationAiAssistant>;
4921
+
4797
4922
  export { ModelTagAppearance }
4798
4923
 
4799
4924
  /**
@@ -5169,6 +5294,13 @@ declare interface ResolvedCostHistoryConfig {
5169
5294
  summaryHint?: string;
5170
5295
  }
5171
5296
 
5297
+ /** `ChatDebugLogNoteConfig` with every option resolved. */
5298
+ export declare interface ResolvedDebugLogNoteConfig {
5299
+ placeholder: string;
5300
+ required: boolean;
5301
+ maxLength: number;
5302
+ }
5303
+
5172
5304
  /**
5173
5305
  * Structured-output schema for an agent. When set, the model's final (non-tool) answer is
5174
5306
  * constrained to this JSON Schema instead of free text. Either a static schema or a function
@@ -5381,6 +5513,11 @@ export declare interface SessionPreferences {
5381
5513
  showThinkingSteps?: boolean;
5382
5514
  showNarration?: boolean;
5383
5515
  showAgentSwitchIndicator?: boolean;
5516
+ /**
5517
+ * When message timestamps are shown (`TimestampDisplay` values, as plain strings).
5518
+ * Absent keeps the `chatConfig.ui.showTimestamps` default, which is `'hover'`.
5519
+ */
5520
+ timestampDisplay?: string;
5384
5521
  /** Enabled loading-animation ids (`AiAssistantAnimation` values, as plain strings). */
5385
5522
  animations?: string[];
5386
5523
  }
@@ -5979,7 +6116,7 @@ export declare interface TurnSnapshot {
5979
6116
  * up from a sub-agent are re-labelled under the parent turn that activated them
5980
6117
  * — a sub-agent invoked on parent turn 5 contributes `"5-1"`, `"5-2"`, …, and a
5981
6118
  * nested sub-agent on `"5-2"` contributes `"5-2-1"`, …. See
5982
- * `forwardSubAgentSnapshots`.
6119
+ * `forwardSubAgent`.
5983
6120
  */
5984
6121
  turnIndex: string;
5985
6122
  /** ISO timestamp captured just before the LLM call. */