@genesislcap/ai-assistant 14.490.0 → 14.491.0-FUI-2567.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/dist/ai-assistant.api.json +6737 -3591
  2. package/dist/ai-assistant.d.ts +879 -183
  3. package/dist/custom-elements.json +1799 -650
  4. package/dist/dts/components/ai-driver/ai-driver.d.ts +32 -8
  5. package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
  6. package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts +2 -0
  7. package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts.map +1 -0
  8. package/dist/dts/components/chat-driver/chat-driver.d.ts +13 -29
  9. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  10. package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts +0 -7
  11. package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts.map +1 -1
  12. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +15 -4
  13. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
  14. package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts +2 -0
  15. package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts.map +1 -0
  16. package/dist/dts/components/popout-manager/popout-manager.d.ts +37 -9
  17. package/dist/dts/components/popout-manager/popout-manager.d.ts.map +1 -1
  18. package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
  19. package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
  20. package/dist/dts/config/config.d.ts +70 -0
  21. package/dist/dts/config/config.d.ts.map +1 -1
  22. package/dist/dts/config/define-stateful-agent.d.ts +73 -1
  23. package/dist/dts/config/define-stateful-agent.d.ts.map +1 -1
  24. package/dist/dts/index.d.ts +1 -0
  25. package/dist/dts/index.d.ts.map +1 -1
  26. package/dist/dts/main/main.d.ts +337 -91
  27. package/dist/dts/main/main.d.ts.map +1 -1
  28. package/dist/dts/main/main.styles.d.ts.map +1 -1
  29. package/dist/dts/main/main.template.d.ts.map +1 -1
  30. package/dist/dts/main/main.types.d.ts +55 -9
  31. package/dist/dts/main/main.types.d.ts.map +1 -1
  32. package/dist/dts/main/popout-interaction-gate.test.d.ts +2 -0
  33. package/dist/dts/main/popout-interaction-gate.test.d.ts.map +1 -0
  34. package/dist/dts/react.d.ts +3 -2
  35. package/dist/dts/state/ai-assistant-slice.d.ts +73 -0
  36. package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
  37. package/dist/dts/state/ai-assistant-slice.test.d.ts +2 -0
  38. package/dist/dts/state/ai-assistant-slice.test.d.ts.map +1 -0
  39. package/dist/dts/state/debug-event-log.d.ts +1 -1
  40. package/dist/dts/state/debug-event-log.d.ts.map +1 -1
  41. package/dist/dts/state/persistence/diagnostics-cursors.d.ts +51 -0
  42. package/dist/dts/state/persistence/diagnostics-cursors.d.ts.map +1 -0
  43. package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts +2 -0
  44. package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts.map +1 -0
  45. package/dist/dts/state/persistence/diagnostics.d.ts +65 -0
  46. package/dist/dts/state/persistence/diagnostics.d.ts.map +1 -0
  47. package/dist/dts/state/persistence/diagnostics.test.d.ts +2 -0
  48. package/dist/dts/state/persistence/diagnostics.test.d.ts.map +1 -0
  49. package/dist/dts/state/persistence/index.d.ts +7 -0
  50. package/dist/dts/state/persistence/index.d.ts.map +1 -0
  51. package/dist/dts/state/persistence/persister-registry.d.ts +22 -0
  52. package/dist/dts/state/persistence/persister-registry.d.ts.map +1 -0
  53. package/dist/dts/state/persistence/session-persistence-provider.d.ts +132 -0
  54. package/dist/dts/state/persistence/session-persistence-provider.d.ts.map +1 -0
  55. package/dist/dts/state/persistence/session-persistence-provider.test.d.ts +2 -0
  56. package/dist/dts/state/persistence/session-persistence-provider.test.d.ts.map +1 -0
  57. package/dist/dts/state/persistence/session-persistence.integration.test.d.ts +2 -0
  58. package/dist/dts/state/persistence/session-persistence.integration.test.d.ts.map +1 -0
  59. package/dist/dts/state/persistence/session-persister.d.ts +173 -0
  60. package/dist/dts/state/persistence/session-persister.d.ts.map +1 -0
  61. package/dist/dts/state/persistence/session-persister.test.d.ts +2 -0
  62. package/dist/dts/state/persistence/session-persister.test.d.ts.map +1 -0
  63. package/dist/dts/state/persistence/session-snapshot.d.ts +218 -0
  64. package/dist/dts/state/persistence/session-snapshot.d.ts.map +1 -0
  65. package/dist/dts/state/persistence/session-snapshot.test.d.ts +2 -0
  66. package/dist/dts/state/persistence/session-snapshot.test.d.ts.map +1 -0
  67. package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts +2 -0
  68. package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts.map +1 -0
  69. package/dist/dts/state/session-store.d.ts +6 -0
  70. package/dist/dts/state/session-store.d.ts.map +1 -1
  71. package/dist/dts/utils/history-transform.d.ts +38 -0
  72. package/dist/dts/utils/history-transform.d.ts.map +1 -1
  73. package/dist/dts/utils/history-transform.test.d.ts +2 -0
  74. package/dist/dts/utils/history-transform.test.d.ts.map +1 -0
  75. package/dist/dts/utils/message-partition.d.ts +27 -0
  76. package/dist/dts/utils/message-partition.d.ts.map +1 -1
  77. package/dist/dts/utils/resolve-preference-baseline.d.ts +43 -0
  78. package/dist/dts/utils/resolve-preference-baseline.d.ts.map +1 -0
  79. package/dist/dts/utils/resolve-preference-baseline.test.d.ts +2 -0
  80. package/dist/dts/utils/resolve-preference-baseline.test.d.ts.map +1 -0
  81. package/dist/dts/utils/with-timeout.d.ts +12 -0
  82. package/dist/dts/utils/with-timeout.d.ts.map +1 -0
  83. package/dist/esm/components/chat-driver/chat-driver.compact.test.js +93 -0
  84. package/dist/esm/components/chat-driver/chat-driver.js +101 -65
  85. package/dist/esm/components/chat-driver/chat-driver.test.js +0 -45
  86. package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.js +17 -35
  87. package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.test.js +0 -62
  88. package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +32 -14
  89. package/dist/esm/components/orchestrating-driver/orchestrating-driver.pin.test.js +61 -0
  90. package/dist/esm/components/popout-manager/popout-manager.js +76 -27
  91. package/dist/esm/components/settings-modal/settings-modal.styles.js +24 -0
  92. package/dist/esm/components/settings-modal/settings-modal.template.js +14 -1
  93. package/dist/esm/config/define-stateful-agent.js +81 -0
  94. package/dist/esm/index.js +1 -0
  95. package/dist/esm/main/main.js +929 -223
  96. package/dist/esm/main/main.styles.js +55 -0
  97. package/dist/esm/main/main.template.js +94 -10
  98. package/dist/esm/main/main.types.js +27 -0
  99. package/dist/esm/main/popout-interaction-gate.test.js +58 -0
  100. package/dist/esm/state/ai-assistant-slice.js +85 -25
  101. package/dist/esm/state/ai-assistant-slice.test.js +85 -0
  102. package/dist/esm/state/debug-event-log.js +10 -0
  103. package/dist/esm/state/persistence/diagnostics-cursors.js +47 -0
  104. package/dist/esm/state/persistence/diagnostics-cursors.test.js +30 -0
  105. package/dist/esm/state/persistence/diagnostics.js +81 -0
  106. package/dist/esm/state/persistence/diagnostics.test.js +72 -0
  107. package/dist/esm/state/persistence/index.js +3 -0
  108. package/dist/esm/state/persistence/persister-registry.js +48 -0
  109. package/dist/esm/state/persistence/session-persistence-provider.js +95 -0
  110. package/dist/esm/state/persistence/session-persistence-provider.test.js +110 -0
  111. package/dist/esm/state/persistence/session-persistence.integration.test.js +109 -0
  112. package/dist/esm/state/persistence/session-persister.js +642 -0
  113. package/dist/esm/state/persistence/session-persister.test.js +314 -0
  114. package/dist/esm/state/persistence/session-snapshot.js +240 -0
  115. package/dist/esm/state/persistence/session-snapshot.test.js +235 -0
  116. package/dist/esm/state/persistence/stateful-restore.e2e.test.js +149 -0
  117. package/dist/esm/utils/history-transform.js +101 -0
  118. package/dist/esm/utils/history-transform.test.js +137 -0
  119. package/dist/esm/utils/message-partition.js +30 -2
  120. package/dist/esm/utils/message-partition.test.js +20 -1
  121. package/dist/esm/utils/resolve-preference-baseline.js +53 -0
  122. package/dist/esm/utils/resolve-preference-baseline.test.js +69 -0
  123. package/dist/esm/utils/with-timeout.js +28 -0
  124. package/dist/react.cjs +6 -1
  125. package/dist/react.mjs +6 -1
  126. package/dist/tsconfig.tsbuildinfo +1 -1
  127. package/docs/migration-GENC-1351.md +172 -0
  128. package/package.json +17 -17
  129. package/src/components/ai-driver/ai-driver.ts +36 -17
  130. package/src/components/chat-driver/chat-driver.compact.test.ts +131 -0
  131. package/src/components/chat-driver/chat-driver.test.ts +0 -71
  132. package/src/components/chat-driver/chat-driver.ts +103 -70
  133. package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts +0 -81
  134. package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts +18 -41
  135. package/src/components/orchestrating-driver/orchestrating-driver.pin.test.ts +96 -0
  136. package/src/components/orchestrating-driver/orchestrating-driver.ts +36 -18
  137. package/src/components/popout-manager/popout-manager.ts +82 -28
  138. package/src/components/settings-modal/settings-modal.styles.ts +24 -0
  139. package/src/components/settings-modal/settings-modal.template.ts +27 -1
  140. package/src/config/config.ts +71 -0
  141. package/src/config/define-stateful-agent.ts +134 -0
  142. package/src/index.ts +1 -0
  143. package/src/main/main.styles.ts +55 -0
  144. package/src/main/main.template.ts +121 -11
  145. package/src/main/main.ts +937 -199
  146. package/src/main/main.types.ts +59 -10
  147. package/src/main/popout-interaction-gate.test.ts +92 -0
  148. package/src/state/ai-assistant-slice.test.ts +114 -0
  149. package/src/state/ai-assistant-slice.ts +134 -25
  150. package/src/state/debug-event-log.ts +22 -1
  151. package/src/state/persistence/diagnostics-cursors.test.ts +53 -0
  152. package/src/state/persistence/diagnostics-cursors.ts +80 -0
  153. package/src/state/persistence/diagnostics.test.ts +95 -0
  154. package/src/state/persistence/diagnostics.ts +110 -0
  155. package/src/state/persistence/index.ts +10 -0
  156. package/src/state/persistence/persister-registry.ts +55 -0
  157. package/src/state/persistence/session-persistence-provider.test.ts +136 -0
  158. package/src/state/persistence/session-persistence-provider.ts +202 -0
  159. package/src/state/persistence/session-persistence.integration.test.ts +134 -0
  160. package/src/state/persistence/session-persister.test.ts +428 -0
  161. package/src/state/persistence/session-persister.ts +689 -0
  162. package/src/state/persistence/session-snapshot.test.ts +327 -0
  163. package/src/state/persistence/session-snapshot.ts +340 -0
  164. package/src/state/persistence/stateful-restore.e2e.test.ts +221 -0
  165. package/src/utils/history-transform.test.ts +197 -0
  166. package/src/utils/history-transform.ts +117 -0
  167. package/src/utils/message-partition.test.ts +27 -1
  168. package/src/utils/message-partition.ts +41 -2
  169. package/src/utils/resolve-preference-baseline.test.ts +84 -0
  170. package/src/utils/resolve-preference-baseline.ts +80 -0
  171. package/src/utils/with-timeout.ts +24 -0
@@ -119,6 +119,14 @@
119
119
  "package": "./config/fallback-agents"
120
120
  }
121
121
  },
122
+ {
123
+ "kind": "js",
124
+ "name": "*",
125
+ "declaration": {
126
+ "name": "*",
127
+ "package": "./state/persistence"
128
+ }
129
+ },
122
130
  {
123
131
  "kind": "js",
124
132
  "name": "*",
@@ -890,6 +898,37 @@
890
898
  "kind": "javascript-module",
891
899
  "path": "src/config/define-stateful-agent.ts",
892
900
  "declarations": [
901
+ {
902
+ "kind": "function",
903
+ "name": "restoreMachine",
904
+ "return": {
905
+ "type": {
906
+ "text": "void"
907
+ }
908
+ },
909
+ "parameters": [
910
+ {
911
+ "name": "machine",
912
+ "type": {
913
+ "text": "{ stop: () => void; start: (options?: { state?: unknown }) => void }"
914
+ },
915
+ "description": "the machine to restore (already constructed/started)."
916
+ },
917
+ {
918
+ "name": "restored",
919
+ "type": {
920
+ "text": "unknown"
921
+ },
922
+ "description": "the agent's serialized image (`ctx.restored` in `init`)."
923
+ },
924
+ {
925
+ "name": "key",
926
+ "default": "'machine'",
927
+ "description": "the property the machine occupies in the snapshot; defaults to\n`'machine'` to match the conventional `{ machine }` state bag."
928
+ }
929
+ ],
930
+ "description": "Restore a foundation-state-machine instance from a snapshot produced by the\ndefault serializer (or `machine.getPersistedSnapshot()`). Call inside a\nstateful agent's `init` to resume the machine in its exact prior place:\n\n```ts\ninit: ({ restored }) => {\n const machine = new MyMachine();\n restoreMachine(machine, restored); // resume, or no-op on a fresh start\n return { machine };\n}\n```\n\nNo-ops when there is nothing to restore (a fresh session), leaving the\nfreshly-constructed machine in its initial state."
931
+ },
893
932
  {
894
933
  "kind": "function",
895
934
  "name": "defineStatefulAgent",
@@ -910,6 +949,14 @@
910
949
  }
911
950
  ],
912
951
  "exports": [
952
+ {
953
+ "kind": "js",
954
+ "name": "restoreMachine",
955
+ "declaration": {
956
+ "name": "restoreMachine",
957
+ "module": "src/config/define-stateful-agent.ts"
958
+ }
959
+ },
913
960
  {
914
961
  "kind": "js",
915
962
  "name": "defineStatefulAgent",
@@ -1106,6 +1153,14 @@
1106
1153
  },
1107
1154
  "default": "'Genesis Assistant'"
1108
1155
  },
1156
+ {
1157
+ "kind": "field",
1158
+ "name": "sessionKey",
1159
+ "type": {
1160
+ "text": "string | undefined"
1161
+ },
1162
+ "description": "Explicit session/persistence key (GENC-1351 §5.12). When set, this is the\nsession identity — the key for the driver/store/persister/diagnostics\nregistries and the `sessionKey` passed to the persistence provider — taking\nprecedence over the DOM `id`. A host that scopes persistence per-entity\n(e.g. one chat session per project) binds this to a stable per-entity id;\nchanging it on a **connected** element re-keys the session in place — tears\ndown the current conversation and restores the new key's — via\n`switchSession`. Falls back to `id` when unset,\nso existing consumers are unaffected."
1163
+ },
1109
1164
  {
1110
1165
  "kind": "field",
1111
1166
  "name": "imageSrc",
@@ -1206,6 +1261,15 @@
1206
1261
  },
1207
1262
  "default": "{}"
1208
1263
  },
1264
+ {
1265
+ "kind": "field",
1266
+ "name": "persistence",
1267
+ "type": {
1268
+ "text": "SessionPersistenceConfig"
1269
+ },
1270
+ "default": "{}",
1271
+ "description": "Optional session persistence (GENC-1351). Off by default — set `enabled`\nand a `provider` (e.g. a `WebStorageSessionProvider`) to have the assistant\nautosave on idle and auto-restore the conversation on page reload. Exposed\nas a top-level property (like `agents`/`providerRegistry`) rather than via\n`chatConfig`, since the provider type lives in this package while\n`ChatConfig` lives in `foundation-ai`."
1272
+ },
1209
1273
  {
1210
1274
  "kind": "field",
1211
1275
  "name": "agentPicker",
@@ -1246,7 +1310,8 @@
1246
1310
  "type": {
1247
1311
  "text": "SessionStoreReturn | undefined"
1248
1312
  },
1249
- "privacy": "private"
1313
+ "privacy": "private",
1314
+ "description": "Pointer to this session's redux store. `@observable` (GENC-1351 §5.12) so that\n**swapping** it — the in-place session switch/re-key (`switchSession`) —\nforces every store-backed getter binding to re-evaluate against the NEW store.\nWithout this, FAST's per-store slice tracking would leave the view subscribed\nto the old store after a swap and it wouldn't re-render. (A same-store reset via\nredux actions re-renders without this; a store *swap* needs it.)"
1250
1315
  },
1251
1316
  {
1252
1317
  "kind": "field",
@@ -1291,6 +1356,16 @@
1291
1356
  "description": "True while a turn is active — `loading` or `cancelling` (a stop was\nrequested but the turn is still winding down). The single \"is a turn\nrunning\" predicate; UI gates use this so `cancelling` behaves like\n`loading` everywhere. `@volatile` so the template re-evaluates it when the\nstore-backed `state` changes.",
1292
1357
  "readonly": true
1293
1358
  },
1359
+ {
1360
+ "kind": "field",
1361
+ "name": "sendBlocked",
1362
+ "type": {
1363
+ "text": "boolean"
1364
+ },
1365
+ "privacy": "private",
1366
+ "description": "True when a new send must be refused: a turn is running (`busy`), a page-reload\nrestore is loading history that would clobber it (`restoring`), or a manual\ncompaction is rewriting history (`compacting`). Mirrors the composer's\n`?disabled` gate so a **programmatic** `send`/`submitMessage` (e.g. a host's\ncustom input while the built-in composer is hidden) can't slip past it and have\nits message wiped when the restored/compacted history lands (GENC-1351 §6).",
1367
+ "readonly": true
1368
+ },
1294
1369
  {
1295
1370
  "kind": "method",
1296
1371
  "name": "applyDeferredAgentsSwap",
@@ -1302,6 +1377,17 @@
1302
1377
  },
