@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.
- package/dist/ai-assistant.api.json +1014 -110
- package/dist/ai-assistant.d.ts +236 -99
- package/dist/chat-driver.cjs +460 -373
- package/dist/chat-driver.cjs.map +4 -4
- package/dist/chat-driver.mjs +460 -373
- package/dist/chat-driver.mjs.map +4 -4
- package/dist/custom-elements.json +1171 -248
- package/dist/dts/components/chat-driver/chat-driver.d.ts +28 -200
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/interaction-controller.d.ts +99 -0
- package/dist/dts/components/chat-driver/interaction-controller.d.ts.map +1 -0
- package/dist/dts/components/chat-driver/turn-recorder.d.ts +191 -0
- package/dist/dts/components/chat-driver/turn-recorder.d.ts.map +1 -0
- package/dist/dts/components/settings-modal/settings-modal.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts +28 -0
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +180 -1
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/main/main.styles.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts +19 -0
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +7 -1
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/persistence/session-persistence-provider.d.ts +5 -0
- package/dist/dts/state/persistence/session-persistence-provider.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +1 -0
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/dts/utils/format-message-timestamp.d.ts +77 -0
- package/dist/dts/utils/format-message-timestamp.d.ts.map +1 -0
- package/dist/dts/utils/resolve-debug-log-note.d.ts +25 -0
- package/dist/dts/utils/resolve-debug-log-note.d.ts.map +1 -0
- package/dist/dts/utils/resolve-preference-baseline.d.ts +18 -1
- package/dist/dts/utils/resolve-preference-baseline.d.ts.map +1 -1
- package/dist/esm/components/chat-driver/chat-driver.js +68 -404
- package/dist/esm/components/chat-driver/interaction-controller.js +235 -0
- package/dist/esm/components/chat-driver/turn-recorder.js +206 -0
- package/dist/esm/components/settings-modal/settings-modal.js +1 -0
- package/dist/esm/components/settings-modal/settings-modal.styles.js +85 -5
- package/dist/esm/components/settings-modal/settings-modal.template.js +220 -25
- package/dist/esm/main/main.js +510 -23
- package/dist/esm/main/main.styles.js +75 -0
- package/dist/esm/main/main.template.js +43 -2
- package/dist/esm/state/ai-assistant-slice.js +5 -0
- package/dist/esm/utils/format-message-timestamp.js +126 -0
- package/dist/esm/utils/resolve-debug-log-note.js +37 -0
- package/dist/esm/utils/resolve-preference-baseline.js +54 -2
- package/package.json +16 -16
- package/sandbox/README.md +45 -2
- package/sandbox/sandbox.ts +95 -3
|
@@ -742,6 +742,14 @@
|
|
|
742
742
|
"module": "./utils/cost-session-history"
|
|
743
743
|
}
|
|
744
744
|
},
|
|
745
|
+
{
|
|
746
|
+
"kind": "js",
|
|
747
|
+
"name": "ResolvedDebugLogNoteConfig",
|
|
748
|
+
"declaration": {
|
|
749
|
+
"name": "ResolvedDebugLogNoteConfig",
|
|
750
|
+
"module": "./utils/resolve-debug-log-note"
|
|
751
|
+
}
|
|
752
|
+
},
|
|
745
753
|
{
|
|
746
754
|
"kind": "js",
|
|
747
755
|
"name": "ModelTagAppearance",
|
|
@@ -1775,6 +1783,12 @@
|
|
|
1775
1783
|
"kind": "javascript-module",
|
|
1776
1784
|
"path": "src/main/main.template.ts",
|
|
1777
1785
|
"declarations": [
|
|
1786
|
+
{
|
|
1787
|
+
"kind": "variable",
|
|
1788
|
+
"name": "messageTimestampTemplate",
|
|
1789
|
+
"default": "html<ChatMessage, FoundationAiAssistant>`\n <time\n class=\"message-timestamp\"\n part=\"message-timestamp\"\n datetime=\"${(m) => messageTimestampDateTime(m.timestamp)}\"\n >\n <span aria-hidden=\"true\">\n ${(m, c) => formatMessageTimestamp(m.timestamp, c.parent.timestampClock)}\n </span>\n <span class=\"visually-hidden\">${(m) => formatAbsoluteTimestamp(m.timestamp)}</span>\n </time>\n`",
|
|
1790
|
+
"description": "The timestamp shown beside the sender name (GENC-1257).\n\nTwo strings, not one. A screen reader announces a `<time>` element's TEXT — it has no\nimplicit ARIA role, and the `datetime` attribute is never surfaced to the user — so the\nrelative text is hidden from assistive tech and paired with a visually-hidden absolute\nstring. Otherwise AT would hear \"5 minutes ago\" with nothing to anchor it, and in\n`'hover'` mode would hear it for a timestamp sighted users never asked to see.\n`datetime` stays because it is correct HTML and useful to tooling, not for a11y.\n\nOnly the VISUAL reveal is hover-gated, in CSS — see `.message-timestamp`. `opacity: 0`\nleaves the element in the accessibility tree, so AT gets a time in both visible modes;\n`'off'` is the only mode that removes it.\n\nReads `timestampClock` rather than `Date.now()` so every row shares one invalidatable\nclock and a tick re-evaluates them all; see `FoundationAiAssistant.timestampClock`."
|
|
1791
|
+
},
|
|
1778
1792
|
{
|
|
1779
1793
|
"kind": "function",
|
|
1780
1794
|
"name": "FoundationAiAssistantTemplate",
|
|
@@ -1794,6 +1808,14 @@
|
|
|
1794
1808
|
}
|
|
1795
1809
|
],
|
|
1796
1810
|
"exports": [
|
|
1811
|
+
{
|
|
1812
|
+
"kind": "js",
|
|
1813
|
+
"name": "messageTimestampTemplate",
|
|
1814
|
+
"declaration": {
|
|
1815
|
+
"name": "messageTimestampTemplate",
|
|
1816
|
+
"module": "src/main/main.template.ts"
|
|
1817
|
+
}
|
|
1818
|
+
},
|
|
1797
1819
|
{
|
|
1798
1820
|
"kind": "js",
|
|
1799
1821
|
"name": "FoundationAiAssistantTemplate",
|
|
@@ -2232,6 +2254,42 @@
|
|
|
2232
2254
|
},
|
|
2233
2255
|
"description": "Current user-facing toggle state for agent switch indicator visibility."
|
|
2234
2256
|
},
|
|
2257
|
+
{
|
|
2258
|
+
"kind": "field",
|
|
2259
|
+
"name": "timestampDisplay",
|
|
2260
|
+
"type": {
|
|
2261
|
+
"text": "TimestampDisplay"
|
|
2262
|
+
},
|
|
2263
|
+
"description": "When each message shows its timestamp — `'off'`, `'hover'` (default) or `'always'`.\n\nFalls back to `DEFAULT_TIMESTAMP_DISPLAY` rather than `'off'` when there is no\nstore yet: this preference defaults ON, so the pre-store render must match the state\nthe baseline is about to resolve to, or timestamps would visibly pop in on connect."
|
|
2264
|
+
},
|
|
2265
|
+
{
|
|
2266
|
+
"kind": "field",
|
|
2267
|
+
"name": "timestampClock",
|
|
2268
|
+
"type": {
|
|
2269
|
+
"text": "number"
|
|
2270
|
+
},
|
|
2271
|
+
"description": "Epoch ms the transcript's relative timestamps are measured against.\n\nA relative label is only correct at the instant it renders: FAST evaluates the\nbinding once, and an idle conversation never re-renders, so \"2 minutes ago\" would\nstill read \"2 minutes ago\" an hour later. Making the formatter read this observable\ninstead of `Date.now()` gives every row one shared, invalidatable clock — a tick\nre-evaluates them all."
|
|
2272
|
+
},
|
|
2273
|
+
{
|
|
2274
|
+
"kind": "field",
|
|
2275
|
+
"name": "_timestampClockTimer",
|
|
2276
|
+
"type": {
|
|
2277
|
+
"text": "ReturnType<typeof setInterval> | undefined"
|
|
2278
|
+
},
|
|
2279
|
+
"privacy": "private",
|
|
2280
|
+
"description": "Handle for the `TIMESTAMP_CLOCK_INTERVAL_MS` ticker; undefined while stopped."
|
|
2281
|
+
},
|
|
2282
|
+
{
|
|
2283
|
+
"kind": "method",
|
|
2284
|
+
"name": "syncTimestampClock",
|
|
2285
|
+
"privacy": "private",
|
|
2286
|
+
"return": {
|
|
2287
|
+
"type": {
|
|
2288
|
+
"text": "void"
|
|
2289
|
+
}
|
|
2290
|
+
},
|
|
2291
|
+
"description": "Start or stop the timestamp clock to match the current mode and connection state.\n\nIdempotent, and safe to call from either lifecycle end — it is driven from\n`connectedCallback`, `disconnectedCallback` and the `timestampDisplay` setter, which\ncan fire in any order. Nothing runs while the mode is `'off'` (no binding reads the\nclock) or while disconnected (a timer outliving its element is a leak, and a\npopped-out view disconnects without the session ending)."
|
|
2292
|
+
},
|
|
2235
2293
|
{
|
|
2236
2294
|
"kind": "field",
|
|
2237
2295
|
"name": "enabledAnimations",
|
|
@@ -2797,6 +2855,78 @@
|
|
|
2797
2855
|
"default": "false",
|
|
2798
2856
|
"description": "True while `downloadDebugLog` is building the log (GENC-1351 §5.8). Drives the\ndownload button's disabled + spinner state — the lifetime-stitch path is async\n(a provider `loadDiagnostics` round-trip), so without feedback a click looks\nlike nothing happened. Per-instance and transient (not shared/persisted): each\nelement has its own settings modal."
|
|
2799
2857
|
},
|
|
2858
|
+
{
|
|
2859
|
+
"kind": "field",
|
|
2860
|
+
"name": "submittingDebugLog",
|
|
2861
|
+
"type": {
|
|
2862
|
+
"text": "boolean"
|
|
2863
|
+
},
|
|
2864
|
+
"default": "false",
|
|
2865
|
+
"description": "True while `submitDebugLog` is building and handing off the log. Same role as\n`downloadingDebugLog` for the Send button: the lifetime-stitch and the host's\n`send` callback are async, so the button needs a visible in-flight state."
|
|
2866
|
+
},
|
|
2867
|
+
{
|
|
2868
|
+
"kind": "field",
|
|
2869
|
+
"name": "debugLogSubmitResult",
|
|
2870
|
+
"type": {
|
|
2871
|
+
"text": "'sent' | 'error' | null"
|
|
2872
|
+
},
|
|
2873
|
+
"default": "null",
|
|
2874
|
+
"description": "Outcome of the last log submission, shown briefly on the button ('Sent' /\n'Failed — retry') then cleared by `setDebugLogSubmitResult`'s timer. `null` when idle."
|
|
2875
|
+
},
|
|
2876
|
+
{
|
|
2877
|
+
"kind": "field",
|
|
2878
|
+
"name": "debugLogSubmitResultTimer",
|
|
2879
|
+
"type": {
|
|
2880
|
+
"text": "ReturnType<typeof setTimeout> | undefined"
|
|
2881
|
+
},
|
|
2882
|
+
"privacy": "private",
|
|
2883
|
+
"description": "Timer that clears `debugLogSubmitResult` back to idle."
|
|
2884
|
+
},
|
|
2885
|
+
{
|
|
2886
|
+
"kind": "field",
|
|
2887
|
+
"name": "debugLogComposeOpen",
|
|
2888
|
+
"type": {
|
|
2889
|
+
"text": "boolean"
|
|
2890
|
+
},
|
|
2891
|
+
"default": "false",
|
|
2892
|
+
"description": "Whether the agent-log compose box (note + Send/Cancel) is open. Opened by the row's\nSend button when `debugLogSubmit.note` is not `false`; closed by Cancel or a\nsuccessful send. Stays open after a failure so the typed note is not lost."
|
|
2893
|
+
},
|
|
2894
|
+
{
|
|
2895
|
+
"kind": "field",
|
|
2896
|
+
"name": "debugLogNote",
|
|
2897
|
+
"type": {
|
|
2898
|
+
"text": "string"
|
|
2899
|
+
},
|
|
2900
|
+
"default": "''",
|
|
2901
|
+
"description": "The note typed in the compose box, raw (trimmed only at submit time)."
|
|
2902
|
+
},
|
|
2903
|
+
{
|
|
2904
|
+
"kind": "field",
|
|
2905
|
+
"name": "debugLogNoteEl",
|
|
2906
|
+
"type": {
|
|
2907
|
+
"text": "HTMLElement | undefined"
|
|
2908
|
+
},
|
|
2909
|
+
"description": "Bound to the compose box's text-area via the template ref, for focus on open."
|
|
2910
|
+
},
|
|
2911
|
+
{
|
|
2912
|
+
"kind": "field",
|
|
2913
|
+
"name": "debugLogSubmitResultFlashMs",
|
|
2914
|
+
"default": "4000",
|
|
2915
|
+
"description": "How long 'Sent' shows before idle. Overridable so tests need not wait 4 seconds.",
|
|
2916
|
+
"type": {
|
|
2917
|
+
"text": "number"
|
|
2918
|
+
}
|
|
2919
|
+
},
|
|
2920
|
+
{
|
|
2921
|
+
"kind": "field",
|
|
2922
|
+
"name": "debugLogSubmitGeneration",
|
|
2923
|
+
"type": {
|
|
2924
|
+
"text": "number"
|
|
2925
|
+
},
|
|
2926
|
+
"privacy": "private",
|
|
2927
|
+
"default": "0",
|
|
2928
|
+
"description": "Bumped by `resetDebugLogSubmitState`. An in-flight `submitDebugLog` captures it and\ndrops its continuation when a reset (disconnect, session switch, Clear) happened\nwhile it awaited — otherwise the stale submission would write state, arm a timer on\na torn-down element, or report 'Sent' into a session it never belonged to."
|
|
2929
|
+
},
|
|
2800
2930
|
{
|
|
2801
2931
|
"kind": "field",
|
|
2802
2932
|
"name": "settingsModalTab",
|
|
@@ -4049,6 +4179,105 @@
|
|
|
4049
4179
|
"description": "Whether session token usage should render on the Usage tab.",
|
|
4050
4180
|
"readonly": true
|
|
4051
4181
|
},
|
|
4182
|
+
{
|
|
4183
|
+
"kind": "field",
|
|
4184
|
+
"name": "settingsAgentLogSectionVisible",
|
|
4185
|
+
"type": {
|
|
4186
|
+
"text": "boolean"
|
|
4187
|
+
},
|
|
4188
|
+
"description": "Whether the settings \"Agent log\" section renders — shown when either action is\nenabled: the download button (`allowDebugDownload`) or the host-transport Send\nbutton (`debugLogSubmit`). Each button is additionally gated on its own flag\ninside the section, so a host can enable one without the other.",
|
|
4189
|
+
"readonly": true
|
|
4190
|
+
},
|
|
4191
|
+
{
|
|
4192
|
+
"kind": "field",
|
|
4193
|
+
"name": "debugLogNoteConfig",
|
|
4194
|
+
"type": {
|
|
4195
|
+
"text": "ResolvedDebugLogNoteConfig | null"
|
|
4196
|
+
},
|
|
4197
|
+
"description": "The resolved compose-box settings for the agent-log Send button, or `null` when the\nhost opted out (`debugLogSubmit.note: false`) and the button sends on first click.",
|
|
4198
|
+
"readonly": true
|
|
4199
|
+
},
|
|
4200
|
+
{
|
|
4201
|
+
"kind": "field",
|
|
4202
|
+
"name": "debugLogNoteMissing",
|
|
4203
|
+
"type": {
|
|
4204
|
+
"text": "boolean"
|
|
4205
|
+
},
|
|
4206
|
+
"description": "Whether the typed note counts as empty — the ONE emptiness rule, shared by the\ncompose box's disabled state and its \"required\" hint so the two cannot drift apart.",
|
|
4207
|
+
"readonly": true
|
|
4208
|
+
},
|
|
4209
|
+
{
|
|
4210
|
+
"kind": "field",
|
|
4211
|
+
"name": "debugLogSubmitLabel",
|
|
4212
|
+
"type": {
|
|
4213
|
+
"text": "string"
|
|
4214
|
+
},
|
|
4215
|
+
"description": "The Send button's idle label, as the host configured it.",
|
|
4216
|
+
"readonly": true
|
|
4217
|
+
},
|
|
4218
|
+
{
|
|
4219
|
+
"kind": "field",
|
|
4220
|
+
"name": "debugLogSubmitButtonLabel",
|
|
4221
|
+
"type": {
|
|
4222
|
+
"text": "string"
|
|
4223
|
+
},
|
|
4224
|
+
"description": "Label on the agent-log row's Send button. While the compose box is open the row\nbutton is just the (disabled) trigger, so it keeps its idle label; otherwise it\nreflects the in-flight / flashed outcome of the last submission.",
|
|
4225
|
+
"readonly": true
|
|
4226
|
+
},
|
|
4227
|
+
{
|
|
4228
|
+
"kind": "field",
|
|
4229
|
+
"name": "debugLogComposeHint",
|
|
4230
|
+
"type": {
|
|
4231
|
+
"text": "string"
|
|
4232
|
+
},
|
|
4233
|
+
"description": "The compose box's footer hint: a failure first, then the \"required\" nudge, else the\nlive counter. Visual only — the same information reaches assistive technology via\n`debugLogNoteAriaLabel` (counter, required) and `debugLogSubmitAnnouncement` (outcome),\nbecause IDREF attributes such as `aria-describedby` cannot point across the\ndesign-system text-area's shadow boundary.",
|
|
4234
|
+
"readonly": true
|
|
4235
|
+
},
|
|
4236
|
+
{
|
|
4237
|
+
"kind": "field",
|
|
4238
|
+
"name": "debugLogNoteAriaLabel",
|
|
4239
|
+
"type": {
|
|
4240
|
+
"text": "string"
|
|
4241
|
+
},
|
|
4242
|
+
"description": "Accessible name for the note. Deliberately STATIC apart from \"(required)\": a name\nthat changed per keystroke would be re-read in full by NVDA on every key and never\nupdated by JAWS. The running count reaches AT through `debugLogSubmitAnnouncement`\nat the thresholds where it matters.",
|
|
4243
|
+
"readonly": true
|
|
4244
|
+
},
|
|
4245
|
+
{
|
|
4246
|
+
"kind": "field",
|
|
4247
|
+
"name": "debugLogSubmitAnnouncement",
|
|
4248
|
+
"type": {
|
|
4249
|
+
"text": "string"
|
|
4250
|
+
},
|
|
4251
|
+
"description": "Text for the always-present live region beside the agent-log row, so the outcome of\na submission is announced even when the compose box is closed or opted out\n(`note: false`), where the only visible change is the button label.",
|
|
4252
|
+
"readonly": true
|
|
4253
|
+
},
|
|
4254
|
+
{
|
|
4255
|
+
"kind": "field",
|
|
4256
|
+
"name": "debugLogRowDescription",
|
|
4257
|
+
"type": {
|
|
4258
|
+
"text": "string"
|
|
4259
|
+
},
|
|
4260
|
+
"description": "The agent-log row's description, phrased for whichever actions the host enabled.\nSend is called out as transmitting: Download keeps the log on the user's machine,\nSend hands the full conversation to wherever the host's transport delivers it.",
|
|
4261
|
+
"readonly": true
|
|
4262
|
+
},
|
|
4263
|
+
{
|
|
4264
|
+
"kind": "field",
|
|
4265
|
+
"name": "debugLogSendDisabled",
|
|
4266
|
+
"type": {
|
|
4267
|
+
"text": "boolean"
|
|
4268
|
+
},
|
|
4269
|
+
"description": "Whether the compose box's Send button is inert: a send is already in flight, or the\nhost made the note required and it is still blank.",
|
|
4270
|
+
"readonly": true
|
|
4271
|
+
},
|
|
4272
|
+
{
|
|
4273
|
+
"kind": "field",
|
|
4274
|
+
"name": "debugLogNoteCounter",
|
|
4275
|
+
"type": {
|
|
4276
|
+
"text": "string"
|
|
4277
|
+
},
|
|
4278
|
+
"description": "Live \"typed / max\" counter for the compose box.",
|
|
4279
|
+
"readonly": true
|
|
4280
|
+
},
|
|
4052
4281
|
{
|
|
4053
4282
|
"kind": "field",
|
|
4054
4283
|
"name": "settingsCogVisible",
|
|
@@ -4245,68 +4474,59 @@
|
|
|
4245
4474
|
},
|
|
4246
4475
|
{
|
|
4247
4476
|
"kind": "method",
|
|
4248
|
-
"name": "
|
|
4249
|
-
"privacy": "private",
|
|
4477
|
+
"name": "submitDebugLog",
|
|
4250
4478
|
"return": {
|
|
4251
4479
|
"type": {
|
|
4252
|
-
"text": "Promise<
|
|
4480
|
+
"text": "Promise<void>"
|
|
4253
4481
|
}
|
|
4254
4482
|
},
|
|
4255
|
-
"description": "
|
|
4483
|
+
"description": "Hand the agent log to the host's `ui.debugLogSubmit.send` callback — the Send\nbutton next to Download. Reuses `buildDownloadLog`, so the submitted log is\nbyte-identical to what Download saves (lifetime-stitched when the provider\npersists diagnostics). The assistant is vendor-agnostic: the callback owns the\ntransport (Sentry feedback, a support API, an upload endpoint). Outcome lands in\n`debugLogSubmitResult` so the button can flash 'Sent'/'Failed'; failures also go\nto the logger with the cause."
|
|
4484
|
+
},
|
|
4485
|
+
{
|
|
4486
|
+
"kind": "field",
|
|
4487
|
+
"name": "debugLogAgentName",
|
|
4488
|
+
"type": {
|
|
4489
|
+
"text": "string"
|
|
4490
|
+
},
|
|
4491
|
+
"privacy": "private",
|
|
4492
|
+
"description": "The agent name stamped on the log: the active agent, else the header title.",
|
|
4493
|
+
"readonly": true
|
|
4256
4494
|
},
|
|
4257
4495
|
{
|
|
4258
4496
|
"kind": "method",
|
|
4259
|
-
"name": "
|
|
4497
|
+
"name": "debugLogFilename",
|
|
4260
4498
|
"privacy": "private",
|
|
4261
4499
|
"return": {
|
|
4262
4500
|
"type": {
|
|
4263
|
-
"text": "
|
|
4501
|
+
"text": "string"
|
|
4264
4502
|
}
|
|
4265
4503
|
},
|
|
4266
|
-
"description": "
|
|
4504
|
+
"description": "Filename for the agent log — the ONE derivation Download saves under and Send hands\nto the host, so `ChatDebugLogSubmission.filename`'s \"same stem as the download\"\npromise is enforced rather than relying on two copies agreeing."
|
|
4267
4505
|
},
|
|
4268
4506
|
{
|
|
4269
4507
|
"kind": "method",
|
|
4270
|
-
"name": "
|
|
4508
|
+
"name": "resetDebugLogSubmitState",
|
|
4271
4509
|
"privacy": "private",
|
|
4272
4510
|
"return": {
|
|
4273
4511
|
"type": {
|
|
4274
|
-
"text": "
|
|
4512
|
+
"text": "void"
|
|
4275
4513
|
}
|
|
4276
4514
|
},
|
|
4277
|
-
"
|
|
4278
|
-
{
|
|
4279
|
-
"name": "key",
|
|
4280
|
-
"type": {
|
|
4281
|
-
"text": "string"
|
|
4282
|
-
}
|
|
4283
|
-
}
|
|
4284
|
-
],
|
|
4285
|
-
"description": "The `SessionPersister` dependency getters bound to THIS element + `key`.\nThe host-owned getters (`getPersistence`/`getAgentNames`/`getDiagnosticEntries`)\nread the live element; `getDriver`/`getStore` resolve by key from the registries.\nRebound onto the shared persister on every activation (see `activateSession`) so\na remounted element becomes the live source, not the torn-down creator (GENC-1351 §5.10 / #7)."
|
|
4515
|
+
"description": "Back to idle: nothing in flight, no flash, no open compose box, no note. Called on\ndisconnect and on a session switch / Clear (a note typed against one conversation\nmust not caption the next one's log). On disconnect — the\nflash timer would otherwise fire against a torn-down element, and clearing ONLY the\ntimer would strand `debugLogSubmitResult` at 'sent'/'error' for good on a pop-out /\npop-in (nothing else resets it), with the box remounting open on a stale note."
|
|
4286
4516
|
},
|
|
4287
4517
|
{
|
|
4288
4518
|
"kind": "method",
|
|
4289
|
-
"name": "
|
|
4519
|
+
"name": "openDebugLogCompose",
|
|
4290
4520
|
"return": {
|
|
4291
4521
|
"type": {
|
|
4292
4522
|
"text": "void"
|
|
4293
4523
|
}
|
|
4294
4524
|
},
|
|
4295
|
-
"
|
|
4296
|
-
{
|
|
4297
|
-
"name": "overrides",
|
|
4298
|
-
"optional": true,
|
|
4299
|
-
"type": {
|
|
4300
|
-
"text": "{\n message?: string;\n detail?: string;\n source?: string;\n }"
|
|
4301
|
-
},
|
|
4302
|
-
"description": "`message` replaces the body; `detail` adds/replaces the second line;\n`source` identifies the reporter so its own recovery withdraws only its own warning. Give\neach independent keyspace its own id — see `brokenSources` for what sharing one costs."
|
|
4303
|
-
}
|
|
4304
|
-
],
|
|
4305
|
-
"description": "Tell the user their work is no longer being saved, and block until they reload (GENC-1511).\n\nPublic because the assistant is not the only thing that persists. Its own persister covers\n`sessions/<key>`; a host may own other keyspaces whose failure is just as costly — Create's\n`projects/<id>.json` holds the entity model, handlers and VFS, i.e. the app itself — and had\nno way to reach this modal (§17 of the GENC-1511 plan).\n\nBoth copy fields are optional and default to the session wording in the template, so the\ncommon case stays a bare call. Idempotent per source while already broken: re-reporting the\nsame source refreshes its copy, and the property change only shows a modal that is not open."
|
|
4525
|
+
"description": "The row's Send button. With a compose box configured (the default) it opens the box\nand focuses the note so the user can caption the log; with `note: false` it sends\nstraight away, as before."
|
|
4306
4526
|
},
|
|
4307
4527
|
{
|
|
4308
4528
|
"kind": "method",
|
|
4309
|
-
"name": "
|
|
4529
|
+
"name": "noteDebugLogInput",
|
|
4310
4530
|
"return": {
|
|
4311
4531
|
"type": {
|
|
4312
4532
|
"text": "void"
|
|
@@ -4314,92 +4534,222 @@
|
|
|
4314
4534
|
},
|
|
4315
4535
|
"parameters": [
|
|
4316
4536
|
{
|
|
4317
|
-
"name": "
|
|
4318
|
-
"default": "DEFAULT_PERSISTENCE_SOURCE",
|
|
4537
|
+
"name": "value",
|
|
4319
4538
|
"type": {
|
|
4320
4539
|
"text": "string"
|
|
4321
|
-
}
|
|
4322
|
-
"description": "must match the id the failure was reported under."
|
|
4540
|
+
}
|
|
4323
4541
|
}
|
|
4324
4542
|
],
|
|
4325
|
-
"description": "
|
|
4543
|
+
"description": "The note's `@input`: track the text, and let typing dismiss a standing failure."
|
|
4326
4544
|
},
|
|
4327
4545
|
{
|
|
4328
4546
|
"kind": "method",
|
|
4329
|
-
"name": "
|
|
4330
|
-
"privacy": "private",
|
|
4547
|
+
"name": "cancelDebugLogCompose",
|
|
4331
4548
|
"return": {
|
|
4332
4549
|
"type": {
|
|
4333
4550
|
"text": "void"
|
|
4334
4551
|
}
|
|
4335
4552
|
},
|
|
4336
|
-
"description": "
|
|
4553
|
+
"description": "Close the compose box and discard the typed note."
|
|
4337
4554
|
},
|
|
4338
4555
|
{
|
|
4339
4556
|
"kind": "method",
|
|
4340
|
-
"name": "
|
|
4557
|
+
"name": "restoreDebugLogTriggerFocus",
|
|
4341
4558
|
"privacy": "private",
|
|
4342
4559
|
"return": {
|
|
4343
4560
|
"type": {
|
|
4344
4561
|
"text": "void"
|
|
4345
4562
|
}
|
|
4346
4563
|
},
|
|
4347
|
-
"
|
|
4348
|
-
{
|
|
4349
|
-
"name": "d",
|
|
4350
|
-
"type": {
|
|
4351
|
-
"text": "{\n unsavedMessages: number;\n lastSavedAt?: string;\n reason: string;\n }"
|
|
4352
|
-
}
|
|
4353
|
-
}
|
|
4354
|
-
],
|
|
4355
|
-
"description": "This element's own persister said the session snapshot is not landing (GENC-1511)."
|
|
4564
|
+
"description": "Closing the compose box unmounts the focused text-area, which drops focus to the\ndocument body and strands keyboard and screen-reader users. Hand it back to the row's\nSend button — next frame, once the `when` block has torn down and the button, disabled\nwhile the box was open, is interactive again."
|
|
4356
4565
|
},
|
|
4357
4566
|
{
|
|
4358
4567
|
"kind": "method",
|
|
4359
|
-
"name": "
|
|
4568
|
+
"name": "restoreDebugLogRetryFocus",
|
|
4360
4569
|
"privacy": "private",
|
|
4361
4570
|
"return": {
|
|
4362
4571
|
"type": {
|
|
4363
4572
|
"text": "void"
|
|
4364
4573
|
}
|
|
4365
4574
|
},
|
|
4366
|
-
"description": "
|
|
4367
|
-
},
|
|
4368
|
-
{
|
|
4369
|
-
"kind": "method",
|
|
4370
|
-
"name": "reloadForPersistence",
|
|
4371
|
-
"return": {
|
|
4372
|
-
"type": {
|
|
4373
|
-
"text": "void"
|
|
4374
|
-
}
|
|
4375
|
-
},
|
|
4376
|
-
"description": "The modal's only action. A reload re-reads the stored snapshot, which is plain data parsed\nfrom the server, so it also clears the serialisation fault that is the most likely cause."
|
|
4575
|
+
"description": "After a FAILED send the controls come back but the element that started the send\nwas disabled meanwhile, so focus has already dropped to the document body. Put it\nwhere the retry happens: the note when the box is open, else the row trigger."
|
|
4377
4576
|
},
|
|
4378
4577
|
{
|
|
4379
4578
|
"kind": "method",
|
|
4380
|
-
"name": "
|
|
4579
|
+
"name": "setDebugLogSubmitResult",
|
|
4381
4580
|
"privacy": "private",
|
|
4382
4581
|
"return": {
|
|
4383
4582
|
"type": {
|
|
4384
|
-
"text": "
|
|
4583
|
+
"text": "void"
|
|
4385
4584
|
}
|
|
4386
4585
|
},
|
|
4387
4586
|
"parameters": [
|
|
4388
4587
|
{
|
|
4389
|
-
"name": "
|
|
4588
|
+
"name": "result",
|
|
4390
4589
|
"type": {
|
|
4391
|
-
"text": "
|
|
4590
|
+
"text": "'sent' | 'error'"
|
|
4392
4591
|
}
|
|
4393
4592
|
}
|
|
4394
4593
|
],
|
|
4395
|
-
"description": "
|
|
4594
|
+
"description": "Record the submit outcome. 'sent' flashes and falls back to idle; 'error' PERSISTS\nuntil the user acts (types, reopens the box, cancels, or retries) — a failure that\nsilently reverted to the counter after four seconds left no trace it had happened."
|
|
4396
4595
|
},
|
|
4397
4596
|
{
|
|
4398
4597
|
"kind": "method",
|
|
4399
|
-
"name": "
|
|
4598
|
+
"name": "buildDownloadLog",
|
|
4599
|
+
"privacy": "private",
|
|
4400
4600
|
"return": {
|
|
4401
4601
|
"type": {
|
|
4402
|
-
"text": "
|
|
4602
|
+
"text": "Promise<DebugLog>"
|
|
4603
|
+
}
|
|
4604
|
+
},
|
|
4605
|
+
"description": "The log to download (GENC-1351 §5.8). When the provider persists diagnostics,\nstitch the **whole lifetime** stream (every page load) rather than just the\ncurrent page's in-memory view: flush the current delta first so it's included,\nthen reassemble everything `loadDiagnostics` returns. Independent of \"remember\nchat\" — diagnostics are a forensic stream keyed on provider capability, not on\nwhether the *chat* is remembered (like preferences). Falls back to the live\ncurrent-page log when diagnostics isn't available or the fetch fails.\n\nThe stored `meta-snapshot`s are replaced by a fresh one (`withFreshMetaSnapshot`)\nbefore reassembly. The persisted stream only re-appends that block when the\nnear-static config signature changes (see `collectDiagnosticsDelta`), so on a session\nwhose config never changes the newest STORED snapshot is the first one — its\n`context` half (session cost/usage, context tokens, live agent state) frozen seconds\ninto the session, which is how a lifetime log came out reporting near-zero spend\nagainst a transcript full of priced messages."
|
|
4606
|
+
},
|
|
4607
|
+
{
|
|
4608
|
+
"kind": "method",
|
|
4609
|
+
"name": "persister",
|
|
4610
|
+
"privacy": "private",
|
|
4611
|
+
"return": {
|
|
4612
|
+
"type": {
|
|
4613
|
+
"text": "SessionPersister | undefined"
|
|
4614
|
+
}
|
|
4615
|
+
},
|
|
4616
|
+
"description": "The shared per-session `SessionPersister` that owns restore-core\nsave/restore/freeze (GENC-1351 §5.10). Created once per `stateKey` and shared by\nevery element view (bubble + panel) via the registry, so there is a single save\ntimer + carry-forward cache — no per-view double-writes. The deps are getters so\nthe persister always reads the current driver/store/config and never holds a\nstale reference. `undefined` before the session key is available."
|
|
4617
|
+
},
|
|
4618
|
+
{
|
|
4619
|
+
"kind": "method",
|
|
4620
|
+
"name": "buildPersisterDeps",
|
|
4621
|
+
"privacy": "private",
|
|
4622
|
+
"return": {
|
|
4623
|
+
"type": {
|
|
4624
|
+
"text": "SessionPersisterDeps"
|
|
4625
|
+
}
|
|
4626
|
+
},
|
|
4627
|
+
"parameters": [
|
|
4628
|
+
{
|
|
4629
|
+
"name": "key",
|
|
4630
|
+
"type": {
|
|
4631
|
+
"text": "string"
|
|
4632
|
+
}
|
|
4633
|
+
}
|
|
4634
|
+
],
|
|
4635
|
+
"description": "The `SessionPersister` dependency getters bound to THIS element + `key`.\nThe host-owned getters (`getPersistence`/`getAgentNames`/`getDiagnosticEntries`)\nread the live element; `getDriver`/`getStore` resolve by key from the registries.\nRebound onto the shared persister on every activation (see `activateSession`) so\na remounted element becomes the live source, not the torn-down creator (GENC-1351 §5.10 / #7)."
|
|
4636
|
+
},
|
|
4637
|
+
{
|
|
4638
|
+
"kind": "method",
|
|
4639
|
+
"name": "reportPersistenceBroken",
|
|
4640
|
+
"return": {
|
|
4641
|
+
"type": {
|
|
4642
|
+
"text": "void"
|
|
4643
|
+
}
|
|
4644
|
+
},
|
|
4645
|
+
"parameters": [
|
|
4646
|
+
{
|
|
4647
|
+
"name": "overrides",
|
|
4648
|
+
"optional": true,
|
|
4649
|
+
"type": {
|
|
4650
|
+
"text": "{\n message?: string;\n detail?: string;\n source?: string;\n }"
|
|
4651
|
+
},
|
|
4652
|
+
"description": "`message` replaces the body; `detail` adds/replaces the second line;\n`source` identifies the reporter so its own recovery withdraws only its own warning. Give\neach independent keyspace its own id — see `brokenSources` for what sharing one costs."
|
|
4653
|
+
}
|
|
4654
|
+
],
|
|
4655
|
+
"description": "Tell the user their work is no longer being saved, and block until they reload (GENC-1511).\n\nPublic because the assistant is not the only thing that persists. Its own persister covers\n`sessions/<key>`; a host may own other keyspaces whose failure is just as costly — Create's\n`projects/<id>.json` holds the entity model, handlers and VFS, i.e. the app itself — and had\nno way to reach this modal (§17 of the GENC-1511 plan).\n\nBoth copy fields are optional and default to the session wording in the template, so the\ncommon case stays a bare call. Idempotent per source while already broken: re-reporting the\nsame source refreshes its copy, and the property change only shows a modal that is not open."
|
|
4656
|
+
},
|
|
4657
|
+
{
|
|
4658
|
+
"kind": "method",
|
|
4659
|
+
"name": "reportPersistenceRecovered",
|
|
4660
|
+
"return": {
|
|
4661
|
+
"type": {
|
|
4662
|
+
"text": "void"
|
|
4663
|
+
}
|
|
4664
|
+
},
|
|
4665
|
+
"parameters": [
|
|
4666
|
+
{
|
|
4667
|
+
"name": "source",
|
|
4668
|
+
"default": "DEFAULT_PERSISTENCE_SOURCE",
|
|
4669
|
+
"type": {
|
|
4670
|
+
"text": "string"
|
|
4671
|
+
},
|
|
4672
|
+
"description": "must match the id the failure was reported under."
|
|
4673
|
+
}
|
|
4674
|
+
],
|
|
4675
|
+
"description": "Withdraw one reporter's warning — its save landed, or the host's own store recovered.\n\nOnly `source`'s entry is removed, so a session recovery cannot cancel a host's still-live\nproject failure (GENC-1511, caught in review; see `brokenSources`). The modal closes\nonly once nothing is broken; while anything remains, the copy falls back to the newest\nsurvivor."
|
|
4676
|
+
},
|
|
4677
|
+
{
|
|
4678
|
+
"kind": "method",
|
|
4679
|
+
"name": "syncPersistenceBrokenCopy",
|
|
4680
|
+
"privacy": "private",
|
|
4681
|
+
"return": {
|
|
4682
|
+
"type": {
|
|
4683
|
+
"text": "void"
|
|
4684
|
+
}
|
|
4685
|
+
},
|
|
4686
|
+
"description": "Recompute the derived flag and the displayed copy from `brokenSources`.\n\nCopy order is last-in-wins, which is both deterministic (`Map` iterates in insertion order)\nand the behaviour a reader expects — the most recent failure is the one described. Setting\n`persistenceBroken` last means the modal is only ever shown or closed once the copy backing\nit is already correct."
|
|
4687
|
+
},
|
|
4688
|
+
{
|
|
4689
|
+
"kind": "method",
|
|
4690
|
+
"name": "onPersistenceBroken",
|
|
4691
|
+
"privacy": "private",
|
|
4692
|
+
"return": {
|
|
4693
|
+
"type": {
|
|
4694
|
+
"text": "void"
|
|
4695
|
+
}
|
|
4696
|
+
},
|
|
4697
|
+
"parameters": [
|
|
4698
|
+
{
|
|
4699
|
+
"name": "d",
|
|
4700
|
+
"type": {
|
|
4701
|
+
"text": "{\n unsavedMessages: number;\n lastSavedAt?: string;\n reason: string;\n }"
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
],
|
|
4705
|
+
"description": "This element's own persister said the session snapshot is not landing (GENC-1511)."
|
|
4706
|
+
},
|
|
4707
|
+
{
|
|
4708
|
+
"kind": "method",
|
|
4709
|
+
"name": "onPersistenceRecovered",
|
|
4710
|
+
"privacy": "private",
|
|
4711
|
+
"return": {
|
|
4712
|
+
"type": {
|
|
4713
|
+
"text": "void"
|
|
4714
|
+
}
|
|
4715
|
+
},
|
|
4716
|
+
"description": "A session save landed after a broken episode — withdraw OUR warning only (GENC-1511).\n\nThe explicit source is the whole point: a host's project store may still be failing, and\nbefore this was per-source a session recovery closed that modal too."
|
|
4717
|
+
},
|
|
4718
|
+
{
|
|
4719
|
+
"kind": "method",
|
|
4720
|
+
"name": "reloadForPersistence",
|
|
4721
|
+
"return": {
|
|
4722
|
+
"type": {
|
|
4723
|
+
"text": "void"
|
|
4724
|
+
}
|
|
4725
|
+
},
|
|
4726
|
+
"description": "The modal's only action. A reload re-reads the stored snapshot, which is plain data parsed\nfrom the server, so it also clears the serialisation fault that is the most likely cause."
|
|
4727
|
+
},
|
|
4728
|
+
{
|
|
4729
|
+
"kind": "method",
|
|
4730
|
+
"name": "initPersistenceForNewStore",
|
|
4731
|
+
"privacy": "private",
|
|
4732
|
+
"return": {
|
|
4733
|
+
"type": {
|
|
4734
|
+
"text": "Promise<void>"
|
|
4735
|
+
}
|
|
4736
|
+
},
|
|
4737
|
+
"parameters": [
|
|
4738
|
+
{
|
|
4739
|
+
"name": "key",
|
|
4740
|
+
"type": {
|
|
4741
|
+
"text": "string"
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
],
|
|
4745
|
+
"description": "First-load persistence init for a freshly created store (GENC-1351). Restores\nthe user's remembered persistence-toggle choice — kept independently of the\nsession snapshot so it survives a clear; the host-configured `enabled` is only\nthe default for a first-ever load — then auto-restores the session when\npersistence is (now) on."
|
|
4746
|
+
},
|
|
4747
|
+
{
|
|
4748
|
+
"kind": "method",
|
|
4749
|
+
"name": "triggerFileInput",
|
|
4750
|
+
"return": {
|
|
4751
|
+
"type": {
|
|
4752
|
+
"text": "void"
|
|
4403
4753
|
}
|
|
4404
4754
|
}
|
|
4405
4755
|
},
|
|
@@ -6785,6 +7135,119 @@
|
|
|
6785
7135
|
"declarations": [],
|
|
6786
7136
|
"exports": []
|
|
6787
7137
|
},
|
|
7138
|
+
{
|
|
7139
|
+
"kind": "javascript-module",
|
|
7140
|
+
"path": "src/utils/format-message-timestamp.ts",
|
|
7141
|
+
"declarations": [
|
|
7142
|
+
{
|
|
7143
|
+
"kind": "variable",
|
|
7144
|
+
"name": "ABSOLUTE_FORMAT_OPTIONS",
|
|
7145
|
+
"type": {
|
|
7146
|
+
"text": "Intl.DateTimeFormatOptions"
|
|
7147
|
+
},
|
|
7148
|
+
"default": "{\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n hourCycle: 'h23',\n}",
|
|
7149
|
+
"description": "Field selection for the absolute tier.\n\nExported so tests can build their expectation from the same options rather than from a\nliteral: every field below renders differently per locale and time zone, so asserting\n`\"Sep\"` or `\"10\"` only asserts the machine the test happened to run on.\n\nLocale is left undefined so it follows the user's, and `hourCycle: 'h23'` pins the clock\nto 24-hour regardless — a locale-chosen 12-hour clock would add \"am\"/\"pm\" and widen the\nstring next to the sender name."
|
|
7150
|
+
},
|
|
7151
|
+
{
|
|
7152
|
+
"kind": "function",
|
|
7153
|
+
"name": "formatMessageTimestamp",
|
|
7154
|
+
"return": {
|
|
7155
|
+
"type": {
|
|
7156
|
+
"text": ""
|
|
7157
|
+
}
|
|
7158
|
+
},
|
|
7159
|
+
"parameters": [
|
|
7160
|
+
{
|
|
7161
|
+
"name": "iso",
|
|
7162
|
+
"type": {
|
|
7163
|
+
"text": "string | undefined"
|
|
7164
|
+
},
|
|
7165
|
+
"description": "ISO-8601 timestamp, as stamped by the driver on append."
|
|
7166
|
+
},
|
|
7167
|
+
{
|
|
7168
|
+
"name": "now",
|
|
7169
|
+
"type": {
|
|
7170
|
+
"text": "number"
|
|
7171
|
+
},
|
|
7172
|
+
"description": "Current epoch ms. Passed in rather than read, so tests pin the clock."
|
|
7173
|
+
}
|
|
7174
|
+
],
|
|
7175
|
+
"description": "Display text for a message timestamp, per the tiers above.\n\nA timestamp slightly in the future (clock skew between a server-stamped message and the\nbrowser) reads `Now` rather than a negative count — \"-3 minutes ago\" looks broken and\ntells the user nothing. That indulgence is bounded at an hour: beyond it the stamp is\nnot skew but bad data (a machine with a badly wrong clock, a hand-edited session), and\nshowing `Now` forever on every message would hide that. Past the bound it falls through\nto the absolute tier, which shows the user what the data actually says."
|
|
7176
|
+
},
|
|
7177
|
+
{
|
|
7178
|
+
"kind": "function",
|
|
7179
|
+
"name": "formatAbsoluteTimestamp",
|
|
7180
|
+
"return": {
|
|
7181
|
+
"type": {
|
|
7182
|
+
"text": ""
|
|
7183
|
+
}
|
|
7184
|
+
},
|
|
7185
|
+
"parameters": [
|
|
7186
|
+
{
|
|
7187
|
+
"name": "iso",
|
|
7188
|
+
"type": {
|
|
7189
|
+
"text": "string | undefined"
|
|
7190
|
+
},
|
|
7191
|
+
"description": "ISO-8601 timestamp, as stamped by the driver on append."
|
|
7192
|
+
}
|
|
7193
|
+
],
|
|
7194
|
+
"description": "The absolute rendering of a stamp, whatever its age — the accessible text behind a\nmessage timestamp.\n\nExists because the visible text is relative and a screen reader announces the element's\nTEXT, not its `datetime` attribute: `<time>` carries no implicit ARIA role, so the\nmachine-readable value reaches tooling and nobody else. The template pairs this with\n`aria-hidden` on the relative string so assistive tech hears one unambiguous time\ninstead of \"5 minutes ago\" with no anchor."
|
|
7195
|
+
},
|
|
7196
|
+
{
|
|
7197
|
+
"kind": "function",
|
|
7198
|
+
"name": "messageTimestampDateTime",
|
|
7199
|
+
"return": {
|
|
7200
|
+
"type": {
|
|
7201
|
+
"text": "string | null"
|
|
7202
|
+
}
|
|
7203
|
+
},
|
|
7204
|
+
"parameters": [
|
|
7205
|
+
{
|
|
7206
|
+
"name": "iso",
|
|
7207
|
+
"type": {
|
|
7208
|
+
"text": "string | undefined"
|
|
7209
|
+
},
|
|
7210
|
+
"description": "ISO-8601 timestamp, as stamped by the driver on append."
|
|
7211
|
+
}
|
|
7212
|
+
],
|
|
7213
|
+
"description": "The `datetime` attribute value for the rendered `<time>` element — the raw ISO string,\nwhich is what the HTML spec wants and what date-aware tooling reads. It is NOT an\naccessibility affordance: screen readers announce the element's text content instead.\n\nReturns `null`, not `''`, for a missing or unparseable stamp: FAST removes an attribute\nonly for `null`/`undefined` (see `DOM.setAttribute`), so an empty string would emit\n`datetime=\"\"`, which is invalid per spec and flagged by HTML validators."
|
|
7214
|
+
}
|
|
7215
|
+
],
|
|
7216
|
+
"exports": [
|
|
7217
|
+
{
|
|
7218
|
+
"kind": "js",
|
|
7219
|
+
"name": "ABSOLUTE_FORMAT_OPTIONS",
|
|
7220
|
+
"declaration": {
|
|
7221
|
+
"name": "ABSOLUTE_FORMAT_OPTIONS",
|
|
7222
|
+
"module": "src/utils/format-message-timestamp.ts"
|
|
7223
|
+
}
|
|
7224
|
+
},
|
|
7225
|
+
{
|
|
7226
|
+
"kind": "js",
|
|
7227
|
+
"name": "formatMessageTimestamp",
|
|
7228
|
+
"declaration": {
|
|
7229
|
+
"name": "formatMessageTimestamp",
|
|
7230
|
+
"module": "src/utils/format-message-timestamp.ts"
|
|
7231
|
+
}
|
|
7232
|
+
},
|
|
7233
|
+
{
|
|
7234
|
+
"kind": "js",
|
|
7235
|
+
"name": "formatAbsoluteTimestamp",
|
|
7236
|
+
"declaration": {
|
|
7237
|
+
"name": "formatAbsoluteTimestamp",
|
|
7238
|
+
"module": "src/utils/format-message-timestamp.ts"
|
|
7239
|
+
}
|
|
7240
|
+
},
|
|
7241
|
+
{
|
|
7242
|
+
"kind": "js",
|
|
7243
|
+
"name": "messageTimestampDateTime",
|
|
7244
|
+
"declaration": {
|
|
7245
|
+
"name": "messageTimestampDateTime",
|
|
7246
|
+
"module": "src/utils/format-message-timestamp.ts"
|
|
7247
|
+
}
|
|
7248
|
+
}
|
|
7249
|
+
]
|
|
7250
|
+
},
|
|
6788
7251
|
{
|
|
6789
7252
|
"kind": "javascript-module",
|
|
6790
7253
|
"path": "src/utils/format-usd.ts",
|
|
@@ -7406,30 +7869,160 @@
|
|
|
7406
7869
|
},
|
|
7407
7870
|
{
|
|
7408
7871
|
"kind": "javascript-module",
|
|
7409
|
-
"path": "src/utils/resolve-
|
|
7410
|
-
"declarations": [],
|
|
7411
|
-
"exports": []
|
|
7412
|
-
},
|
|
7413
|
-
{
|
|
7414
|
-
"kind": "javascript-module",
|
|
7415
|
-
"path": "src/utils/resolve-turn-input.ts",
|
|
7872
|
+
"path": "src/utils/resolve-debug-log-note.ts",
|
|
7416
7873
|
"declarations": [
|
|
7417
7874
|
{
|
|
7418
|
-
"kind": "
|
|
7419
|
-
"name": "
|
|
7420
|
-
"
|
|
7421
|
-
"
|
|
7422
|
-
"text": "Promise<T | undefined>"
|
|
7423
|
-
}
|
|
7875
|
+
"kind": "variable",
|
|
7876
|
+
"name": "DEBUG_LOG_NOTE_DEFAULT_MAX_LENGTH",
|
|
7877
|
+
"type": {
|
|
7878
|
+
"text": "number"
|
|
7424
7879
|
},
|
|
7425
|
-
"
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7880
|
+
"default": "500",
|
|
7881
|
+
"description": "Default cap on the user's note. Short by design — it is a caption for the log, not a report."
|
|
7882
|
+
},
|
|
7883
|
+
{
|
|
7884
|
+
"kind": "variable",
|
|
7885
|
+
"name": "DEBUG_LOG_NOTE_DEFAULT_PLACEHOLDER",
|
|
7886
|
+
"type": {
|
|
7887
|
+
"text": "string"
|
|
7888
|
+
},
|
|
7889
|
+
"default": "'What were you doing, or what went wrong? (optional)'",
|
|
7890
|
+
"description": "Default prompt in the empty note."
|
|
7891
|
+
},
|
|
7892
|
+
{
|
|
7893
|
+
"kind": "variable",
|
|
7894
|
+
"name": "DEBUG_LOG_NOTE_REQUIRED_PLACEHOLDER",
|
|
7895
|
+
"type": {
|
|
7896
|
+
"text": "string"
|
|
7897
|
+
},
|
|
7898
|
+
"default": "'What were you doing, or what went wrong?'",
|
|
7899
|
+
"description": "The same prompt for a `required` note — \"(optional)\" would contradict the disabled Send."
|
|
7900
|
+
},
|
|
7901
|
+
{
|
|
7902
|
+
"kind": "function",
|
|
7903
|
+
"name": "resolveDebugLogNoteConfig",
|
|
7904
|
+
"return": {
|
|
7905
|
+
"type": {
|
|
7906
|
+
"text": "ResolvedDebugLogNoteConfig | null"
|
|
7907
|
+
}
|
|
7908
|
+
},
|
|
7909
|
+
"parameters": [
|
|
7910
|
+
{
|
|
7911
|
+
"name": "config",
|
|
7912
|
+
"type": {
|
|
7913
|
+
"text": "ChatDebugLogSubmitConfig | undefined"
|
|
7914
|
+
}
|
|
7915
|
+
}
|
|
7916
|
+
],
|
|
7917
|
+
"description": "Resolve `debugLogSubmit.note` — `undefined`/`true` mean \"compose box with defaults\",\n`false` means \"no compose box, send on first click\" (→ `null`), and an object customises\nthe box. Keeps the template free of the boolean-or-object dance."
|
|
7918
|
+
},
|
|
7919
|
+
{
|
|
7920
|
+
"kind": "function",
|
|
7921
|
+
"name": "normalizeDebugLogNote",
|
|
7922
|
+
"return": {
|
|
7923
|
+
"type": {
|
|
7924
|
+
"text": "string | undefined"
|
|
7925
|
+
}
|
|
7926
|
+
},
|
|
7927
|
+
"parameters": [
|
|
7928
|
+
{
|
|
7929
|
+
"name": "note",
|
|
7930
|
+
"type": {
|
|
7931
|
+
"text": "string"
|
|
7932
|
+
}
|
|
7933
|
+
}
|
|
7934
|
+
],
|
|
7935
|
+
"description": "Normalise the typed note for the submission: trimmed, and `undefined` when empty so a\nhost can `message ?? fallback` without checking for whitespace."
|
|
7936
|
+
}
|
|
7937
|
+
],
|
|
7938
|
+
"exports": [
|
|
7939
|
+
{
|
|
7940
|
+
"kind": "js",
|
|
7941
|
+
"name": "DEBUG_LOG_NOTE_DEFAULT_MAX_LENGTH",
|
|
7942
|
+
"declaration": {
|
|
7943
|
+
"name": "DEBUG_LOG_NOTE_DEFAULT_MAX_LENGTH",
|
|
7944
|
+
"module": "src/utils/resolve-debug-log-note.ts"
|
|
7945
|
+
}
|
|
7946
|
+
},
|
|
7947
|
+
{
|
|
7948
|
+
"kind": "js",
|
|
7949
|
+
"name": "DEBUG_LOG_NOTE_DEFAULT_PLACEHOLDER",
|
|
7950
|
+
"declaration": {
|
|
7951
|
+
"name": "DEBUG_LOG_NOTE_DEFAULT_PLACEHOLDER",
|
|
7952
|
+
"module": "src/utils/resolve-debug-log-note.ts"
|
|
7953
|
+
}
|
|
7954
|
+
},
|
|
7955
|
+
{
|
|
7956
|
+
"kind": "js",
|
|
7957
|
+
"name": "DEBUG_LOG_NOTE_REQUIRED_PLACEHOLDER",
|
|
7958
|
+
"declaration": {
|
|
7959
|
+
"name": "DEBUG_LOG_NOTE_REQUIRED_PLACEHOLDER",
|
|
7960
|
+
"module": "src/utils/resolve-debug-log-note.ts"
|
|
7961
|
+
}
|
|
7962
|
+
},
|
|
7963
|
+
{
|
|
7964
|
+
"kind": "js",
|
|
7965
|
+
"name": "resolveDebugLogNoteConfig",
|
|
7966
|
+
"declaration": {
|
|
7967
|
+
"name": "resolveDebugLogNoteConfig",
|
|
7968
|
+
"module": "src/utils/resolve-debug-log-note.ts"
|
|
7969
|
+
}
|
|
7970
|
+
},
|
|
7971
|
+
{
|
|
7972
|
+
"kind": "js",
|
|
7973
|
+
"name": "normalizeDebugLogNote",
|
|
7974
|
+
"declaration": {
|
|
7975
|
+
"name": "normalizeDebugLogNote",
|
|
7976
|
+
"module": "src/utils/resolve-debug-log-note.ts"
|
|
7977
|
+
}
|
|
7978
|
+
}
|
|
7979
|
+
]
|
|
7980
|
+
},
|
|
7981
|
+
{
|
|
7982
|
+
"kind": "javascript-module",
|
|
7983
|
+
"path": "src/utils/resolve-preference-baseline.ts",
|
|
7984
|
+
"declarations": [
|
|
7985
|
+
{
|
|
7986
|
+
"kind": "variable",
|
|
7987
|
+
"name": "DEFAULT_TIMESTAMP_DISPLAY",
|
|
7988
|
+
"type": {
|
|
7989
|
+
"text": "TimestampDisplay"
|
|
7990
|
+
},
|
|
7991
|
+
"default": "'hover'",
|
|
7992
|
+
"description": "The mode used when neither the host config nor stored prefs name a valid one."
|
|
7993
|
+
}
|
|
7994
|
+
],
|
|
7995
|
+
"exports": [
|
|
7996
|
+
{
|
|
7997
|
+
"kind": "js",
|
|
7998
|
+
"name": "DEFAULT_TIMESTAMP_DISPLAY",
|
|
7999
|
+
"declaration": {
|
|
8000
|
+
"name": "DEFAULT_TIMESTAMP_DISPLAY",
|
|
8001
|
+
"module": "src/utils/resolve-preference-baseline.ts"
|
|
8002
|
+
}
|
|
8003
|
+
}
|
|
8004
|
+
]
|
|
8005
|
+
},
|
|
8006
|
+
{
|
|
8007
|
+
"kind": "javascript-module",
|
|
8008
|
+
"path": "src/utils/resolve-turn-input.ts",
|
|
8009
|
+
"declarations": [
|
|
8010
|
+
{
|
|
8011
|
+
"kind": "function",
|
|
8012
|
+
"name": "resolveTurnInput",
|
|
8013
|
+
"return": {
|
|
8014
|
+
"type": {
|
|
8015
|
+
"text": "Promise<T | undefined>"
|
|
8016
|
+
}
|
|
8017
|
+
},
|
|
8018
|
+
"parameters": [
|
|
8019
|
+
{
|
|
8020
|
+
"name": "input",
|
|
8021
|
+
"type": {
|
|
8022
|
+
"text": "T | ((ctx: SystemPromptContext) => T | Promise<T>) | undefined"
|
|
8023
|
+
}
|
|
8024
|
+
},
|
|
8025
|
+
{
|
|
7433
8026
|
"name": "ctx",
|
|
7434
8027
|
"type": {
|
|
7435
8028
|
"text": "SystemPromptContext"
|
|
@@ -9095,16 +9688,14 @@
|
|
|
9095
9688
|
},
|
|
9096
9689
|
{
|
|
9097
9690
|
"kind": "field",
|
|
9098
|
-
"name": "
|
|
9099
|
-
"
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
{
|
|
9103
|
-
"kind": "field",
|
|
9104
|
-
"name": "interactionContexts",
|
|
9691
|
+
"name": "interactions",
|
|
9692
|
+
"type": {
|
|
9693
|
+
"text": "InteractionController"
|
|
9694
|
+
},
|
|
9105
9695
|
"privacy": "private",
|
|
9106
|
-
"
|
|
9107
|
-
"description": "
|
|
9696
|
+
"readonly": true,
|
|
9697
|
+
"description": "Custom UI interactions: the pending call, its live context, and any host to delegate to.",
|
|
9698
|
+
"default": "new InteractionController({\n sessionKey,\n activityBus,\n activeAgentName: () => this.activeAgentName,\n appendToHistory: (message) => this.appendToHistory(message),\n patchInteractionMessage: (interactionId, patch) =>\n this.patchInteractionMessage(interactionId, patch),\n notifyHistoryUpdated: () => this.notifyHistoryUpdated(),\n emit: (event) => this.dispatchEvent(event),\n foldDiagnostics: (interactionId, harvested) =>\n this.turnRecorder.foldDiagnostics(interactionId, harvested),\n })"
|
|
9108
9699
|
},
|
|
9109
9700
|
{
|
|
9110
9701
|
"kind": "field",
|
|
@@ -9194,15 +9785,6 @@
|
|
|
9194
9785
|
},
|
|
9195
9786
|
"privacy": "private"
|
|
9196
9787
|
},
|
|
9197
|
-
{
|
|
9198
|
-
"kind": "field",
|
|
9199
|
-
"name": "hostInteractionRequester",
|
|
9200
|
-
"type": {
|
|
9201
|
-
"text": "<T>(\n componentName: string,\n data: any,\n options?: InteractionRequestOptions,\n ) => Promise<T> | undefined"
|
|
9202
|
-
},
|
|
9203
|
-
"privacy": "private",
|
|
9204
|
-
"description": "When set, `requestInteraction` delegates to this callback instead of using\nthis driver's own pending map. Wired by `invokeSubAgent` so a sub-agent's\nwidget renders in — and resolves through — the parent (ultimately the\nroot) driver, where the main UI is listening."
|
|
9205
|
-
},
|
|
9206
9788
|
{
|
|
9207
9789
|
"kind": "field",
|
|
9208
9790
|
"name": "providerHistoryTransform",
|
|
@@ -9362,63 +9944,14 @@
|
|
|
9362
9944
|
},
|
|
9363
9945
|
{
|
|
9364
9946
|
"kind": "field",
|
|
9365
|
-
"name": "
|
|
9366
|
-
"type": {
|
|
9367
|
-
"text": "TurnSnapshot[]"
|
|
9368
|
-
},
|
|
9369
|
-
"privacy": "private",
|
|
9370
|
-
"default": "[]",
|
|
9371
|
-
"description": "Ring buffer of per-LLM-call snapshots. Cap is configurable via\n`chatConfig.agent.maxTurnSnapshots`; older entries drop off as new ones\narrive. See TurnSnapshot for the captured shape."
|
|
9372
|
-
},
|
|
9373
|
-
{
|
|
9374
|
-
"kind": "field",
|
|
9375
|
-
"name": "externalDiagnostics",
|
|
9376
|
-
"type": {
|
|
9377
|
-
"text": "DiagnosticEntry[]"
|
|
9378
|
-
},
|
|
9379
|
-
"privacy": "private",
|
|
9380
|
-
"readonly": true,
|
|
9381
|
-
"default": "[]",
|
|
9382
|
-
"description": "`turn` + `message` diagnostic-log entries harvested from an out-of-band source (a resolved\ninteraction whose widget returned `InteractionResult.diagnostics` — e.g. a server-side\nChatDriver's debug log). `event` entries are NOT kept here — they're folded into the session's\nmeta-event registry via `mergeMetaEvents` (see `resolveInteraction`) so they inherit fresh host\nindices, and reach the log through `getMetaEvents`. Append-only; the host folds these into its\ndebug log alongside this driver's own timeline. Not cleared here — it lives with the driver\ninstance, like `turnSnapshots`, so a new chat (fresh driver) starts empty while a compaction\n(same instance) keeps it. (GENC-1461.)"
|
|
9383
|
-
},
|
|
9384
|
-
{
|
|
9385
|
-
"kind": "field",
|
|
9386
|
-
"name": "externalDiagnosticsBatches",
|
|
9387
|
-
"type": {
|
|
9388
|
-
"text": "number"
|
|
9389
|
-
},
|
|
9390
|
-
"privacy": "private",
|
|
9391
|
-
"default": "0",
|
|
9392
|
-
"description": "Monotonic count of external-diagnostics batches harvested this driver-lifetime. Namespaces each\nbatch's re-keyed `turn` entries so distinct server generations in one chat session can't collide\non `turnIndex` in the forward-capture persister (which dedups turns by that key). (GENC-1461.)"
|
|
9393
|
-
},
|
|
9394
|
-
{
|
|
9395
|
-
"kind": "field",
|
|
9396
|
-
"name": "globalTurnIndex",
|
|
9397
|
-
"type": {
|
|
9398
|
-
"text": "number"
|
|
9399
|
-
},
|
|
9400
|
-
"privacy": "private",
|
|
9401
|
-
"default": "0",
|
|
9402
|
-
"description": "Monotonic counter that survives agent swaps — useful for cross-referencing with history."
|
|
9403
|
-
},
|
|
9404
|
-
{
|
|
9405
|
-
"kind": "field",
|
|
9406
|
-
"name": "debugSnapshotter",
|
|
9407
|
-
"type": {
|
|
9408
|
-
"text": "() => unknown | undefined"
|
|
9409
|
-
},
|
|
9410
|
-
"privacy": "private",
|
|
9411
|
-
"description": "Captured from `applyAgent` so we don't store the whole `AgentConfig`."
|
|
9412
|
-
},
|
|
9413
|
-
{
|
|
9414
|
-
"kind": "field",
|
|
9415
|
-
"name": "maxTurnSnapshots",
|
|
9947
|
+
"name": "turnRecorder",
|
|
9416
9948
|
"type": {
|
|
9417
|
-
"text": "
|
|
9949
|
+
"text": "TurnRecorder"
|
|
9418
9950
|
},
|
|
9419
9951
|
"privacy": "private",
|
|
9420
9952
|
"readonly": true,
|
|
9421
|
-
"
|
|
9953
|
+
"description": "Per-turn snapshots, forwarded sub-agent snapshots, and harvested external diagnostics —\neverything the exported debug log draws from this driver.",
|
|
9954
|
+
"default": "new TurnRecorder(sessionKey, maxTurnSnapshots)"
|
|
9422
9955
|
},
|
|
9423
9956
|
{
|
|
9424
9957
|
"kind": "field",
|
|
@@ -9727,7 +10260,7 @@
|
|
|
9727
10260
|
"text": "Promise<void>"
|
|
9728
10261
|
}
|
|
9729
10262
|
},
|
|
9730
|
-
"description": "Tear down the driver: aborts the lifecycle signal so any in-flight provider\nrequest (and prompt/tool factories awaiting it) cancels instead of running\non to completion or the transport timeout. Called by the host on driver\nswap and by `OrchestratingDriver.dispose()`. Idempotent.\n\nDeliberately does NOT settle
|
|
10263
|
+
"description": "Tear down the driver: aborts the lifecycle signal so any in-flight provider\nrequest (and prompt/tool factories awaiting it) cancels instead of running\non to completion or the transport timeout. Called by the host on driver\nswap and by `OrchestratingDriver.dispose()`. Idempotent.\n\nDeliberately does NOT settle pending interactions here: dispose is never\nreached while one is pending. The only host-level dispose is the agent-swap\nrebuild, which is guarded by `isBusy()` — a pending interaction keeps the\ntool loop suspended (`busy === true`), so the swap is deferred until the\nwidget resolves. Sub-agent child disposes always have an empty pending map\n(widgets park on the parent via `setHostInteractionRequester`). A pending\ninteraction is instead settled by `resolveInteraction` (user response or\ntimeout), which also stamps history and reverts the chat-input override."
|
|
9731
10264
|
},
|
|
9732
10265
|
{
|
|
9733
10266
|
"kind": "method",
|
|
@@ -10174,7 +10707,7 @@
|
|
|
10174
10707
|
"text": "ReadonlyArray<TurnSnapshot>"
|
|
10175
10708
|
}
|
|
10176
10709
|
},
|
|
10177
|
-
"description": "Return the per-turn snapshots captured so far. Used by the host's debug\nlog exporter to show what the LLM saw on each turn — system prompt, tool\nsurface, and agent-supplied state (e.g. a machine snapshot).\n\nRing-buffered at `
|
|
10710
|
+
"description": "Return the per-turn snapshots captured so far. Used by the host's debug\nlog exporter to show what the LLM saw on each turn — system prompt, tool\nsurface, and agent-supplied state (e.g. a machine snapshot).\n\nRing-buffered at `maxTurnSnapshots`; older entries are dropped."
|
|
10178
10711
|
},
|
|
10179
10712
|
{
|
|
10180
10713
|
"kind": "method",
|
|
@@ -10184,63 +10717,7 @@
|
|
|
10184
10717
|
"text": "ReadonlyArray<DiagnosticEntry>"
|
|
10185
10718
|
}
|
|
10186
10719
|
},
|
|
10187
|
-
"description": "The `turn` + `message` diagnostic-log entries harvested from resolved interactions'\n`InteractionResult.diagnostics` (e.g. a server-side ChatDriver's collated debug log). The host\nconcatenates these into its own debug log so `downloadDebugLog`/the persisted diagnostics stream\ninclude external-engine logs; `event` entries are excluded here because they're merged into the\nsession's meta-event registry instead
|
|
10188
|
-
},
|
|
10189
|
-
{
|
|
10190
|
-
"kind": "method",
|
|
10191
|
-
"name": "forwardSubAgentSnapshots",
|
|
10192
|
-
"privacy": "private",
|
|
10193
|
-
"return": {
|
|
10194
|
-
"type": {
|
|
10195
|
-
"text": "void"
|
|
10196
|
-
}
|
|
10197
|
-
},
|
|
10198
|
-
"parameters": [
|
|
10199
|
-
{
|
|
10200
|
-
"name": "childSnapshots",
|
|
10201
|
-
"type": {
|
|
10202
|
-
"text": "ReadonlyArray<TurnSnapshot>"
|
|
10203
|
-
}
|
|
10204
|
-
}
|
|
10205
|
-
],
|
|
10206
|
-
"description": "Merge a sub-agent's turn snapshots into this driver's buffer so they surface\nas `kind:'turn'` entries in the exported debug log. The child runs as a\nseparate, discarded driver, so its snapshots would otherwise be lost. Each is\nre-labelled under the parent turn that activated the sub-agent: the child's\nown (numeric) turns become `\"<parentTurn>-1\"`, `\"-2\"`, … (1-based, in order);\nany already-forwarded grand-child labels (strings) have their leading segment\nremapped the same way, so nesting composes (`\"5-2\"` → `\"5-2-1\"`).\n\nNote: two sub-agents invoked in the *same* parent turn share the prefix, so\ntheir labels can repeat — `agentName` on each snapshot disambiguates them."
|
|
10207
|
-
},
|
|
10208
|
-
{
|
|
10209
|
-
"kind": "method",
|
|
10210
|
-
"name": "recordTurnSnapshot",
|
|
10211
|
-
"privacy": "private",
|
|
10212
|
-
"return": {
|
|
10213
|
-
"type": {
|
|
10214
|
-
"text": "TurnSnapshot"
|
|
10215
|
-
}
|
|
10216
|
-
},
|
|
10217
|
-
"parameters": [
|
|
10218
|
-
{
|
|
10219
|
-
"name": "resolvedSystemPrompt",
|
|
10220
|
-
"type": {
|
|
10221
|
-
"text": "string | undefined"
|
|
10222
|
-
}
|
|
10223
|
-
},
|
|
10224
|
-
{
|
|
10225
|
-
"name": "temperature",
|
|
10226
|
-
"type": {
|
|
10227
|
-
"text": "number | undefined"
|
|
10228
|
-
}
|
|
10229
|
-
},
|
|
10230
|
-
{
|
|
10231
|
-
"name": "toolChoice",
|
|
10232
|
-
"type": {
|
|
10233
|
-
"text": "ChatToolChoice | undefined"
|
|
10234
|
-
}
|
|
10235
|
-
},
|
|
10236
|
-
{
|
|
10237
|
-
"name": "tailContext",
|
|
10238
|
-
"type": {
|
|
10239
|
-
"text": "string | undefined"
|
|
10240
|
-
}
|
|
10241
|
-
}
|
|
10242
|
-
],
|
|
10243
|
-
"description": "Push one snapshot to the ring buffer. Called inside `runToolLoop` just\nbefore each LLM call — that's the latest point where the prompt, tool\nsurface, and agent state line up with what the model is about to see.\n\nReturns the pushed object so the caller can back-fill what only the response\nknows (`usage`). Mutating it after the fact is safe whether or not the ring\nbuffer has since evicted it — an evicted snapshot is simply no longer exported."
|
|
10720
|
+
"description": "The `turn` + `message` diagnostic-log entries harvested from resolved interactions'\n`InteractionResult.diagnostics` (e.g. a server-side ChatDriver's collated debug log). The host\nconcatenates these into its own debug log so `downloadDebugLog`/the persisted diagnostics stream\ninclude external-engine logs; `event` entries are excluded here because they're merged into the\nsession's meta-event registry instead and reach the log via `getMetaEvents`. Opaque,\nchronologically sorted by the host at assemble time. (GENC-1461.)"
|
|
10244
10721
|
},
|
|
10245
10722
|
{
|
|
10246
10723
|
"kind": "field",
|
|
@@ -10321,7 +10798,8 @@
|
|
|
10321
10798
|
"text": "(history: ChatMessage[]) => ChatMessage[]"
|
|
10322
10799
|
}
|
|
10323
10800
|
}
|
|
10324
|
-
]
|
|
10801
|
+
],
|
|
10802
|
+
"description": "Optional transform applied to conversation history immediately before each LLM request.\nCleared when `undefined`. Does not alter stored history."
|
|
10325
10803
|
},
|
|
10326
10804
|
{
|
|
10327
10805
|
"kind": "method",
|
|
@@ -10553,7 +11031,7 @@
|
|
|
10553
11031
|
"description": "a positive delta in USD. Non-finite, zero and negative values are ignored."
|
|
10554
11032
|
}
|
|
10555
11033
|
],
|
|
10556
|
-
"description": "Add external (non-LLM) spend to an interaction's message AFTER it has resolved
|
|
11034
|
+
"description": "Add external (non-LLM) spend to an interaction's message AFTER it has resolved — for a widget\nthat resolves early so the assistant stops waiting, then keeps doing paid work on the user's\nbehalf. `InteractionController.recordExternalCost` explains why the resolution path cannot\ncarry this.\n\nAdditive by design: the caller reports a DELTA, not a running total, so repeated calls sum.\n\nDeliberately does NOT require the interaction to be pending, does not resurrect it, and has no\nloading/turn side effects — this is bookkeeping about a turn that already happened."
|
|
10557
11035
|
},
|
|
10558
11036
|
{
|
|
10559
11037
|
"kind": "method",
|
|
@@ -10601,22 +11079,28 @@
|
|
|
10601
11079
|
},
|
|
10602
11080
|
{
|
|
10603
11081
|
"kind": "method",
|
|
10604
|
-
"name": "
|
|
11082
|
+
"name": "patchInteractionMessage",
|
|
10605
11083
|
"privacy": "private",
|
|
10606
11084
|
"return": {
|
|
10607
11085
|
"type": {
|
|
10608
|
-
"text": "
|
|
11086
|
+
"text": "boolean"
|
|
10609
11087
|
}
|
|
10610
11088
|
},
|
|
10611
11089
|
"parameters": [
|
|
10612
11090
|
{
|
|
10613
|
-
"name": "
|
|
11091
|
+
"name": "interactionId",
|
|
10614
11092
|
"type": {
|
|
10615
11093
|
"text": "string"
|
|
10616
11094
|
}
|
|
11095
|
+
},
|
|
11096
|
+
{
|
|
11097
|
+
"name": "patch",
|
|
11098
|
+
"type": {
|
|
11099
|
+
"text": "(message: ChatMessage) => ChatMessage"
|
|
11100
|
+
}
|
|
10617
11101
|
}
|
|
10618
11102
|
],
|
|
10619
|
-
"description": "
|
|
11103
|
+
"description": "Replace the history message owning `interactionId`. `false` when it is no longer in history.\nDoes not announce the change — the interaction paths differ on whether they should."
|
|
10620
11104
|
},
|
|
10621
11105
|
{
|
|
10622
11106
|
"kind": "method",
|
|
@@ -10798,6 +11282,17 @@
|
|
|
10798
11282
|
}
|
|
10799
11283
|
}
|
|
10800
11284
|
]
|
|
11285
|
+
},
|
|
11286
|
+
{
|
|
11287
|
+
"kind": "method",
|
|
11288
|
+
"name": "notifyHistoryUpdated",
|
|
11289
|
+
"privacy": "private",
|
|
11290
|
+
"return": {
|
|
11291
|
+
"type": {
|
|
11292
|
+
"text": "void"
|
|
11293
|
+
}
|
|
11294
|
+
},
|
|
11295
|
+
"description": "Announce the current history to the host."
|
|
10801
11296
|
}
|
|
10802
11297
|
],
|
|
10803
11298
|
"events": [
|
|
@@ -10808,43 +11303,25 @@
|
|
|
10808
11303
|
}
|
|
10809
11304
|
},
|
|
10810
11305
|
{
|
|
10811
|
-
"name": "
|
|
10812
|
-
"type": {
|
|
10813
|
-
"text": "CustomEvent"
|
|
10814
|
-
}
|
|
10815
|
-
},
|
|
10816
|
-
{
|
|
10817
|
-
"name": "external-cost-recorded",
|
|
10818
|
-
"type": {
|
|
10819
|
-
"text": "CustomEvent"
|
|
10820
|
-
}
|
|
10821
|
-
},
|
|
10822
|
-
{
|
|
10823
|
-
"name": "history-updated",
|
|
11306
|
+
"name": "sub-agent-history-updated",
|
|
10824
11307
|
"type": {
|
|
10825
11308
|
"text": "CustomEvent"
|
|
10826
11309
|
}
|
|
10827
11310
|
},
|
|
10828
11311
|
{
|
|
10829
|
-
"name": "
|
|
11312
|
+
"name": "sub-agent-start",
|
|
10830
11313
|
"type": {
|
|
10831
11314
|
"text": "CustomEvent"
|
|
10832
11315
|
}
|
|
10833
11316
|
},
|
|
10834
11317
|
{
|
|
10835
|
-
"name": "sub-agent-
|
|
11318
|
+
"name": "sub-agent-stop",
|
|
10836
11319
|
"type": {
|
|
10837
11320
|
"text": "CustomEvent"
|
|
10838
11321
|
}
|
|
10839
11322
|
},
|
|
10840
11323
|
{
|
|
10841
|
-
"name": "
|
|
10842
|
-
"type": {
|
|
10843
|
-
"text": "CustomEvent"
|
|
10844
|
-
}
|
|
10845
|
-
},
|
|
10846
|
-
{
|
|
10847
|
-
"name": "sub-agent-stop",
|
|
11324
|
+
"name": "history-updated",
|
|
10848
11325
|
"type": {
|
|
10849
11326
|
"text": "CustomEvent"
|
|
10850
11327
|
}
|
|
@@ -10881,6 +11358,14 @@
|
|
|
10881
11358
|
"module": "./chat-driver.constants"
|
|
10882
11359
|
}
|
|
10883
11360
|
},
|
|
11361
|
+
{
|
|
11362
|
+
"kind": "js",
|
|
11363
|
+
"name": "TurnSnapshot",
|
|
11364
|
+
"declaration": {
|
|
11365
|
+
"name": "TurnSnapshot",
|
|
11366
|
+
"module": "./turn-recorder"
|
|
11367
|
+
}
|
|
11368
|
+
},
|
|
10884
11369
|
{
|
|
10885
11370
|
"kind": "js",
|
|
10886
11371
|
"name": "ChatDriver",
|
|
@@ -11166,6 +11651,196 @@
|
|
|
11166
11651
|
}
|
|
11167
11652
|
]
|
|
11168
11653
|
},
|
|
11654
|
+
{
|
|
11655
|
+
"kind": "javascript-module",
|
|
11656
|
+
"path": "src/components/chat-driver/interaction-controller.ts",
|
|
11657
|
+
"declarations": [
|
|
11658
|
+
{
|
|
11659
|
+
"kind": "class",
|
|
11660
|
+
"description": "Custom UI interactions: parking a tool handler on a widget, and settling it when the user (or a\ntimeout) answers.\n\nOwns the pending call and its live context, which are created and destroyed together. Everything\nelse it needs is the driver's history and event target, reached through `InteractionDeps`.",
|
|
11661
|
+
"name": "InteractionController",
|
|
11662
|
+
"members": [
|
|
11663
|
+
{
|
|
11664
|
+
"kind": "field",
|
|
11665
|
+
"name": "pending",
|
|
11666
|
+
"privacy": "private",
|
|
11667
|
+
"readonly": true,
|
|
11668
|
+
"default": "new Map<string, PendingInteraction>()"
|
|
11669
|
+
},
|
|
11670
|
+
{
|
|
11671
|
+
"kind": "field",
|
|
11672
|
+
"name": "contexts",
|
|
11673
|
+
"privacy": "private",
|
|
11674
|
+
"readonly": true,
|
|
11675
|
+
"default": "new Map<string, InteractionContextHandle>()",
|
|
11676
|
+
"description": "Live per-interaction contexts (GENC-1390), keyed by interactionId. Created in `request`\nalongside the pending entry, disposed + removed in `resolve`. Non-serialisable (sockets,\ntimers, subscriber sets), so they live here — not on the DOM, not in the persisted store — and\ntherefore survive the element remounts (layout reflow/drag, transcript re-render) that this\nfeature exists to make harmless. At most one is live at a time (see the\none-interaction-at-a-time guard in `request`)."
|
|
11677
|
+
},
|
|
11678
|
+
{
|
|
11679
|
+
"kind": "field",
|
|
11680
|
+
"name": "hostRequester",
|
|
11681
|
+
"type": {
|
|
11682
|
+
"text": "<T>(\n componentName: string,\n data: any,\n options?: InteractionRequestOptions,\n ) => Promise<T> | undefined"
|
|
11683
|
+
},
|
|
11684
|
+
"privacy": "private",
|
|
11685
|
+
"description": "When set, `request` delegates to this callback instead of using this controller's own pending\nmap. Wired by `invokeSubAgent` so a sub-agent's widget renders in — and resolves through — the\nparent (ultimately the root) driver, where the main UI is listening."
|
|
11686
|
+
},
|
|
11687
|
+
{
|
|
11688
|
+
"kind": "method",
|
|
11689
|
+
"name": "setHostRequester",
|
|
11690
|
+
"return": {
|
|
11691
|
+
"type": {
|
|
11692
|
+
"text": "void"
|
|
11693
|
+
}
|
|
11694
|
+
},
|
|
11695
|
+
"parameters": [
|
|
11696
|
+
{
|
|
11697
|
+
"name": "fn",
|
|
11698
|
+
"type": {
|
|
11699
|
+
"text": "<T>(componentName: string, data: any, options?: InteractionRequestOptions) => Promise<T>"
|
|
11700
|
+
}
|
|
11701
|
+
}
|
|
11702
|
+
],
|
|
11703
|
+
"description": "See `ChatDriver.setHostInteractionRequester`."
|
|
11704
|
+
},
|
|
11705
|
+
{
|
|
11706
|
+
"kind": "method",
|
|
11707
|
+
"name": "request",
|
|
11708
|
+
"return": {
|
|
11709
|
+
"type": {
|
|
11710
|
+
"text": "Promise<T>"
|
|
11711
|
+
}
|
|
11712
|
+
},
|
|
11713
|
+
"parameters": [
|
|
11714
|
+
{
|
|
11715
|
+
"name": "componentName",
|
|
11716
|
+
"type": {
|
|
11717
|
+
"text": "string"
|
|
11718
|
+
}
|
|
11719
|
+
},
|
|
11720
|
+
{
|
|
11721
|
+
"name": "data",
|
|
11722
|
+
"type": {
|
|
11723
|
+
"text": "any"
|
|
11724
|
+
}
|
|
11725
|
+
},
|
|
11726
|
+
{
|
|
11727
|
+
"name": "options",
|
|
11728
|
+
"optional": true,
|
|
11729
|
+
"type": {
|
|
11730
|
+
"text": "InteractionRequestOptions"
|
|
11731
|
+
}
|
|
11732
|
+
}
|
|
11733
|
+
],
|
|
11734
|
+
"description": "See `ChatDriver.requestInteraction`."
|
|
11735
|
+
},
|
|
11736
|
+
{
|
|
11737
|
+
"kind": "method",
|
|
11738
|
+
"name": "resolve",
|
|
11739
|
+
"return": {
|
|
11740
|
+
"type": {
|
|
11741
|
+
"text": "void"
|
|
11742
|
+
}
|
|
11743
|
+
},
|
|
11744
|
+
"parameters": [
|
|
11745
|
+
{
|
|
11746
|
+
"name": "interactionId",
|
|
11747
|
+
"type": {
|
|
11748
|
+
"text": "string"
|
|
11749
|
+
}
|
|
11750
|
+
},
|
|
11751
|
+
{
|
|
11752
|
+
"name": "result",
|
|
11753
|
+
"type": {
|
|
11754
|
+
"text": "any"
|
|
11755
|
+
}
|
|
11756
|
+
}
|
|
11757
|
+
],
|
|
11758
|
+
"description": "See `ChatDriver.resolveInteraction`. Warns and returns when the id is unknown — a widget can\nreport twice, and the second report has nothing left to settle."
|
|
11759
|
+
},
|
|
11760
|
+
{
|
|
11761
|
+
"kind": "method",
|
|
11762
|
+
"name": "recordExternalCost",
|
|
11763
|
+
"return": {
|
|
11764
|
+
"type": {
|
|
11765
|
+
"text": "boolean"
|
|
11766
|
+
}
|
|
11767
|
+
},
|
|
11768
|
+
"parameters": [
|
|
11769
|
+
{
|
|
11770
|
+
"name": "interactionId",
|
|
11771
|
+
"type": {
|
|
11772
|
+
"text": "string"
|
|
11773
|
+
}
|
|
11774
|
+
},
|
|
11775
|
+
{
|
|
11776
|
+
"name": "costUsd",
|
|
11777
|
+
"type": {
|
|
11778
|
+
"text": "number"
|
|
11779
|
+
}
|
|
11780
|
+
}
|
|
11781
|
+
],
|
|
11782
|
+
"description": "See `ChatDriver.recordExternalCost`.\n\n**Why this exists separately from `resolve`.** A widget's spend reaches the session total only\nthrough `InteractionResult.costUsd`, which is read exactly once — `resolve` does its whole job\nagainst a live pending entry and then deletes it. That is correct for the resolution itself,\nbut it assumes a widget stops costing money when it resolves, and several deliberately do not:\na widget that resolves EARLY so the assistant stops waiting (options shown, a preview\nrendered) may stay interactive for minutes afterwards and do more paid work on the user's\nbehalf. Re-emitting `interaction-completed` does not help — with the interaction gone from the\nmap the call is a silent no-op — so that spend had nowhere to go and was simply missing from\nthe figure shown to the user.\n\nTouches only `externalCostUsd`: the recorded `interaction.resolved` payload is left exactly as\nthe resolution wrote it, because this is not a second resolution and must not read like one."
|
|
11783
|
+
},
|
|
11784
|
+
{
|
|
11785
|
+
"kind": "method",
|
|
11786
|
+
"name": "context",
|
|
11787
|
+
"return": {
|
|
11788
|
+
"type": {
|
|
11789
|
+
"text": "InteractionContext | undefined"
|
|
11790
|
+
}
|
|
11791
|
+
},
|
|
11792
|
+
"parameters": [
|
|
11793
|
+
{
|
|
11794
|
+
"name": "interactionId",
|
|
11795
|
+
"type": {
|
|
11796
|
+
"text": "string"
|
|
11797
|
+
}
|
|
11798
|
+
}
|
|
11799
|
+
],
|
|
11800
|
+
"description": "See `ChatDriver.getInteractionContext`."
|
|
11801
|
+
},
|
|
11802
|
+
{
|
|
11803
|
+
"kind": "method",
|
|
11804
|
+
"name": "cancelAll",
|
|
11805
|
+
"return": {
|
|
11806
|
+
"type": {
|
|
11807
|
+
"text": "void"
|
|
11808
|
+
}
|
|
11809
|
+
},
|
|
11810
|
+
"parameters": [
|
|
11811
|
+
{
|
|
11812
|
+
"name": "message",
|
|
11813
|
+
"type": {
|
|
11814
|
+
"text": "string"
|
|
11815
|
+
}
|
|
11816
|
+
}
|
|
11817
|
+
],
|
|
11818
|
+
"description": "Resolve every in-flight interaction with a `'timeout'` result, closing its\nwidget read-only. Used when a sub-agent that owns the open widget times out:\nthe widget is parked in *this* driver's map (interactions resolve on the\nhost, not the child), so cancelling it here unblocks the sub-agent handler\nawaiting it. The \"one interaction at a time\" invariant means there is at\nmost one."
|
|
11819
|
+
},
|
|
11820
|
+
{
|
|
11821
|
+
"kind": "method",
|
|
11822
|
+
"name": "disposeContexts",
|
|
11823
|
+
"return": {
|
|
11824
|
+
"type": {
|
|
11825
|
+
"text": "void"
|
|
11826
|
+
}
|
|
11827
|
+
},
|
|
11828
|
+
"description": "Drop any live interaction contexts on driver teardown. Normally empty (a context is created\nand destroyed with its pending interaction, and dispose is not reached mid-interaction);\ndisposed defensively so a stray context can never leak an open socket/timer."
|
|
11829
|
+
}
|
|
11830
|
+
]
|
|
11831
|
+
}
|
|
11832
|
+
],
|
|
11833
|
+
"exports": [
|
|
11834
|
+
{
|
|
11835
|
+
"kind": "js",
|
|
11836
|
+
"name": "InteractionController",
|
|
11837
|
+
"declaration": {
|
|
11838
|
+
"name": "InteractionController",
|
|
11839
|
+
"module": "src/components/chat-driver/interaction-controller.ts"
|
|
11840
|
+
}
|
|
11841
|
+
}
|
|
11842
|
+
]
|
|
11843
|
+
},
|
|
11169
11844
|
{
|
|
11170
11845
|
"kind": "javascript-module",
|
|
11171
11846
|
"path": "src/components/chat-driver/turn-failures.ts",
|
|
@@ -11258,6 +11933,190 @@
|
|
|
11258
11933
|
}
|
|
11259
11934
|
]
|
|
11260
11935
|
},
|
|
11936
|
+
{
|
|
11937
|
+
"kind": "javascript-module",
|
|
11938
|
+
"path": "src/components/chat-driver/turn-recorder.ts",
|
|
11939
|
+
"declarations": [
|
|
11940
|
+
{
|
|
11941
|
+
"kind": "class",
|
|
11942
|
+
"description": "Everything the exported debug log draws from one driver: its own per-LLM-call snapshots, the\nones forwarded up from sub-agents, and the diagnostics harvested from resolved interactions.\n\nAll three feed the same timeline and all three are keyed in this driver's turn space, which is\nwhy they share an owner — a forwarded child turn and a harvested server turn are both re-labelled\nagainst the counter kept here.",
|
|
11943
|
+
"name": "TurnRecorder",
|
|
11944
|
+
"members": [
|
|
11945
|
+
{
|
|
11946
|
+
"kind": "field",
|
|
11947
|
+
"name": "buffer",
|
|
11948
|
+
"type": {
|
|
11949
|
+
"text": "TurnSnapshot[]"
|
|
11950
|
+
},
|
|
11951
|
+
"privacy": "private",
|
|
11952
|
+
"readonly": true,
|
|
11953
|
+
"default": "[]",
|
|
11954
|
+
"description": "Ring buffer of per-LLM-call snapshots, capped at `maxSnapshots`; older entries drop off as\nnew ones arrive."
|
|
11955
|
+
},
|
|
11956
|
+
{
|
|
11957
|
+
"kind": "field",
|
|
11958
|
+
"name": "turnIndex",
|
|
11959
|
+
"type": {
|
|
11960
|
+
"text": "number"
|
|
11961
|
+
},
|
|
11962
|
+
"privacy": "private",
|
|
11963
|
+
"default": "0",
|
|
11964
|
+
"description": "Monotonic counter that survives agent swaps — useful for cross-referencing with history."
|
|
11965
|
+
},
|
|
11966
|
+
{
|
|
11967
|
+
"kind": "field",
|
|
11968
|
+
"name": "externalEntries",
|
|
11969
|
+
"type": {
|
|
11970
|
+
"text": "DiagnosticEntry[]"
|
|
11971
|
+
},
|
|
11972
|
+
"privacy": "private",
|
|
11973
|
+
"readonly": true,
|
|
11974
|
+
"default": "[]",
|
|
11975
|
+
"description": "`turn` + `message` diagnostic entries harvested from an out-of-band source. `event` entries\nare NOT kept here — they are folded into the session's meta-event registry so they inherit\nfresh host indices, and reach the log through `getMetaEvents`. Append-only, and never cleared:\nit lives with the recorder, so a new chat (fresh driver) starts empty while a compaction (same\ninstance) keeps it. (GENC-1461.)"
|
|
11976
|
+
},
|
|
11977
|
+
{
|
|
11978
|
+
"kind": "field",
|
|
11979
|
+
"name": "externalBatches",
|
|
11980
|
+
"type": {
|
|
11981
|
+
"text": "number"
|
|
11982
|
+
},
|
|
11983
|
+
"privacy": "private",
|
|
11984
|
+
"default": "0",
|
|
11985
|
+
"description": "Monotonic count of external-diagnostics batches folded this driver-lifetime. Namespaces each\nbatch's re-keyed `turn` entries so distinct server generations in one chat session can't\ncollide on `turnIndex` in the forward-capture persister (which dedups turns by that key)."
|
|
11986
|
+
},
|
|
11987
|
+
{
|
|
11988
|
+
"kind": "field",
|
|
11989
|
+
"name": "snapshotter",
|
|
11990
|
+
"type": {
|
|
11991
|
+
"text": "() => unknown | undefined"
|
|
11992
|
+
},
|
|
11993
|
+
"privacy": "private",
|
|
11994
|
+
"description": "The active agent's `getDebugSnapshot`, captured on install so the whole config isn't held."
|
|
11995
|
+
},
|
|
11996
|
+
{
|
|
11997
|
+
"kind": "method",
|
|
11998
|
+
"name": "setSnapshotter",
|
|
11999
|
+
"return": {
|
|
12000
|
+
"type": {
|
|
12001
|
+
"text": "void"
|
|
12002
|
+
}
|
|
12003
|
+
},
|
|
12004
|
+
"parameters": [
|
|
12005
|
+
{
|
|
12006
|
+
"name": "snapshotter",
|
|
12007
|
+
"optional": true,
|
|
12008
|
+
"type": {
|
|
12009
|
+
"text": "() => unknown"
|
|
12010
|
+
}
|
|
12011
|
+
}
|
|
12012
|
+
],
|
|
12013
|
+
"description": "Point at the incoming agent's `getDebugSnapshot`, or clear it when the agent supplies none."
|
|
12014
|
+
},
|
|
12015
|
+
{
|
|
12016
|
+
"kind": "method",
|
|
12017
|
+
"name": "snapshots",
|
|
12018
|
+
"return": {
|
|
12019
|
+
"type": {
|
|
12020
|
+
"text": "ReadonlyArray<TurnSnapshot>"
|
|
12021
|
+
}
|
|
12022
|
+
},
|
|
12023
|
+
"description": "The per-turn snapshots captured so far — what the LLM saw on each turn: system prompt, tool\nsurface, and agent-supplied state (e.g. a machine snapshot)."
|
|
12024
|
+
},
|
|
12025
|
+
{
|
|
12026
|
+
"kind": "method",
|
|
12027
|
+
"name": "externalDiagnostics",
|
|
12028
|
+
"return": {
|
|
12029
|
+
"type": {
|
|
12030
|
+
"text": "ReadonlyArray<DiagnosticEntry>"
|
|
12031
|
+
}
|
|
12032
|
+
},
|
|
12033
|
+
"description": "The harvested `turn` + `message` diagnostic entries. Opaque, and chronologically sorted by the\nhost at assemble time."
|
|
12034
|
+
},
|
|
12035
|
+
{
|
|
12036
|
+
"kind": "method",
|
|
12037
|
+
"name": "record",
|
|
12038
|
+
"return": {
|
|
12039
|
+
"type": {
|
|
12040
|
+
"text": "TurnSnapshot"
|
|
12041
|
+
}
|
|
12042
|
+
},
|
|
12043
|
+
"parameters": [
|
|
12044
|
+
{
|
|
12045
|
+
"name": "turn",
|
|
12046
|
+
"type": {
|
|
12047
|
+
"text": "RecordedTurn"
|
|
12048
|
+
}
|
|
12049
|
+
}
|
|
12050
|
+
],
|
|
12051
|
+
"description": "Push one snapshot to the ring buffer. Called inside `runToolLoop` just\nbefore each LLM call — that's the latest point where the prompt, tool\nsurface, and agent state line up with what the model is about to see.\n\nReturns the pushed object so the caller can back-fill what only the response\nknows (`usage`). Mutating it after the fact is safe whether or not the ring\nbuffer has since evicted it — an evicted snapshot is simply no longer exported."
|
|
12052
|
+
},
|
|
12053
|
+
{
|
|
12054
|
+
"kind": "method",
|
|
12055
|
+
"name": "forwardSubAgent",
|
|
12056
|
+
"return": {
|
|
12057
|
+
"type": {
|
|
12058
|
+
"text": "void"
|
|
12059
|
+
}
|
|
12060
|
+
},
|
|
12061
|
+
"parameters": [
|
|
12062
|
+
{
|
|
12063
|
+
"name": "childSnapshots",
|
|
12064
|
+
"type": {
|
|
12065
|
+
"text": "ReadonlyArray<TurnSnapshot>"
|
|
12066
|
+
}
|
|
12067
|
+
}
|
|
12068
|
+
],
|
|
12069
|
+
"description": "Merge a sub-agent's turn snapshots into this driver's buffer so they surface\nas `kind:'turn'` entries in the exported debug log. The child runs as a\nseparate, discarded driver, so its snapshots would otherwise be lost. Each is\nre-labelled under the parent turn that activated the sub-agent: the child's\nown (numeric) turns become `\"<parentTurn>-1\"`, `\"-2\"`, … (1-based, in order);\nany already-forwarded grand-child labels (strings) have their leading segment\nremapped the same way, so nesting composes (`\"5-2\"` → `\"5-2-1\"`).\n\nNote: two sub-agents invoked in the *same* parent turn share the prefix, so\ntheir labels can repeat — `agentName` on each snapshot disambiguates them."
|
|
12070
|
+
},
|
|
12071
|
+
{
|
|
12072
|
+
"kind": "method",
|
|
12073
|
+
"name": "foldDiagnostics",
|
|
12074
|
+
"return": {
|
|
12075
|
+
"type": {
|
|
12076
|
+
"text": "void"
|
|
12077
|
+
}
|
|
12078
|
+
},
|
|
12079
|
+
"parameters": [
|
|
12080
|
+
{
|
|
12081
|
+
"name": "interactionId",
|
|
12082
|
+
"type": {
|
|
12083
|
+
"text": "string"
|
|
12084
|
+
}
|
|
12085
|
+
},
|
|
12086
|
+
{
|
|
12087
|
+
"name": "harvested",
|
|
12088
|
+
"type": {
|
|
12089
|
+
"text": "unknown"
|
|
12090
|
+
}
|
|
12091
|
+
}
|
|
12092
|
+
],
|
|
12093
|
+
"description": "Fold a widget's out-of-band diagnostics into this session — typically a server-side\nChatDriver's collated log, arriving on `InteractionResult.diagnostics` — so the host's debug\nlog and persisted diagnostics stream include them. Independent of the interaction's own\nmessage: these describe the widget's work, not that message. A non-array or empty harvest is\na no-op."
|
|
12094
|
+
},
|
|
12095
|
+
{
|
|
12096
|
+
"kind": "method",
|
|
12097
|
+
"name": "trim",
|
|
12098
|
+
"privacy": "private",
|
|
12099
|
+
"return": {
|
|
12100
|
+
"type": {
|
|
12101
|
+
"text": "void"
|
|
12102
|
+
}
|
|
12103
|
+
},
|
|
12104
|
+
"description": "Hold the ring buffer at its cap, dropping oldest-first."
|
|
12105
|
+
}
|
|
12106
|
+
]
|
|
12107
|
+
}
|
|
12108
|
+
],
|
|
12109
|
+
"exports": [
|
|
12110
|
+
{
|
|
12111
|
+
"kind": "js",
|
|
12112
|
+
"name": "TurnRecorder",
|
|
12113
|
+
"declaration": {
|
|
12114
|
+
"name": "TurnRecorder",
|
|
12115
|
+
"module": "src/components/chat-driver/turn-recorder.ts"
|
|
12116
|
+
}
|
|
12117
|
+
}
|
|
12118
|
+
]
|
|
12119
|
+
},
|
|
11261
12120
|
{
|
|
11262
12121
|
"kind": "javascript-module",
|
|
11263
12122
|
"path": "src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts",
|
|
@@ -12627,7 +13486,7 @@
|
|
|
12627
13486
|
{
|
|
12628
13487
|
"kind": "variable",
|
|
12629
13488
|
"name": "settingsModalStyles",
|
|
12630
|
-
"default": "css`\n /*\n * Section headings come from the shared fragment the package also exports, so a host titling\n * its own slotted section applies the same rule rather than a copy of it.\n */\n ${assistantSettingsSectionTitleStyles}\n\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n .settings-modal {\n --ai-tier-badge-bg-mix: 14%;\n --ai-tier-badge-text-lighten: 18%;\n }\n\n .settings-modal::part(dialog) {\n max-width: 620px;\n width: calc(100vw - 48px);\n max-height: calc(100vh - 48px);\n padding: 0;\n }\n\n .settings-modal::part(content) {\n display: flex;\n flex-direction: column;\n min-height: 0;\n padding: 0;\n width: 100%;\n }\n\n .settings-modal::part(top) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal::part(bottom) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-top: 1px solid var(--neutral-stroke-rest);\n border-bottom-left-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n border-bottom-right-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n background-color: var(--neutral-layer-2);\n }\n\n .settings-modal-header {\n display: flex;\n align-items: center;\n min-width: 0;\n }\n\n .settings-modal-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-content {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n }\n\n .settings-modal-tabs::part(tablist) {\n border-bottom: 0;\n padding: 0 calc(var(--design-unit) * 5px);\n column-gap: calc(var(--design-unit) * 5px);\n }\n\n .settings-modal-tabs::part(activeIndicator) {\n height: 2px;\n }\n\n .settings-modal-tab {\n padding: 0;\n font-weight: 600;\n gap: 6px;\n }\n\n .settings-modal-tab[aria-selected='true'] {\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-tabs::part(tabpanel) {\n border-top: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-tab-panel {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n padding: 0;\n border-radius: 0;\n }\n\n .settings-modal-tab-panel[hidden] {\n display: none !important;\n }\n\n .settings-modal-body {\n overflow-y: auto;\n padding: 0 calc(var(--design-unit) * 5px) calc(var(--design-unit) * 2px);\n max-height: min(60vh, 520px);\n }\n\n .settings-modal-section {\n padding: calc(var(--design-unit) * 5px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-section:last-child {\n border-bottom: none;\n }\n\n /*\n * Only the spacing. Everything else about this heading comes from the exported fragment\n * above, which the assistant and its hosts share; margin is deliberately not in there,\n * since the gap below a heading depends on the layout around it.\n */\n .ai-settings-section-title {\n margin: 0 0 calc(var(--design-unit) * 3px);\n }\n\n .settings-modal-section-note {\n margin: calc(var(--design-unit) * -2px) 0 calc(var(--design-unit) * 3px);\n font-size: 12px;\n line-height: 1.5;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-modal-section-body {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-toggle-row {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 3px);\n padding: 0 0 calc(var(--design-unit) * 4px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-toggle-row:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-row.is-stacked {\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * For rows whose control is a button rather than a switch. The base row top-aligns, which suits\n * a switch (it lands level with the title), but a button is tall enough that top-aligning leaves\n * it above the title-plus-description block it acts on.\n */\n .settings-toggle-row.is-centered {\n align-items: center;\n }\n\n .settings-animation-list {\n display: flex;\n flex-direction: column;\n width: 100%;\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.2px);\n padding: calc(var(--design-unit) * 2px);\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-list .settings-toggle-row {\n border: 0;\n }\n\n .settings-animation-category {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-animation-category-label {\n font-weight: 600;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-toggle-row + .settings-animation-category-label {\n border-top: 1px solid var(--neutral-stroke-rest);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-option {\n padding: 0;\n margin: 0;\n }\n\n .settings-animation-option:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-toggle-text {\n flex: 1;\n min-width: 0;\n }\n\n .settings-toggle-title {\n font-size: 14px;\n font-weight: 500;\n color: var(--neutral-foreground-rest);\n }\n\n .settings-toggle-desc {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.5;\n max-width: 92%;\n }\n\n .settings-toggle-control {\n flex: 0 0 auto;\n min-width: 0;\n }\n\n .settings-toggle-control-wide {\n width: 100%;\n max-width: 280px;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-desc {\n max-width: none;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-control-wide {\n width: 100%;\n max-width: none;\n }\n\n /*\n * Sub-heading over the provider toggle group. Unlike the section headings it sits INSIDE\n * .settings-modal-section-body, so the parent's 4-unit flex gap already separates it from the\n * first toggle — and flex does not collapse margins, so the shared rule's 3-unit margin-bottom\n * would add to that gap rather than replace it, leaving the label adrift from the rows it\n * names. Zero the margin and pull back 2 of the 4 gap units, expressed in the same token so it\n * tracks if that gap changes.\n */\n .settings-app-toggles-title {\n margin: 0 0 calc(var(--design-unit) * -2px);\n }\n\n .settings-app-toggle-block {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-hint {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.4;\n padding-left: calc(var(--design-unit) * 1px);\n font-style: italic;\n }\n\n /*\n * The budget meter (GENC-1464) is the context indicator's money sibling and\n * shares its row anatomy 1:1, so the budget classes JOIN these rules rather\n * than restating them — one place to restyle the header/label/figures shape,\n * and the two indicators cannot drift apart. Design-system tokens only, and\n * unfallbacked: every token here ships a DS default, so a var(--x, y)\n * fallback would be dead code that hides a broken token name (#2411/#2436\n * review rule, pinned by settings-modal.styles.test.ts).\n */\n .settings-context-header,\n .settings-budget-header {\n display: flex;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 2px);\n font-size: 12px;\n }\n\n .settings-context-label,\n .settings-budget-label {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n }\n\n .settings-context-tokens,\n .settings-budget-figures {\n color: var(--neutral-foreground-rest);\n }\n\n /* Freshness footer (GENC-1464): refresh button + label under the vendor\n rows, left-aligned — a footnote to the figures above it. The button's\n inline padding is pinned and cancelled by the container margin so the\n ICON GLYPH (not the button box) sits flush with the budget labels'\n left edge, whatever the density tokens say. */\n .settings-budget-toolbar {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n gap: 4px;\n margin-inline-start: -4px;\n }\n\n .settings-budget-refresh::part(control) {\n padding-inline: 4px;\n }\n\n .settings-budget-updated {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n }\n\n /*\n * ONE rhythm for every meter row. The outer wrapper holds the context\n * indicator and the budget meter; the inner one holds the budget meter's\n * vendor rows — and both gap by the same 2 units (half the section body's 4)\n * so that visually identical meter rows are evenly spaced whatever mix of\n * them is on screen. Without the wrapper the context row inherits the body's\n * 4-unit gap while the vendor rows keep 2, and three identical-looking rows\n * read as an uneven 4/2/2. The wrapper renders only when at least one meter\n * does — see settingsUsageMetersTemplate for why an always-on one would cost\n * a stray gap.\n */\n .settings-usage-meters,\n .settings-budget-usage {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-current-build,\n .settings-lifetime-usage {\n background: var(--neutral-layer-2);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n margin: calc(var(--design-unit) * 3px) 0;\n }\n\n /*\n * Deliberately quieter than the live block: no pulsing badge and no accent, so the eye lands\n * on what is being built now — which is why that block leads the tab and this one follows,\n * under the history heading whose rows it totals.\n */\n .settings-lifetime-usage-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-lifetime-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-current-build-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n /*\n * Optically centring these 10px caps against the 14px project name beside them. Flex offers\n * only two alignments and neither lands it, because a box centre and a text baseline are\n * different lines:\n * - align-items: center sits the badge baseline about 1.2px high\n * - align-items: baseline matches baselines, but the caps then read as bottom-aligned\n * against the name's ascenders, so the badge looks low\n * The eye wants the midpoint, so: centre the boxes, then translate down by the ~1px of\n * overshoot. This is a nudge, but it corrects a fixed relationship between two font sizes\n * rather than some neighbouring element's layout, so unlike a margin tuned to a sibling it\n * cannot rot when that sibling changes. In em, so it tracks the badge text.\n *\n * display: block, not inline-flex: a flex container has no text baseline of its own and\n * synthesizes one from its first child, which here is the dot, an empty span. As a block box\n * the badge takes the baseline of its first line, i.e. the text.\n */\n .settings-live-badge {\n display: block;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--accent-fill-rest);\n white-space: nowrap;\n transform: translateY(0.1em);\n }\n\n .settings-live-dot {\n display: inline-block;\n width: 7px;\n height: 7px;\n\n /* Replaces the flex gap the badge no longer has. */\n margin-right: calc(var(--design-unit) * 1px);\n\n /* Centres the dot on the text beside it without disturbing that text's baseline. */\n vertical-align: middle;\n border-radius: 50%;\n background: var(--accent-fill-rest);\n animation: settings-live-pulse 1.6s ease-out infinite;\n }\n\n @keyframes settings-live-pulse {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-fill-rest) 55%, transparent);\n }\n\n 70% {\n box-shadow: 0 0 0 7px transparent;\n }\n\n 100% {\n box-shadow: 0 0 0 0 transparent;\n }\n }\n\n .settings-current-build-name {\n font-size: 14px;\n line-height: 1;\n font-weight: 600;\n }\n\n /*\n * Cost and the token buckets side by side: one number in its own box, the four buckets\n * sharing the box next to it. Stretch, so the two are the same height however tall the 22px\n * cost value makes the left one.\n */\n .settings-usage-row {\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n gap: calc(var(--design-unit) * 3px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-usage-row-tokens {\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .settings-build-stat {\n min-width: 0;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n padding: calc(var(--design-unit) * 3px);\n }\n\n .settings-build-stat-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-build-stat-value {\n font-size: 22px;\n font-weight: 700;\n margin-top: calc(var(--design-unit) * 1px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-build-stat-value .prefix,\n .settings-build-stat-value .suffix {\n color: var(--accent-fill-rest);\n }\n\n /*\n * Per-bucket token split, beneath the headline cost. Small paired label/value cells\n * rather than four more stat cards: they are the detail behind the cost above, so they\n * have to read as subordinate to it rather than compete with it. The four buckets ARE\n * the token figure now — there is no merged total anywhere for them to break down.\n */\n .settings-token-breakdown {\n display: flex;\n flex-direction: column;\n\n /*\n * Tight against the buckets below. One design unit rather than two, because each bucket\n * separates its own label from its value by only 2px — at two units the title sat four\n * times further from the bucket labels than they sit from their own numbers, which read\n * as a gap between unrelated blocks instead of a heading over its content.\n */\n gap: calc(var(--design-unit) * 1px);\n margin-bottom: calc(var(--design-unit) * 3px);\n padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n }\n\n /*\n * Titles the box, because nothing else in it named the unit. Same styling and position as\n * the cost box's label, so two boxes sitting side by side are titled the same way; the\n * hierarchy against the bucket labels comes from position, not a second type size.\n */\n .settings-token-breakdown-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-token-buckets {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-token-bucket {\n display: flex;\n\n /*\n * min-content (not 0) so a bucket cannot be shrunk narrower than its own unbreakable label.\n * With the label set to nowrap, a zero minimum would overflow it into the next column instead\n * of wrapping — so the container's flex-wrap takes over and moves a bucket to a second row,\n * which is the degradation we want when the modal is dragged narrow.\n */\n min-width: min-content;\n flex-direction: column;\n gap: 2px;\n }\n\n .settings-token-bucket-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n\n /*\n * One line, always. The rate marker is a separate inline box after collapsible whitespace, so\n * a wrappable label gives it a break opportunity of its own — in a narrow column it orphaned\n * onto line 2, which also pushed that bucket's value a line below the other three and broke\n * the row of figures. nowrap removes every break opportunity in the label, the space before\n * the marker included, so no glue character is needed.\n */\n white-space: nowrap;\n }\n\n .settings-token-bucket-value {\n font-size: 13px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n }\n\n /*\n * The price-direction marker on a cache bucket's label — down for reads (a fraction of the\n * uncached input rate), up for writes (a premium over it). Three tiers, so a bucket with no\n * marker is the reference rate rather than an unlabelled fourth case.\n *\n * Carried by the label rather than the value, which is what this used to do: cache reads are\n * usually the largest bucket by a wide margin in an agentic session, so the value was muted to\n * stop the biggest number reading as the dominant cost driver. That priced the treatment to the\n * wrong thing — a dimmed 0 (every Gemini cache write) looked disabled next to a normal 0, and a\n * rate is a property of the bucket, not of this turn's figure.\n *\n * Sized down and nudged up rather than tinted: the label is already the hint colour, so a\n * dimmer marker would vanish and a brighter one would out-shout the word it qualifies.\n */\n .settings-token-bucket-rate {\n font-size: 8px;\n line-height: 1;\n vertical-align: 0.15em;\n letter-spacing: 0;\n }\n\n /*\n * Usage-row overrides. Placed after the base rules they refine rather than up beside\n * .settings-usage-row itself, because stylelint's no-descending-specificity rejects a\n * compound selector appearing before the plain one it overrides.\n */\n\n /* Sized by its content; the buckets take the rest, since four cells need the width. */\n .settings-usage-row > .settings-build-stat {\n flex: 0 1 auto;\n }\n\n .settings-usage-row .settings-token-breakdown {\n flex: 1 1 auto;\n\n /* The row owns the spacing now; this centres the column against the taller cost box. */\n justify-content: center;\n margin-bottom: 0;\n }\n\n /*\n * Basis auto, not 0: a zero basis splits the row into four equal columns, so CACHE WRITE is\n * squeezed exactly as hard as INPUT despite being twice the label. Sizing from content gives the\n * long labels the room their text needs and lets the short ones concede it, which is what makes\n * white-space: nowrap above safe — every column starts at least as wide as its own content,\n * then shares the slack. Still grows and shrinks, so the four stay flush edge to edge.\n */\n .settings-usage-row .settings-token-bucket {\n flex: 1 1 auto;\n }\n\n .settings-model-tags {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-model-tag {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 9px;\n border-radius: 20px;\n font-family: ui-monospace, monospace;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-model-tag,\n .settings-cost-history-icon {\n --model-tag-color: var(--neutral-foreground-rest);\n\n background: color-mix(\n in srgb,\n var(--model-tag-color) var(--ai-tier-badge-bg-mix),\n var(--neutral-layer-1)\n );\n border-color: color-mix(in srgb, var(--model-tag-color) 20%, var(--neutral-layer-1));\n color: color-mix(in srgb, var(--model-tag-color), white var(--ai-tier-badge-text-lighten));\n }\n\n .settings-cost-history-title {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--neutral-foreground-hint);\n font-weight: 600;\n margin: calc(var(--design-unit) * 4px) 0 calc(var(--design-unit) * 2px);\n }\n\n /*\n * The heading labels the lifetime card as well as the rows, so the card gives up its own top\n * margin and the gap becomes the heading's alone. Adjacent siblings collapse to the LARGER of\n * the two margins, so leaving both would space the caps 3 units off the block they label while\n * the rows below sit at 2 — reading as though the heading belonged to neither.\n */\n .settings-cost-history-title + .settings-lifetime-usage {\n margin-top: 0;\n }\n\n .settings-cost-history {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-icon {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n border-radius: calc(var(--control-corner-radius) * 1px);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 700;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-cost-history-row {\n display: flex;\n flex-direction: column;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n }\n\n .settings-cost-history-row-content {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * All of these carry a ?hidden binding, and all declare display: flex — which silently beat the\n * UA [hidden] { display: none } rule, because author-origin declarations outrank user-agent\n * origin whatever the specificity. Without this, showTokens: false still rendered the full\n * breakdown in the lifetime block, the live block and every history row, and an empty row list\n * still occupied its padding under the lifetime total. Sibling elements that hide correctly do\n * so only by declaring no display at all. Same treatment as .settings-modal-tab-panel[hidden]\n * near the top of this file.\n */\n .settings-usage-row-tokens[hidden],\n .settings-cost-history[hidden],\n .settings-cost-history-row-content[hidden] {\n display: none !important;\n }\n\n /*\n * The buckets inside a history row drop the panel treatment they carry in the summary\n * blocks — the row is already a bordered card, and a second box inside it reads as a\n * nested panel. The adjacent-sibling rule above supplies the separator instead.\n */\n .settings-cost-history-row-breakdown .settings-token-breakdown {\n flex: 1 1 auto;\n margin-bottom: 0;\n padding: 0;\n background: none;\n border: none;\n }\n\n .settings-cost-history-row-content + .settings-cost-history-row-content {\n border-top: 1px solid var(--neutral-stroke-rest);\n margin-top: calc(var(--design-unit) * 2px);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-row-body {\n flex: 1 1 auto;\n min-width: 0;\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n justify-content: space-between;\n }\n\n /*\n * Holds the cost and the delete button as one centred pair. The button used to be a sibling\n * of the whole row body, kept in place by a -2px nudge tuned for when the metrics column had\n * two lines (cost plus a merged token total). Dropping that second line left the nudge\n * compensating for nothing. Centring the two against each other needs no magic number and\n * cannot drift again if the metrics content changes.\n *\n * NB this rule previously set align-items with no display:flex, so it had no effect at all.\n */\n .settings-cost-history-row-right {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 1px);\n flex: 0 0 auto;\n }\n\n .settings-cost-history-row-cost,\n .settings-cost-history-row-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n min-width: 0;\n }\n\n .settings-cost-history-row-metrics {\n display: flex;\n flex-direction: column;\n flex: 0 0 auto;\n font-size: 13px;\n font-family: ui-monospace, monospace;\n color: var(--neutral-foreground-rest);\n white-space: nowrap;\n }\n\n .settings-cost-history-row-date {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete {\n flex: 0 0 auto;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete:hover {\n color: var(--error-color);\n }\n\n .settings-cost-history ::slotted(*) {\n display: block;\n }\n\n .settings-modal-footer {\n width: 100%;\n }\n\n .settings-done-button {\n margin-left: auto;\n }\n\n .settings-modal-footer-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n width: 100%;\n }\n\n .settings-disclaimer {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n max-width: 60%;\n line-height: 1.4;\n }\n\n /*\n * Inline spinner shown in the \"Download agent log\" button while the log builds\n * (GENC-1351 §5.8) — the lifetime-stitch path is an async provider round-trip.\n * Sized to the button label and tinted with currentColor so it tracks the\n * button's text colour in every appearance / theme.\n */\n [part='download-button'] .download-spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n margin-right: calc(var(--design-unit) * 1px);\n vertical-align: -1px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: download-spin 0.6s linear infinite;\n }\n\n @keyframes download-spin {\n to {\n transform: rotate(360deg);\n }\n }\n`",
|
|
13489
|
+
"default": "css`\n /*\n * Section headings come from the shared fragment the package also exports, so a host titling\n * its own slotted section applies the same rule rather than a copy of it.\n */\n ${assistantSettingsSectionTitleStyles}\n\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n .settings-modal {\n --ai-tier-badge-bg-mix: 14%;\n --ai-tier-badge-text-lighten: 18%;\n }\n\n .settings-modal::part(dialog) {\n max-width: 620px;\n width: calc(100vw - 48px);\n max-height: calc(100vh - 48px);\n padding: 0;\n }\n\n .settings-modal::part(content) {\n display: flex;\n flex-direction: column;\n min-height: 0;\n padding: 0;\n width: 100%;\n }\n\n .settings-modal::part(top) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal::part(bottom) {\n padding: calc(var(--design-unit) * 4px) calc(var(--design-unit) * 5px);\n border-top: 1px solid var(--neutral-stroke-rest);\n border-bottom-left-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n border-bottom-right-radius: var(--card-border-radius, calc(var(--control-corner-radius) * 1px));\n background-color: var(--neutral-layer-2);\n }\n\n .settings-modal-header {\n display: flex;\n align-items: center;\n min-width: 0;\n }\n\n .settings-modal-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-content {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n }\n\n .settings-modal-tabs::part(tablist) {\n border-bottom: 0;\n padding: 0 calc(var(--design-unit) * 5px);\n column-gap: calc(var(--design-unit) * 5px);\n }\n\n .settings-modal-tabs::part(activeIndicator) {\n height: 2px;\n }\n\n .settings-modal-tab {\n padding: 0;\n font-weight: 600;\n gap: 6px;\n }\n\n .settings-modal-tab[aria-selected='true'] {\n color: var(--neutral-foreground-rest);\n }\n\n .settings-modal-tabs::part(tabpanel) {\n border-top: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-tab-panel {\n display: flex;\n flex-direction: column;\n min-height: 0;\n flex: 1 1 auto;\n padding: 0;\n border-radius: 0;\n }\n\n .settings-modal-tab-panel[hidden] {\n display: none !important;\n }\n\n .settings-modal-body {\n overflow-y: auto;\n padding: 0 calc(var(--design-unit) * 5px) calc(var(--design-unit) * 2px);\n max-height: min(60vh, 520px);\n }\n\n .settings-modal-section {\n padding: calc(var(--design-unit) * 5px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-modal-section:last-child {\n border-bottom: none;\n }\n\n /*\n * Only the spacing. Everything else about this heading comes from the exported fragment\n * above, which the assistant and its hosts share; margin is deliberately not in there,\n * since the gap below a heading depends on the layout around it.\n */\n .ai-settings-section-title {\n margin: 0 0 calc(var(--design-unit) * 3px);\n }\n\n .settings-modal-section-note {\n margin: calc(var(--design-unit) * -2px) 0 calc(var(--design-unit) * 3px);\n font-size: 12px;\n line-height: 1.5;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-modal-section-body {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-toggle-row {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 3px);\n padding: 0 0 calc(var(--design-unit) * 4px) 0;\n border-bottom: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-toggle-row:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-row.is-stacked {\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * For rows whose control is a button rather than a switch. The base row top-aligns, which suits\n * a switch (it lands level with the title), but a button is tall enough that top-aligning leaves\n * it above the title-plus-description block it acts on.\n */\n .settings-toggle-row.is-centered {\n align-items: center;\n }\n\n .settings-animation-list {\n display: flex;\n flex-direction: column;\n width: 100%;\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.2px);\n padding: calc(var(--design-unit) * 2px);\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-list .settings-toggle-row {\n border: 0;\n }\n\n .settings-animation-category {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-animation-category-label {\n font-weight: 600;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-toggle-row + .settings-animation-category-label {\n border-top: 1px solid var(--neutral-stroke-rest);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-animation-option {\n padding: 0;\n margin: 0;\n }\n\n .settings-animation-option:last-child {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-toggle-text {\n flex: 1;\n min-width: 0;\n }\n\n .settings-toggle-title {\n font-size: 14px;\n font-weight: 500;\n color: var(--neutral-foreground-rest);\n }\n\n .settings-toggle-desc {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.5;\n max-width: 92%;\n }\n\n .settings-toggle-control {\n flex: 0 0 auto;\n min-width: 0;\n }\n\n .settings-toggle-control-wide {\n width: 100%;\n max-width: 280px;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-desc {\n max-width: none;\n }\n\n .settings-toggle-row.is-stacked .settings-toggle-control-wide {\n width: 100%;\n max-width: none;\n }\n\n /*\n * Sub-heading over the provider toggle group. Unlike the section headings it sits INSIDE\n * .settings-modal-section-body, so the parent's 4-unit flex gap already separates it from the\n * first toggle — and flex does not collapse margins, so the shared rule's 3-unit margin-bottom\n * would add to that gap rather than replace it, leaving the label adrift from the rows it\n * names. Zero the margin and pull back 2 of the 4 gap units, expressed in the same token so it\n * tracks if that gap changes.\n */\n .settings-app-toggles-title {\n margin: 0 0 calc(var(--design-unit) * -2px);\n }\n\n .settings-app-toggle-block {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 1px);\n }\n\n .settings-toggle-hint {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n line-height: 1.4;\n padding-left: calc(var(--design-unit) * 1px);\n font-style: italic;\n }\n\n /*\n * The budget meter (GENC-1464) is the context indicator's money sibling and\n * shares its row anatomy 1:1, so the budget classes JOIN these rules rather\n * than restating them — one place to restyle the header/label/figures shape,\n * and the two indicators cannot drift apart. Design-system tokens only, and\n * unfallbacked: every token here ships a DS default, so a var(--x, y)\n * fallback would be dead code that hides a broken token name (#2411/#2436\n * review rule, pinned by settings-modal.styles.test.ts).\n */\n .settings-context-header,\n .settings-budget-header {\n display: flex;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 2px);\n font-size: 12px;\n }\n\n .settings-context-label,\n .settings-budget-label {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n }\n\n .settings-context-tokens,\n .settings-budget-figures {\n color: var(--neutral-foreground-rest);\n }\n\n /* Freshness footer (GENC-1464): refresh button + label under the vendor\n rows, left-aligned — a footnote to the figures above it. The button's\n inline padding is pinned and cancelled by the container margin so the\n ICON GLYPH (not the button box) sits flush with the budget labels'\n left edge, whatever the density tokens say. */\n .settings-budget-toolbar {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n gap: 4px;\n margin-inline-start: -4px;\n }\n\n .settings-budget-refresh::part(control) {\n padding-inline: 4px;\n }\n\n .settings-budget-updated {\n color: var(--neutral-foreground-hint);\n font-size: 11px;\n }\n\n /*\n * ONE rhythm for every meter row. The outer wrapper holds the context\n * indicator and the budget meter; the inner one holds the budget meter's\n * vendor rows — and both gap by the same 2 units (half the section body's 4)\n * so that visually identical meter rows are evenly spaced whatever mix of\n * them is on screen. Without the wrapper the context row inherits the body's\n * 4-unit gap while the vendor rows keep 2, and three identical-looking rows\n * read as an uneven 4/2/2. The wrapper renders only when at least one meter\n * does — see settingsUsageMetersTemplate for why an always-on one would cost\n * a stray gap.\n */\n .settings-usage-meters,\n .settings-budget-usage {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-current-build,\n .settings-lifetime-usage {\n background: var(--neutral-layer-2);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n margin: calc(var(--design-unit) * 3px) 0;\n }\n\n /*\n * Deliberately quieter than the live block: no pulsing badge and no accent, so the eye lands\n * on what is being built now — which is why that block leads the tab and this one follows,\n * under the history heading whose rows it totals.\n */\n .settings-lifetime-usage-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-lifetime-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-current-build-top {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n /*\n * Optically centring these 10px caps against the 14px project name beside them. Flex offers\n * only two alignments and neither lands it, because a box centre and a text baseline are\n * different lines:\n * - align-items: center sits the badge baseline about 1.2px high\n * - align-items: baseline matches baselines, but the caps then read as bottom-aligned\n * against the name's ascenders, so the badge looks low\n * The eye wants the midpoint, so: centre the boxes, then translate down by the ~1px of\n * overshoot. This is a nudge, but it corrects a fixed relationship between two font sizes\n * rather than some neighbouring element's layout, so unlike a margin tuned to a sibling it\n * cannot rot when that sibling changes. In em, so it tracks the badge text.\n *\n * display: block, not inline-flex: a flex container has no text baseline of its own and\n * synthesizes one from its first child, which here is the dot, an empty span. As a block box\n * the badge takes the baseline of its first line, i.e. the text.\n */\n .settings-live-badge {\n display: block;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--accent-fill-rest);\n white-space: nowrap;\n transform: translateY(0.1em);\n }\n\n .settings-live-dot {\n display: inline-block;\n width: 7px;\n height: 7px;\n\n /* Replaces the flex gap the badge no longer has. */\n margin-right: calc(var(--design-unit) * 1px);\n\n /* Centres the dot on the text beside it without disturbing that text's baseline. */\n vertical-align: middle;\n border-radius: 50%;\n background: var(--accent-fill-rest);\n animation: settings-live-pulse 1.6s ease-out infinite;\n }\n\n @keyframes settings-live-pulse {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-fill-rest) 55%, transparent);\n }\n\n 70% {\n box-shadow: 0 0 0 7px transparent;\n }\n\n 100% {\n box-shadow: 0 0 0 0 transparent;\n }\n }\n\n .settings-current-build-name {\n font-size: 14px;\n line-height: 1;\n font-weight: 600;\n }\n\n /*\n * Cost and the token buckets side by side: one number in its own box, the four buckets\n * sharing the box next to it. Stretch, so the two are the same height however tall the 22px\n * cost value makes the left one.\n */\n .settings-usage-row {\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n gap: calc(var(--design-unit) * 3px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-usage-row-tokens {\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .settings-build-stat {\n min-width: 0;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n padding: calc(var(--design-unit) * 3px);\n }\n\n .settings-build-stat-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-build-stat-value {\n font-size: 22px;\n font-weight: 700;\n margin-top: calc(var(--design-unit) * 1px);\n color: var(--neutral-foreground-rest);\n }\n\n .settings-build-stat-value .prefix,\n .settings-build-stat-value .suffix {\n color: var(--accent-fill-rest);\n }\n\n /*\n * Per-bucket token split, beneath the headline cost. Small paired label/value cells\n * rather than four more stat cards: they are the detail behind the cost above, so they\n * have to read as subordinate to it rather than compete with it. The four buckets ARE\n * the token figure now — there is no merged total anywhere for them to break down.\n */\n .settings-token-breakdown {\n display: flex;\n flex-direction: column;\n\n /*\n * Tight against the buckets below. One design unit rather than two, because each bucket\n * separates its own label from its value by only 2px — at two units the title sat four\n * times further from the bucket labels than they sit from their own numbers, which read\n * as a gap between unrelated blocks instead of a heading over its content.\n */\n gap: calc(var(--design-unit) * 1px);\n margin-bottom: calc(var(--design-unit) * 3px);\n padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n }\n\n /*\n * Titles the box, because nothing else in it named the unit. Same styling and position as\n * the cost box's label, so two boxes sitting side by side are titled the same way; the\n * hierarchy against the bucket labels comes from position, not a second type size.\n */\n .settings-token-breakdown-label {\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-token-buckets {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 4px);\n }\n\n .settings-token-bucket {\n display: flex;\n\n /*\n * min-content (not 0) so a bucket cannot be shrunk narrower than its own unbreakable label.\n * With the label set to nowrap, a zero minimum would overflow it into the next column instead\n * of wrapping — so the container's flex-wrap takes over and moves a bucket to a second row,\n * which is the degradation we want when the modal is dragged narrow.\n */\n min-width: min-content;\n flex-direction: column;\n gap: 2px;\n }\n\n .settings-token-bucket-label {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--neutral-foreground-hint);\n\n /*\n * One line, always. The rate marker is a separate inline box after collapsible whitespace, so\n * a wrappable label gives it a break opportunity of its own — in a narrow column it orphaned\n * onto line 2, which also pushed that bucket's value a line below the other three and broke\n * the row of figures. nowrap removes every break opportunity in the label, the space before\n * the marker included, so no glue character is needed.\n */\n white-space: nowrap;\n }\n\n .settings-token-bucket-value {\n font-size: 13px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n }\n\n /*\n * The price-direction marker on a cache bucket's label — down for reads (a fraction of the\n * uncached input rate), up for writes (a premium over it). Three tiers, so a bucket with no\n * marker is the reference rate rather than an unlabelled fourth case.\n *\n * Carried by the label rather than the value, which is what this used to do: cache reads are\n * usually the largest bucket by a wide margin in an agentic session, so the value was muted to\n * stop the biggest number reading as the dominant cost driver. That priced the treatment to the\n * wrong thing — a dimmed 0 (every Gemini cache write) looked disabled next to a normal 0, and a\n * rate is a property of the bucket, not of this turn's figure.\n *\n * Sized down and nudged up rather than tinted: the label is already the hint colour, so a\n * dimmer marker would vanish and a brighter one would out-shout the word it qualifies.\n */\n .settings-token-bucket-rate {\n font-size: 8px;\n line-height: 1;\n vertical-align: 0.15em;\n letter-spacing: 0;\n }\n\n /*\n * Usage-row overrides. Placed after the base rules they refine rather than up beside\n * .settings-usage-row itself, because stylelint's no-descending-specificity rejects a\n * compound selector appearing before the plain one it overrides.\n */\n\n /* Sized by its content; the buckets take the rest, since four cells need the width. */\n .settings-usage-row > .settings-build-stat {\n flex: 0 1 auto;\n }\n\n .settings-usage-row .settings-token-breakdown {\n flex: 1 1 auto;\n\n /* The row owns the spacing now; this centres the column against the taller cost box. */\n justify-content: center;\n margin-bottom: 0;\n }\n\n /*\n * Basis auto, not 0: a zero basis splits the row into four equal columns, so CACHE WRITE is\n * squeezed exactly as hard as INPUT despite being twice the label. Sizing from content gives the\n * long labels the room their text needs and lets the short ones concede it, which is what makes\n * white-space: nowrap above safe — every column starts at least as wide as its own content,\n * then shares the slack. Still grows and shrinks, so the four stay flush edge to edge.\n */\n .settings-usage-row .settings-token-bucket {\n flex: 1 1 auto;\n }\n\n .settings-model-tags {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .settings-model-tag {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 9px;\n border-radius: 20px;\n font-family: ui-monospace, monospace;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-model-tag,\n .settings-cost-history-icon {\n --model-tag-color: var(--neutral-foreground-rest);\n\n background: color-mix(\n in srgb,\n var(--model-tag-color) var(--ai-tier-badge-bg-mix),\n var(--neutral-layer-1)\n );\n border-color: color-mix(in srgb, var(--model-tag-color) 20%, var(--neutral-layer-1));\n color: color-mix(in srgb, var(--model-tag-color), white var(--ai-tier-badge-text-lighten));\n }\n\n .settings-cost-history-title {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--neutral-foreground-hint);\n font-weight: 600;\n margin: calc(var(--design-unit) * 4px) 0 calc(var(--design-unit) * 2px);\n }\n\n /*\n * The heading labels the lifetime card as well as the rows, so the card gives up its own top\n * margin and the gap becomes the heading's alone. Adjacent siblings collapse to the LARGER of\n * the two margins, so leaving both would space the caps 3 units off the block they label while\n * the rows below sit at 2 — reading as though the heading belonged to neither.\n */\n .settings-cost-history-title + .settings-lifetime-usage {\n margin-top: 0;\n }\n\n .settings-cost-history {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n padding-bottom: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-icon {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n border-radius: calc(var(--control-corner-radius) * 1px);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 700;\n border: 1px solid var(--neutral-stroke-rest);\n }\n\n .settings-cost-history-row {\n display: flex;\n flex-direction: column;\n background: var(--neutral-layer-1);\n border: 1px solid var(--neutral-stroke-rest);\n border-radius: calc(var(--control-corner-radius) * 1.5px);\n padding: calc(var(--design-unit) * 4px);\n }\n\n .settings-cost-history-row-content {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * All of these carry a ?hidden binding, and all declare display: flex — which silently beat the\n * UA [hidden] { display: none } rule, because author-origin declarations outrank user-agent\n * origin whatever the specificity. Without this, showTokens: false still rendered the full\n * breakdown in the lifetime block, the live block and every history row, and an empty row list\n * still occupied its padding under the lifetime total. Sibling elements that hide correctly do\n * so only by declaring no display at all. Same treatment as .settings-modal-tab-panel[hidden]\n * near the top of this file.\n */\n .settings-usage-row-tokens[hidden],\n .settings-cost-history[hidden],\n .settings-cost-history-row-content[hidden] {\n display: none !important;\n }\n\n /*\n * The buckets inside a history row drop the panel treatment they carry in the summary\n * blocks — the row is already a bordered card, and a second box inside it reads as a\n * nested panel. The adjacent-sibling rule above supplies the separator instead.\n */\n .settings-cost-history-row-breakdown .settings-token-breakdown {\n flex: 1 1 auto;\n margin-bottom: 0;\n padding: 0;\n background: none;\n border: none;\n }\n\n .settings-cost-history-row-content + .settings-cost-history-row-content {\n border-top: 1px solid var(--neutral-stroke-rest);\n margin-top: calc(var(--design-unit) * 2px);\n padding-top: calc(var(--design-unit) * 2px);\n }\n\n .settings-cost-history-row-body {\n flex: 1 1 auto;\n min-width: 0;\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n justify-content: space-between;\n }\n\n /*\n * Holds the cost and the delete button as one centred pair. The button used to be a sibling\n * of the whole row body, kept in place by a -2px nudge tuned for when the metrics column had\n * two lines (cost plus a merged token total). Dropping that second line left the nudge\n * compensating for nothing. Centring the two against each other needs no magic number and\n * cannot drift again if the metrics content changes.\n *\n * NB this rule previously set align-items with no display:flex, so it had no effect at all.\n */\n .settings-cost-history-row-right {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 1px);\n flex: 0 0 auto;\n }\n\n .settings-cost-history-row-cost,\n .settings-cost-history-row-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--neutral-foreground-rest);\n min-width: 0;\n }\n\n .settings-cost-history-row-metrics {\n display: flex;\n flex-direction: column;\n flex: 0 0 auto;\n font-size: 13px;\n font-family: ui-monospace, monospace;\n color: var(--neutral-foreground-rest);\n white-space: nowrap;\n }\n\n .settings-cost-history-row-date {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete {\n flex: 0 0 auto;\n color: var(--neutral-foreground-hint);\n }\n\n .settings-cost-history-delete:hover {\n color: var(--error-color);\n }\n\n .settings-cost-history ::slotted(*) {\n display: block;\n }\n\n .settings-modal-footer {\n width: 100%;\n }\n\n .settings-done-button {\n margin-left: auto;\n }\n\n .settings-modal-footer-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 2px);\n width: 100%;\n }\n\n .settings-disclaimer {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n max-width: 60%;\n line-height: 1.4;\n }\n\n /* The agent-log row's two actions (Download / Send) side by side. */\n .agent-log-actions {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n }\n\n /*\n * Row + compose box. The row is normally the section's last child (no divider); inside\n * the wrapper it is only the last child while the box is closed, so drop the divider\n * explicitly and let the box supply its own spacing beneath the row.\n */\n .agent-log-block {\n display: flex;\n flex-direction: column;\n }\n\n .agent-log-block .settings-toggle-row {\n border-bottom: none;\n padding-bottom: calc(var(--design-unit) * 1px);\n }\n\n .agent-log-compose {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n margin-top: calc(var(--design-unit) * 2px);\n }\n\n .agent-log-note {\n width: 100%;\n }\n\n .agent-log-note::part(control) {\n width: 100%;\n box-sizing: border-box;\n font-size: 13px;\n line-height: 1.5;\n }\n\n .agent-log-compose-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--design-unit) * 3px);\n }\n\n /* Counter / validation / failure line. Hint-coloured until it carries an error. */\n .agent-log-compose-hint {\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n min-width: 0;\n }\n\n /*\n * Failure state without leaning on --error-color: rapid's fixed brand red is 3.02:1 on a\n * light surface, under AA for 12px text, and the failure line is the one that most needs\n * reading. The contrast-adaptive foreground plus weight carries it; the text itself also\n * changes, so colour was never the only channel.\n */\n .agent-log-compose-hint.is-error {\n color: var(--neutral-foreground-rest);\n font-weight: 600;\n }\n\n /* Screen-reader-only live region for submission outcomes (same recipe as main.styles). */\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n\n /*\n * Inline spinner shown in the agent-log buttons (Download / Send) while the log\n * builds (GENC-1351 §5.8) — the lifetime-stitch path is an async provider\n * round-trip. Sized to the button label and tinted with currentColor so it tracks\n * the button's text colour in every appearance / theme.\n */\n [part='download-button'] .download-spinner,\n [part='submit-log-button'] .download-spinner,\n [part='agent-log-send-button'] .download-spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n margin-right: calc(var(--design-unit) * 1px);\n vertical-align: -1px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: download-spin 0.6s linear infinite;\n }\n\n @keyframes download-spin {\n to {\n transform: rotate(360deg);\n }\n }\n`",
|
|
12631
13490
|
"description": "Styles for the assistant settings modal (tabs, sections, toggles, cost summary)."
|
|
12632
13491
|
}
|
|
12633
13492
|
],
|
|
@@ -12646,6 +13505,54 @@
|
|
|
12646
13505
|
"kind": "javascript-module",
|
|
12647
13506
|
"path": "src/components/settings-modal/settings-modal.template.ts",
|
|
12648
13507
|
"declarations": [
|
|
13508
|
+
{
|
|
13509
|
+
"kind": "function",
|
|
13510
|
+
"name": "timestampModePickerTemplate",
|
|
13511
|
+
"return": {
|
|
13512
|
+
"type": {
|
|
13513
|
+
"text": "ViewTemplate<FoundationAiAssistant>"
|
|
13514
|
+
}
|
|
13515
|
+
},
|
|
13516
|
+
"parameters": [
|
|
13517
|
+
{
|
|
13518
|
+
"name": "segmentedControlTag",
|
|
13519
|
+
"type": {
|
|
13520
|
+
"text": "string"
|
|
13521
|
+
}
|
|
13522
|
+
},
|
|
13523
|
+
{
|
|
13524
|
+
"name": "segmentedItemTag",
|
|
13525
|
+
"type": {
|
|
13526
|
+
"text": "string"
|
|
13527
|
+
}
|
|
13528
|
+
}
|
|
13529
|
+
],
|
|
13530
|
+
"description": "Three-way picker for TimestampDisplay (GENC-1257).\n\nThe design system's segmented control rather than the `switch` every other row uses,\nbecause the setting genuinely has three states — and rather than hand-rolled buttons\ncarrying `role=\"radio\"`, because ARIA roles supply semantics but never behaviour:\npromising a radio group means owning roving `tabindex` and arrow-key navigation.\n\n`SegmentedControl extends FASTRadioGroup` (and `SegmentedItem extends FASTRadio`), so\nthis IS the DS radio group — it inherits the whole keyboard pattern — just skinned as\nsegments rather than dots, which is the right affordance for three short mode labels.\n\nThe usual reason to avoid a DS control here does not apply. `RadioGroup.valueChanged`\nemits `change` whenever `value` is written — including the write this template's own\nbinding performs on render, exactly the phantom-change footgun the DS switch has\n(GENC-1351 #1). It is harmless because the `timestampDisplay` setter guards on\n`preferenceUnchanged`, as every preference setter does, so a render-time echo returns early\nand never reaches the store or marks preferences user-changed."
|
|
13531
|
+
},
|
|
13532
|
+
{
|
|
13533
|
+
"kind": "function",
|
|
13534
|
+
"name": "agentLogSectionTemplate",
|
|
13535
|
+
"return": {
|
|
13536
|
+
"type": {
|
|
13537
|
+
"text": "ViewTemplate<FoundationAiAssistant>"
|
|
13538
|
+
}
|
|
13539
|
+
},
|
|
13540
|
+
"parameters": [
|
|
13541
|
+
{
|
|
13542
|
+
"name": "buttonTag",
|
|
13543
|
+
"type": {
|
|
13544
|
+
"text": "string"
|
|
13545
|
+
}
|
|
13546
|
+
},
|
|
13547
|
+
{
|
|
13548
|
+
"name": "textareaTag",
|
|
13549
|
+
"type": {
|
|
13550
|
+
"text": "string"
|
|
13551
|
+
}
|
|
13552
|
+
}
|
|
13553
|
+
],
|
|
13554
|
+
"description": "The settings \"Agent log\" section: the Download / Send row, the always-present status\nlive region, and the Send button's compose box. Exported (like\n`settingsUsageMetersTemplate`) so `agent-log-section.template.test.ts` can render it on\nan unconnected element and pin what the getters alone cannot show — that the `when`s,\n`?disabled`s and part tokens are actually wired to them."
|
|
13555
|
+
},
|
|
12649
13556
|
{
|
|
12650
13557
|
"kind": "function",
|
|
12651
13558
|
"name": "SettingsModalTemplate",
|
|
@@ -12666,6 +13573,22 @@
|
|
|
12666
13573
|
}
|
|
12667
13574
|
],
|
|
12668
13575
|
"exports": [
|
|
13576
|
+
{
|
|
13577
|
+
"kind": "js",
|
|
13578
|
+
"name": "timestampModePickerTemplate",
|
|
13579
|
+
"declaration": {
|
|
13580
|
+
"name": "timestampModePickerTemplate",
|
|
13581
|
+
"module": "src/components/settings-modal/settings-modal.template.ts"
|
|
13582
|
+
}
|
|
13583
|
+
},
|
|
13584
|
+
{
|
|
13585
|
+
"kind": "js",
|
|
13586
|
+
"name": "agentLogSectionTemplate",
|
|
13587
|
+
"declaration": {
|
|
13588
|
+
"name": "agentLogSectionTemplate",
|
|
13589
|
+
"module": "src/components/settings-modal/settings-modal.template.ts"
|
|
13590
|
+
}
|
|
13591
|
+
},
|
|
12669
13592
|
{
|
|
12670
13593
|
"kind": "js",
|
|
12671
13594
|
"name": "SettingsModalTemplate",
|