@genesislcap/ai-assistant 15.19.0 → 15.19.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 (288) hide show
  1. package/package.json +17 -18
  2. package/api-extractor.json +0 -11
  3. package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts +0 -2
  4. package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts.map +0 -1
  5. package/dist/dts/components/chat-driver/chat-driver.invocation-scope.test.d.ts +0 -2
  6. package/dist/dts/components/chat-driver/chat-driver.invocation-scope.test.d.ts.map +0 -1
  7. package/dist/dts/components/chat-driver/chat-driver.test.d.ts +0 -2
  8. package/dist/dts/components/chat-driver/chat-driver.test.d.ts.map +0 -1
  9. package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts +0 -2
  10. package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts.map +0 -1
  11. package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts +0 -2
  12. package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts.map +0 -1
  13. package/dist/dts/components/chat-driver/chat-driver.turn-usage.test.d.ts +0 -2
  14. package/dist/dts/components/chat-driver/chat-driver.turn-usage.test.d.ts.map +0 -1
  15. package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.test.d.ts +0 -2
  16. package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.test.d.ts.map +0 -1
  17. package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts +0 -2
  18. package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts.map +0 -1
  19. package/dist/dts/components/orchestrating-driver/orchestrating-driver.cost.test.d.ts +0 -2
  20. package/dist/dts/components/orchestrating-driver/orchestrating-driver.cost.test.d.ts.map +0 -1
  21. package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts +0 -2
  22. package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts.map +0 -1
  23. package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts +0 -2
  24. package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts.map +0 -1
  25. package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts +0 -2
  26. package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts.map +0 -1
  27. package/dist/dts/config/define-stateful-agent.test.d.ts +0 -2
  28. package/dist/dts/config/define-stateful-agent.test.d.ts.map +0 -1
  29. package/dist/dts/config/validate-providers.test.d.ts +0 -2
  30. package/dist/dts/config/validate-providers.test.d.ts.map +0 -1
  31. package/dist/dts/main/blocked-state.test.d.ts +0 -2
  32. package/dist/dts/main/blocked-state.test.d.ts.map +0 -1
  33. package/dist/dts/main/budget-meter.test.d.ts +0 -2
  34. package/dist/dts/main/budget-meter.test.d.ts.map +0 -1
  35. package/dist/dts/main/cost-session-banking.test.d.ts +0 -2
  36. package/dist/dts/main/cost-session-banking.test.d.ts.map +0 -1
  37. package/dist/dts/main/file-attachments.test.d.ts +0 -2
  38. package/dist/dts/main/file-attachments.test.d.ts.map +0 -1
  39. package/dist/dts/main/interaction-cost.test.d.ts +0 -2
  40. package/dist/dts/main/interaction-cost.test.d.ts.map +0 -1
  41. package/dist/dts/main/main.styles.test.d.ts +0 -2
  42. package/dist/dts/main/main.styles.test.d.ts.map +0 -1
  43. package/dist/dts/main/persistence-broken-sources.test.d.ts +0 -2
  44. package/dist/dts/main/persistence-broken-sources.test.d.ts.map +0 -1
  45. package/dist/dts/main/popout-interaction-gate.test.d.ts +0 -2
  46. package/dist/dts/main/popout-interaction-gate.test.d.ts.map +0 -1
  47. package/dist/dts/state/ai-assistant-slice.test.d.ts +0 -2
  48. package/dist/dts/state/ai-assistant-slice.test.d.ts.map +0 -1
  49. package/dist/dts/state/debug-event-log.test.d.ts +0 -2
  50. package/dist/dts/state/debug-event-log.test.d.ts.map +0 -1
  51. package/dist/dts/state/driver-registry.test.d.ts +0 -2
  52. package/dist/dts/state/driver-registry.test.d.ts.map +0 -1
  53. package/dist/dts/state/interaction-context.test.d.ts +0 -2
  54. package/dist/dts/state/interaction-context.test.d.ts.map +0 -1
  55. package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts +0 -2
  56. package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts.map +0 -1
  57. package/dist/dts/state/persistence/diagnostics.test.d.ts +0 -2
  58. package/dist/dts/state/persistence/diagnostics.test.d.ts.map +0 -1
  59. package/dist/dts/state/persistence/session-persistence-provider.test.d.ts +0 -2
  60. package/dist/dts/state/persistence/session-persistence-provider.test.d.ts.map +0 -1
  61. package/dist/dts/state/persistence/session-persistence.integration.test.d.ts +0 -2
  62. package/dist/dts/state/persistence/session-persistence.integration.test.d.ts.map +0 -1
  63. package/dist/dts/state/persistence/session-persister.test.d.ts +0 -2
  64. package/dist/dts/state/persistence/session-persister.test.d.ts.map +0 -1
  65. package/dist/dts/state/persistence/session-snapshot.test.d.ts +0 -2
  66. package/dist/dts/state/persistence/session-snapshot.test.d.ts.map +0 -1
  67. package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts +0 -2
  68. package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts.map +0 -1
  69. package/dist/dts/utils/animation-exclusivity.test.d.ts +0 -2
  70. package/dist/dts/utils/animation-exclusivity.test.d.ts.map +0 -1
  71. package/dist/dts/utils/collect-session-models.test.d.ts +0 -2
  72. package/dist/dts/utils/collect-session-models.test.d.ts.map +0 -1
  73. package/dist/dts/utils/condense-history.test.d.ts +0 -2
  74. package/dist/dts/utils/condense-history.test.d.ts.map +0 -1
  75. package/dist/dts/utils/cost-session-history.test.d.ts +0 -2
  76. package/dist/dts/utils/cost-session-history.test.d.ts.map +0 -1
  77. package/dist/dts/utils/derive-cost-session-title.test.d.ts +0 -2
  78. package/dist/dts/utils/derive-cost-session-title.test.d.ts.map +0 -1
  79. package/dist/dts/utils/flatten-sub-agent-messages.test.d.ts +0 -2
  80. package/dist/dts/utils/flatten-sub-agent-messages.test.d.ts.map +0 -1
  81. package/dist/dts/utils/history-transform.test.d.ts +0 -2
  82. package/dist/dts/utils/history-transform.test.d.ts.map +0 -1
  83. package/dist/dts/utils/message-partition.test.d.ts +0 -2
  84. package/dist/dts/utils/message-partition.test.d.ts.map +0 -1
  85. package/dist/dts/utils/resolve-cost-history-config.test.d.ts +0 -2
  86. package/dist/dts/utils/resolve-cost-history-config.test.d.ts.map +0 -1
  87. package/dist/dts/utils/resolve-preference-baseline.test.d.ts +0 -2
  88. package/dist/dts/utils/resolve-preference-baseline.test.d.ts.map +0 -1
  89. package/dist/dts/utils/strip-agent-handlers.test.d.ts +0 -2
  90. package/dist/dts/utils/strip-agent-handlers.test.d.ts.map +0 -1
  91. package/dist/dts/utils/sum-costs.test.d.ts +0 -2
  92. package/dist/dts/utils/sum-costs.test.d.ts.map +0 -1
  93. package/dist/dts/utils/sum-tokens.test.d.ts +0 -2
  94. package/dist/dts/utils/sum-tokens.test.d.ts.map +0 -1
  95. package/dist/dts/utils/sum-usage.test.d.ts +0 -2
  96. package/dist/dts/utils/sum-usage.test.d.ts.map +0 -1
  97. package/dist/dts/utils/usage-rows.test.d.ts +0 -2
  98. package/dist/dts/utils/usage-rows.test.d.ts.map +0 -1
  99. package/dist/esm/components/chat-driver/chat-driver.compact.test.js +0 -93
  100. package/dist/esm/components/chat-driver/chat-driver.invocation-scope.test.js +0 -238
  101. package/dist/esm/components/chat-driver/chat-driver.test.js +0 -2770
  102. package/dist/esm/components/chat-driver/chat-driver.thinking-policy.test.js +0 -137
  103. package/dist/esm/components/chat-driver/chat-driver.trace-capture.test.js +0 -200
  104. package/dist/esm/components/chat-driver/chat-driver.turn-usage.test.js +0 -268
  105. package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.test.js +0 -104
  106. package/dist/esm/components/orchestrating-driver/orchestrating-driver.budget.test.js +0 -312
  107. package/dist/esm/components/orchestrating-driver/orchestrating-driver.cost.test.js +0 -76
  108. package/dist/esm/components/orchestrating-driver/orchestrating-driver.pin.test.js +0 -61
  109. package/dist/esm/components/settings-modal/settings-modal.styles.test.js +0 -80
  110. package/dist/esm/components/settings-modal/settings-modal.template.test.js +0 -91
  111. package/dist/esm/config/define-stateful-agent.test.js +0 -53
  112. package/dist/esm/config/validate-providers.test.js +0 -100
  113. package/dist/esm/main/blocked-state.test.js +0 -1065
  114. package/dist/esm/main/budget-meter.test.js +0 -359
  115. package/dist/esm/main/cost-session-banking.test.js +0 -538
  116. package/dist/esm/main/file-attachments.test.js +0 -164
  117. package/dist/esm/main/interaction-cost.test.js +0 -107
  118. package/dist/esm/main/main.styles.test.js +0 -161
  119. package/dist/esm/main/persistence-broken-sources.test.js +0 -180
  120. package/dist/esm/main/popout-interaction-gate.test.js +0 -54
  121. package/dist/esm/state/ai-assistant-slice.test.js +0 -229
  122. package/dist/esm/state/debug-event-log.test.js +0 -117
  123. package/dist/esm/state/driver-registry.test.js +0 -55
  124. package/dist/esm/state/interaction-context.test.js +0 -78
  125. package/dist/esm/state/persistence/diagnostics-cursors.test.js +0 -30
  126. package/dist/esm/state/persistence/diagnostics.test.js +0 -280
  127. package/dist/esm/state/persistence/session-persistence-provider.test.js +0 -110
  128. package/dist/esm/state/persistence/session-persistence.integration.test.js +0 -113
  129. package/dist/esm/state/persistence/session-persister.test.js +0 -613
  130. package/dist/esm/state/persistence/session-snapshot.test.js +0 -256
  131. package/dist/esm/state/persistence/stateful-restore.e2e.test.js +0 -158
  132. package/dist/esm/utils/animation-exclusivity.test.js +0 -52
  133. package/dist/esm/utils/collect-session-models.test.js +0 -53
  134. package/dist/esm/utils/condense-history.test.js +0 -547
  135. package/dist/esm/utils/cost-session-history.test.js +0 -174
  136. package/dist/esm/utils/derive-cost-session-title.test.js +0 -37
  137. package/dist/esm/utils/flatten-sub-agent-messages.test.js +0 -139
  138. package/dist/esm/utils/history-transform.test.js +0 -158
  139. package/dist/esm/utils/message-partition.test.js +0 -90
  140. package/dist/esm/utils/resolve-cost-history-config.test.js +0 -32
  141. package/dist/esm/utils/resolve-preference-baseline.test.js +0 -69
  142. package/dist/esm/utils/strip-agent-handlers.test.js +0 -81
  143. package/dist/esm/utils/sum-costs.test.js +0 -114
  144. package/dist/esm/utils/sum-tokens.test.js +0 -51
  145. package/dist/esm/utils/sum-usage.test.js +0 -164
  146. package/dist/esm/utils/usage-rows.test.js +0 -189
  147. package/dist/tsconfig.tsbuildinfo +0 -1
  148. package/license.txt +0 -46
  149. package/sandbox/tsconfig.json +0 -8
  150. package/src/channel/ai-activity-bus.ts +0 -209
  151. package/src/channel/ai-activity-channel.ts +0 -146
  152. package/src/chat-driver-node.ts +0 -159
  153. package/src/components/activity-halo/activity-halo.ts +0 -106
  154. package/src/components/agent-picker/agent-picker.constants.ts +0 -2
  155. package/src/components/agent-picker/agent-picker.styles.ts +0 -24
  156. package/src/components/agent-picker/agent-picker.template.ts +0 -54
  157. package/src/components/agent-picker/agent-picker.ts +0 -99
  158. package/src/components/agent-picker/index.ts +0 -1
  159. package/src/components/ai-driver/ai-driver.ts +0 -166
  160. package/src/components/ai-driver/index.ts +0 -1
  161. package/src/components/chat-bubble/chat-bubble.styles.ts +0 -194
  162. package/src/components/chat-bubble/chat-bubble.template.ts +0 -67
  163. package/src/components/chat-bubble/chat-bubble.ts +0 -436
  164. package/src/components/chat-bubble/index.ts +0 -1
  165. package/src/components/chat-driver/align-event-globals.ts +0 -23
  166. package/src/components/chat-driver/chat-driver.compact.test.ts +0 -131
  167. package/src/components/chat-driver/chat-driver.invocation-scope.test.ts +0 -285
  168. package/src/components/chat-driver/chat-driver.test.ts +0 -3679
  169. package/src/components/chat-driver/chat-driver.thinking-policy.test.ts +0 -185
  170. package/src/components/chat-driver/chat-driver.trace-capture.test.ts +0 -251
  171. package/src/components/chat-driver/chat-driver.ts +0 -3925
  172. package/src/components/chat-driver/chat-driver.turn-usage.test.ts +0 -362
  173. package/src/components/chat-driver/index.ts +0 -1
  174. package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts +0 -7
  175. package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts +0 -6
  176. package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts +0 -144
  177. package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts +0 -243
  178. package/src/components/chat-interaction-wrapper/index.ts +0 -3
  179. package/src/components/chat-markdown/chat-markdown.ts +0 -89
  180. package/src/components/chat-markdown/index.ts +0 -1
  181. package/src/components/flowing-waves-indicator.ts +0 -286
  182. package/src/components/halo-overlay.ts +0 -184
  183. package/src/components/orchestrating-driver/index.ts +0 -1
  184. package/src/components/orchestrating-driver/orchestrating-driver.budget.test.ts +0 -438
  185. package/src/components/orchestrating-driver/orchestrating-driver.cost.test.ts +0 -107
  186. package/src/components/orchestrating-driver/orchestrating-driver.pin.test.ts +0 -96
  187. package/src/components/orchestrating-driver/orchestrating-driver.ts +0 -813
  188. package/src/components/plasma-orb-indicator.ts +0 -281
  189. package/src/components/popout-manager/index.ts +0 -1
  190. package/src/components/popout-manager/popout-manager.ts +0 -212
  191. package/src/components/settings-modal/index.ts +0 -2
  192. package/src/components/settings-modal/settings-modal.styles.test.ts +0 -94
  193. package/src/components/settings-modal/settings-modal.styles.ts +0 -853
  194. package/src/components/settings-modal/settings-modal.template.test.ts +0 -124
  195. package/src/components/settings-modal/settings-modal.template.ts +0 -943
  196. package/src/components/waves-indicator.ts +0 -241
  197. package/src/config/config.ts +0 -608
  198. package/src/config/define-stateful-agent.test.ts +0 -64
  199. package/src/config/define-stateful-agent.ts +0 -642
  200. package/src/config/fallback-agents.ts +0 -29
  201. package/src/config/index.ts +0 -2
  202. package/src/config/validate-providers.test.ts +0 -148
  203. package/src/config/validate-providers.ts +0 -58
  204. package/src/index.ts +0 -29
  205. package/src/main/blocked-state.test.ts +0 -1444
  206. package/src/main/budget-meter.test.ts +0 -477
  207. package/src/main/cost-session-banking.test.ts +0 -679
  208. package/src/main/file-attachments.test.ts +0 -215
  209. package/src/main/index.ts +0 -3
  210. package/src/main/interaction-cost.test.ts +0 -140
  211. package/src/main/main.styles.test.ts +0 -216
  212. package/src/main/main.styles.ts +0 -995
  213. package/src/main/main.template.ts +0 -1119
  214. package/src/main/main.ts +0 -5432
  215. package/src/main/main.types.ts +0 -225
  216. package/src/main/persistence-broken-sources.test.ts +0 -219
  217. package/src/main/popout-interaction-gate.test.ts +0 -87
  218. package/src/provider/ai-provider-switcher.ts +0 -40
  219. package/src/provider/assistant-app-settings.ts +0 -84
  220. package/src/state/ai-assistant-slice.test.ts +0 -336
  221. package/src/state/ai-assistant-slice.ts +0 -604
  222. package/src/state/debug-event-log.test.ts +0 -154
  223. package/src/state/debug-event-log.ts +0 -358
  224. package/src/state/driver-registry.test.ts +0 -70
  225. package/src/state/driver-registry.ts +0 -79
  226. package/src/state/interaction-context.test.ts +0 -90
  227. package/src/state/interaction-context.ts +0 -101
  228. package/src/state/persistence/build-timeline-entries.ts +0 -66
  229. package/src/state/persistence/diagnostics-cursors.test.ts +0 -53
  230. package/src/state/persistence/diagnostics-cursors.ts +0 -80
  231. package/src/state/persistence/diagnostics.test.ts +0 -346
  232. package/src/state/persistence/diagnostics.ts +0 -220
  233. package/src/state/persistence/index.ts +0 -10
  234. package/src/state/persistence/persister-registry.ts +0 -55
  235. package/src/state/persistence/session-persistence-provider.test.ts +0 -136
  236. package/src/state/persistence/session-persistence-provider.ts +0 -226
  237. package/src/state/persistence/session-persistence.integration.test.ts +0 -141
  238. package/src/state/persistence/session-persister.test.ts +0 -787
  239. package/src/state/persistence/session-persister.ts +0 -917
  240. package/src/state/persistence/session-snapshot.test.ts +0 -352
  241. package/src/state/persistence/session-snapshot.ts +0 -344
  242. package/src/state/persistence/stateful-restore.e2e.test.ts +0 -229
  243. package/src/state/session-store.ts +0 -56
  244. package/src/styles/ai-colours.ts +0 -30
  245. package/src/styles/menu.ts +0 -187
  246. package/src/styles/settings-section.ts +0 -40
  247. package/src/suggestions/chat-suggestions.ts +0 -186
  248. package/src/tags/index.ts +0 -1
  249. package/src/types/ai-chat-widget.ts +0 -67
  250. package/src/types/interaction-context.ts +0 -82
  251. package/src/utils/animated-panel-toggle.ts +0 -62
  252. package/src/utils/animation-exclusivity.test.ts +0 -72
  253. package/src/utils/animation-exclusivity.ts +0 -40
  254. package/src/utils/banked-usage-baselines.ts +0 -90
  255. package/src/utils/collect-session-models.test.ts +0 -82
  256. package/src/utils/collect-session-models.ts +0 -65
  257. package/src/utils/condense-history.test.ts +0 -746
  258. package/src/utils/condense-history.ts +0 -448
  259. package/src/utils/cost-session-history.test.ts +0 -226
  260. package/src/utils/cost-session-history.ts +0 -218
  261. package/src/utils/derive-cost-session-title.test.ts +0 -63
  262. package/src/utils/derive-cost-session-title.ts +0 -76
  263. package/src/utils/flatten-sub-agent-messages.test.ts +0 -163
  264. package/src/utils/flatten-sub-agent-messages.ts +0 -88
  265. package/src/utils/format-usd.ts +0 -26
  266. package/src/utils/history-transform.test.ts +0 -228
  267. package/src/utils/history-transform.ts +0 -163
  268. package/src/utils/index.ts +0 -3
  269. package/src/utils/logger.ts +0 -3
  270. package/src/utils/message-partition.test.ts +0 -129
  271. package/src/utils/message-partition.ts +0 -115
  272. package/src/utils/resolve-cost-history-config.test.ts +0 -38
  273. package/src/utils/resolve-cost-history-config.ts +0 -38
  274. package/src/utils/resolve-preference-baseline.test.ts +0 -84
  275. package/src/utils/resolve-preference-baseline.ts +0 -80
  276. package/src/utils/strip-agent-handlers.test.ts +0 -99
  277. package/src/utils/strip-agent-handlers.ts +0 -53
  278. package/src/utils/sum-costs.test.ts +0 -136
  279. package/src/utils/sum-costs.ts +0 -18
  280. package/src/utils/sum-tokens.test.ts +0 -93
  281. package/src/utils/sum-tokens.ts +0 -68
  282. package/src/utils/sum-usage.test.ts +0 -191
  283. package/src/utils/sum-usage.ts +0 -208
  284. package/src/utils/tool-fold.ts +0 -181
  285. package/src/utils/usage-rows.test.ts +0 -237
  286. package/src/utils/usage-rows.ts +0 -187
  287. package/src/utils/with-timeout.ts +0 -24
  288. package/tsconfig.json +0 -9