1303
1378
  "description": "Re-runs `agentsChanged` if the live `agents` array no longer matches the\nfingerprint of the currently installed driver. Used to apply swaps that\nlanded during a turn (and were skipped by the `isBusy()` guard) once the\ndriver returns to idle."
1304
1379
  },
1380
+ {
1381
+ "kind": "method",
1382
+ "name": "applyDeferredSessionSwitch",
1383
+ "privacy": "private",
1384
+ "return": {
1385
+ "type": {
1386
+ "text": "void"
1387
+ }
1388
+ },
1389
+ "description": "Apply a `session-key` re-key that arrived mid-turn and was deferred by\n`switchSession`'s busy guard (GENC-1351 §5.12). Run at each point the driver\nreturns to idle, BEFORE `applyDeferredAgentsSwap` — a switch rebuilds the\ndriver against the current agents, so a pending agents-swap then no-ops."
1390
+ },
1305
1391
  {
1306
1392
  "kind": "method",
1307
1393
  "name": "maybeAutoFocusChatInput",
@@ -1370,6 +1456,30 @@
1370
1456
  },
1371
1457
  "description": "Whether the agent picker slide-out panel is open. Lives on the session\nstore so the bubble-dialog and popout-panel instances stay in sync."
1372
1458
  },
1459
+ {
1460
+ "kind": "field",
1461
+ "name": "sessionMenuOpen",
1462
+ "type": {
1463
+ "text": "boolean"
1464
+ },
1465
+ "description": "Whether the lifecycle (session) menu slide-out panel is open. Like the\nagent picker, lives on the session store so bubble/popout stay in sync."
1466
+ },
1467
+ {
1468
+ "kind": "field",
1469
+ "name": "compacting",
1470
+ "type": {
1471
+ "text": "boolean"
1472
+ },
1473
+ "description": "Whether a manual compaction is in flight (GENC-1351 §5.7). On the session\nstore (not element-local) so the \"Compacting…\" view + input-disable stay in\nsync across pop-in/out, like the panel flags."
1474
+ },
1475
+ {
1476
+ "kind": "field",
1477
+ "name": "restoring",
1478
+ "type": {
1479
+ "text": "boolean"
1480
+ },
1481
+ "description": "Whether a page-reload restore is in flight (GENC-1351 §6). On the session\nstore (like `compacting`) so the \"Restoring…\" view + input-disable stay in\nsync across pop-in/out. Gating input while true prevents a mid-load send from\nbeing clobbered when the restored history loads."
1482
+ },
1373
1483
  {
1374
1484
  "kind": "field",
1375
1485
  "name": "pinnedAgentName",
@@ -1671,6 +1781,15 @@
1671
1781
  "default": "false",
1672
1782
  "description": "Whether the settings modal is open."
1673
1783
  },
1784
+ {
1785
+ "kind": "field",
1786
+ "name": "downloadingDebugLog",
1787
+ "type": {
1788
+ "text": "boolean"
1789
+ },
1790
+ "default": "false",
1791
+ "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."
1792
+ },
1674
1793
  {
1675
1794
  "kind": "field",
1676
1795
  "name": "settingsModalTab",
@@ -1817,31 +1936,11 @@
1817
1936
  "default": "false",
1818
1937
  "description": "Prevents double-finalize for the same session instance (pagehide + title change)."
1819
1938
  },
1820
- {
1821
- "kind": "field",
1822
- "name": "_finalizeCostSessionOnPageHide",
1823
- "type": {
1824
- "text": "boolean"
1825
- },
1826
- "privacy": "private",
1827
- "default": "true",
1828
- "description": "Only the visible assistant instance should snapshot on tab close (bubble vs docked panel)."
1829
- },
1830
1939
  {
1831
1940
  "kind": "field",
1832
1941
  "name": "_handlePageHide",
1833
1942
  "privacy": "private"
1834
1943
  },
1835
- {
1836
- "kind": "method",
1837
- "name": "_syncFinalizeCostSessionOnPageHide",
1838
- "privacy": "private",
1839
- "return": {
1840
- "type": {
1841
- "text": "void"
1842
- }
1843
- }
1844
- },
1845
1944
  {
1846
1945
  "kind": "field",
1847
1946
  "name": "haloStartPublished",
@@ -1933,13 +2032,6 @@
1933
2032
  "default": "true",
1934
2033
  "description": "True when the user's last interaction (pointer or keyboard focus) was inside\nthe assistant. Defaults to true so the assistant claims focus on first mount.\nAuto-focus features (chat input on idle, widget inputs on mount) gate on this\nto avoid stealing focus from elsewhere on the page."
1935
2034
  },
1936
- {
1937
- "kind": "field",
1938
- "name": "hostId",
1939
- "privacy": "private",
1940
- "readonly": true,
1941
- "description": "GENC-1410 (Error 3): stable id for this assistant view. Reported to the shared driver so it\ncan elect a single owner to render (and run) each interaction's widget when more than one view\n(e.g. a bubble and a docked panel) is wired to the same driver — so it fires once, not per view."
1942
- },
1943
2035
  {
1944
2036
  "kind": "field",
1945
2037
  "name": "_handleGlobalInteraction",
@@ -2021,6 +2113,54 @@
2021
2113
  "privacy": "private",
2022
2114
  "description": "Unsubscribes a one-shot state subscription created when this element connects\nmid-execution. The subscription watches for `state` becoming 'idle' so that\nthis element can stop its loading timer and sync the halo even when the\noriginating `send()` ran on a different element instance."
2023
2115
  },
2116
+ {
2117
+ "kind": "field",
2118
+ "name": "_applyingPreferences",
2119
+ "type": {
2120
+ "text": "boolean"
2121
+ },
2122
+ "privacy": "private",
2123
+ "default": "false",
2124
+ "description": "True while UI preferences are being applied programmatically (config defaults\non connect, or a loaded-preferences restore) — suppresses the save hook so we\ndon't persist config defaults or re-persist what we just loaded. Cleared once\nthe apply completes; a genuine *user* toggle (menu switch) runs with it false\nand saves (GENC-1351)."
2125
+ },
2126
+ {
2127
+ "kind": "field",
2128
+ "name": "_freshStore",
2129
+ "type": {
2130
+ "text": "boolean"
2131
+ },
2132
+ "privacy": "private",
2133
+ "default": "false",
2134
+ "description": "Fresh-store flag (`= isNewStore`) captured in `connectedCallback`. Only a\nfreshly created store takes the config/stored-prefs baseline; an existing\nstore — a reload with a live in-realm store, or the popped-out second instance\n— already holds the correct state, so `applyPreferenceBaseline` no-ops for it."
2135
+ },
2136
+ {
2137
+ "kind": "field",
2138
+ "name": "_sessionActive",
2139
+ "type": {
2140
+ "text": "boolean"
2141
+ },
2142
+ "privacy": "private",
2143
+ "default": "false",
2144
+ "description": "True once `connectedCallback` has fully wired the initial session (GENC-1351\n§5.12). Guards `sessionKeyChanged` so the initial, pre-connect `session-key`\nset doesn't trigger a re-key — only a genuine change to a connected element\nswitches the session. Reset on disconnect."
2145
+ },
2146
+ {
2147
+ "kind": "field",
2148
+ "name": "_activeStateKey",
2149
+ "type": {
2150
+ "text": "string | undefined"
2151
+ },
2152
+ "privacy": "private",
2153
+ "description": "The key of the session currently WIRED to this element (its driver/store/\n`_sessionRef`). Authoritative for `getStateKey()` once a session is active,\nbecause the `session-key` attr can run ahead of an actual switch: a mid-turn\nrebind is deferred to idle (§5.12), and reading the attr in that window would\nretarget autosave/diagnostics at a not-yet-activated key and silently drop the\nrest of the live turn. Set by `activateSession`. Undefined before first connect."
2154
+ },
2155
+ {
2156
+ "kind": "field",
2157
+ "name": "_deferredSwitchToKey",
2158
+ "type": {
2159
+ "text": "string | undefined"
2160
+ },
2161
+ "privacy": "private",
2162
+ "description": "Target key of a `session-key` rebind that arrived mid-turn and was deferred\n(§5.12). Applied by `applyDeferredSessionSwitch` once the driver goes idle. The\nlatest rebind wins if several land while busy. Undefined = no switch pending."
2163
+ },
2024
2164
  {
2025
2165
  "kind": "field",
2026
2166
  "name": "showHalo",
@@ -2149,290 +2289,274 @@
2149
2289
  },
2150
2290
  {
2151
2291
  "kind": "method",
2152
- "name": "resolveContextLimit",
2292
+ "name": "teardownDriver",
2153
2293
  "privacy": "private",
2154
2294
  "return": {
2155
2295
  "type": {
2156
- "text": "Promise<void>"
2296
+ "text": "void"
2157
2297
  }
2158
- }
2159
- },
2160
- {
2161
- "kind": "method",
2162
- "name": "loadProviderStatuses",
2163
- "privacy": "private",
2164
- "return": {
2165
- "type": {
2166
- "text": "Promise<void>"
2298
+ },
2299
+ "parameters": [
2300
+ {
2301
+ "name": "key",
2302
+ "type": {
2303
+ "text": "string | undefined"
2304
+ }
2167
2305
  }
2168
- }
2169
- },
2170
- {
2171
- "kind": "method",
2172
- "name": "chatConfigChanged"
2173
- },
2174
- {
2175
- "kind": "method",
2176
- "name": "showingSplashChanged"
2177
- },
2178
- {
2179
- "kind": "method",
2180
- "name": "syncShowingSplash",
2181
- "privacy": "private"
2306
+ ],
2307
+ "description": "Tear down the session's currently-wired driver (GENC-1351): unwire this view, drop\nthe driver from the registry, and dispose it — which fires the active agent's\n`onDeactivate` → `machine.stop()`. Shared by `agentsChanged`, `clearSession`, and\n`switchSession` so the teardown stays identical. `unwireDriver` does not clear\n`this.driver`, so the instance is still readable here for disposal."
2182
2308
  },
2183
2309
  {
2184
2310
  "kind": "method",
2185
- "name": "handleMessagesUpdate",
2311
+ "name": "rebuildDriver",
2186
2312
  "privacy": "private",
2187
2313
  "return": {
2188
2314
  "type": {
2189
2315
  "text": "void"
2190
2316
  }
2191
2317
  },
2192
- "description": "Runs side effects that were previously in `messagesChanged()`.\nCalled from the `messages` setter after dispatching to the store."
2193
- },
2194
- {
2195
- "kind": "method",
2196
- "name": "showLoadingIndicatorChanged"
2318
+ "parameters": [
2319
+ {
2320
+ "name": "key",
2321
+ "type": {
2322
+ "text": "string"
2323
+ }
2324
+ }
2325
+ ],
2326
+ "description": "Build (or adopt from the registry) a fresh driver for `key` against the current\nagents and wire it to this view (GENC-1351). Records the agents fingerprint so a\nlater `agentsChanged` skips a spurious rebuild. Shared by `agentsChanged` and\n`clearSession`."
2197
2327
  },
2198
2328
  {
2199
2329
  "kind": "method",
2200
- "name": "scrollToBottom",
2201
- "privacy": "private"
2202
- },
2203
- {
2204
- "kind": "field",
2205
- "name": "DEFAULT_LOADING_DELAY_S",
2206
- "type": {
2207
- "text": "number"
2208
- },
2209
- "privacy": "private",
2210
- "static": true,
2211
- "readonly": true,
2212
- "default": "0"
2213
- },
2214
- {
2215
- "kind": "field",
2216
- "name": "DEFAULT_SUGGESTION_COUNT",
2217
- "type": {
2218
- "text": "number"
2219
- },
2220
- "privacy": "private",
2221
- "static": true,
2222
- "readonly": true,
2223
- "default": "3"
2224
- },
2225
- {
2226
- "kind": "field",
2227
- "name": "MS_PER_SECOND",
2228
- "type": {
2229
- "text": "number"
2230
- },
2330
+ "name": "activateSession",
2231
2331
  "privacy": "private",
2232
- "static": true,
2233
- "readonly": true,
2234
- "default": "1000"
2235
- },
2236
- {
2237
- "kind": "method",
2238
- "name": "startLoadingTimer",
2239
- "privacy": "private"
2240
- },
2241
- {
2242
- "kind": "method",
2243
- "name": "clearLoadingTimer",
2244
- "privacy": "private"
2245
- },
2246
- {
2247
- "kind": "method",
2248
- "name": "stopLoadingTimer",
2249
- "privacy": "private"
2250
- },
2251
- {
2252
- "kind": "method",
2253
- "name": "claimSideEffect",
2254
2332
  "return": {
2255
2333
  "type": {
2256
- "text": "boolean"
2334
+ "text": "void"
2257
2335
  }
2258
2336
  },
2259
2337
  "parameters": [
2260
2338
  {
2261
- "name": "interactionId",
2339
+ "name": "key",
2262
2340
  "type": {
2263
2341
  "text": "string"
2264
2342
  }
2343
+ },
2344
+ {
2345
+ "name": "isNewStore",
2346
+ "type": {
2347
+ "text": "boolean"
2348
+ }
2265
2349
  }
2266
2350
  ],
2267
- "description": "GENC-1410 (Error 3): claim the right to run a side-effecting interaction's server work for\nTHIS view, via the shared driver's first-writer-wins latch. Returns `true` when this view may\nrun it (first/owning claimant, or a re-render of the same view), `false` when another view\nalready holds it. Fail-open when the driver has no latch. Called by `ai-chat-interaction-wrapper`."
2351
+ "description": "Wire up the session identified by `key` on this element: preference baseline,\ndriver (build/reuse) + wiring, restore (fresh store only), and the per-session\nview state (splash, loading-resume, suggestions, context/provider status, cost\nhistory). Extracted from `connectedCallback` (GENC-1351 §5.12) so an in-place\nsession switch (`switchSession`) can re-run exactly this against a new\nkey without re-adding element-lifetime listeners. Session-scoped only — the\nelement-lifetime wiring (DOM/document/window listeners, provider-registry\nsubscription, app-settings, pagehide) stays in `connectedCallback`."
2268
2352
  },
2269
2353
  {
2270
2354
  "kind": "method",
2271
- "name": "claimInteractionOwnership",
2355
+ "name": "switchSession",
2272
2356
  "return": {
2273
2357
  "type": {
2274
2358
  "text": "void"
2275
2359
  }
2276
2360
  },
2277
- "description": "GENC-1410 (Error 3): mark THIS view as the interaction owner on the shared driver, so it (not a\nsibling view sharing the same driver) is elected to render side-effecting widgets. The bubble\nand docked panel normally claim this automatically on the pop-in / dock lifecycle, but that\nlifecycle only runs once `popout-mode` is active. A host that establishes a view outside that\nlifecycle — e.g. a page that restores a docked assistant from a persisted layout before the\npop-out affordance is enabled — calls this to seize ownership deterministically rather than\nleaving it to the last-interaction / first-registered fallback. Idempotent; safe to call on\nevery layout (re)establish. No-op if the driver was never wired."
2361
+ "parameters": [
2362
+ {
2363
+ "name": "oldKey",
2364
+ "type": {
2365
+ "text": "string"
2366
+ },
2367
+ "description": "the state key being switched away from."
2368
+ },
2369
+ {
2370
+ "name": "newKey",
2371
+ "type": {
2372
+ "text": "string"
2373
+ },
2374
+ "description": "the state key to activate."
2375
+ }
2376
+ ],
2377
+ "description": "Switch this element to a different session **in place**, without a page reload\n(GENC-1351 §5.12) — the load-a-different-project flow. Tears down the current\nsession's driver + per-key registries and restores the target key's session\n(its transcript and any mid-flow stateful agent). Fired automatically by\n`sessionKeyChanged` when a host rebinds\n`session-key` on a connected element; may also be called directly.\n\nClobber-safe: the outgoing session's pending autosave is cancelled BEFORE the\nstore swaps, so its transcript can never be written to the incoming session's\nfile. Idle-only — a switch while a turn is running is refused.",
2378
+ "privacy": "public"
2278
2379
  },
2279
2380
  {
2280
2381
  "kind": "method",
2281
- "name": "handlePopout",
2382
+ "name": "sessionKeyChanged",
2282
2383
  "return": {
2283
2384
  "type": {
2284
2385
  "text": "void"
2285
2386
  }
2286
- }
2387
+ },
2388
+ "parameters": [
2389
+ {
2390
+ "name": "_oldValue",
2391
+ "type": {
2392
+ "text": "string | undefined"
2393
+ }
2394
+ },
2395
+ {
2396
+ "name": "_newValue",
2397
+ "type": {
2398
+ "text": "string | undefined"
2399
+ }
2400
+ }
2401
+ ],
2402
+ "description": "FAST reflection hook for the `session-key` attr: a change on a **connected**\nelement re-keys the session in place (GENC-1351 §5.12). Guarded by\n`_sessionActive` so the initial, pre-connect set does not switch — the first\nkey is wired by `connectedCallback`."
2287
2403
  },
2288
2404
  {
2289
2405
  "kind": "method",
2290
- "name": "getStateKey",
2406
+ "name": "resolveContextLimit",
2291
2407
  "privacy": "private",
2292
2408
  "return": {
2293
2409
  "type": {
2294
- "text": "string | undefined"
2410
+ "text": "Promise<void>"
2295
2411
  }
2296
- },
2297
- "description": "Returns a cache key for this instance, or undefined if the component has no identity."
2412
+ }
2298
2413
  },
2299
2414
  {
2300
2415
  "kind": "method",
2301
- "name": "logMeta",
2416
+ "name": "loadProviderStatuses",
2302
2417
  "privacy": "private",
2303
2418
  "return": {
2304
2419
  "type": {
2305
- "text": "void"
2420
+ "text": "Promise<void>"
2306
2421
  }
2307
- },
2422
+ }
2423
+ },
2424
+ {
2425
+ "kind": "method",
2426
+ "name": "chatConfigChanged"
2427
+ },
2428
+ {
2429
+ "kind": "method",
2430
+ "name": "persistenceChanged",
2308
2431
  "parameters": [
2309
2432
  {
2310
- "name": "type",
2433
+ "name": "oldValue",
2311
2434
  "type": {
2312
- "text": "MetaEventType"
2435
+ "text": "SessionPersistenceConfig | undefined"
2313
2436
  }
2314
2437
  },
2315
2438
  {
2316
- "name": "detail",
2317
- "optional": true,
2439
+ "name": "newValue",
2318
2440
  "type": {
2319
- "text": "Record<string, unknown>"
2441
+ "text": "SessionPersistenceConfig | undefined"
2320
2442
  }
2321
2443
  }
2322
2444
  ],
2323
- "description": "Record a meta/lifecycle event onto this session's debug-log timeline\n(exported via FoundationAiAssistant.getDebugLog). Every event\nauto-carries `placement` so a session emitted from both the bubble and the\nlayout panel stays disambiguated. Keyed by `stateKey` so the timeline is\nshared across pop-in/pop-out and survives driver rebuilds."
2445
+ "description": "`persistence` (like `chatConfig`) can bind after `connectedCallback` — a host may\nresolve the `provider` asynchronously (an auth token, a feature flag). The connect\npath gates the whole persistence init on a provider being present *at connect*, and\nnothing else re-triggers it — so a late provider would silently never restore the\nsession or load stored preferences (GENC-1351 #13). Mirror `chatConfigChanged`: when\na provider first appears on a connected element whose store is still fresh, run the\nfresh-store init now. Guards keep it a one-shot:\n - pre-connect sets are handled by `connectedCallback` (`_sessionActive` is false);\n - a provider that was already present (incl. the internal `enabled`-only\n reassignments) is a no-op (`oldValue?.provider`);\n - a non-fresh (restored) store already holds its session (`_freshStore`)."
2324
2446
  },
2325
2447
  {
2326
- "kind": "field",
2327
- "name": "_agentPickerToggle",
2328
- "privacy": "private",
2329
- "readonly": true,
2330
- "default": "new AnimatedPanelToggle(\n this,\n '.agent-picker-panel',\n AGENT_PICKER_CLOSE_MS,\n () => this.agentPickerOpen,\n (v) => {\n this.agentPickerOpen = v;\n },\n )"
2448
+ "kind": "method",
2449
+ "name": "showingSplashChanged"
2331
2450
  },
2332
2451
  {
2333
2452
  "kind": "method",
2334
- "name": "toggleAgentPicker"
2453
+ "name": "syncShowingSplash",
2454
+ "privacy": "private"
2335
2455
  },
2336
2456
  {
2337
2457
  "kind": "method",
2338
- "name": "setAgent",
2458
+ "name": "handleMessagesUpdate",
2459
+ "privacy": "private",
2339
2460
  "return": {
2340
2461
  "type": {
2341
- "text": "boolean"
2462
+ "text": "void"
2342
2463
  }
2343
2464
  },
2344
- "parameters": [
2345
- {
2346
- "name": "agentName",
2347
- "type": {
2348
- "text": "string"
2349
- }
2350
- },
2351
- {
2352
- "name": "options",
2353
- "optional": true,
2354
- "type": {
2355
- "text": "{ force?: boolean }"
2356
- }
2357
- }
2358
- ],
2359
- "description": "Programmatically pin an agent by name. Returns `true` if the pin was\napplied, `false` if the agent isn't in the configured agents array or\nthe call was suppressed by `force: false`.\n\nWith `force: false`, the call is a no-op when a `picker.defaultAgent` is\nconfigured and the user has already moved away from it (either by picking\nanother agent or by switching to Auto). This lets hosts seed an opinion\nwithout overriding an explicit user choice.",
2360
- "privacy": "public"
2465
+ "description": "Runs side effects that were previously in `messagesChanged()`.\nCalled from the `messages` setter after dispatching to the store."
2361
2466
  },
2362
2467
  {
2363
- "kind": "field",
2364
- "name": "agentPickerEnabled",
2365
- "type": {
2366
- "text": "boolean"
2367
- },
2368
- "description": "Whether the picker toggle button should appear. Mirrors the picker's own visibility rule.",
2369
- "readonly": true
2468
+ "kind": "method",
2469
+ "name": "showLoadingIndicatorChanged"
2370
2470
  },
2371
2471
  {
2372
- "kind": "field",
2373
- "name": "settingsModelSectionVisible",
2374
- "type": {
2375
- "text": "boolean"
2376
- },
2377
- "description": "Whether the settings modal AI Model section has slotted app content or context usage.",
2378
- "readonly": true
2472
+ "kind": "method",
2473
+ "name": "scrollToBottom",
2474
+ "privacy": "private"
2379
2475
  },
2380
2476
  {
2381
2477
  "kind": "field",
2382
- "name": "settingsContextUsageVisible",
2478
+ "name": "DEFAULT_LOADING_DELAY_S",
2383
2479
  "type": {
2384
- "text": "boolean"
2480
+ "text": "number"
2385
2481
  },
2386
- "description": "Built-in context window indicator (generic platform concern).",
2387
- "readonly": true
2482
+ "privacy": "private",
2483
+ "static": true,
2484
+ "readonly": true,
2485
+ "default": "0"
2388
2486
  },
2389
2487
  {
2390
2488
  "kind": "field",
2391
- "name": "settingsAppSectionVisible",
2489
+ "name": "DEFAULT_SUGGESTION_COUNT",
2392
2490
  "type": {
2393
- "text": "boolean"
2491
+ "text": "number"
2394
2492
  },
2395
- "description": "Whether the settings modal UI Builder section should render.",
2396
- "readonly": true
2493
+ "privacy": "private",
2494
+ "static": true,
2495
+ "readonly": true,
2496
+ "default": "3"
2397
2497
  },
2398
2498
  {
2399
2499
  "kind": "field",
2400
- "name": "appSettingsSectionTitle",
2500
+ "name": "MS_PER_SECOND",
2401
2501
  "type": {
2402
- "text": "string"
2502
+ "text": "number"
2403
2503
  },
2404
- "description": "Section title for the app settings block.",
2405
- "readonly": true
2504
+ "privacy": "private",
2505
+ "static": true,
2506
+ "readonly": true,
2507
+ "default": "1000"
2406
2508
  },