@@ -1,243 +0,0 @@
1
- import type { InteractionResult } from '@genesislcap/foundation-ai';
2
- import { customElement, GenesisElement, observable } from '@genesislcap/web-core';
3
- import { createInteractionContext } from '../../state/interaction-context';
4
- import type { AiChatInteraction, AiChatWidget } from '../../types/ai-chat-widget';
5
- import type { InteractionContext } from '../../types/interaction-context';
6
- import { logger } from '../../utils/logger';
7
- import { AiChatInteractionWrapperStyles } from './chat-interaction-wrapper.styles';
8
- import { AiChatInteractionWrapperTemplate } from './chat-interaction-wrapper.template';
9
-
10
- /** Structural view of the assistant host, pierced across the wrapper's shadow boundary. */
11
- type InteractionHost = {
12
- isEngaged?: boolean;
13
- getInteractionContext?: (id: string) => InteractionContext | undefined;
14
- };
15
-
16
- export type ChatInteractionEventsMap = {
17
- 'interaction-completed': InteractionResult<unknown> & { interactionId: string };
18
- 'interaction-cost': { interactionId: string; costUsd: number };
19
- };
20
-
21
- /**
22
- * Detail payload for the `interaction-completed` event.
23
- * @public
24
- */
25
- export type InteractionCompletedEventDetail = ChatInteractionEventsMap['interaction-completed'];
26
-
27
- /**
28
- * Detail payload for the `interaction-cost` event — a POSITIVE DELTA in USD, not a running total.
29
- * @public
30
- */
31
- export type InteractionCostEventDetail = ChatInteractionEventsMap['interaction-cost'];
32
-
33
- /**
34
- * Hosts an interactive AI chat sub-component by tag name.
35
- * @public
36
- *
37
- * @fires interaction-completed - Fired when the interaction finishes. detail: `InteractionCompletedEventDetail`
38
- * @fires interaction-cost - Fired when a widget spends money AFTER resolving. detail: `InteractionCostEventDetail`
39
- */
40
- @customElement({
41
- name: 'ai-chat-interaction-wrapper',
42
- template: AiChatInteractionWrapperTemplate,
43
- styles: AiChatInteractionWrapperStyles,
44
- })
45
- export class AiChatInteractionWrapper extends GenesisElement {
46
- /** @internal */
47
- @observable componentName: string = '';
48
- /** @internal */
49
- @observable data: any;
50
- /** @internal */
51
- @observable interactionId: string = '';
52
- /** The resolved result once the interaction has completed. Forwarded to the rendered component. @internal */
53
- @observable resolved: InteractionResult<unknown> | undefined = undefined;
54
- /** @internal */
55
- container!: HTMLElement;
56
-
57
- /** Observes the rendered widget for mid-lifecycle size changes — see {@link observeWidgetResize}. */
58
- private _resizeObserver?: ResizeObserver;
59
-
60
- connectedCallback() {
61
- super.connectedCallback();
62
- this.renderComponent();
63
- }
64
-
65
- disconnectedCallback() {
66
- super.disconnectedCallback();
67
- this._resizeObserver?.disconnect();
68
- this._resizeObserver = undefined;
69
- }
70
-
71
- componentNameChanged() {
72
- this.renderComponent();
73
- }
74
-
75
- /**
76
- * Re-render the hosted widget when the interaction identity changes. This
77
- * ensures widgets don't go stale with them being rendered with `recycle: true`
78
- * when messages are dynamically filtered, showing/hiding thinking/tool calls
79
- *
80
- * `interactionId` is a per-interaction UUID, so it changes exactly when the
81
- * hosted interaction does. Property bindings apply in template order
82
- * (componentName, data, interactionId), so `data` is already rebound by the
83
- * time this fires and the fresh widget is built with the correct data.
84
- */
85
- interactionIdChanged() {
86
- this.renderComponent();
87
- }
88
-
89
- resolvedChanged() {
90
- const element = this.container?.firstElementChild as (AiChatWidget & HTMLElement) | null;
91
- // The interaction just resolved: forward the resolved descriptor to the LIVE widget
92
- // in place, preserving its DOM/state (no re-create). If no matching element exists
93
- // yet (e.g. a history re-render straight into the resolved state), render it fresh.
94
- if (element && element.tagName?.toLowerCase() === this.componentName) {
95
- if (this.resolved) {
96
- element.interaction = { status: 'resolved', data: this.data, result: this.resolved };
97
- }
98
- } else if (this.resolved) {
99
- this.renderComponent();
100
- }
101
- }
102
-
103
- /**
104
- * Watch the rendered widget element for box-size changes. When the widget
105
- * grows or shrinks mid-lifecycle (e.g. expanding a "More info" panel,
106
- * appending an SSE status row, revealing generated code), bubble a
107
- * `request-scroll-to-bottom` event so `FoundationAiAssistant` re-snaps to
108
- * the bottom. `scrollToBottom` respects `_userScrolledAway`, so a user
109
- * reading old messages is not yanked back.
110
- *
111
- * The first ResizeObserver callback fires synchronously with the initial
112
- * size when `observe()` is called; we skip it so freshly-rendered widgets
113
- * don't double up with the existing `handleMessagesUpdate` auto-scroll for
114
- * new messages.
115
- */
116
- private observeWidgetResize(element: Element) {
117
- this._resizeObserver?.disconnect();
118
- let initialFireSkipped = false;
119
- this._resizeObserver = new ResizeObserver(() => {
120
- if (!initialFireSkipped) {
121
- initialFireSkipped = true;
122
- return;
123
- }
124
- this.dispatchEvent(
125
- new CustomEvent('request-scroll-to-bottom', { bubbles: true, composed: true }),
126
- );
127
- });
128
- this._resizeObserver.observe(element);
129
- }
130
-
131
- private renderComponent() {
132
- if (!this.container || !this.componentName) return;
133
-
134
- // Clear children without using innerHTML
135
- this._resizeObserver?.disconnect();
136
- this._resizeObserver = undefined;
137
- this.container.replaceChildren();
138
-
139
- if (!customElements.get(this.componentName)) {
140
- logger.warn(
141
- `Interactive component "${this.componentName}" is not registered in the customElements registry.`,
142
- );
143
- const errorDiv = document.createElement('div');
144
- errorDiv.textContent = `Error: Component "${this.componentName}" is not available in this application.`;
145
- this.container.appendChild(errorDiv);
146
- return;
147
- }
148
-
149
- try {
150
- // Pierce the wrapper's shadow boundary to read host state: `isEngaged` (gates
151
- // autofocus) and the driver-owned interaction context. Single-view model
152
- // (GENC-1351): one assistant view always renders the live widget.
153
- const root = this.getRootNode();
154
- const host = root instanceof ShadowRoot ? (root.host as InteractionHost) : null;
155
-
156
- const element = document.createElement(this.componentName) as AiChatWidget & HTMLElement;
157
-
158
- // GENC-1390: the widget's whole input surface is the discriminated interaction
159
- // descriptor + its stable id. Rebuilt on every (re)mount; the pending variant's
160
- // `interactionContext` is the SAME driver-owned object across remounts, which is
161
- // what lets a widget's live state survive the element teardown/recreate.
162
- element.interactionId = this.interactionId;
163
- element.interaction = this.buildInteraction(host);
164
-
165
- // Handle completion from the inner component. Guard against re-emission if the
166
- // interaction was already resolved (auto-resolve widgets fire on connectedCallback
167
- // when rendering history).
168
- element.addEventListener('interaction-completed', (e: CustomEvent) => {
169
- e.stopPropagation();
170
- if (this.resolved) return;
171
-
172
- this.$emit('interaction-completed', {
173
- interactionId: this.interactionId,
174
- ...e.detail,
175
- });
176
- });
177
-
178
- /**
179
- * Spend the widget incurs AFTER it has resolved.
180
- *
181
- * Deliberately NOT guarded by `this.resolved`, which is the entire point: a widget that
182
- * resolves early so the assistant stops waiting can stay interactive for minutes and do more
183
- * paid work for the user. The completion listener above is guarded because a second
184
- * RESOLUTION would be wrong; a second charge is simply true, and before this event that spend
185
- * had no way to reach the total the user is shown.
186
- */
187
- element.addEventListener('interaction-cost', (e: CustomEvent) => {
188
- e.stopPropagation();
189
- // Forwarded UNVALIDATED. `recordExternalCost` already rejects anything that is not a
190
- // positive finite amount AND records why it dropped it; validating here as well made that
191
- // trace unreachable through the event path — which is a widget's only way in — so a widget
192
- // emitting NaN or a negative got silently nothing, anywhere. One validator, one trace.
193
- this.$emit('interaction-cost', {
194
- interactionId: this.interactionId,
195
- costUsd: e.detail?.costUsd,
196
- });
197
- });
198
-
199
- this.container.appendChild(element as unknown as Node);
200
- this.observeWidgetResize(element as unknown as Element);
201
- } catch (e) {
202
- logger.error(`Failed to create interactive component: ${this.componentName}`, e);
203
- const errorDiv = document.createElement('div');
204
- errorDiv.textContent = `Error: Could not load component ${this.componentName}`;
205
- this.container.appendChild(errorDiv);
206
- }
207
- }
208
-
209
- /**
210
- * Project the wrapper's current `data`/`resolved`/`interactionId` into the
211
- * discriminated {@link AiChatInteraction} the widget consumes (GENC-1390).
212
- */
213
- private buildInteraction(host: InteractionHost | null): AiChatInteraction {
214
- if (this.resolved) {
215
- return { status: 'resolved', data: this.data, result: this.resolved };
216
- }
217
- // Pending. The driver creates a live context for EVERY pending interaction BEFORE the widget
218
- // mounts, returns the SAME instance on every remount, and drops it the instant the interaction
219
- // resolves (see `ChatDriver.resolveInteraction`). So a MISSING context is not "pending, context
220
- // lost" — it means this interaction is no longer live: it has resolved/evicted (the `resolved`
221
- // binding above can lag a render behind that during a layout rebuild), or the widget was rendered
222
- // outside the normal host flow (e.g. a unit test). In none of those cases may a `once`-guarded
223
- // side effect run — re-firing one re-opened a just-closed side panel, whose layout rebuild
224
- // re-mounted the widget, which re-opened it… a tab-locking loop (GENC-1390). Fall back to an
225
- // INERT context (disposed up front, so `once` refuses and `state`/subscribers are inert) rather
226
- // than a live throwaway, so the widget degrades safely instead of re-running its open-once effect.
227
- let interactionContext = host?.getInteractionContext?.(this.interactionId);
228
- if (!interactionContext) {
229
- logger.warn(
230
- `No live InteractionContext for interaction "${this.interactionId}"; using an inert context (once-guarded effects will not run).`,
231
- );
232
- const handle = createInteractionContext(this.interactionId);
233
- handle.dispose();
234
- interactionContext = handle.context;
235
- }
236
- return {
237
- status: 'pending',
238
- data: this.data,
239
- shouldAutoFocus: !!host?.isEngaged,
240
- interactionContext,
241
- };
242
- }
243
- }
@@ -1,3 +0,0 @@
1
- export * from './chat-interaction-wrapper';
2
- export * from './chat-interaction-wrapper.styles';
3
- export * from './chat-interaction-wrapper.template';
@@ -1,89 +0,0 @@
1
- import { css, customElement, GenesisElement, html, observable } from '@genesislcap/web-core';
2
- import DOMPurify from 'dompurify';
3
- import { marked } from 'marked';
4
-
5
- const styles = css`
6
- :host {
7
- display: block;
8
- font-size: var(--type-ramp-base-font-size);
9
- line-height: var(--type-ramp-base-line-height);
10
- }
11
-
12
- p {
13
- margin: 0 0 calc(var(--design-unit, 4) * 2px);
14
- }
15
-
16
- p:last-child {
17
- margin-bottom: 0;
18
- }
19
-
20
- ul,
21
- ol {
22
- margin: 0 0 calc(var(--design-unit, 4) * 2px);
23
- padding-left: calc(var(--design-unit, 4) * 5px);
24
- }
25
-
26
- code {
27
- background-color: var(--neutral-fill-rest);
28
- padding: 2px 4px;
29
- border-radius: calc(var(--design-unit, 4) * 0.5px);
30
- font-family: monospace;
31
- }
32
-
33
- pre {
34
- background-color: var(--neutral-fill-rest);
35
- padding: calc(var(--design-unit, 4) * 2px);
36
- border-radius: calc(var(--design-unit, 4) * 1px);
37
- overflow-x: auto;
38
- border: 1px solid var(--neutral-stroke-rest);
39
- margin: calc(var(--design-unit, 4) * 2px) 0;
40
- }
41
-
42
- pre code {
43
- background-color: transparent;
44
- padding: 0;
45
- border-radius: 0;
46
- border: none;
47
- font-family: inherit;
48
- color: inherit;
49
- }
50
-
51
- table {
52
- display: block;
53
- overflow-x: auto;
54
- border-collapse: collapse;
55
- max-width: 100%;
56
- margin: calc(var(--design-unit, 4) * 2px) 0;
57
- }
58
-
59
- th,
60
- td {
61
- border: 1px solid var(--neutral-stroke-rest);
62
- padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2.5px);
63
- white-space: nowrap;
64
- }
65
-
66
- th {
67
- background-color: var(--neutral-fill-stealth-rest);
68
- font-weight: 600;
69
- }
70
- `;
71
-
72
- @customElement({
73
- name: 'ai-chat-markdown',
74
- template: html<AiChatMarkdown>`
75
- <div :innerHTML="${(x) => x.renderMarkdown()}"></div>
76
- `,
77
- styles,
78
- })
79
- export class AiChatMarkdown extends GenesisElement {
80
- /** The markdown string to render. */
81
- @observable content: string = '';
82
-
83
- /** @internal */
84
- renderMarkdown() {
85
- if (!this.content) return '';
86
- const rawHtml = marked.parse(this.content) as string;
87
- return DOMPurify.sanitize(rawHtml);
88
- }
89
- }
@@ -1 +0,0 @@
1
- export * from './chat-markdown';
@@ -1,286 +0,0 @@
1
- import { css, customElement, GenesisElement, html } from '@genesislcap/web-core';
2
- import {
3
- AI_COLOUR_AMBER,
4
- AI_COLOUR_CYAN,
5
- AI_COLOUR_PINK,
6
- AI_COLOUR_VIOLET,
7
- } from '../styles/ai-colours';
8
-
9
- /**
10
- * SVG coordinate space the bands are drawn in. The bands stretch to fill the
11
- * host box (the band SVGs use `preserveAspectRatio="none"`), so this aspect need
12
- * not match the host's. `VIEW_H` is kept just tall enough to bound the crests,
13
- * leaving minimal dead space above/below the line — otherwise the waves float in
14
- * the vertical middle of the host and read as sitting too low beside the avatar.
15
- */
16
- const VIEW_W = 225;
17
- const VIEW_H = 50;
18
- const CENTRE_Y = VIEW_H / 2;
19
- /** Number of samples traced across each band. */
20
- const POINTS = 90;
21
- /** Fraction of the width over which thickness ramps from 0 up to full. */
22
- const EDGE = 0.16;
23
- /** Global multiplier on the harmonic drift speeds — raise to morph faster. */
24
- const MORPH_SPEED = 3;
25
- /** Global multiplier on the harmonic frequencies — raise for narrower peaks. */
26
- const FREQ_SCALE = 2;
27
- /** Milliseconds in one second. */
28
- const MS_PER_SECOND = 1000;
29
- /** Baseline frame rate (fps) the harmonic speeds are tuned against. */
30
- const BASELINE_FPS = 60;
31
- /**
32
- * Frame duration (ms) at the baseline rate. The morph is driven by elapsed
33
- * wall-clock time divided by this — not by the rAF callback count — so it
34
- * advances at a constant real-world rate regardless of the display's refresh
35
- * rate or dropped frames. At the baseline rate the resulting frame index
36
- * matches the old per-callback counter, preserving the current look.
37
- */
38
- const FRAME_MS = MS_PER_SECOND / BASELINE_FPS;
39
- /**
40
- * Half-thickness (viewBox units) each band keeps even between peaks, so the
41
- * waves emerge from a continuous line rather than leaving gaps. The four bands
42
- * overlap along this line and screen-blend to white.
43
- */
44
- const LINE_THICKNESS = 1.2;
45
- /**
46
- * Amplitude boost added toward the middle of the width (a hump that is 0 at the
47
- * ends, max in the centre). Makes peaks more likely to pop up centrally, while
48
- * still allowing tall crests to appear nearer the edges.
49
- */
50
- const CENTRE_BIAS = 4;
51
-
52
- /** One sine component of a band's thickness profile. */
53
- interface Harmonic {
54
- /** Cycles across the band width. */
55
- freq: number;
56
- /** Contribution to the half-thickness, in viewBox units. */
57
- amp: number;
58
- /** Phase drift per frame (radians); differing speeds make the bumps morph. */
59
- speed: number;
60
- /** Starting phase offset. */
61
- phase: number;
62
- }
63
-
64
- /**
65
- * One band's thickness profile: a baseline plus a few sine harmonics. Because
66
- * the harmonics drift at different speeds, their sum continually changes shape —
67
- * bumps grow, shrink, merge and split — and where the sum dips below zero the
68
- * band pinches to nothing, so a wave may have a single bump one moment and
69
- * several the next. A different harmonic mix per band keeps the colours from
70
- * lining up.
71
- */
72
- interface BandConfig {
73
- /**
74
- * Vertical offset the harmonics oscillate around. Negative values act as a
75
- * threshold: only the taller crests clear zero, so the band shows fewer,
76
- * narrower, isolated peaks (the small ripples between crests are clipped away).
77
- */
78
- baseline: number;
79
- harmonics: Harmonic[];
80
- }
81
-
82
- const BANDS: BandConfig[] = [
83
- {
84
- baseline: -4,
85
- harmonics: [
86
- { freq: 1.0, amp: 11, speed: 0.03, phase: 0.0 },
87
- { freq: 2.3, amp: 6, speed: -0.021, phase: 1.3 },
88
- { freq: 3.4, amp: 3, speed: 0.041, phase: 2.7 },
89
- ],
90
- },
91
- {
92
- baseline: -4,
93
- harmonics: [
94
- { freq: 1.3, amp: 10, speed: -0.026, phase: 0.8 },
95
- { freq: 2.0, amp: 7, speed: 0.034, phase: 2.1 },
96
- { freq: 3.1, amp: 3, speed: -0.045, phase: 0.4 },
97
- ],
98
- },
99
- {
100
- baseline: -4,
101
- harmonics: [
102
- { freq: 0.9, amp: 9, speed: 0.038, phase: 1.9 },
103
- { freq: 2.6, amp: 6, speed: 0.019, phase: 3.0 },
104
- { freq: 3.7, amp: 3, speed: -0.03, phase: 0.6 },
105
- ],
106
- },
107
- {
108
- baseline: -4,
109
- harmonics: [
110
- { freq: 1.1, amp: 8, speed: -0.034, phase: 2.4 },
111
- { freq: 2.4, amp: 5, speed: 0.027, phase: 0.2 },
112
- { freq: 3.2, amp: 3, speed: 0.048, phase: 1.5 },
113
- ],
114
- },
115
- ];
116
-
117
- // Each band is its own stacked <svg> LAYER. The white-on-overlap effect uses
118
- // `mix-blend-mode: screen`, which composites reliably between HTML-level layers
119
- // but NOT between sibling SVG <path>/<g> elements in many browsers — hence one
120
- // svg per band rather than four paths in a single svg.
121
- const bandLayersMarkup = BANDS.map(
122
- (_b, i) =>
123
- `<svg class="layer band-layer" viewBox="0 0 ${VIEW_W} ${VIEW_H}" preserveAspectRatio="none"><path class="band b${i + 1}" data-band="${i}" /></svg>`,
124
- ).join('');
125
-
126
- /**
127
- * Animated "flowing waves" loading indicator — coloured organic waves (in the
128
- * four brand colours) whose bumps swell, shrink, merge and split across a line,
129
- * tapering to nothing at both ends. Where the colours overlap they blend
130
- * additively toward white.
131
- *
132
- * Visual sibling of the dots loading indicator; interchangeable with the other
133
- * loading styles for the "assistant is working" state.
134
- *
135
- * @example
136
- * ```html
137
- * <ai-flowing-waves-indicator></ai-flowing-waves-indicator>
138
- * ```
139
- *
140
- * @beta
141
- */
142
- @customElement({
143
- name: 'ai-flowing-waves-indicator',
144
- template: html<AiFlowingWavesIndicator>`
145
- <div class="flow" role="img" aria-label="Assistant is working">${bandLayersMarkup}</div>
146
- `,
147
- styles: css`
148
- :host {
149
- display: inline-block;
150
- width: 180px;
151
- /* Height matches the message avatar (32px) so the wave line sits level
152
- with it. The bands stretch to fill via preserveAspectRatio="none". */
153
- height: 32px;
154
- }
155
-
156
- /* Transparent — sits directly on the chat surface (no backdrop). 'isolation:
157
- isolate' scopes the band layers' 'screen' blend to each other, so where
158
- colours overlap they add toward white, while the group still composites
159
- normally onto the page (works on light and dark, no wash-out). */
160
- .flow {
161
- position: relative;
162
- width: 100%;
163
- height: 100%;
164
- isolation: isolate;
165
- }
166
-
167
- .layer {
168
- position: absolute;
169
- inset: 0;
170
- width: 100%;
171
- height: 100%;
172
- overflow: hidden;
173
- }
174
-
175
- .band-layer {
176
- mix-blend-mode: screen;
177
- }
178
-
179
- .band {
180
- filter: drop-shadow(0 0 1.5px currentColor);
181
- }
182
- .band.b1 {
183
- color: ${AI_COLOUR_AMBER};
184
- fill: ${AI_COLOUR_AMBER};
185
- }
186
- .band.b2 {
187
- color: ${AI_COLOUR_PINK};
188
- fill: ${AI_COLOUR_PINK};
189
- }
190
- .band.b3 {
191
- color: ${AI_COLOUR_CYAN};
192
- fill: ${AI_COLOUR_CYAN};
193
- }
194
- .band.b4 {
195
- color: ${AI_COLOUR_VIOLET};
196
- fill: ${AI_COLOUR_VIOLET};
197
- }
198
- `,
199
- })
200
- export class AiFlowingWavesIndicator extends GenesisElement {
201
- // A rAF loop morphs the band shapes: pure CSS can't continuously reshape the
202
- // bumps (different sizes appearing at different times), and the per-frame sine
203
- // sums are cheap. Same approach as the sine-tracing waves indicator. The morph
204
- // is keyed to elapsed wall-clock time (see FRAME_MS), not the rAF callback
205
- // count, so it holds a constant speed even when frames are dropped.
206
-
207
- private startTime?: number;
208
- private animFrame?: number;
209
- private bandPaths?: SVGPathElement[];
210
-
211
- connectedCallback() {
212
- super.connectedCallback();
213
- // Guard against a reconnect starting a second concurrent loop.
214
- if (this.animFrame === undefined) {
215
- this.tick();
216
- }
217
- }
218
-
219
- disconnectedCallback() {
220
- super.disconnectedCallback();
221
- if (this.animFrame !== undefined) {
222
- cancelAnimationFrame(this.animFrame);
223
- this.animFrame = undefined;
224
- }
225
- // Reset the clock so a later reconnect restarts the morph cleanly at frame 0.
226
- this.startTime = undefined;
227
- }
228
-
229
- private tick(now?: number) {
230
- // Stop ticking once disconnected (belt-and-braces alongside the cancel in
231
- // disconnectedCallback) so no frames are scheduled while detached.
232
- if (!this.isConnected) {
233
- this.animFrame = undefined;
234
- return;
235
- }
236
- if (!this.bandPaths) {
237
- const paths = this.shadowRoot?.querySelectorAll<SVGPathElement>('.band');
238
- if (paths?.length) this.bandPaths = Array.from(paths);
239
- }
240
- // Anchor to the first real rAF timestamp; the initial synchronous call (no
241
- // timestamp) renders frame 0. `frame` is then elapsed time in 60fps frames.
242
- if (now !== undefined && this.startTime === undefined) this.startTime = now;
243
- const frame =
244
- now === undefined || this.startTime === undefined ? 0 : (now - this.startTime) / FRAME_MS;
245
- this.bandPaths?.forEach((path, i) => {
246
- const cfg = BANDS[i];
247
- if (cfg) path.setAttribute('d', AiFlowingWavesIndicator.buildBand(cfg, frame));
248
- });
249
- this.animFrame = requestAnimationFrame((t) => this.tick(t));
250
- }
251
-
252
- /**
253
- * Trace one band for the given frame: a baseline-plus-harmonics half-thickness
254
- * profile, clamped at 0 (so the band pinches to nothing between bumps) and
255
- * tapered to 0 at both ends.
256
- */
257
- private static buildBand(cfg: BandConfig, frame: number): string {
258
- const top: Array<[number, number]> = [];
259
- const bottom: Array<[number, number]> = [];
260
- for (let i = 0; i <= POINTS; i += 1) {
261
- const u = i / POINTS;
262
- const x = u * VIEW_W;
263
- // Plateau edge taper: 0 at both ends, full across the middle.
264
- const edge = Math.min(1, Math.min(u, 1 - u) / EDGE);
265
- // Sum the drifting harmonics, then clamp so dips pinch the band to nothing.
266
- let wave = 0;
267
- for (const h of cfg.harmonics) {
268
- wave +=
269
- h.amp *
270
- Math.sin(u * Math.PI * 2 * h.freq * FREQ_SCALE + frame * h.speed * MORPH_SPEED + h.phase);
271
- }
272
- // Hump that favours the middle (0 at the ends, 1 at the centre).
273
- const centre = Math.sin(Math.PI * u);
274
- const env = edge * (LINE_THICKNESS + Math.max(0, cfg.baseline + wave + CENTRE_BIAS * centre));
275
- top.push([x, CENTRE_Y - env]);
276
- bottom.push([x, CENTRE_Y + env]);
277
- }
278
- let d = `M${top[0][0].toFixed(1)} ${top[0][1].toFixed(1)}`;
279
- for (let i = 1; i < top.length; i += 1)
280
- d += ` L${top[i][0].toFixed(1)} ${top[i][1].toFixed(1)}`;
281
- for (let i = bottom.length - 1; i >= 0; i -= 1) {
282
- d += ` L${bottom[i][0].toFixed(1)} ${bottom[i][1].toFixed(1)}`;
283
- }
284
- return `${d} Z`;
285
- }
286
- }