2407
2509
  {
2408
- "kind": "field",
2409
- "name": "visibleAppSettingsToggles",
2410
- "type": {
2411
- "text": "AssistantAppSettingsToggle[]"
2510
+ "kind": "method",
2511
+ "name": "startLoadingTimer",
2512
+ "privacy": "private"
2513
+ },
2514
+ {
2515
+ "kind": "method",
2516
+ "name": "clearLoadingTimer",
2517
+ "privacy": "private"
2518
+ },
2519
+ {
2520
+ "kind": "method",
2521
+ "name": "stopLoadingTimer",
2522
+ "privacy": "private"
2523
+ },
2524
+ {
2525
+ "kind": "method",
2526
+ "name": "handlePopout",
2527
+ "return": {
2528
+ "type": {
2529
+ "text": "void"
2530
+ }
2412
2531
  },
2413
- "description": "App toggles currently visible per each entry's `visible()` predicate.",
2414
- "readonly": true
2532
+ "description": "Called when the user clicks the popout button."
2415
2533
  },
2416
2534
  {
2417
2535
  "kind": "method",
2418
- "name": "getAppSettingValue",
2536
+ "name": "getStateKey",
2537
+ "privacy": "private",
2419
2538
  "return": {
2420
2539
  "type": {
2421
- "text": "boolean"
2540
+ "text": "string | undefined"
2422
2541
  }
2423
2542
  },
2424
- "parameters": [
2425
- {
2426
- "name": "id",
2427
- "type": {
2428
- "text": "string"
2429
- }
2543
+ "description": "Returns a cache key for this instance, or undefined if the component has no identity."
2544
+ },
2545
+ {
2546
+ "kind": "method",
2547
+ "name": "computeStateKeyFromAttrs",
2548
+ "privacy": "private",
2549
+ "return": {
2550
+ "type": {
2551
+ "text": "string | undefined"
2430
2552
  }
2431
- ]
2553
+ },
2554
+ "description": "The session key implied by the element's current attributes (GENC-1351 §5.12).\nAn explicit `session-key` IS the complete session identity — the host fully\nqualifies it (e.g. a per-project id), so `headerTitle` is NOT appended\n(appending it was multi-window disambiguation, obsolete under the single-window\norchestration/pinning model for keyed hosts). Without a `session-key`, fall back\nto `id` + `headerTitle` (the original scheme, kept so existing consumers — e.g. a\ntitle-only key with no `id` — aren't re-keyed). This is the *desired* key;\n`getStateKey` returns the *wired* key, which can lag during a deferred switch."
2432
2555
  },
2433
2556
  {
2434
2557
  "kind": "method",
2435
- "name": "setAppSettingValue",
2558
+ "name": "logMeta",
2559
+ "privacy": "private",
2436
2560
  "return": {
2437
2561
  "type": {
2438
2562
  "text": "void"
@@ -2440,276 +2564,362 @@
2440
2564
  },
2441
2565
  "parameters": [
2442
2566
  {
2443
- "name": "id",
2567
+ "name": "type",
2444
2568
  "type": {
2445
- "text": "string"
2569
+ "text": "MetaEventType"
2446
2570
  }
2447
2571
  },
2448
2572
  {
2449
- "name": "value",
2573
+ "name": "detail",
2574
+ "optional": true,
2450
2575
  "type": {
2451
- "text": "boolean"
2576
+ "text": "Record<string, unknown>"
2452
2577
  }
2453
2578
  }
2454
- ]
2579
+ ],
2580
+ "description": "Record a meta/lifecycle event onto this session's debug-log timeline\n(exported via FoundationAiAssistant.getDebugLog). Every event\nauto-carries `placement` so a session emitted from both the bubble and the\nlayout panel stays disambiguated. Keyed by `stateKey` so the timeline is\nshared across pop-in/pop-out and survives driver rebuilds."
2455
2581
  },
2456
2582
  {
2457
- "kind": "method",
2458
- "name": "wireAppSettingsProvider",
2583
+ "kind": "field",
2584
+ "name": "_agentPickerToggle",
2459
2585
  "privacy": "private",
2460
- "return": {
2461
- "type": {
2462
- "text": "void"
2463
- }
2464
- }
2586
+ "readonly": true,
2587
+ "default": "new AnimatedPanelToggle(\n this,\n '.agent-picker-panel',\n AGENT_PICKER_CLOSE_MS,\n () => this.agentPickerOpen,\n (v) => {\n this.agentPickerOpen = v;\n },\n )"
2465
2588
  },
2466
2589
  {
2467
2590
  "kind": "method",
2468
- "name": "unwireAppSettingsProvider",
2469
- "privacy": "private",
2470
- "return": {
2471
- "type": {
2472
- "text": "void"
2473
- }
2474
- }
2591
+ "name": "toggleAgentPicker"
2475
2592
  },
2476
2593
  {
2477
2594
  "kind": "field",
2478
- "name": "settingsCostCurrentSectionVisible",
2595
+ "name": "confirmingClear",
2479
2596
  "type": {
2480
2597
  "text": "boolean"
2481
2598
  },
2482
- "readonly": true
2599
+ "default": "false",
2600
+ "description": "Two-step confirm for the destructive Clear action; reset whenever the menu toggles."
2483
2601
  },
2484
2602
  {
2485
2603
  "kind": "field",
2486
- "name": "settingsCostHistorySectionVisible",
2604
+ "name": "confirmingCompact",
2487
2605
  "type": {
2488
2606
  "text": "boolean"
2489
2607
  },
2490
- "readonly": true
2608
+ "default": "false"
2491
2609
  },
2492
2610
  {
2493
2611
  "kind": "field",
2494
- "name": "settingsCostSummaryVisible",
2612
+ "name": "_sessionMenuToggle",
2613
+ "privacy": "private",
2614
+ "readonly": true,
2615
+ "default": "new AnimatedPanelToggle(\n this,\n '.session-menu-panel',\n SESSION_MENU_CLOSE_MS,\n () => this.sessionMenuOpen,\n (v) => {\n this.sessionMenuOpen = v;\n },\n )"
2616
+ },
2617
+ {
2618
+ "kind": "field",
2619
+ "name": "sessionMenuEnabled",
2495
2620
  "type": {
2496
2621
  "text": "boolean"
2497
2622
  },
2498
- "description": "Whether the built-in Cost tab summary block has anything to show.",
2623
+ "description": "Whether the lifecycle-menu button shows. It occupies the stop-button slot,\nso it only appears when idle (mutually exclusive with Stop). Gated on\npersistence — the menu's actions (Compact, Clear, the \"remember chat\" toggle)\nonly make sense with a provider configured, so it's hidden entirely without\none. A host can additionally force it off via `chatConfig.ui.showSessionMenu:\nfalse` even when a provider is present (e.g. a guided onboarding flow where\nclearing/compacting mid-journey would be disruptive).",
2499
2624
  "readonly": true
2500
2625
  },
2501
2626
  {
2502
2627
  "kind": "field",
2503
- "name": "settingsCostTabVisible",
2628
+ "name": "persistenceToggleable",
2504
2629
  "type": {
2505
2630
  "text": "boolean"
2506
2631
  },
2507
- "description": "Whether the Cost tab should appear in the settings modal.",
2632
+ "description": "The persistence toggle row renders only when a provider is configured.",
2508
2633
  "readonly": true
2509
2634
  },
2510
2635
  {
2511
2636
  "kind": "field",
2512
- "name": "settingsSessionTokensVisible",
2637
+ "name": "persistenceActive",
2513
2638
  "type": {
2514
2639
  "text": "boolean"
2515
2640
  },
2516
- "description": "Whether session token usage should render on the Cost tab.",
2641
+ "description": "Whether persistence is currently active (on + a provider) for this session.",
2517
2642
  "readonly": true
2518
2643
  },
2519
2644
  {
2520
2645
  "kind": "field",
2521
- "name": "settingsCogVisible",
2646
+ "name": "compactable",
2522
2647
  "type": {
2523
2648
  "text": "boolean"
2524
2649
  },
2525
- "description": "Whether the chat header (and settings cog) should render.",
2650
+ "description": "Whether the menu's \"Compact\" action would do anything (GENC-1351 §5.7).\nDelegates to `driver.canCompact()` so the gate uses the exact same history\n`compact()` acts on — one source of truth. Also reads `messages`, purely to\nstay reactive as the conversation grows: the driver's history isn't a tracked\nobservable, so the button keys its re-evaluation off the Redux mirror.",
2526
2651
  "readonly": true
2527
2652
  },
2528
2653
  {
2529
2654
  "kind": "method",
2530
- "name": "openSettingsModal",
2531
- "return": {
2532
- "type": {
2533
- "text": "void"
2534
- }
2535
- }
2655
+ "name": "toggleSessionMenu"
2536
2656
  },
2537
2657
  {
2538
2658
  "kind": "method",
2539
- "name": "closeSettingsModal",
2540
- "return": {
2541
- "type": {
2542
- "text": "void"
2659
+ "name": "setPersistenceEnabled",
2660
+ "parameters": [
2661
+ {
2662
+ "name": "enabled",
2663
+ "type": {
2664
+ "text": "boolean"
2665
+ }
2543
2666
  }
2544
- }
2667
+ ],
2668
+ "description": "Set persistence on/off for this session (the menu switch). Reassigns the\n`persistence` object so the `@observable` fires. Turning it **off** drops the\nstored snapshot; **on** captures the current chat immediately. Either way the\n*choice* is remembered in the preferences blob (`persistPreferences`) — stored\nindependently of the snapshot, so it survives the clear and re-applies on the\nnext load (GENC-1351)."
2545
2669
  },
2546
2670
  {
2547
2671
  "kind": "method",
2548
- "name": "onSettingsModalClosed",
2549
- "return": {
2672
+ "name": "togglePersistence",
2673
+ "description": "Toggle persistence (convenience / programmatic)."
2674
+ },
2675
+ {
2676
+ "kind": "method",
2677
+ "name": "gatherPreferences",
2678
+ "privacy": "private",
2679
+ "return": {
2550
2680
  "type": {
2551
- "text": "void"
2681
+ "text": "SessionPreferences"
2552
2682
  }
2553
- }
2683
+ },
2684
+ "description": "Snapshot the user-changeable settings into a persistable preferences blob."
2554
2685
  },
2555
2686
  {
2556
2687
  "kind": "method",
2557
- "name": "setSettingsModalTab",
2688
+ "name": "persistPreferences",
2689
+ "privacy": "private",
2558
2690
  "return": {
2559
2691
  "type": {
2560
2692
  "text": "void"
2561
2693
  }
2562
2694
  },
2563
- "parameters": [
2564
- {
2565
- "name": "tab",
2566
- "type": {
2567
- "text": "SettingsModalTab"
2568
- }
2569
- }
2570
- ]
2695
+ "description": "Persist the current UI preferences whenever the user changes a setting\n(GENC-1351). Fires **regardless of \"remember chat\"** — display choices are the\nuser's, not tied to whether the chat is remembered — needing only a provider\nthat implements `savePreferences`. No-op while preferences are being applied\nprogrammatically (`_applyingPreferences`), so config defaults and loaded prefs\naren't re-saved."
2571
2696
  },
2572
2697
  {
2573
2698
  "kind": "method",
2574
- "name": "onSettingsModalTabsChange",
2699
+ "name": "applyPreferenceBaseline",
2700
+ "privacy": "private",
2575
2701
  "return": {
2576
2702
  "type": {
2577
2703
  "text": "void"
2578
2704
  }
2579
2705
  },
2580
- "parameters": [
2581
- {
2582
- "name": "event",
2583
- "type": {
2584
- "text": "Event"
2585
- }
2586
- }
2587
- ],
2588
- "description": "Sync the active settings modal tab when the design-system tab bar changes."
2706
+ "description": "Apply the effective UI-preference baseline onto the live toggles for a fresh\nstore (GENC-1351 #2). Precedence, lowest → highest:\n\n slice defaults < `chatConfig.ui` defaults < stored user preferences\n\nRecomputed from scratch (not layered) on every call, because its two inputs\narrive at unpredictable times: `chatConfig` is a parent-supplied `@observable`\nthat may bind *after* `connectedCallback`, and stored prefs load asynchronously.\nSo it re-runs from `connectedCallback`, `chatConfigChanged`, and once\n`loadPreferences` resolves — whichever order they happen in, the final state is\nthe same. No-op once the store isn't fresh (an existing/popped-out store owns\nits state) or the user has toggled something (their choice then wins, and\n`chatConfig` doesn't change post-startup in practice). Save hook suppressed so\napplying the baseline never persists as if it were a user choice.\n\nThis is the fix for \"nuking server prefs drops to all-disabled instead of the\n`chatConfig` defaults\": stored prefs are simply absent, so the baseline falls\nthrough to the config layer — which the old apply-once-on-connect path missed\nwhenever `chatConfig` hadn't bound yet."
2589
2707
  },
2590
2708
  {
2591
2709
  "kind": "method",
2592
- "name": "resetSettingsModalTabsOnOpen",
2593
- "privacy": "private",
2710
+ "name": "compactSession",
2594
2711
  "return": {
2595
2712
  "type": {
2596
- "text": "void"
2713
+ "text": "Promise<void>"
2597
2714
  }
2598
2715
  },
2599
- "description": "Ensure the settings tab is selected when the modal opens."
2716
+ "description": "Compact the conversation (GENC-1351 §5.7) — the menu's \"Compact\" action.\nDelegates to the driver, which summarizes older turns into a single\n`compacted-summary` message (destructive, atomic). On success records a\nhigh-importance `context.compacted` meta-event capturing the summary; the\nnormal `history-updated` → autosave path then persists the smaller\ntranscript. No-op when there is nothing to compact or the provider cannot\nsummarize (the driver returns `null`)."
2600
2717
  },
2601
2718
  {
2602
2719
  "kind": "method",
2603
- "name": "resetSettingsModalTabsOnClose",
2604
- "privacy": "private",
2720
+ "name": "clearSession",
2605
2721
  "return": {
2606
2722
  "type": {
2607
- "text": "void"
2723
+ "text": "Promise<void>"
2608
2724
  }
2609
2725
  },
2610
- "description": "Return to the settings tab when the modal closes on Cost."
2726
+ "description": "Clear the session — the \"New chat\" action (GENC-1351 §5.6). Tears down the\nactive driver (firing the stateful agent's `onDeactivate` → `machine.stop()`),\nresets the store, rebuilds a fresh driver with no history, and wipes durable\nstorage. Mirrors `agentsChanged`'s teardown, minus the history reseed.\n\nEmits `session-cleared` (`SessionClearedDetail`, declared on the class `@fires`)\nwith `sessionKey`, `agentName`, and `agentSnapshot` captured *before* teardown, so\nthe host can clean up any external state the active agent was working on (generated\nfiles, server-side scratch, etc.). Bubbles and composed."
2611
2727
  },
2612
2728
  {
2613
2729
  "kind": "method",
2614
- "name": "snapSettingsModalTabIndicator",
2615
- "privacy": "private",
2730
+ "name": "setAgent",
2616
2731
  "return": {
2617
2732
  "type": {
2618
- "text": "void"
2733
+ "text": "boolean"
2619
2734
  }
2620
2735
  },
2621
2736
  "parameters": [
2622
2737
  {
2623
- "name": "retry",
2624
- "default": "true"
2738
+ "name": "agentName",
2739
+ "type": {
2740
+ "text": "string"
2741
+ }
2742
+ },
2743
+ {
2744
+ "name": "options",
2745
+ "optional": true,
2746
+ "type": {
2747
+ "text": "{ force?: boolean }"
2748
+ }
2625
2749
  }
2626
2750
  ],
2627
- "description": "Snap the tab underline to the settings tab without animating from Cost.\nUsed after hide/show when aria state is correct but the indicator drifted."
2751
+ "description": "Programmatically pin an agent by name. Returns `true` if the pin was\napplied, `false` if the agent isn't in the configured agents array or\nthe call was suppressed by `force: false`.\n\nWith `force: false`, the call is a no-op when a `picker.defaultAgent` is\nconfigured and the user has already moved away from it (either by picking\nanother agent or by switching to Auto). This lets hosts seed an opinion\nwithout overriding an explicit user choice.",
2752
+ "privacy": "public"
2628
2753
  },
2629
2754
  {
2630
2755
  "kind": "field",
2631
- "name": "pinnedAgentHint",
2756
+ "name": "agentPickerEnabled",
2632
2757
  "type": {
2633
- "text": "string | undefined"
2758
+ "text": "boolean"
2634
2759
  },
2635
- "description": "Hint text for the currently pinned agent, if any. Used in the toggle button tooltip.",
2760
+ "description": "Whether the picker toggle button should appear. Mirrors the picker's own visibility rule.",
2636
2761
  "readonly": true
2637
2762
  },
2638
2763
  {
2639
2764
  "kind": "field",
2640
- "name": "pinLocked",
2765
+ "name": "settingsModelSectionVisible",
2641
2766
  "type": {
2642
2767
  "text": "boolean"
2643
2768
  },
2644
- "description": "The pin is locked when a stateful flow is mid-stream — i.e. some agent's\n`onActivate` has fired and it owns live state, and it hasn't yet called\n`releaseAgent`. Derives directly from `flowOwnerAgentName`, the\nsingle source of truth the orchestrator writes on activation and clears\non release. Until the user sends their first message, a freshly pinned\nstateful agent is not yet active and the picker should remain free; the\nuser might change their mind and unpin without anything to clean up.",
2769
+ "description": "Whether the settings modal AI Model section has slotted app content or context usage.",
2645
2770
  "readonly": true
2646
2771
  },
2647
2772
  {
2648
2773
  "kind": "field",
2649
- "name": "agentToggleTitle",
2774
+ "name": "settingsContextUsageVisible",
2650
2775
  "type": {
2651
- "text": "string"
2776
+ "text": "boolean"
2652
2777
  },
2653
- "description": "Tooltip shown on the picker toggle button.",
2778
+ "description": "Built-in context window indicator (generic platform concern).",
2654
2779
  "readonly": true
2655
2780
  },
2656
2781
  {
2657
2782
  "kind": "field",
2658
- "name": "pinnedAgentColour",
2783
+ "name": "settingsAppSectionVisible",
2659
2784
  "type": {
2660
- "text": "string | undefined"
2785
+ "text": "boolean"
2661
2786
  },
2662
- "description": "Tint applied to the pin icon when an agent is pinned. Picked from the\nbrand palette by agent position (modulo the palette length), so each agent\ngets a consistent colour across renders. `undefined` when nothing is\npinned, the agent isn't in the current array, or the host has opted out\nvia `chatConfig.picker.disablePinColours`.",
2787
+ "description": "Whether the settings modal UI Builder section should render.",
2663
2788
  "readonly": true
2664
2789
  },
2665
2790
  {
2666
2791
  "kind": "field",
2667
- "name": "effectivePlaceholder",
2792
+ "name": "appSettingsSectionTitle",
2668
2793
  "type": {
2669
2794
  "text": "string"
2670
2795
  },
2671
- "description": "Placeholder shown in the chat input. Substitutes the pinned agent's name\nwhen one is selected so the user has a clearer signal of where their\nmessage will go; otherwise falls back to the host-provided placeholder.",
2796
+ "description": "Section title for the app settings block.",
2672
2797
  "readonly": true
2673
2798
  },
2674
2799
  {
2675
- "kind": "method",
2676
- "name": "toggleShowToolCalls"
2677
- },
2678
- {
2679
- "kind": "method",
2680
- "name": "toggleShowThinkingSteps"
2681
- },
2682
- {
2683
- "kind": "method",
2684
- "name": "toggleShowNarration"
2800
+ "kind": "field",
2801
+ "name": "visibleAppSettingsToggles",
2802
+ "type": {
2803
+ "text": "AssistantAppSettingsToggle[]"
2804
+ },
2805
+ "description": "App toggles currently visible per each entry's `visible()` predicate.",
2806
+ "readonly": true
2685
2807
  },
2686
2808
  {
2687
2809
  "kind": "method",
2688
- "name": "toggleShowAgentSwitchIndicator"
2810
+ "name": "getAppSettingValue",
2811
+ "return": {
2812
+ "type": {
2813
+ "text": "boolean"
2814
+ }
2815
+ },
2816
+ "parameters": [
2817
+ {
2818
+ "name": "id",
2819
+ "type": {
2820
+ "text": "string"
2821
+ }
2822
+ }
2823
+ ]
2689
2824
  },
2690
2825
  {
2691
2826
  "kind": "method",
2692
- "name": "setEnabledAnimations",
2827
+ "name": "setAppSettingValue",
2828
+ "return": {
2829
+ "type": {
2830
+ "text": "void"
2831
+ }
2832
+ },
2693
2833
  "parameters": [
2694
2834
  {
2695
- "name": "animations",
2835
+ "name": "id",
2696
2836
  "type": {
2697
- "text": "AiAssistantAnimation[]"
2837
+ "text": "string"
2838
+ }
2839
+ },
2840
+ {
2841
+ "name": "value",
2842
+ "type": {
2843
+ "text": "boolean"
2698
2844
  }
2699
2845
  }
2700
2846
  ]
2701
2847
  },
2702
2848
  {
2703
2849
  "kind": "method",
2704
- "name": "getDebugLog"
2850
+ "name": "wireAppSettingsProvider",
2851
+ "privacy": "private",
2852
+ "return": {
2853
+ "type": {
2854
+ "text": "void"
2855
+ }
2856
+ }
2705
2857
  },
2706
2858
  {
2707
2859
  "kind": "method",
2708
- "name": "downloadDebugLog"
2860
+ "name": "unwireAppSettingsProvider",
2861
+ "privacy": "private",
2862
+ "return": {
2863
+ "type": {
2864
+ "text": "void"
2865
+ }
2866
+ }
2867
+ },
2868
+ {
2869
+ "kind": "field",
2870
+ "name": "settingsCostCurrentSectionVisible",
2871
+ "type": {
2872
+ "text": "boolean"
2873
+ },
2874
+ "readonly": true
2875
+ },
2876
+ {
2877
+ "kind": "field",
2878
+ "name": "settingsCostHistorySectionVisible",
2879
+ "type": {
2880
+ "text": "boolean"
2881
+ },
2882
+ "readonly": true
2883
+ },
2884
+ {
2885
+ "kind": "field",
2886
+ "name": "settingsCostSummaryVisible",
2887
+ "type": {
2888
+ "text": "boolean"
2889
+ },
2890
+ "description": "Whether the built-in Cost tab summary block has anything to show.",
2891
+ "readonly": true
2892
+ },
2893
+ {
2894
+ "kind": "field",
2895
+ "name": "settingsCostTabVisible",
2896
+ "type": {
2897
+ "text": "boolean"
2898
+ },
2899
+ "description": "Whether the Cost tab should appear in the settings modal.",
2900
+ "readonly": true
2901
+ },
2902
+ {
2903
+ "kind": "field",
2904
+ "name": "settingsSessionTokensVisible",
2905
+ "type": {
2906
+ "text": "boolean"
2907
+ },
2908
+ "description": "Whether session token usage should render on the Cost tab.",
2909
+ "readonly": true
2910
+ },
2911
+ {
2912
+ "kind": "field",
2913
+ "name": "settingsCogVisible",
2914
+ "type": {
2915
+ "text": "boolean"
2916
+ },
2917
+ "description": "Whether the chat header (and settings cog) should render.",
2918
+ "readonly": true
2709
2919
  },
2710
2920
  {
2711
2921
  "kind": "method",
2712
- "name": "triggerFileInput",
2922
+ "name": "openSettingsModal",
2713
2923
  "return": {
2714
2924
  "type": {
2715
2925
  "text": "void"
@@ -2718,24 +2928,25 @@
2718
2928
  },
2719
2929
  {
2720
2930
  "kind": "method",
2721
- "name": "handleFileSelect",
2931
+ "name": "closeSettingsModal",
2722
2932
  "return": {
2723
2933
  "type": {
2724
2934
  "text": "void"
2725
2935
  }
2726
- },
2727
- "parameters": [
2728
- {
2729
- "name": "e",
2730
- "type": {
2731
- "text": "Event"
2732
- }
2936
+ }
2937
+ },
2938
+ {
2939
+ "kind": "method",
2940
+ "name": "onSettingsModalClosed",
2941
+ "return": {
2942
+ "type": {
2943
+ "text": "void"
2733
2944
  }
2734
- ]
2945
+ }
2735
2946
  },
2736
2947
  {
2737
2948
  "kind": "method",
2738
- "name": "removeAttachment",
2949
+ "name": "setSettingsModalTab",
2739
2950
  "return": {
2740
2951
  "type": {
2741
2952
  "text": "void"
@@ -2743,16 +2954,16 @@
2743
2954
  },
2744
2955
  "parameters": [
2745
2956
  {
2746
- "name": "attachment",
2957
+ "name": "tab",
2747
2958
  "type": {
2748
- "text": "ChatAttachment"
2959
+ "text": "SettingsModalTab"
2749
2960
  }
2750
2961
  }
2751
2962
  ]
2752
2963
  },
2753
2964
  {
2754
2965
  "kind": "method",
2755
- "name": "removeAttachmentError",
2966
+ "name": "onSettingsModalTabsChange",
2756
2967
  "return": {
2757
2968
  "type": {
2758
2969
  "text": "void"
@@ -2760,239 +2971,517 @@
2760
2971
  },
2761
2972
  "parameters": [
2762
2973
  {
2763
- "name": "message",
2974
+ "name": "event",
2764
2975
  "type": {
2765
- "text": "string"
2976
+ "text": "Event"
2766
2977
  }
2767
2978
  }
2768
- ]
2979
+ ],
2980
+ "description": "Sync the active settings modal tab when the design-system tab bar changes."
2769
2981
  },
2770
2982
  {
2771
2983
  "kind": "method",
2772
- "name": "isAcceptedFile",
2984
+ "name": "resetSettingsModalTabsOnOpen",
2773
2985
  "privacy": "private",
2774
2986
  "return": {
2775
2987
  "type": {
2776
- "text": "boolean"
2988
+ "text": "void"
2777
2989
  }
2778
2990
  },
2779
- "parameters": [
2780
- {
2781
- "name": "file",
2782
- "type": {
2783
- "text": "File"
2784
- }
2785
- }
2786
- ]
2991
+ "description": "Ensure the settings tab is selected when the modal opens."
2787
2992
  },
2788
2993
  {
2789
2994
  "kind": "method",
2790
- "name": "readFileAsText",
2995
+ "name": "resetSettingsModalTabsOnClose",
2791
2996
  "privacy": "private",
2792
2997
  "return": {
2793
2998
  "type": {
2794
- "text": "Promise<string>"
2999
+ "text": "void"
2795
3000
  }
2796
3001
  },
2797
- "parameters": [
2798
- {
2799
- "name": "file",
2800
- "type": {
2801
- "text": "File"
2802
- }
2803
- }
2804
- ]
3002
+ "description": "Return to the settings tab when the modal closes on Cost."
2805
3003
  },
2806
3004
  {
2807
3005
  "kind": "method",
2808
- "name": "processFiles",
3006
+ "name": "snapSettingsModalTabIndicator",
2809
3007
  "privacy": "private",
2810
3008
  "return": {
2811
3009
  "type": {
2812
- "text": "Promise<{ attachments: ChatAttachment[]; errors: string[] }>"
3010
+ "text": "void"
2813
3011
  }
2814
3012
  },
2815
3013
  "parameters": [
2816
3014
  {
2817
- "name": "files",
3015
+ "name": "retry",
3016
+ "default": "true"
3017
+ }
3018
+ ],
3019
+ "description": "Snap the tab underline to the settings tab without animating from Cost.\nUsed after hide/show when aria state is correct but the indicator drifted."
3020
+ },
3021
+ {
3022
+ "kind": "field",
3023
+ "name": "pinnedAgentHint",
3024
+ "type": {
3025
+ "text": "string | undefined"
3026
+ },
3027
+ "description": "Hint text for the currently pinned agent, if any. Used in the toggle button tooltip.",
3028
+ "readonly": true
3029
+ },
3030
+ {
3031
+ "kind": "field",
3032
+ "name": "pinLocked",
3033
+ "type": {
3034
+ "text": "boolean"
3035
+ },
3036
+ "description": "The pin is locked when a stateful flow is mid-stream — i.e. some agent's\n`onActivate` has fired and it owns live state, and it hasn't yet called\n`releaseAgent`. Derives directly from `flowOwnerAgentName`, the\nsingle source of truth the orchestrator writes on activation and clears\non release. Until the user sends their first message, a freshly pinned\nstateful agent is not yet active and the picker should remain free; the\nuser might change their mind and unpin without anything to clean up.",
3037
+ "readonly": true
3038
+ },
3039
+ {
3040
+ "kind": "field",
3041
+ "name": "agentToggleTitle",
3042
+ "type": {
3043
+ "text": "string"
3044
+ },
3045
+ "description": "Tooltip shown on the picker toggle button.",
3046
+ "readonly": true
3047
+ },
3048
+ {
3049
+ "kind": "field",
3050
+ "name": "pinnedAgentColour",
3051
+ "type": {
3052
+ "text": "string | undefined"
3053
+ },
3054
+ "description": "Tint applied to the pin icon when an agent is pinned. Picked from the\nbrand palette by agent position (modulo the palette length), so each agent\ngets a consistent colour across renders. `undefined` when nothing is\npinned, the agent isn't in the current array, or the host has opted out\nvia `chatConfig.picker.disablePinColours`.",
3055
+ "readonly": true
3056
+ },
3057
+ {
3058
+ "kind": "field",
3059
+ "name": "effectivePlaceholder",
3060
+ "type": {
3061
+ "text": "string"
3062
+ },
3063
+ "description": "Placeholder shown in the chat input. Substitutes the pinned agent's name\nwhen one is selected so the user has a clearer signal of where their\nmessage will go; otherwise falls back to the host-provided placeholder.",
3064
+ "readonly": true
3065
+ },
3066
+ {
3067
+ "kind": "method",
3068
+ "name": "toggleShowToolCalls"
3069
+ },
3070
+ {
3071
+ "kind": "method",
3072
+ "name": "toggleShowThinkingSteps"
3073
+ },
3074
+ {
3075
+ "kind": "method",
3076
+ "name": "toggleShowNarration"
3077
+ },
3078
+ {
3079
+ "kind": "method",
3080
+ "name": "toggleShowAgentSwitchIndicator"
3081
+ },
3082
+ {
3083
+ "kind": "method",
3084
+ "name": "setEnabledAnimations",
3085
+ "parameters": [
3086
+ {
3087
+ "name": "animations",
2818
3088
  "type": {
2819
- "text": "File[]"
3089
+ "text": "AiAssistantAnimation[]"
2820
3090
  }
2821
3091
  }
2822
3092
  ]
2823
3093
  },
2824
3094
  {
2825
3095
  "kind": "method",
2826
- "name": "loadSelectedFiles",
3096
+ "name": "getDebugLog",
3097
+ "return": {
3098
+ "type": {
3099
+ "text": "DebugLog"
3100
+ }
3101
+ },
3102
+ "description": "The live current-page debug log (`{ readme, timeline, meta }`). @public"
3103
+ },
3104
+ {
3105
+ "kind": "method",
3106
+ "name": "buildDiagnosticEntries",
2827
3107
  "privacy": "private",
2828
3108
  "return": {
2829
3109
  "type": {
2830
- "text": "Promise<void>"
3110
+ "text": "DiagnosticEntry[]"
2831
3111
  }
2832
3112
  },
2833
- "parameters": [
2834
- {
2835
- "name": "e",
2836
- "type": {
2837
- "text": "Event"
2838
- }
3113
+ "description": "Build the current page's diagnostic entries (GENC-1351 §5.8) — the debug-log\ntimeline entries (`message`/`turn`/`event`) plus one `meta-snapshot` carrying\nthe export-time `meta` block. `getDebugLog()` reassembles these into the live\nlog; the persister's forward-capture path (`SessionPersister.flushDiagnostics`,\nfed these via the `getDiagnosticEntries` dep) diffs them against what's already\nbeen appended to the persisted stream."
3114
+ },
3115
+ {
3116
+ "kind": "method",
3117
+ "name": "downloadDebugLog",
3118
+ "return": {
3119
+ "type": {
3120
+ "text": "Promise<void>"
2839
3121
  }
2840
- ]
3122
+ }
2841
3123
  },
2842
3124
  {
2843
3125
  "kind": "method",
2844
- "name": "handleSendClick"
3126
+ "name": "buildDownloadLog",
3127
+ "privacy": "private",
3128
+ "return": {
3129
+ "type": {
3130
+ "text": "Promise<DebugLog>"
3131
+ }
3132
+ },
3133
+ "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."
2845
3134
  },
2846
3135
  {
2847
3136
  "kind": "method",
2848
- "name": "handleStopClick",
2849
- "description": "User clicked Stop. Cancels the current turn via the driver and flips the\nbutton to \"Stopping…\" until the turn winds down (a tool mid-execution\nfinishes first). Guarded so a second click is a no-op."
3137
+ "name": "persister",
3138
+ "privacy": "private",
3139
+ "return": {
3140
+ "type": {
3141
+ "text": "SessionPersister | undefined"
3142
+ }
3143
+ },
3144
+ "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."
2850
3145
  },
2851
3146
  {
2852
3147
  "kind": "method",
2853
- "name": "handleSuggestionClick",
3148
+ "name": "buildPersisterDeps",
3149
+ "privacy": "private",
3150
+ "return": {
3151
+ "type": {
3152
+ "text": "SessionPersisterDeps"
3153
+ }
3154
+ },
2854
3155
  "parameters": [
2855
3156
  {
2856
- "name": "suggestion",
3157
+ "name": "key",
2857
3158
  "type": {
2858
3159
  "text": "string"
2859
3160
  }
2860
3161
  }
2861
- ]
3162
+ ],
3163
+ "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)."
2862
3164
  },
2863
3165
  {
2864
3166
  "kind": "method",
2865
- "name": "submitMessage",
3167
+ "name": "initPersistenceForNewStore",
3168
+ "privacy": "private",
2866
3169
  "return": {
2867
3170
  "type": {
2868
- "text": "Promise<SubmitMessageResult>"
3171
+ "text": "Promise<void>"
2869
3172
  }
2870
3173
  },
2871
3174
  "parameters": [
2872
3175
  {
2873
- "name": "input",
3176
+ "name": "key",
2874
3177
  "type": {
2875
- "text": "{ text?: string; files?: File[] }"
3178
+ "text": "string"
2876
3179
  }
2877
3180
  }
2878
3181
  ],
2879
- "description": "Programmatically submit a message. Equivalent to the user typing into the\nbuilt-in composer and pressing send, but callable from external code — most\ncommonly a custom input rendered inside `slot=\"splash\"` when paired with\n`chatConfig.ui.hideComposer`.\n\nThe input fully describes the turn: `text` and `files` REPLACE any current\ncomposer state (they are not appended to it). Files are validated against\n`chatConfig.ui.acceptedFiles` using the same pipeline as the composer's\nattach button.\n\nAtomic on validation: if any file fails validation, no attachments are\ncommitted and no send is dispatched. Failure messages are returned in\n`errors` AND appended to the `attachmentErrors` observable so the built-in\nchip UI still surfaces them when visible.\n\nResolves once the underlying send has been kicked off — it does NOT await\nthe assistant's response."
2880
- },
2881
- {
2882
- "kind": "method",
2883
- "name": "fetchSuggestions",
2884
- "privacy": "private"
3182
+ "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."
2885
3183
  },
2886
3184
  {
2887
3185
  "kind": "method",
2888
- "name": "send",
2889
- "privacy": "private"
3186
+ "name": "triggerFileInput",
3187
+ "return": {
3188
+ "type": {
3189
+ "text": "void"
3190
+ }
3191
+ }
2890
3192
  },
2891
3193
  {
2892
3194
  "kind": "method",
2893
- "name": "onChatHeaderMouseDown",
3195
+ "name": "handleFileSelect",
3196
+ "return": {
3197
+ "type": {
3198
+ "text": "void"
3199
+ }
3200
+ },
2894
3201
  "parameters": [
2895
3202
  {
2896
3203
  "name": "e",
2897
3204
  "type": {
2898
- "text": "MouseEvent"
3205
+ "text": "Event"
2899
3206
  }
2900
3207
  }
2901
3208
  ]
2902
3209
  },
2903
3210
  {
2904
3211
  "kind": "method",
2905
- "name": "handleInteractionCompleted",
3212
+ "name": "removeAttachment",
3213
+ "return": {
3214
+ "type": {
3215
+ "text": "void"
3216
+ }
3217
+ },
2906
3218
  "parameters": [
2907
3219
  {
2908
- "name": "e",
3220
+ "name": "attachment",
2909
3221
  "type": {
2910
- "text": "Event"
3222
+ "text": "ChatAttachment"
2911
3223
  }
2912
3224
  }
2913
3225
  ]
2914
3226
  },
2915
3227
  {
2916
- "kind": "field",
2917
- "name": "isComposerResizable",
2918
- "type": {
2919
- "text": "boolean"
3228
+ "kind": "method",
3229
+ "name": "removeAttachmentError",
3230
+ "return": {
3231
+ "type": {
3232
+ "text": "void"
3233
+ }
2920
3234
  },
2921
- "description": "Whether the message input shows a drag handle to resize its height.\nOn by default; hosts opt out via `chatConfig.ui.resizableInput: false`.",
2922
- "readonly": true
3235
+ "parameters": [
3236
+ {
3237
+ "name": "message",
3238
+ "type": {
3239
+ "text": "string"
3240
+ }
3241
+ }
3242
+ ]
2923
3243
  },
2924
3244
  {
2925
- "kind": "field",
2926
- "name": "composerHeightStyle",
2927
- "type": {
2928
- "text": "string"
3245
+ "kind": "method",
3246
+ "name": "isAcceptedFile",
3247
+ "privacy": "private",
3248
+ "return": {
3249
+ "type": {
3250
+ "text": "boolean"
3251
+ }
2929
3252
  },
2930
- "description": "Inline style for the chat input: writes the chosen height into the\n`--composer-height` custom property (read by `.chat-input` + its control in\n`main.styles.ts`). Empty until the user drags (or when resizing is disabled),\nso the default applies.",
2931
- "readonly": true
3253
+ "parameters": [
3254
+ {
3255
+ "name": "file",
3256
+ "type": {
3257
+ "text": "File"
3258
+ }
3259
+ }
3260
+ ]
2932
3261
  },
2933
3262
  {
2934
3263
  "kind": "method",
2935
- "name": "onComposerResizeStart",
3264
+ "name": "readFileAsText",
3265
+ "privacy": "private",
2936
3266
  "return": {
2937
3267
  "type": {
2938
- "text": "void"
3268
+ "text": "Promise<string>"
2939
3269
  }
2940
3270
  },
2941
3271
  "parameters": [
2942
3272
  {
2943
- "name": "e",
3273
+ "name": "file",
2944
3274
  "type": {
2945
- "text": "PointerEvent"
3275
+ "text": "File"
2946
3276
  }
2947
3277
  }
2948
- ],
2949
- "description": "Begin a composer resize drag. Captures the pointer so move/up keep firing\non the handle even when the cursor leaves its 7px band."
3278
+ ]
2950
3279
  },
2951
3280
  {
2952
3281
  "kind": "method",
2953
- "name": "onComposerResizeMove",
3282
+ "name": "processFiles",
3283
+ "privacy": "private",
2954
3284
  "return": {
2955
3285
  "type": {
2956
- "text": "void"
3286
+ "text": "Promise<{ attachments: ChatAttachment[]; errors: string[] }>"
2957
3287
  }
2958
3288
  },
2959
3289
  "parameters": [
2960
3290
  {
2961
- "name": "e",
3291
+ "name": "files",
2962
3292
  "type": {
2963
- "text": "PointerEvent"
3293
+ "text": "File[]"
2964
3294
  }
2965
3295
  }
2966
- ],
2967
- "description": "Resize while dragging. Dragging up (clientY decreases) grows the composer;\nthe result is clamped between the natural height (lower) and the available\nheadroom/max (upper). No-op unless a drag is active (the handle holds pointer\ncapture), so plain hover-moves are ignored."
3296
+ ]
2968
3297
  },
2969
3298
  {
2970
3299
  "kind": "method",
2971
- "name": "onComposerResizeEnd",
3300
+ "name": "loadSelectedFiles",
3301
+ "privacy": "private",
2972
3302
  "return": {
2973
3303
  "type": {
2974
- "text": "void"
3304
+ "text": "Promise<void>"
2975
3305
  }
2976
3306
  },
2977
3307
  "parameters": [
2978
3308
  {
2979
3309
  "name": "e",
2980
3310
  "type": {
2981
- "text": "PointerEvent"
3311
+ "text": "Event"
2982
3312
  }
2983
3313
  }
2984
- ],
2985
- "description": "End a resize drag and release the pointer capture."
2986
- }
2987
- ],
2988
- "events": [
3314
+ ]
3315
+ },
2989
3316
  {
2990
- "name": "chat-header-mousedown",
2991
- "type": {
2992
- "text": "CustomEvent"
2993
- },
2994
- "description": "Fired when the user presses the chat header in `popout-mode=\"expand\"` (for drag-to-popout hosts). Bubbles and composed. detail: `ChatHeaderMousedownEventDetail`"
2995
- }
3317
+ "kind": "method",
3318
+ "name": "handleSendClick"
3319
+ },
3320
+ {
3321
+ "kind": "method",
3322
+ "name": "handleStopClick",
3323
+ "description": "User clicked Stop. Cancels the current turn via the driver and flips the\nbutton to \"Stopping…\" until the turn winds down (a tool mid-execution\nfinishes first). Guarded so a second click is a no-op."
3324
+ },
3325
+ {
3326
+ "kind": "method",
3327
+ "name": "handleSuggestionClick",
3328
+ "parameters": [
3329
+ {
3330
+ "name": "suggestion",
3331
+ "type": {
3332
+ "text": "string"
3333
+ }
3334
+ }
3335
+ ]
3336
+ },
3337
+ {
3338
+ "kind": "method",
3339
+ "name": "submitMessage",
3340
+ "return": {
3341
+ "type": {
3342
+ "text": "Promise<SubmitMessageResult>"
3343
+ }
3344
+ },
3345
+ "parameters": [
3346
+ {
3347
+ "name": "input",
3348
+ "type": {
3349
+ "text": "{ text?: string; files?: File[] }"
3350
+ }
3351
+ }
3352
+ ],
3353
+ "description": "Programmatically submit a message. Equivalent to the user typing into the\nbuilt-in composer and pressing send, but callable from external code — most\ncommonly a custom input rendered inside `slot=\"splash\"` when paired with\n`chatConfig.ui.hideComposer`.\n\nThe input fully describes the turn: `text` and `files` REPLACE any current\ncomposer state (they are not appended to it). Files are validated against\n`chatConfig.ui.acceptedFiles` using the same pipeline as the composer's\nattach button.\n\nAtomic on validation: if any file fails validation, no attachments are\ncommitted and no send is dispatched. Failure messages are returned in\n`errors` AND appended to the `attachmentErrors` observable so the built-in\nchip UI still surfaces them when visible.\n\nResolves once the underlying send has been kicked off — it does NOT await\nthe assistant's response."
3354
+ },
3355
+ {
3356
+ "kind": "method",
3357
+ "name": "fetchSuggestions",
3358
+ "privacy": "private"
3359
+ },
3360
+ {
3361
+ "kind": "field",
3362
+ "name": "_pendingSendPrompt",
3363
+ "type": {
3364
+ "text": "string | undefined"
3365
+ },
3366
+ "privacy": "private",
3367
+ "description": "User text of the message currently being sent, stashed for the lifetime of `send()`.\n`flow-owner-changed` fires while the driver routes this turn — before the message is\nappended to raw history — so the flow-activation-prompt capture reads this rather than\na stale raw-history lookup. Cleared once the send settles. (GENC-1351 §5.9)"
3368
+ },
3369
+ {
3370
+ "kind": "method",
3371
+ "name": "send",
3372
+ "privacy": "private"
3373
+ },
3374
+ {
3375
+ "kind": "method",
3376
+ "name": "onChatHeaderMouseDown",
3377
+ "parameters": [
3378
+ {
3379
+ "name": "e",
3380
+ "type": {
3381
+ "text": "MouseEvent"
3382
+ }
3383
+ }
3384
+ ]
3385
+ },
3386
+ {
3387
+ "kind": "method",
3388
+ "name": "handleInteractionCompleted",
3389
+ "parameters": [
3390
+ {
3391
+ "name": "e",
3392
+ "type": {
3393
+ "text": "Event"
3394
+ }
3395
+ }
3396
+ ]
3397
+ },
3398
+ {
3399
+ "kind": "field",
3400
+ "name": "isComposerResizable",
3401
+ "type": {
3402
+ "text": "boolean"
3403
+ },
3404
+ "description": "Whether the message input shows a drag handle to resize its height.\nOn by default; hosts opt out via `chatConfig.ui.resizableInput: false`.",
3405
+ "readonly": true
3406
+ },
3407
+ {
3408
+ "kind": "field",
3409
+ "name": "composerHeightStyle",
3410
+ "type": {
3411
+ "text": "string"
3412
+ },
3413
+ "description": "Inline style for the chat input: writes the chosen height into the\n`--composer-height` custom property (read by `.chat-input` + its control in\n`main.styles.ts`). Empty until the user drags (or when resizing is disabled),\nso the default applies.",
3414
+ "readonly": true
3415
+ },
3416
+ {
3417
+ "kind": "method",
3418
+ "name": "onComposerResizeStart",
3419
+ "return": {
3420
+ "type": {
3421
+ "text": "void"
3422
+ }
3423
+ },
3424
+ "parameters": [
3425
+ {
3426
+ "name": "e",
3427
+ "type": {
3428
+ "text": "PointerEvent"
3429
+ }
3430
+ }
3431
+ ],
3432
+ "description": "Begin a composer resize drag. Captures the pointer so move/up keep firing\non the handle even when the cursor leaves its 7px band."
3433
+ },
3434
+ {
3435
+ "kind": "method",
3436
+ "name": "onComposerResizeMove",
3437
+ "return": {
3438
+ "type": {
3439
+ "text": "void"
3440
+ }
3441
+ },
3442
+ "parameters": [
3443
+ {
3444
+ "name": "e",
3445
+ "type": {
3446
+ "text": "PointerEvent"
3447
+ }
3448
+ }
3449
+ ],
3450
+ "description": "Resize while dragging. Dragging up (clientY decreases) grows the composer;\nthe result is clamped between the natural height (lower) and the available\nheadroom/max (upper). No-op unless a drag is active (the handle holds pointer\ncapture), so plain hover-moves are ignored."
3451
+ },
3452
+ {
3453
+ "kind": "method",
3454
+ "name": "onComposerResizeEnd",
3455
+ "return": {
3456
+ "type": {
3457
+ "text": "void"
3458
+ }
3459
+ },
3460
+ "parameters": [
3461
+ {
3462
+ "name": "e",
3463
+ "type": {
3464
+ "text": "PointerEvent"
3465
+ }
3466
+ }
3467
+ ],
3468
+ "description": "End a resize drag and release the pointer capture."
3469
+ }
3470
+ ],
3471
+ "events": [
3472
+ {
3473
+ "type": {
3474
+ "text": "CustomEvent"
3475
+ }
3476
+ },
3477
+ {
3478
+ "description": "Fired when the user presses the chat header in `popout-mode=\"expand\"` (for drag-to-popout hosts). Bubbles and composed. detail: `ChatHeaderMouseDownDetail`",
3479
+ "name": "chat-header-mousedown"
3480
+ },
3481
+ {
3482
+ "description": "Fired after the session is wiped (the lifecycle menu's Clear). The payload is captured before teardown so the host can clean up any external state the active agent was working on. Bubbles and composed. detail: `SessionClearedDetail`",
3483
+ "name": "session-cleared"
3484
+ }
2996
3485
  ],
2997
3486
  "attributes": [
2998
3487
  {
@@ -3003,6 +3492,14 @@
3003
3492
  "default": "'Genesis Assistant'",
3004
3493
  "fieldName": "headerTitle"
3005
3494
  },
3495
+ {
3496
+ "name": "session-key",
3497
+ "type": {
3498
+ "text": "string | undefined"
3499
+ },
3500
+ "description": "Explicit session/persistence key (GENC-1351 §5.12). When set, this is the\nsession identity — the key for the driver/store/persister/diagnostics\nregistries and the `sessionKey` passed to the persistence provider — taking\nprecedence over the DOM `id`. A host that scopes persistence per-entity\n(e.g. one chat session per project) binds this to a stable per-entity id;\nchanging it on a **connected** element re-keys the session in place — tears\ndown the current conversation and restores the new key's — via\n`switchSession`. Falls back to `id` when unset,\nso existing consumers are unaffected.",
3501
+ "fieldName": "sessionKey"
3502
+ },
3006
3503
  {
3007
3504
  "name": "image-src",
3008
3505
  "type": {
@@ -3098,6 +3595,15 @@
3098
3595
  "kind": "javascript-module",
3099
3596
  "path": "src/main/main.types.ts",
3100
3597
  "declarations": [
3598
+ {
3599
+ "kind": "variable",
3600
+ "name": "AiAssistantEvent",
3601
+ "type": {
3602
+ "text": "{\n /** Session wiped via the lifecycle menu's Clear. `detail`: `SessionClearedDetail`. */\n SessionCleared: 'session-cleared',\n /** Header pressed in `popout-mode=\"expand\"` (drag-to-popout hosts). `detail`: `ChatHeaderMouseDownDetail`. */\n ChatHeaderMouseDown: 'chat-header-mousedown',\n}"
3603
+ },
3604
+ "default": "{\n /** Session wiped via the lifecycle menu's Clear. `detail`: `SessionClearedDetail`. */\n SessionCleared: 'session-cleared',\n /** Header pressed in `popout-mode=\"expand\"` (drag-to-popout hosts). `detail`: `ChatHeaderMouseDownDetail`. */\n ChatHeaderMouseDown: 'chat-header-mousedown',\n}",
3605
+ "description": "DOM events the `<foundation-ai-assistant>` element dispatches to its host.\nAll bubble and are `composed` (they cross the shadow boundary), so a host can\nlisten on the element — or any ancestor — to react. Use these constants to\nwire listeners instead of hand-typing event-name strings.\n\nAn `as const` map (not a TS `enum` — this package ships none), so it serves as\nboth the listener-name value and, via the same-named type below, a union."
3606
+ },
3101
3607
  {
3102
3608
  "kind": "variable",
3103
3609
  "name": "ANIMATION_DEFS",
@@ -3127,6 +3633,14 @@
3127
3633
  "package": "@genesislcap/foundation-ai"
3128
3634
  }
3129
3635
  },
3636
+ {
3637
+ "kind": "js",
3638
+ "name": "AiAssistantEvent",
3639
+ "declaration": {
3640
+ "name": "AiAssistantEvent",
3641
+ "module": "src/main/main.types.ts"
3642
+ }
3643
+ },
3130
3644
  {
3131
3645
  "kind": "js",
3132
3646
  "name": "ANIMATION_DEFS",
@@ -3199,13 +3713,22 @@
3199
3713
  "kind": "javascript-module",
3200
3714
  "path": "src/state/ai-assistant-slice.ts",
3201
3715
  "declarations": [
3716
+ {
3717
+ "kind": "function",
3718
+ "name": "createDefaultSessionState",
3719
+ "return": {
3720
+ "type": {
3721
+ "text": "AiAssistantSessionState"
3722
+ }
3723
+ },
3724
+ "description": "Build a fresh default session state. A factory (not just a shared const) so\neach call returns independent collections — `resetSession` can hand back a\nclean slate without aliasing the initial state's arrays."
3725
+ },
3202
3726
  {
3203
3727
  "kind": "variable",
3204
3728
  "name": "defaultSessionState",
3205
3729
  "type": {
3206
3730
  "text": "AiAssistantSessionState"
3207
- },
3208
- "default": "{\n messages: [],\n state: 'idle',\n showToolCalls: false,\n showThinkingSteps: false,\n showNarration: false,\n showAgentSwitchIndicator: false,\n enabledAnimations: [],\n suggestionsState: { status: 'idle' },\n contextTokens: undefined,\n contextLimit: undefined,\n sessionCostUsd: 0,\n sessionTokensConsumed: 0,\n activeModel: undefined,\n activeProviderName: undefined,\n providerStatuses: [],\n activeAgent: undefined,\n pinnedAgentName: null,\n flowOwnerAgentName: null,\n agentPickerOpen: false,\n inputValue: '',\n liveSubAgentTrace: [],\n liveSubAgentName: null,\n inputOverrides: [],\n}"
3731
+ }
3209
3732
  },
3210
3733
  {
3211
3734
  "kind": "variable",
@@ -3213,6 +3736,14 @@
3213
3736
  }
3214
3737
  ],
3215
3738
  "exports": [
3739
+ {
3740
+ "kind": "js",
3741
+ "name": "createDefaultSessionState",
3742
+ "declaration": {
3743
+ "name": "createDefaultSessionState",
3744
+ "module": "src/state/ai-assistant-slice.ts"
3745
+ }
3746
+ },
3216
3747
  {
3217
3748
  "kind": "js",
3218
3749
  "name": "defaultSessionState",
@@ -3241,7 +3772,7 @@
3241
3772
  "type": {
3242
3773
  "text": "Record<MetaEventType, MetaEventImportance>"
3243
3774
  },
3244
- "default": "{\n 'turn.error': 'high',\n 'tool.failed': 'high',\n 'subagent.failed': 'high',\n 'file.read-failed': 'high',\n 'suggestions.failed': 'high',\n 'context.threshold-crossed': 'high',\n\n 'assistant.connected': 'normal',\n 'assistant.disconnected': 'normal',\n 'assistant.popout': 'normal',\n 'assistant.popin': 'normal',\n 'driver.created': 'normal',\n 'state.changed': 'normal',\n 'turn.start': 'normal',\n 'turn.end': 'normal',\n 'turn.retry': 'normal',\n 'tool.unresolved': 'normal',\n 'subagent.started': 'normal',\n 'subagent.completed': 'normal',\n 'agent.handoff': 'normal',\n 'agent.pinned': 'normal',\n 'agent.unpinned': 'normal',\n 'provider.selected': 'normal',\n 'interaction.requested': 'normal',\n 'interaction.resolved': 'normal',\n\n 'driver.wired': 'low',\n 'driver.unwired': 'low',\n 'context.updated': 'low',\n 'context.condensed': 'low',\n 'panel.toggled': 'low',\n 'attachment.added': 'low',\n}",
3775
+ "default": "{\n 'turn.error': 'high',\n 'tool.failed': 'high',\n 'subagent.failed': 'high',\n 'file.read-failed': 'high',\n 'suggestions.failed': 'high',\n 'context.threshold-crossed': 'high',\n 'context.compacted': 'high',\n 'persistence.restore-orphan': 'high',\n\n 'assistant.connected': 'normal',\n 'assistant.disconnected': 'normal',\n 'assistant.popout': 'normal',\n 'assistant.popin': 'normal',\n 'driver.created': 'normal',\n 'state.changed': 'normal',\n 'turn.start': 'normal',\n 'turn.end': 'normal',\n 'turn.retry': 'normal',\n 'tool.unresolved': 'normal',\n 'subagent.started': 'normal',\n 'subagent.completed': 'normal',\n 'agent.handoff': 'normal',\n 'agent.pinned': 'normal',\n 'agent.unpinned': 'normal',\n 'provider.selected': 'normal',\n 'interaction.requested': 'normal',\n 'interaction.resolved': 'normal',\n 'session.cleared': 'normal',\n 'session.switched': 'low',\n 'session.switch-deferred': 'low',\n 'persistence.restored': 'normal',\n 'persistence.suppressed': 'normal',\n 'persistence.not-resumable': 'normal',\n\n 'driver.wired': 'low',\n 'driver.unwired': 'low',\n 'context.updated': 'low',\n 'context.condensed': 'low',\n 'panel.toggled': 'low',\n 'persistence.toggled': 'low',\n 'persistence.saved': 'low',\n 'attachment.added': 'low',\n}",
3245
3776
  "description": "Importance is intrinsic to the event *type*, not the instance, so it's\ndefined once here and stamped automatically by recordMetaEvent — call\nsites never pass it. The `Record` is exhaustive: adding a `MetaEventType`\nwithout a level here is a compile error.\n\n- `high` — failures and hard limits you almost always want to see.\n- `normal` — meaningful session flow you read to follow what happened.\n- `low` — frequent UI / bookkeeping noise, usually safe to skip."
3246
3777
  },
3247
3778
  {
@@ -4437,54 +4968,192 @@
4437
4968
  }
4438
4969
  ],
4439
4970
  "description": "Applies a history cap for sub-agent context: the last `cap` messages are passed\nverbatim; older messages have their tool payloads masked."
4440
- }
4441
- ],
4442
- "exports": [
4443
- {
4444
- "kind": "js",
4445
- "name": "transformHistoryForAgent",
4446
- "declaration": {
4447
- "name": "transformHistoryForAgent",
4448
- "module": "src/utils/history-transform.ts"
4449
- }
4450
4971
  },
4451
4972
  {
4452
- "kind": "js",
4453
- "name": "applyHistoryCap",
4454
- "declaration": {
4455
- "name": "applyHistoryCap",
4456
- "module": "src/utils/history-transform.ts"
4457
- }
4458
- }
4459
- ]
4460
- },
4461
- {
4462
- "kind": "javascript-module",
4463
- "path": "src/utils/index.ts",
4464
- "declarations": [],
4465
- "exports": [
4973
+ "kind": "variable",
4974
+ "name": "COMPACT_KEEP_RECENT_MESSAGES",
4975
+ "type": {
4976
+ "text": "number"
4977
+ },
4978
+ "default": "4",
4979
+ "description": "Recent messages kept verbatim when compacting; everything earlier is summarized."
4980
+ },
4466
4981
  {
4467
- "kind": "js",
4468
- "name": "*",
4469
- "declaration": {
4470
- "name": "*",
4471
- "package": "./animated-panel-toggle"
4472
- }
4982
+ "kind": "variable",
4983
+ "name": "COMPACT_MIN_MESSAGES_TO_COMPACT",
4984
+ "type": {
4985
+ "text": "number"
4986
+ },
4987
+ "default": "4",
4988
+ "description": "Don't bother compacting unless at least this many messages would be summarized."
4473
4989
  },
4474
4990
  {
4475
- "kind": "js",
4476
- "name": "*",
4477
- "declaration": {
4478
- "name": "*",
4479
- "package": "./logger"
4480
- }
4991
+ "kind": "function",
4992
+ "name": "findCompactionCut",
4993
+ "return": {
4994
+ "type": {
4995
+ "text": "number | null"
4996
+ }
4997
+ },
4998
+ "parameters": [
4999
+ {
5000
+ "name": "history",
5001
+ "type": {
5002
+ "text": "readonly ChatMessage[]"
5003
+ }
5004
+ }
5005
+ ],
5006
+ "description": "Index at which the verbatim tail begins — everything before it gets summarized.\nThe tail starts on a clean turn boundary (a `user` message): a user message\nnever appears between a `tool_use` and its `tool_result`, so cutting there\nguarantees the summarized region is tool-pair-balanced (compaction only runs\nwhen idle, so history is turn-complete). Returns `null` when there is nothing\nworth compacting (too short, or no earlier user boundary) — e.g. a freshly\nrestored session whose only user turn is the current one."
4481
5007
  },
4482
5008
  {
4483
- "kind": "js",
4484
- "name": "*",
4485
- "declaration": {
4486
- "name": "*",
4487
- "package": "./tool-fold"
5009
+ "kind": "function",
5010
+ "name": "buildCompactionSummaryPrompt",
5011
+ "return": {
5012
+ "type": {
5013
+ "text": "{\n systemPrompt: string;\n userMessage: string;\n}"
5014
+ }
5015
+ },
5016
+ "parameters": [
5017
+ {
5018
+ "name": "toCompact",
5019
+ "type": {
5020
+ "text": "readonly ChatMessage[]"
5021
+ }
5022
+ }
5023
+ ],
5024
+ "description": "Build the one-shot summarizer prompt for a run of older messages (used with\n`AIProvider.prompt`). Mirrors the `<conversation_history>` block convention\nthat suggestions use. Any existing `compacted-summary` at the head is folded\nin (rendered as prior-summary context), so rolling re-compaction produces one\ncombined summary."
5025
+ },
5026
+ {
5027
+ "kind": "function",
5028
+ "name": "normalizeForProvider",
5029
+ "return": {
5030
+ "type": {
5031
+ "text": "ChatMessage[]"
5032
+ }
5033
+ },
5034
+ "parameters": [
5035
+ {
5036
+ "name": "history",
5037
+ "type": {
5038
+ "text": "readonly ChatMessage[]"
5039
+ }
5040
+ }
5041
+ ],
5042
+ "description": "Normalize history for a provider request (GENC-1351 §5.7): translate each\n`compacted-summary` message into a `user` message that wraps its summary in a\n`<conversation_summary>` block, so the raw display-only role never reaches a\ntransport. Other roles pass through untouched. Pure — returns a new array.\n\nApplied at the request-build chokepoint *before* per-agent masking, so the\nguarantee holds for every provider/transport regardless of any optional\nper-agent history transform."
5043
+ },
5044
+ {
5045
+ "kind": "function",
5046
+ "name": "compactionDividerLabel",
5047
+ "return": {
5048
+ "type": {
5049
+ "text": "string"
5050
+ }
5051
+ },
5052
+ "parameters": [
5053
+ {
5054
+ "name": "m",
5055
+ "type": {
5056
+ "text": "ChatMessage"
5057
+ }
5058
+ }
5059
+ ],
5060
+ "description": "Human-facing divider label for a `compacted-summary` message."
5061
+ }
5062
+ ],
5063
+ "exports": [
5064
+ {
5065
+ "kind": "js",
5066
+ "name": "transformHistoryForAgent",
5067
+ "declaration": {
5068
+ "name": "transformHistoryForAgent",
5069
+ "module": "src/utils/history-transform.ts"
5070
+ }
5071
+ },
5072
+ {
5073
+ "kind": "js",
5074
+ "name": "applyHistoryCap",
5075
+ "declaration": {
5076
+ "name": "applyHistoryCap",
5077
+ "module": "src/utils/history-transform.ts"
5078
+ }
5079
+ },
5080
+ {
5081
+ "kind": "js",
5082
+ "name": "COMPACT_KEEP_RECENT_MESSAGES",
5083
+ "declaration": {
5084
+ "name": "COMPACT_KEEP_RECENT_MESSAGES",
5085
+ "module": "src/utils/history-transform.ts"
5086
+ }
5087
+ },
5088
+ {
5089
+ "kind": "js",
5090
+ "name": "COMPACT_MIN_MESSAGES_TO_COMPACT",
5091
+ "declaration": {
5092
+ "name": "COMPACT_MIN_MESSAGES_TO_COMPACT",
5093
+ "module": "src/utils/history-transform.ts"
5094
+ }
5095
+ },
5096
+ {
5097
+ "kind": "js",
5098
+ "name": "findCompactionCut",
5099
+ "declaration": {
5100
+ "name": "findCompactionCut",
5101
+ "module": "src/utils/history-transform.ts"
5102
+ }
5103
+ },
5104
+ {
5105
+ "kind": "js",
5106
+ "name": "buildCompactionSummaryPrompt",
5107
+ "declaration": {
5108
+ "name": "buildCompactionSummaryPrompt",
5109
+ "module": "src/utils/history-transform.ts"
5110
+ }
5111
+ },
5112
+ {
5113
+ "kind": "js",
5114
+ "name": "normalizeForProvider",
5115
+ "declaration": {
5116
+ "name": "normalizeForProvider",
5117
+ "module": "src/utils/history-transform.ts"
5118
+ }
5119
+ },
5120
+ {
5121
+ "kind": "js",
5122
+ "name": "compactionDividerLabel",
5123
+ "declaration": {
5124
+ "name": "compactionDividerLabel",
5125
+ "module": "src/utils/history-transform.ts"
5126
+ }
5127
+ }
5128
+ ]
5129
+ },
5130
+ {
5131
+ "kind": "javascript-module",
5132
+ "path": "src/utils/index.ts",
5133
+ "declarations": [],
5134
+ "exports": [
5135
+ {
5136
+ "kind": "js",
5137
+ "name": "*",
5138
+ "declaration": {
5139
+ "name": "*",
5140
+ "package": "./animated-panel-toggle"
5141
+ }
5142
+ },
5143
+ {
5144
+ "kind": "js",
5145
+ "name": "*",
5146
+ "declaration": {
5147
+ "name": "*",
5148
+ "package": "./logger"
5149
+ }
5150
+ },
5151
+ {
5152
+ "kind": "js",
5153
+ "name": "*",
5154
+ "declaration": {
5155
+ "name": "*",
5156
+ "package": "./tool-fold"
4488
5157
  }
4489
5158
  }
4490
5159
  ]
@@ -4513,6 +5182,24 @@
4513
5182
  "kind": "javascript-module",
4514
5183
  "path": "src/utils/message-partition.ts",
4515
5184
  "declarations": [
5185
+ {
5186
+ "kind": "function",
5187
+ "name": "isSessionNoticeMarker",
5188
+ "return": {
5189
+ "type": {
5190
+ "text": "boolean"
5191
+ }
5192
+ },
5193
+ "parameters": [
5194
+ {
5195
+ "name": "m",
5196
+ "type": {
5197
+ "text": "ChatMessage"
5198
+ }
5199
+ }
5200
+ ],
5201
+ "description": "Either restore notice — both display-only, stripped before persist. @internal"
5202
+ },
4516
5203
  {
4517
5204
  "kind": "function",
4518
5205
  "name": "trailingInteractionRow",
@@ -4557,6 +5244,14 @@
4557
5244
  }
4558
5245
  ],
4559
5246
  "exports": [
5247
+ {
5248
+ "kind": "js",
5249
+ "name": "isSessionNoticeMarker",
5250
+ "declaration": {
5251
+ "name": "isSessionNoticeMarker",
5252
+ "module": "src/utils/message-partition.ts"
5253
+ }
5254
+ },
4560
5255
  {
4561
5256
  "kind": "js",
4562
5257
  "name": "trailingInteractionRow",
@@ -4609,6 +5304,12 @@
4609
5304
  }
4610
5305
  ]
4611
5306
  },
5307
+ {
5308
+ "kind": "javascript-module",
5309
+ "path": "src/utils/resolve-preference-baseline.ts",
5310
+ "declarations": [],
5311
+ "exports": []
5312
+ },
4612
5313
  {
4613
5314
  "kind": "javascript-module",
4614
5315
  "path": "src/utils/strip-agent-handlers.ts",
@@ -4721,6 +5422,12 @@
4721
5422
  }
4722
5423
  ]
4723
5424
  },
5425
+ {
5426
+ "kind": "javascript-module",
5427
+ "path": "src/utils/with-timeout.ts",
5428
+ "declarations": [],
5429
+ "exports": []
5430
+ },
4724
5431
  {
4725
5432
  "kind": "javascript-module",
4726
5433
  "path": "src/components/activity-halo/activity-halo.ts",
@@ -5654,29 +6361,6 @@
5654
6361
  "privacy": "private",
5655
6362
  "default": "new Map<\n string,\n {\n resolve: (value: any) => void;\n reject: (reason?: any) => void;\n /** Present when the call requested a chat-input override. */\n overrideId?: string;\n /** Present when the call set `timeoutMs`; cleared on resolution. */\n timeoutHandle?: ReturnType<typeof setTimeout>;\n }\n >()"
5656
6363
  },
5657
- {
5658
- "kind": "field",
5659
- "name": "hosts",
5660
- "privacy": "private",
5661
- "default": "new Set<string>()",
5662
- "description": "Assistant host ids currently wired to this driver, in registration (insertion) order."
5663
- },
5664
- {
5665
- "kind": "field",
5666
- "name": "lastActiveHostId",
5667
- "type": {
5668
- "text": "string | undefined"
5669
- },
5670
- "privacy": "private",
5671
- "description": "The host whose subtree the user most recently interacted in — the primary owner signal."
5672
- },
5673
- {
5674
- "kind": "field",
5675
- "name": "startedSideEffects",
5676
- "privacy": "private",
5677
- "default": "new Map<string, string>()",
5678
- "description": "Interaction id → host id that claimed its side effect (first-writer-wins latch)."
5679
- },
5680
6364
  {
5681
6365
  "kind": "field",
5682
6366
  "name": "systemPrompt",
@@ -6536,101 +7220,32 @@
6536
7220
  },
6537
7221
  {
6538
7222
  "kind": "method",
6539
- "name": "isBusy",
7223
+ "name": "canCompact",
6540
7224
  "return": {
6541
7225
  "type": {
6542
7226
  "text": "boolean"
6543
7227
  }
6544
- }
6545
- },
6546
- {
6547
- "kind": "method",
6548
- "name": "registerHost",
6549
- "return": {
6550
- "type": {
6551
- "text": "void"
6552
- }
6553
- },
6554
- "parameters": [
6555
- {
6556
- "name": "hostId",
6557
- "type": {
6558
- "text": "string"
6559
- }
6560
- }
6561
- ],
6562
- "description": "Register an assistant view (host) wired to this shared driver. @internal"
6563
- },
6564
- {
6565
- "kind": "method",
6566
- "name": "unregisterHost",
6567
- "return": {
6568
- "type": {
6569
- "text": "void"
6570
- }
6571
7228
  },
6572
- "parameters": [
6573
- {
6574
- "name": "hostId",
6575
- "type": {
6576
- "text": "string"
6577
- }
6578
- }
6579
- ],
6580
- "description": "Deregister a host on unwire/disconnect. @internal"
7229
+ "description": "Whether `compact()` would do anything right now — a summarizable run of older\nturns exists behind a clean boundary. Uses the same `history` `compact()`\nacts on, so the UI's gate can't disagree with the action (GENC-1351 follow-up)."
6581
7230
  },
6582
7231
  {
6583
7232
  "kind": "method",
6584
- "name": "setActiveHost",
7233
+ "name": "compact",
6585
7234
  "return": {
6586
7235
  "type": {
6587
- "text": "void"
7236
+ "text": "Promise<ChatMessage | null>"
6588
7237
  }
6589
7238
  },
6590
- "parameters": [
6591
- {
6592
- "name": "hostId",
6593
- "type": {
6594
- "text": "string"
6595
- }
6596
- }
6597
- ],
6598
- "description": "Record the host whose subtree the user most recently interacted in — the primary signal for\nelecting which single view renders an interaction's widget. Sticky (unlike focus): it only\nmoves when the user actually uses a different assistant view, not when they click elsewhere\nin the layout. @internal"
7239
+ "description": "Destructively compact older turns into a single `compacted-summary` message\n(GENC-1351 §5.7). Summarizes everything before a clean recent-tail boundary\nvia the registry-default provider's one-shot `prompt()`, then **atomically**\nreplaces the covered turns with one summary message at the head — history is\nmutated only on success. Rolling: any existing head summary is folded into\nthe new one. Returns the created summary message, or `null` when there is\nnothing worth compacting or the default provider cannot summarize."
6599
7240
  },
6600
7241
  {
6601
7242
  "kind": "method",
6602
- "name": "claimSideEffect",
7243
+ "name": "isBusy",
6603
7244
  "return": {
6604
7245
  "type": {
6605
7246
  "text": "boolean"
6606
7247
  }
6607
- },
6608
- "parameters": [
6609
- {
6610
- "name": "interactionId",
6611
- "type": {
6612
- "text": "string"
6613
- }
6614
- },
6615
- {
6616
- "name": "hostId",
6617
- "type": {
6618
- "text": "string"
6619
- }
6620
- }
6621
- ],
6622
- "description": "First-writer-wins latch guarding a side effect. A host claims before rendering the live\nwidget: the first host to claim an interaction id gets `true` (run it); a *different* host\ngets `false` (render passive, do NOT re-fire). Re-claim by the SAME host returns `true`, so a\nbenign re-render of the owner keeps its widget. Single-threaded, so check-and-set is race-free\n— the backstop that makes duplicate execution impossible even if owner election ever slips. @internal"
6623
- },
6624
- {
6625
- "kind": "method",
6626
- "name": "electInteractionOwner",
6627
- "privacy": "private",
6628
- "return": {
6629
- "type": {
6630
- "text": "string | undefined"
6631
- }
6632
- },
6633
- "description": "Elect the single host that owns (renders + runs) an interaction's widget: the most-recently-\nactive host if still connected, else a deterministic default (first registered host — `Set`\npreserves insertion order) so exactly one owner is always chosen. Returns `undefined` only when\nno host is registered, in which case the interaction renders everywhere (fail-open) not nowhere."
7248
+ }
6634
7249
  },
6635
7250
  {
6636
7251
  "kind": "method",
@@ -7205,15 +7820,6 @@
7205
7820
  "default": "undefined",
7206
7821
  "description": "The resolved result once the interaction has completed. Forwarded to the rendered component. @internal"
7207
7822
  },
7208
- {
7209
- "kind": "field",
7210
- "name": "ownerHostId",
7211
- "type": {
7212
- "text": "string"
7213
- },
7214
- "default": "''",
7215
- "description": "GENC-1410 (Error 3): id of the host the driver elected to render (and thus run) this\ninteraction. When several views share one driver, only the matching host renders the live\nwidget; others show a passive placeholder so the widget fires once. Empty = no owner elected\n(single view, or none registered) → render everywhere (fail-open). @internal"
7216
- },
7217
7823
  {
7218
7824
  "kind": "field",
7219
7825
  "name": "_resizeObserver",
@@ -7513,6 +8119,16 @@
7513
8119
  "default": "null",
7514
8120
  "description": "Transient flow lock — set when a stateful agent's `onActivate` fires,\ncleared by `releaseActiveAgent`. While non-null, routing precedence goes\nto this agent and the picker is locked. Independent of\n`pinnedAgentName` so completing a flow doesn't wipe the user's sticky\nchoice."
7515
8121
  },
8122
+ {
8123
+ "kind": "field",
8124
+ "name": "restoredAgentStates",
8125
+ "type": {
8126
+ "text": "Record<string, unknown>"
8127
+ },
8128
+ "privacy": "private",
8129
+ "default": "{}",
8130
+ "description": "Per-agent restored state for a rehydrated session, keyed by agent name.\nPrimed by the host on restore; each entry is passed to that agent's\n`onActivate` as `ctx.restored` on its next activation, then deleted so a\nlater re-activation starts fresh."
8131
+ },
7516
8132
  {
7517
8133
  "kind": "field",
7518
8134
  "name": "activeAgent",
@@ -7554,84 +8170,10 @@
7554
8170
  },
7555
8171
  {
7556
8172
  "kind": "method",
7557
- "name": "registerHost",
8173
+ "name": "getActiveProviderName",
7558
8174
  "return": {
7559
8175
  "type": {
7560
- "text": "void"
7561
- }
7562
- },
7563
- "parameters": [
7564
- {
7565
- "name": "hostId",
7566
- "type": {
7567
- "text": "string"
7568
- }
7569
- }
7570
- ]
7571
- },
7572
- {
7573
- "kind": "method",
7574
- "name": "unregisterHost",
7575
- "return": {
7576
- "type": {
7577
- "text": "void"
7578
- }
7579
- },
7580
- "parameters": [
7581
- {
7582
- "name": "hostId",
7583
- "type": {
7584
- "text": "string"
7585
- }
7586
- }
7587
- ]
7588
- },
7589
- {
7590
- "kind": "method",
7591
- "name": "setActiveHost",
7592
- "return": {
7593
- "type": {
7594
- "text": "void"
7595
- }
7596
- },
7597
- "parameters": [
7598
- {
7599
- "name": "hostId",
7600
- "type": {
7601
- "text": "string"
7602
- }
7603
- }
7604
- ]
7605
- },
7606
- {
7607
- "kind": "method",
7608
- "name": "claimSideEffect",
7609
- "return": {
7610
- "type": {
7611
- "text": "boolean"
7612
- }
7613
- },
7614
- "parameters": [
7615
- {
7616
- "name": "interactionId",
7617
- "type": {
7618
- "text": "string"
7619
- }
7620
- },
7621
- {
7622
- "name": "hostId",
7623
- "type": {
7624
- "text": "string"
7625
- }
7626
- }
7627
- ]
7628
- },
7629
- {
7630
- "kind": "method",
7631
- "name": "getActiveProviderName",
7632
- "return": {
7633
- "type": {
7634
- "text": "string"
8176
+ "text": "string"
7635
8177
  }
7636
8178
  },
7637
8179
  "description": "Currently active provider name from the underlying ChatDriver."
@@ -7698,6 +8240,26 @@
7698
8240
  }
7699
8241
  }
7700
8242
  },
8243
+ {
8244
+ "kind": "method",
8245
+ "name": "compact",
8246
+ "return": {
8247
+ "type": {
8248
+ "text": "Promise<ChatMessage | null>"
8249
+ }
8250
+ },
8251
+ "description": "{@inheritDoc AiDriver.compact}"
8252
+ },
8253
+ {
8254
+ "kind": "method",
8255
+ "name": "canCompact",
8256
+ "return": {
8257
+ "type": {
8258
+ "text": "boolean"
8259
+ }
8260
+ },
8261
+ "description": "{@inheritDoc AiDriver.canCompact}"
8262
+ },
7701
8263
  {
7702
8264
  "kind": "method",
7703
8265
  "name": "getTurnSnapshots",
@@ -7786,6 +8348,34 @@
7786
8348
  }
7787
8349
  ]
7788
8350
  },
8351
+ {
8352
+ "kind": "method",
8353
+ "name": "primeRestoredAgentState",
8354
+ "return": {
8355
+ "type": {
8356
+ "text": "void"
8357
+ }
8358
+ },
8359
+ "parameters": [
8360
+ {
8361
+ "name": "snapshots",
8362
+ "type": {
8363
+ "text": "Record<string, unknown>"
8364
+ }
8365
+ }
8366
+ ],
8367
+ "description": "{@inheritDoc AiDriver.primeRestoredAgentState}"
8368
+ },
8369
+ {
8370
+ "kind": "method",
8371
+ "name": "getActiveAgent",
8372
+ "return": {
8373
+ "type": {
8374
+ "text": "AgentConfig | undefined"
8375
+ }
8376
+ },
8377
+ "description": "{@inheritDoc AiDriver.getActiveAgent}"
8378
+ },
7789
8379
  {
7790
8380
  "kind": "method",
7791
8381
  "name": "applyAgent",
@@ -7986,12 +8576,13 @@
7986
8576
  },
7987
8577
  {
7988
8578
  "kind": "field",
7989
- "name": "collapseEl",
8579
+ "name": "assistantEl",
7990
8580
  "type": {
7991
8581
  "text": "HTMLElement | null"
7992
8582
  },
7993
8583
  "privacy": "private",
7994
- "default": "null"
8584
+ "default": "null",
8585
+ "description": "The single assistant element. Captured while it's in the bubble slot and held\nacross the move (it's the same instance whether docked or in the bubble), so\npop-in can re-home it even though it's no longer a child of this manager."
7995
8586
  },
7996
8587
  {
7997
8588
  "kind": "field",
@@ -8019,6 +8610,52 @@
8019
8610
  },
8020
8611
  "privacy": "private"
8021
8612
  },
8613
+ {
8614
+ "kind": "method",
8615
+ "name": "findAssistant",
8616
+ "privacy": "private",
8617
+ "return": {
8618
+ "type": {
8619
+ "text": "HTMLElement | null"
8620
+ }
8621
+ },
8622
+ "description": "Locate the assistant element currently slotted into the bubble."
8623
+ },
8624
+ {
8625
+ "kind": "method",
8626
+ "name": "adoptAssistant",
8627
+ "return": {
8628
+ "type": {
8629
+ "text": "void"
8630
+ }
8631
+ },
8632
+ "parameters": [
8633
+ {
8634
+ "name": "el",
8635
+ "type": {
8636
+ "text": "HTMLElement"
8637
+ }
8638
+ },
8639
+ {
8640
+ "name": "docked",
8641
+ "type": {
8642
+ "text": "boolean"
8643
+ }
8644
+ }
8645
+ ],
8646
+ "description": "Register an externally-created assistant element and its docked state. For\nsingle-element hosts that create the assistant directly in a layout pane (rather\nthan statically in the bubble), so the manager tracks the one element, whether it's\ncurrently docked (for pop-in re-homing), reflects the right `popout-mode` on it\n(drives the header button), and hides the empty bubble."
8647
+ },
8648
+ {
8649
+ "kind": "method",
8650
+ "name": "syncBubbleVisibility",
8651
+ "privacy": "private",
8652
+ "return": {
8653
+ "type": {
8654
+ "text": "void"
8655
+ }
8656
+ },
8657
+ "description": "Hide the floating bubble unless it currently contains the assistant."
8658
+ },
8022
8659
  {
8023
8660
  "kind": "method",
8024
8661
  "name": "canDockChanged"
@@ -8075,7 +8712,7 @@
8075
8712
  "text": "boolean"
8076
8713
  }
8077
8714
  },
8078
- "description": "True when the collapse-mode assistant is active in the layout panel."
8715
+ "description": "True when the assistant is active in the layout panel (docked) rather than the bubble."
8079
8716
  },
8080
8717
  {
8081
8718
  "kind": "function",
@@ -8169,7 +8806,7 @@
8169
8806
  {
8170
8807
  "kind": "variable",
8171
8808
  "name": "settingsModalStyles",
8172
- "default": "css`\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 .settings-modal-section-title {\n margin: 0 0 calc(var(--design-unit) * 3px);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--neutral-foreground-hint);\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\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 .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 .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 .settings-context-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 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 color: var(--neutral-foreground-rest);\n }\n\n .settings-current-build {\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 .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 .settings-live-badge {\n display: inline-flex;\n align-items: center;\n gap: calc(var(--design-unit) * 1px);\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--accent-fill-rest);\n }\n\n .settings-live-dot {\n width: 7px;\n height: 7px;\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 font-weight: 600;\n }\n\n .settings-current-build-stats {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 3px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-build-stat {\n flex: 1;\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 .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 .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 .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 .settings-cost-history-row-right {\n align-items: flex-end;\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-tokens,\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 margin-top: -2px;\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`",
8809
+ "default": "css`\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 .settings-modal-section-title {\n margin: 0 0 calc(var(--design-unit) * 3px);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--neutral-foreground-hint);\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\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 .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 .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 .settings-context-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 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 color: var(--neutral-foreground-rest);\n }\n\n .settings-current-build {\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 .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 .settings-live-badge {\n display: inline-flex;\n align-items: center;\n gap: calc(var(--design-unit) * 1px);\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--accent-fill-rest);\n }\n\n .settings-live-dot {\n width: 7px;\n height: 7px;\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 font-weight: 600;\n }\n\n .settings-current-build-stats {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit) * 3px);\n margin-bottom: calc(var(--design-unit) * 3px);\n }\n\n .settings-build-stat {\n flex: 1;\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 .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 .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 .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 .settings-cost-history-row-right {\n align-items: flex-end;\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-tokens,\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 margin-top: -2px;\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`",
8173
8810
  "description": "Styles for the assistant settings modal (tabs, sections, toggles, cost summary)."
8174
8811
  }
8175
8812
  ],
@@ -8217,6 +8854,518 @@
8217
8854
  }
8218
8855
  }
8219
8856
  ]
8857
+ },
8858
+ {
8859
+ "kind": "javascript-module",
8860
+ "path": "src/state/persistence/diagnostics-cursors.ts",
8861
+ "declarations": [
8862
+ {
8863
+ "kind": "function",
8864
+ "name": "getDiagnosticsCursors",
8865
+ "return": {
8866
+ "type": {
8867
+ "text": "DiagnosticsCursors"
8868
+ }
8869
+ },
8870
+ "parameters": [
8871
+ {
8872
+ "name": "key",
8873
+ "type": {
8874
+ "text": "string"
8875
+ }
8876
+ }
8877
+ ],
8878
+ "description": "The shared cursors for `key`, created (empty) on first access. @internal"
8879
+ },
8880
+ {
8881
+ "kind": "function",
8882
+ "name": "clearDiagnosticsCursorRegistry",
8883
+ "return": {
8884
+ "type": {
8885
+ "text": "void"
8886
+ }
8887
+ },
8888
+ "description": "Drop all cursors — test isolation only. @internal"
8889
+ }
8890
+ ],
8891
+ "exports": [
8892
+ {
8893
+ "kind": "js",
8894
+ "name": "getDiagnosticsCursors",
8895
+ "declaration": {
8896
+ "name": "getDiagnosticsCursors",
8897
+ "module": "src/state/persistence/diagnostics-cursors.ts"
8898
+ }
8899
+ },
8900
+ {
8901
+ "kind": "js",
8902
+ "name": "clearDiagnosticsCursorRegistry",
8903
+ "declaration": {
8904
+ "name": "clearDiagnosticsCursorRegistry",
8905
+ "module": "src/state/persistence/diagnostics-cursors.ts"
8906
+ }
8907
+ }
8908
+ ]
8909
+ },
8910
+ {
8911
+ "kind": "javascript-module",
8912
+ "path": "src/state/persistence/diagnostics.ts",
8913
+ "declarations": [
8914
+ {
8915
+ "kind": "function",
8916
+ "name": "assembleDebugLog",
8917
+ "return": {
8918
+ "type": {
8919
+ "text": "DebugLog"
8920
+ }
8921
+ },
8922
+ "parameters": [
8923
+ {
8924
+ "name": "entries",
8925
+ "type": {
8926
+ "text": "DiagnosticEntry[]"
8927
+ }
8928
+ },
8929
+ {
8930
+ "name": "readme",
8931
+ "type": {
8932
+ "text": "readonly string[]"
8933
+ }
8934
+ }
8935
+ ],
8936
+ "description": "Reassemble diagnostic entries into the `{ readme, timeline, meta }` debug-log\nshape (GENC-1351 §5.8). `timeline` = the `message`/`turn`/`event` entries sorted\nby ISO `timestamp` (kind-rank tie-break). `meta` = the **newest** `meta-snapshot`'s\nblock only — a \"state at export\" photo, matching the single-page log. The older\nsnapshots are intentionally dropped: the per-turn evolution they would show is\nalready in the timeline (`turn.agentSnapshot` + `context.updated` events), so\nkeeping them would just repeat the bulky, near-static `agentSummary`. `readme` =\nthe passed (current) constant. Pure — reused for both the live current-page log\nand the reassembled lifetime log stitched from the persisted stream, so both\ncome out shape-identical."
8937
+ }
8938
+ ],
8939
+ "exports": [
8940
+ {
8941
+ "kind": "js",
8942
+ "name": "assembleDebugLog",
8943
+ "declaration": {
8944
+ "name": "assembleDebugLog",
8945
+ "module": "src/state/persistence/diagnostics.ts"
8946
+ }
8947
+ }
8948
+ ]
8949
+ },
8950
+ {
8951
+ "kind": "javascript-module",
8952
+ "path": "src/state/persistence/index.ts",
8953
+ "declarations": [],
8954
+ "exports": [
8955
+ {
8956
+ "kind": "js",
8957
+ "name": "PERSISTED_SESSION_VERSION",
8958
+ "declaration": {
8959
+ "name": "PERSISTED_SESSION_VERSION",
8960
+ "module": "./session-snapshot"
8961
+ }
8962
+ },
8963
+ {
8964
+ "kind": "js",
8965
+ "name": "PersistedSession",
8966
+ "declaration": {
8967
+ "name": "PersistedSession",
8968
+ "module": "./session-snapshot"
8969
+ }
8970
+ },
8971
+ {
8972
+ "kind": "js",
8973
+ "name": "WebStorageSessionProvider",
8974
+ "declaration": {
8975
+ "name": "WebStorageSessionProvider",
8976
+ "module": "./session-persistence-provider"
8977
+ }
8978
+ },
8979
+ {
8980
+ "kind": "js",
8981
+ "name": "SessionPersistenceProvider",
8982
+ "declaration": {
8983
+ "name": "SessionPersistenceProvider",
8984
+ "module": "./session-persistence-provider"
8985
+ }
8986
+ },
8987
+ {
8988
+ "kind": "js",
8989
+ "name": "SessionPersistenceConfig",
8990
+ "declaration": {
8991
+ "name": "SessionPersistenceConfig",
8992
+ "module": "./session-persistence-provider"
8993
+ }
8994
+ },
8995
+ {
8996
+ "kind": "js",
8997
+ "name": "SessionPreferences",
8998
+ "declaration": {
8999
+ "name": "SessionPreferences",
9000
+ "module": "./session-persistence-provider"
9001
+ }
9002
+ },
9003
+ {
9004
+ "kind": "js",
9005
+ "name": "assembleDebugLog",
9006
+ "declaration": {
9007
+ "name": "assembleDebugLog",
9008
+ "module": "./diagnostics"
9009
+ }
9010
+ },
9011
+ {
9012
+ "kind": "js",
9013
+ "name": "DiagnosticEntry",
9014
+ "declaration": {
9015
+ "name": "DiagnosticEntry",
9016
+ "module": "./diagnostics"
9017
+ }
9018
+ },
9019
+ {
9020
+ "kind": "js",
9021
+ "name": "DebugLog",
9022
+ "declaration": {
9023
+ "name": "DebugLog",
9024
+ "module": "./diagnostics"
9025
+ }
9026
+ }
9027
+ ]
9028
+ },
9029
+ {
9030
+ "kind": "javascript-module",
9031
+ "path": "src/state/persistence/persister-registry.ts",
9032
+ "declarations": [
9033
+ {
9034
+ "kind": "function",
9035
+ "name": "getOrCreatePersister",
9036
+ "return": {
9037
+ "type": {
9038
+ "text": "SessionPersister"
9039
+ }
9040
+ },
9041
+ "parameters": [
9042
+ {
9043
+ "name": "key",
9044
+ "type": {
9045
+ "text": "string"
9046
+ }
9047
+ },
9048
+ {
9049
+ "name": "factory",
9050
+ "type": {
9051
+ "text": "() => SessionPersister"
9052
+ }
9053
+ }
9054
+ ],
9055
+ "description": "Returns the existing persister for `key`, or calls `factory` to create and\nregister a new one. First view to connect creates it; later views share it."
9056
+ },
9057
+ {
9058
+ "kind": "function",
9059
+ "name": "getPersister",
9060
+ "return": {
9061
+ "type": {
9062
+ "text": "SessionPersister | undefined"
9063
+ }
9064
+ },
9065
+ "parameters": [
9066
+ {
9067
+ "name": "key",
9068
+ "type": {
9069
+ "text": "string"
9070
+ }
9071
+ }
9072
+ ],
9073
+ "description": "Returns the existing persister for `key`, or `undefined`."
9074
+ },
9075
+ {
9076
+ "kind": "function",
9077
+ "name": "deletePersister",
9078
+ "return": {
9079
+ "type": {
9080
+ "text": "void"
9081
+ }
9082
+ },
9083
+ "parameters": [
9084
+ {
9085
+ "name": "key",
9086
+ "type": {
9087
+ "text": "string"
9088
+ }
9089
+ }
9090
+ ],
9091
+ "description": "Removes the persister for `key` (explicit session teardown). Disposes it first\nso its debounced save AND diagnostics timers are cancelled — otherwise a timer\nscheduled by the outgoing session fires after the in-place switch and flushes the\nNEW session's entries under the OLD key, corrupting its stream (GENC-1351 §5.12)."
9092
+ }
9093
+ ],
9094
+ "exports": [
9095
+ {
9096
+ "kind": "js",
9097
+ "name": "getOrCreatePersister",
9098
+ "declaration": {
9099
+ "name": "getOrCreatePersister",
9100
+ "module": "src/state/persistence/persister-registry.ts"
9101
+ }
9102
+ },
9103
+ {
9104
+ "kind": "js",
9105
+ "name": "getPersister",
9106
+ "declaration": {
9107
+ "name": "getPersister",
9108
+ "module": "src/state/persistence/persister-registry.ts"
9109
+ }
9110
+ },
9111
+ {
9112
+ "kind": "js",
9113
+ "name": "deletePersister",
9114
+ "declaration": {
9115
+ "name": "deletePersister",
9116
+ "module": "src/state/persistence/persister-registry.ts"
9117
+ }
9118
+ }
9119
+ ]
9120
+ },
9121
+ {
9122
+ "kind": "javascript-module",
9123
+ "path": "src/state/persistence/session-persistence-provider.ts",
9124
+ "declarations": [
9125
+ {
9126
+ "kind": "class",
9127
+ "description": "A SessionPersistenceProvider backed by a Web Storage area. Both\n`window.sessionStorage` and `window.localStorage` implement the `Storage`\nAPI, so one class serves both: point it at `sessionStorage` for\nrefresh-survival that clears on tab close (the showcase default, O6), or at\n`localStorage` for durable local persistence.\n\nOpt-in: a host constructs it and passes it through `chatConfig`; the library\nnever instantiates it on its own.",
9128
+ "name": "WebStorageSessionProvider",
9129
+ "members": [
9130
+ {
9131
+ "kind": "field",
9132
+ "name": "storage",
9133
+ "type": {
9134
+ "text": "Storage"
9135
+ },
9136
+ "privacy": "private",
9137
+ "readonly": true,
9138
+ "default": "storage"
9139
+ },
9140
+ {
9141
+ "kind": "field",
9142
+ "name": "keyPrefix",
9143
+ "type": {
9144
+ "text": "string"
9145
+ },
9146
+ "privacy": "private",
9147
+ "readonly": true
9148
+ },
9149
+ {
9150
+ "kind": "field",
9151
+ "name": "saveDebounceMs",
9152
+ "type": {
9153
+ "text": "number"
9154
+ },
9155
+ "readonly": true,
9156
+ "description": "Web storage is synchronous and cheap, so the default is `0` — save as\nsoon as the tick settles, no throttle. Override via `options.saveDebounceMs`\n(e.g. if pointing at `localStorage` and you'd rather coalesce large writes)."
9157
+ },
9158
+ {
9159
+ "kind": "method",
9160
+ "name": "storageKey",
9161
+ "privacy": "private",
9162
+ "return": {
9163
+ "type": {
9164
+ "text": "string"
9165
+ }
9166
+ },
9167
+ "parameters": [
9168
+ {
9169
+ "name": "sessionKey",
9170
+ "type": {
9171
+ "text": "string"
9172
+ }
9173
+ }
9174
+ ]
9175
+ },
9176
+ {
9177
+ "kind": "method",
9178
+ "name": "preferencesKey",
9179
+ "privacy": "private",
9180
+ "return": {
9181
+ "type": {
9182
+ "text": "string"
9183
+ }
9184
+ },
9185
+ "parameters": [
9186
+ {
9187
+ "name": "sessionKey",
9188
+ "type": {
9189
+ "text": "string"
9190
+ }
9191
+ }
9192
+ ],
9193
+ "description": "Preferences key, namespaced apart from the session key so `clear` leaves it."
9194
+ },
9195
+ {
9196
+ "kind": "method",
9197
+ "name": "load",
9198
+ "return": {
9199
+ "type": {
9200
+ "text": "Promise<PersistedSession | null>"
9201
+ }
9202
+ },
9203
+ "parameters": [
9204
+ {
9205
+ "name": "sessionKey",
9206
+ "type": {
9207
+ "text": "string"
9208
+ }
9209
+ }
9210
+ ]
9211
+ },
9212
+ {
9213
+ "kind": "method",
9214
+ "name": "save",
9215
+ "return": {
9216
+ "type": {
9217
+ "text": "Promise<void>"
9218
+ }
9219
+ },
9220
+ "parameters": [
9221
+ {
9222
+ "name": "sessionKey",
9223
+ "type": {
9224
+ "text": "string"
9225
+ }
9226
+ },
9227
+ {
9228
+ "name": "snapshot",
9229
+ "type": {
9230
+ "text": "PersistedSession"
9231
+ }
9232
+ }
9233
+ ]
9234
+ },
9235
+ {
9236
+ "kind": "method",
9237
+ "name": "clear",
9238
+ "return": {
9239
+ "type": {
9240
+ "text": "Promise<void>"
9241
+ }
9242
+ },
9243
+ "parameters": [
9244
+ {
9245
+ "name": "sessionKey",
9246
+ "type": {
9247
+ "text": "string"
9248
+ }
9249
+ }
9250
+ ]
9251
+ },
9252
+ {
9253
+ "kind": "method",
9254
+ "name": "loadPreferences",
9255
+ "return": {
9256
+ "type": {
9257
+ "text": "Promise<SessionPreferences | undefined>"
9258
+ }
9259
+ },
9260
+ "parameters": [
9261
+ {
9262
+ "name": "sessionKey",
9263
+ "type": {
9264
+ "text": "string"
9265
+ }
9266
+ }
9267
+ ]
9268
+ },
9269
+ {
9270
+ "kind": "method",
9271
+ "name": "savePreferences",
9272
+ "return": {
9273
+ "type": {
9274
+ "text": "Promise<void>"
9275
+ }
9276
+ },
9277
+ "parameters": [
9278
+ {
9279
+ "name": "sessionKey",
9280
+ "type": {
9281
+ "text": "string"
9282
+ }
9283
+ },
9284
+ {
9285
+ "name": "preferences",
9286
+ "type": {
9287
+ "text": "SessionPreferences"
9288
+ }
9289
+ }
9290
+ ]
9291
+ }
9292
+ ]
9293
+ }
9294
+ ],
9295
+ "exports": [
9296
+ {
9297
+ "kind": "js",
9298
+ "name": "WebStorageSessionProvider",
9299
+ "declaration": {
9300
+ "name": "WebStorageSessionProvider",
9301
+ "module": "src/state/persistence/session-persistence-provider.ts"
9302
+ }
9303
+ }
9304
+ ]
9305
+ },
9306
+ {
9307
+ "kind": "javascript-module",
9308
+ "path": "src/state/persistence/session-persister.ts",
9309
+ "declarations": [],
9310
+ "exports": []
9311
+ },
9312
+ {
9313
+ "kind": "javascript-module",
9314
+ "path": "src/state/persistence/session-snapshot.ts",
9315
+ "declarations": [
9316
+ {
9317
+ "kind": "variable",
9318
+ "name": "PERSISTED_SESSION_VERSION",
9319
+ "type": {
9320
+ "text": "number"
9321
+ },
9322
+ "default": "1",
9323
+ "description": "Schema version of the persisted session shape. Bump on an incompatible\nchange; a snapshot whose `version` doesn't match is discarded on load rather\nthan risk feeding a stale shape into restore.",
9324
+ "privacy": "public"
9325
+ },
9326
+ {
9327
+ "kind": "function",
9328
+ "name": "unknownAgentSnapshots",
9329
+ "return": {
9330
+ "type": {
9331
+ "text": "string[]"
9332
+ }
9333
+ },
9334
+ "parameters": [
9335
+ {
9336
+ "name": "snapshot",
9337
+ "type": {
9338
+ "text": "PersistedSession"
9339
+ }
9340
+ },
9341
+ {
9342
+ "name": "knownAgentNames",
9343
+ "type": {
9344
+ "text": "Iterable<string>"
9345
+ }
9346
+ }
9347
+ ],
9348
+ "description": "Names of agents the restored session holds machine/state snapshots for but\nwhich are **not** in the currently-configured agent set — their flow cannot\nresume. Common when the host's agent array is dynamic (agents gated by feature\nflags, project state, or permissions; e.g. genesis-create). Callers should\nsurface these; the restore is otherwise non-fatal (the transcript and any\nknown agents still restore). Returns `[]` when `knownAgentNames` is empty —\nthe agent set isn't known yet, so we can't classify without false positives."
9349
+ }
9350
+ ],
9351
+ "exports": [
9352
+ {
9353
+ "kind": "js",
9354
+ "name": "PERSISTED_SESSION_VERSION",
9355
+ "declaration": {
9356
+ "name": "PERSISTED_SESSION_VERSION",
9357
+ "module": "src/state/persistence/session-snapshot.ts"
9358
+ }
9359
+ },
9360
+ {
9361
+ "kind": "js",
9362
+ "name": "unknownAgentSnapshots",
9363
+ "declaration": {
9364
+ "name": "unknownAgentSnapshots",
9365
+ "module": "src/state/persistence/session-snapshot.ts"
9366
+ }
9367
+ }
9368
+ ]
8220
9369
  }
8221
9370
  ]
8222
9371
  }