@flamingo-stack/openframe-frontend-core 0.0.458-snapshot.20260720215024 → 0.0.458

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 (281) hide show
  1. package/dist/{chunk-BLZZXZNM.cjs → chunk-5USSSRAL.cjs} +26 -26
  2. package/dist/{chunk-BLZZXZNM.cjs.map → chunk-5USSSRAL.cjs.map} +1 -1
  3. package/dist/{chunk-CGNDAJ7V.js → chunk-6B27O3ZB.js} +4 -4
  4. package/dist/{chunk-P5JQDFRM.cjs → chunk-7IRPMNRL.cjs} +60 -60
  5. package/dist/chunk-7IRPMNRL.cjs.map +1 -0
  6. package/dist/{chunk-4XDWNAZW.cjs → chunk-DQ3EHM6G.cjs} +9 -9
  7. package/dist/{chunk-4XDWNAZW.cjs.map → chunk-DQ3EHM6G.cjs.map} +1 -1
  8. package/dist/{chunk-7KSEINAE.cjs → chunk-FTXDIDNX.cjs} +15 -15
  9. package/dist/{chunk-7KSEINAE.cjs.map → chunk-FTXDIDNX.cjs.map} +1 -1
  10. package/dist/{chunk-4R6H2U77.js → chunk-H7ETLG65.js} +4 -4
  11. package/dist/{chunk-LAOO7XHO.js → chunk-HWTUVLYB.js} +2 -2
  12. package/dist/{chunk-F2NMWV44.js → chunk-IDKDOQZL.js} +2 -2
  13. package/dist/{chunk-BQ7PMWLM.cjs → chunk-KIIOBK7G.cjs} +27 -28
  14. package/dist/chunk-KIIOBK7G.cjs.map +1 -0
  15. package/dist/{chunk-QO2XD3FR.js → chunk-KQGFKG6Y.js} +2 -2
  16. package/dist/{chunk-3N3TMZ62.cjs → chunk-L676XVP4.cjs} +7 -7
  17. package/dist/{chunk-3N3TMZ62.cjs.map → chunk-L676XVP4.cjs.map} +1 -1
  18. package/dist/{chunk-F7F43U7Q.cjs → chunk-LDAOPWXZ.cjs} +11 -11
  19. package/dist/{chunk-F7F43U7Q.cjs.map → chunk-LDAOPWXZ.cjs.map} +1 -1
  20. package/dist/{chunk-ADD3FPDG.cjs → chunk-MKLP2SOZ.cjs} +4886 -7004
  21. package/dist/chunk-MKLP2SOZ.cjs.map +1 -0
  22. package/dist/{chunk-VXJH5TDN.js → chunk-QL7ODLJA.js} +10 -10
  23. package/dist/chunk-QL7ODLJA.js.map +1 -0
  24. package/dist/{chunk-OR5AMXYN.js → chunk-R5QYMUKN.js} +2 -2
  25. package/dist/{chunk-REWRUV3K.js → chunk-TNLFAJPA.js} +9673 -11791
  26. package/dist/chunk-TNLFAJPA.js.map +1 -0
  27. package/dist/{chunk-XF5ROTMQ.js → chunk-U2YDR5DT.js} +2 -2
  28. package/dist/{chunk-PXZ7YQ5V.cjs → chunk-VTQSB6QB.cjs} +5 -5
  29. package/dist/{chunk-PXZ7YQ5V.cjs.map → chunk-VTQSB6QB.cjs.map} +1 -1
  30. package/dist/{chunk-UI7CIUAR.js → chunk-WGJPTFRH.js} +2 -2
  31. package/dist/{chunk-WCE66C2Z.cjs → chunk-XUNJILJT.cjs} +62 -62
  32. package/dist/{chunk-WCE66C2Z.cjs.map → chunk-XUNJILJT.cjs.map} +1 -1
  33. package/dist/{chunk-APF5QBAU.js → chunk-YQBPIUZU.js} +2 -2
  34. package/dist/{chunk-TA7MFVUS.cjs → chunk-YV2YA3QH.cjs} +31 -31
  35. package/dist/{chunk-TA7MFVUS.cjs.map → chunk-YV2YA3QH.cjs.map} +1 -1
  36. package/dist/{chunk-QSGZE6AZ.cjs → chunk-ZDJ4ZUQ4.cjs} +37 -37
  37. package/dist/{chunk-QSGZE6AZ.cjs.map → chunk-ZDJ4ZUQ4.cjs.map} +1 -1
  38. package/dist/{chunk-LJKZIIK4.js → chunk-ZHQQRYMB.js} +5 -6
  39. package/dist/chunk-ZHQQRYMB.js.map +1 -0
  40. package/dist/components/case-studies/index.cjs +8 -8
  41. package/dist/components/case-studies/index.js +2 -2
  42. package/dist/components/chart.d.ts +1 -1
  43. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  44. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  45. package/dist/components/chat/hooks/index.d.ts +1 -0
  46. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  47. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  48. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +48 -15
  49. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  50. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +6 -0
  51. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -0
  52. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +47 -3
  53. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  54. package/dist/components/chat/index.cjs +2 -10
  55. package/dist/components/chat/index.cjs.map +1 -1
  56. package/dist/components/chat/index.d.ts +0 -1
  57. package/dist/components/chat/index.d.ts.map +1 -1
  58. package/dist/components/chat/index.js +13 -21
  59. package/dist/components/chat/types/api.types.d.ts +81 -1
  60. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  61. package/dist/components/chat/types/processing.types.d.ts +90 -2
  62. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  63. package/dist/components/chat/utils/chunk-parser.d.ts +25 -0
  64. package/dist/components/chat/utils/chunk-parser.d.ts.map +1 -0
  65. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +6 -34
  66. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  67. package/dist/components/chat/utils/index.d.ts +3 -2
  68. package/dist/components/chat/utils/index.d.ts.map +1 -1
  69. package/dist/components/chat/utils/process-historical-messages.d.ts +11 -59
  70. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  71. package/dist/components/contact/index.cjs +3 -3
  72. package/dist/components/contact/index.js +2 -2
  73. package/dist/components/docs/index.cjs +5 -5
  74. package/dist/components/docs/index.js +4 -4
  75. package/dist/components/embeds/index.cjs +3 -3
  76. package/dist/components/embeds/index.js +2 -2
  77. package/dist/components/faq/index.cjs +3 -3
  78. package/dist/components/faq/index.js +2 -2
  79. package/dist/components/features/index.cjs +2 -2
  80. package/dist/components/features/index.js +1 -1
  81. package/dist/components/help-center-pages/index.cjs +20 -20
  82. package/dist/components/help-center-pages/index.js +11 -11
  83. package/dist/components/index.cjs +129 -171
  84. package/dist/components/index.cjs.map +1 -1
  85. package/dist/components/index.js +21 -63
  86. package/dist/components/index.js.map +1 -1
  87. package/dist/components/navigation/index.cjs +2 -2
  88. package/dist/components/navigation/index.js +1 -1
  89. package/dist/components/onboarding-guides/index.cjs +5 -5
  90. package/dist/components/onboarding-guides/index.js +4 -4
  91. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  92. package/dist/components/related-content/index.cjs +3 -3
  93. package/dist/components/related-content/index.js +2 -2
  94. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  95. package/dist/components/tickets/index.cjs +5 -5
  96. package/dist/components/tickets/index.js +4 -4
  97. package/dist/components/ui/index.cjs +2 -44
  98. package/dist/components/ui/index.cjs.map +1 -1
  99. package/dist/components/ui/index.d.ts +2 -1
  100. package/dist/components/ui/index.d.ts.map +1 -1
  101. package/dist/components/ui/index.js +13 -55
  102. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  103. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  104. package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
  105. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
  106. package/dist/index.cjs +2 -60
  107. package/dist/index.cjs.map +1 -1
  108. package/dist/index.js +13 -71
  109. package/dist/utils/index.cjs +40 -169
  110. package/dist/utils/index.cjs.map +1 -1
  111. package/dist/utils/index.d.ts +0 -1
  112. package/dist/utils/index.d.ts.map +1 -1
  113. package/dist/utils/index.js +41 -162
  114. package/dist/utils/index.js.map +1 -1
  115. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  116. package/package.json +1 -7
  117. package/src/components/chat/__tests__/chat-message-list.test.tsx +5 -293
  118. package/src/components/chat/chat-message-enhanced.tsx +17 -111
  119. package/src/components/chat/chat-message-list.tsx +113 -367
  120. package/src/components/chat/embeddable-chat.tsx +0 -6
  121. package/src/components/chat/hooks/.index.md +1 -1
  122. package/src/components/chat/hooks/.use-nats-chat-adapter.md +1 -1
  123. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +50 -0
  124. package/src/components/chat/hooks/index.ts +1 -0
  125. package/src/components/chat/hooks/use-chat.ts +0 -8
  126. package/src/components/chat/hooks/use-nats-chat-adapter.ts +822 -243
  127. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +479 -0
  128. package/src/components/chat/hooks/use-sse-chat-adapter.ts +666 -318
  129. package/src/components/chat/index.ts +0 -5
  130. package/src/components/chat/thinking-display.tsx +1 -1
  131. package/src/components/chat/types/.api.types.md +3 -1
  132. package/src/components/chat/types/.processing.types.md +23 -6
  133. package/src/components/chat/types/api.types.ts +73 -6
  134. package/src/components/chat/types/processing.types.ts +52 -11
  135. package/src/components/chat/utils/.chunk-parser.md +51 -0
  136. package/src/components/chat/utils/.index.md +5 -0
  137. package/src/components/chat/utils/chunk-parser.ts +255 -0
  138. package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
  139. package/src/components/chat/utils/index.ts +8 -5
  140. package/src/components/chat/utils/process-historical-messages.ts +383 -352
  141. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
  142. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  143. package/src/components/shared/product-release/release-detail-page.tsx +4 -19
  144. package/src/components/ui/.simple-markdown-renderer.md +40 -0
  145. package/src/components/ui/index.ts +2 -1
  146. package/src/components/ui/release-changelog-section.tsx +1 -1
  147. package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
  148. package/src/components/ui/simple-markdown-renderer.tsx +965 -0
  149. package/src/components/ui/ticket-info-section.tsx +1 -1
  150. package/src/utils/index.ts +0 -1
  151. package/src/utils/markdown-section-extractor.ts +56 -41
  152. package/dist/chat-protocol/decode.d.ts +0 -58
  153. package/dist/chat-protocol/decode.d.ts.map +0 -1
  154. package/dist/chat-protocol/encode.d.ts +0 -44
  155. package/dist/chat-protocol/encode.d.ts.map +0 -1
  156. package/dist/chat-protocol/env-flag.d.ts +0 -35
  157. package/dist/chat-protocol/env-flag.d.ts.map +0 -1
  158. package/dist/chat-protocol/events.d.ts +0 -192
  159. package/dist/chat-protocol/events.d.ts.map +0 -1
  160. package/dist/chat-protocol/frames.d.ts +0 -206
  161. package/dist/chat-protocol/frames.d.ts.map +0 -1
  162. package/dist/chat-protocol/index.cjs +0 -493
  163. package/dist/chat-protocol/index.cjs.map +0 -1
  164. package/dist/chat-protocol/index.d.ts +0 -18
  165. package/dist/chat-protocol/index.d.ts.map +0 -1
  166. package/dist/chat-protocol/index.js +0 -477
  167. package/dist/chat-protocol/index.js.map +0 -1
  168. package/dist/chat-protocol/ip-normalize.d.ts +0 -44
  169. package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
  170. package/dist/chat-protocol/nats-decoder.d.ts +0 -26
  171. package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
  172. package/dist/chunk-ADD3FPDG.cjs.map +0 -1
  173. package/dist/chunk-BQ7PMWLM.cjs.map +0 -1
  174. package/dist/chunk-LJKZIIK4.js.map +0 -1
  175. package/dist/chunk-P5JQDFRM.cjs.map +0 -1
  176. package/dist/chunk-REWRUV3K.js.map +0 -1
  177. package/dist/chunk-VXJH5TDN.js.map +0 -1
  178. package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
  179. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
  180. package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
  181. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
  182. package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
  183. package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
  184. package/dist/components/chat/stream/index.d.ts +0 -17
  185. package/dist/components/chat/stream/index.d.ts.map +0 -1
  186. package/dist/components/chat/stream/message-mutations.d.ts +0 -77
  187. package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
  188. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
  189. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
  190. package/dist/components/ui/markdown/base-components.d.ts +0 -56
  191. package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
  192. package/dist/components/ui/markdown/engine.d.ts +0 -99
  193. package/dist/components/ui/markdown/engine.d.ts.map +0 -1
  194. package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
  195. package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
  196. package/dist/components/ui/markdown/index.d.ts +0 -18
  197. package/dist/components/ui/markdown/index.d.ts.map +0 -1
  198. package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
  199. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
  200. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
  201. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
  202. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
  203. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
  204. package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
  205. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
  206. package/dist/components/ui/markdown/sanitize.d.ts +0 -153
  207. package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
  208. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
  209. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
  210. package/dist/components/ui/markdown/streaming.d.ts +0 -78
  211. package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
  212. package/dist/components/ui/markdown/text-size.d.ts +0 -34
  213. package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
  214. package/dist/utils/markdown-fences.d.ts +0 -42
  215. package/dist/utils/markdown-fences.d.ts.map +0 -1
  216. package/dist/utils/markdown-heading-id.d.ts +0 -85
  217. package/dist/utils/markdown-heading-id.d.ts.map +0 -1
  218. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -307
  219. package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -515
  220. package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
  221. package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
  222. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -228
  223. package/src/chat-protocol/decode.ts +0 -277
  224. package/src/chat-protocol/encode.ts +0 -71
  225. package/src/chat-protocol/env-flag.ts +0 -39
  226. package/src/chat-protocol/events.ts +0 -228
  227. package/src/chat-protocol/frames.ts +0 -238
  228. package/src/chat-protocol/index.ts +0 -21
  229. package/src/chat-protocol/ip-normalize.ts +0 -146
  230. package/src/chat-protocol/nats-decoder.ts +0 -252
  231. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
  232. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -209
  233. package/src/components/chat/hooks/__tests__/__snapshots__/persisted-state-v1-golden.test.ts.snap +0 -297
  234. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  235. package/src/components/chat/hooks/__tests__/persisted-state-v1-golden.test.ts +0 -272
  236. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
  237. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -937
  238. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -756
  239. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -460
  240. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -894
  241. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
  242. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -98
  243. package/src/components/chat/stream/chat-dialog-store.ts +0 -536
  244. package/src/components/chat/stream/chat-stream-reducer.ts +0 -1796
  245. package/src/components/chat/stream/delta-batcher.ts +0 -159
  246. package/src/components/chat/stream/index.ts +0 -55
  247. package/src/components/chat/stream/message-mutations.ts +0 -338
  248. package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
  249. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -418
  250. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -599
  251. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -317
  252. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
  253. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
  254. package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2528
  255. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -115
  256. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -95
  257. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -309
  258. package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -388
  259. package/src/components/ui/markdown/base-components.tsx +0 -341
  260. package/src/components/ui/markdown/engine.tsx +0 -315
  261. package/src/components/ui/markdown/heading-ids.ts +0 -239
  262. package/src/components/ui/markdown/index.ts +0 -49
  263. package/src/components/ui/markdown/mermaid-diagram.tsx +0 -291
  264. package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
  265. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
  266. package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
  267. package/src/components/ui/markdown/sanitize.ts +0 -3499
  268. package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
  269. package/src/components/ui/markdown/streaming.ts +0 -362
  270. package/src/components/ui/markdown/text-size.ts +0 -106
  271. package/src/utils/markdown-fences.ts +0 -127
  272. package/src/utils/markdown-heading-id.ts +0 -348
  273. /package/dist/{chunk-CGNDAJ7V.js.map → chunk-6B27O3ZB.js.map} +0 -0
  274. /package/dist/{chunk-4R6H2U77.js.map → chunk-H7ETLG65.js.map} +0 -0
  275. /package/dist/{chunk-LAOO7XHO.js.map → chunk-HWTUVLYB.js.map} +0 -0
  276. /package/dist/{chunk-F2NMWV44.js.map → chunk-IDKDOQZL.js.map} +0 -0
  277. /package/dist/{chunk-QO2XD3FR.js.map → chunk-KQGFKG6Y.js.map} +0 -0
  278. /package/dist/{chunk-OR5AMXYN.js.map → chunk-R5QYMUKN.js.map} +0 -0
  279. /package/dist/{chunk-XF5ROTMQ.js.map → chunk-U2YDR5DT.js.map} +0 -0
  280. /package/dist/{chunk-UI7CIUAR.js.map → chunk-WGJPTFRH.js.map} +0 -0
  281. /package/dist/{chunk-APF5QBAU.js.map → chunk-YQBPIUZU.js.map} +0 -0
@@ -1,317 +0,0 @@
1
- /**
2
- * Phase-0 GOLDEN CHARACTERIZATION TESTS — `processHistoricalMessages`.
3
- *
4
- * Pins the CURRENT GraphQL-history → ProcessedMessage[] transformation
5
- * before the stream-reader unification. A recorded corpus of messageData
6
- * rows is processed and the FULL output array is snapshotted.
7
- *
8
- * NOTE: `process-historical-messages-approvals.test.ts` already guards
9
- * displayApprovalTypes semantics — this file deliberately does not
10
- * duplicate it and instead records the full-output shape.
11
- */
12
-
13
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
14
- import { processHistoricalMessages, extractErrorMessages, processHistoricalMessagesWithErrors } from '../process-historical-messages'
15
- import type { HistoricalMessage } from '../../types'
16
-
17
- // Deterministic Date.now for the `pending-approvals-${Date.now()}` synthetic
18
- // message id + its `new Date()` timestamp.
19
- const FIXED_NOW = new Date('2026-07-20T10:00:00.000Z')
20
-
21
- beforeEach(() => {
22
- vi.useFakeTimers()
23
- vi.setSystemTime(FIXED_NOW)
24
- })
25
-
26
- afterEach(() => {
27
- vi.useRealTimers()
28
- })
29
-
30
- /** Recorded corpus — one realistic dialog covering every row shape. */
31
- const CORPUS: HistoricalMessage[] = [
32
- // 1. User message with contextItems (CLIENT owner).
33
- {
34
- id: 'u1',
35
- chatType: 'CLIENT_CHAT',
36
- createdAt: '2026-07-19T09:00:00Z',
37
- owner: { type: 'CLIENT', userId: 'user-42' },
38
- lastChunkStreamSeq: 10,
39
- messageData: [
40
- {
41
- type: 'TEXT',
42
- text: 'diagnose this device please',
43
- // wire shape: [{ type, id }] — label falls back to id
44
- contextItems: [
45
- { type: 'device', id: 'dev-1' },
46
- { type: 'bad' }, // missing id → filtered
47
- ],
48
- } as any,
49
- ],
50
- },
51
- // 2. Assistant: thinking + text (grouped into one bubble).
52
- {
53
- id: 'a1',
54
- chatType: 'CLIENT_CHAT',
55
- createdAt: '2026-07-19T09:00:05Z',
56
- owner: { type: 'ASSISTANT', model: 'claude-sonnet-x' },
57
- lastChunkStreamSeq: 20,
58
- messageData: [
59
- { type: 'THINKING', text: 'Checking device state… ' },
60
- { type: 'THINKING', text: 'looks like disk pressure.' },
61
- { type: 'TEXT', text: 'The device is low on disk. ' },
62
- ],
63
- },
64
- // 3. Assistant continued: EXECUTING + EXECUTED tool pair merges in place.
65
- {
66
- id: 'a2',
67
- chatType: 'CLIENT_CHAT',
68
- createdAt: '2026-07-19T09:00:10Z',
69
- owner: { type: 'ASSISTANT' },
70
- lastChunkStreamSeq: 15, // lower than a1's — MAX (20) must win on the flushed turn
71
- messageData: [
72
- {
73
- type: 'EXECUTING_TOOL',
74
- integratedToolType: 'TACTICAL_RMM',
75
- toolFunction: 'run_script',
76
- title: 'Run cleanup script',
77
- parameters: { script: 'cleanup.sh' },
78
- toolExecutionRequestId: 'exec-1',
79
- },
80
- {
81
- type: 'EXECUTED_TOOL',
82
- integratedToolType: 'TACTICAL_RMM',
83
- toolFunction: 'run_script',
84
- parameters: { script: 'cleanup.sh' },
85
- result: 'Freed 2.3 GB',
86
- success: true,
87
- toolExecutionRequestId: 'exec-1',
88
- },
89
- { type: 'TEXT', text: 'Cleanup done.' },
90
- ],
91
- },
92
- // 4. ADMIN-owned user message (owner-type author resolution: display name from user).
93
- {
94
- id: 'u2',
95
- chatType: 'CLIENT_CHAT',
96
- createdAt: '2026-07-19T09:01:00Z',
97
- owner: {
98
- type: 'ADMIN',
99
- user: {
100
- id: 'admin-7',
101
- firstName: 'Jane',
102
- lastName: 'Admin',
103
- image: { imageUrl: '/avatars/jane.png' },
104
- },
105
- },
106
- messageData: [{ type: 'TEXT', text: 'please restart the broker' }],
107
- },
108
- // 5. Assistant: single approval request + result (resolved in-history).
109
- {
110
- id: 'a3',
111
- chatType: 'CLIENT_CHAT',
112
- createdAt: '2026-07-19T09:01:05Z',
113
- owner: { type: 'ASSISTANT' },
114
- lastChunkStreamSeq: 30,
115
- messageData: [
116
- { type: 'TEXT', text: 'I need approval to restart it.' },
117
- {
118
- type: 'APPROVAL_REQUEST',
119
- approvalRequestId: 'req-1',
120
- approvalType: 'CLIENT',
121
- command: 'systemctl restart nats',
122
- explanation: 'Restart the message broker',
123
- },
124
- {
125
- type: 'APPROVAL_RESULT',
126
- approvalRequestId: 'req-1',
127
- approved: true,
128
- approvalType: 'CLIENT',
129
- resolvedByName: 'Jane Admin',
130
- },
131
- ],
132
- },
133
- // 6. Assistant: batch approval + per-tool executions merged into the batch.
134
- {
135
- id: 'a4',
136
- chatType: 'CLIENT_CHAT',
137
- createdAt: '2026-07-19T09:02:00Z',
138
- owner: { type: 'ASSISTANT' },
139
- messageData: [
140
- {
141
- type: 'APPROVAL_REQUEST',
142
- approvalRequestId: 'batch-1',
143
- approvalType: 'CLIENT',
144
- toolCalls: [
145
- {
146
- toolExecutionRequestId: 'exec-a',
147
- toolName: 'create_ticket',
148
- toolTitle: 'Create ticket',
149
- requiresApproval: true,
150
- approvalType: 'CLIENT',
151
- toolCallArguments: { subject: 'Printer down' },
152
- },
153
- {
154
- toolExecutionRequestId: 'exec-b',
155
- toolName: 'read_kb',
156
- requiresApproval: false,
157
- },
158
- ],
159
- },
160
- {
161
- type: 'APPROVAL_RESULT',
162
- approvalRequestId: 'batch-1',
163
- approved: true,
164
- resolvedByName: 'Alice Client',
165
- },
166
- {
167
- type: 'EXECUTING_TOOL',
168
- integratedToolType: 'PSA',
169
- toolFunction: 'create_ticket',
170
- toolExecutionRequestId: 'exec-a',
171
- },
172
- {
173
- type: 'EXECUTED_TOOL',
174
- integratedToolType: 'PSA',
175
- toolFunction: 'create_ticket',
176
- result: 'Ticket #77 created',
177
- success: true,
178
- toolExecutionRequestId: 'exec-a',
179
- },
180
- ],
181
- },
182
- // 7. Standalone SYSTEM message row — flushes the assistant turn and
183
- // renders as a system-authored row.
184
- {
185
- id: 's1',
186
- chatType: 'CLIENT_CHAT',
187
- createdAt: '2026-07-19T09:03:00Z',
188
- owner: { type: 'ASSISTANT' },
189
- lastChunkStreamSeq: 40,
190
- messageData: [{ type: 'SYSTEM', text: 'Technician joined the chat' } as any],
191
- },
192
- // 8. DIRECT_MESSAGE row. CHARACTERIZATION: DIRECT_MESSAGE is a
193
- // realtime-only concept — the history processors have NO branch for
194
- // it. This ADMIN-owned row takes the user-message path, which only
195
- // renders TEXT data, so it contributes NOTHING to the output (the
196
- // bubble is lost on reload). Recording current behavior as-is; see
197
- // unification plan.
198
- {
199
- id: 'd1',
200
- chatType: 'CLIENT_CHAT',
201
- createdAt: '2026-07-19T09:03:30Z',
202
- owner: { type: 'ADMIN', user: { id: 'admin-7', firstName: 'Jane' } },
203
- messageData: [{ type: 'DIRECT_MESSAGE', text: 'Human here, taking over' } as any],
204
- },
205
- // 9. Error row inside an assistant turn.
206
- {
207
- id: 'a5',
208
- chatType: 'CLIENT_CHAT',
209
- createdAt: '2026-07-19T09:04:00Z',
210
- owner: { type: 'ASSISTANT' },
211
- messageData: [
212
- { type: 'TEXT', text: 'Attempting one more thing… ' },
213
- { type: 'ERROR', error: 'Agent crashed', details: '{"error":{"message":"boom"}}' },
214
- ],
215
- },
216
- ]
217
-
218
- describe('processHistoricalMessages — golden corpus', () => {
219
- it('processes the full recorded dialog (snapshot)', () => {
220
- const result = processHistoricalMessages(CORPUS, {
221
- assistantName: 'Mingo AI',
222
- assistantType: 'mingo',
223
- assistantAvatar: '/avatars/mingo.png',
224
- })
225
- expect({
226
- messages: result.messages,
227
- escalatedApprovals: Array.from(result.escalatedApprovals.entries()),
228
- }).toMatchSnapshot()
229
- })
230
-
231
- it('unresolved single approval is resurrected as a synthetic pending-approvals bubble', () => {
232
- const result = processHistoricalMessages([
233
- {
234
- id: 'a1',
235
- createdAt: '2026-07-19T09:00:00Z',
236
- owner: { type: 'ASSISTANT' },
237
- messageData: [
238
- {
239
- type: 'APPROVAL_REQUEST',
240
- approvalRequestId: 'req-pending',
241
- approvalType: 'CLIENT',
242
- command: 'reboot server',
243
- },
244
- ],
245
- },
246
- ])
247
- // Date.now is frozen → deterministic synthetic id.
248
- expect(result.messages).toMatchSnapshot()
249
- })
250
-
251
- it('owner-type author resolution: CLIENT vs ADMIN vs ADMIN-without-name display names/avatars', () => {
252
- const rows: HistoricalMessage[] = [
253
- {
254
- id: 'u-client',
255
- createdAt: '2026-07-19T09:00:00Z',
256
- owner: { type: 'CLIENT', userId: 'user-1' },
257
- messageData: [{ type: 'TEXT', text: 'from client' }],
258
- },
259
- {
260
- id: 'u-admin-named',
261
- createdAt: '2026-07-19T09:00:01Z',
262
- owner: {
263
- type: 'ADMIN',
264
- user: { id: 'adm', firstName: 'Jane', lastName: 'Admin', image: { imageUrl: '/a.png' } },
265
- },
266
- messageData: [{ type: 'TEXT', text: 'from named admin' }],
267
- },
268
- {
269
- id: 'u-admin-anon',
270
- createdAt: '2026-07-19T09:00:02Z',
271
- owner: { type: 'ADMIN' },
272
- messageData: [{ type: 'TEXT', text: 'from anonymous admin' }],
273
- },
274
- ]
275
- expect(processHistoricalMessages(rows).messages).toMatchSnapshot()
276
- })
277
-
278
- it('chatTypeFilter drops rows of other chat types', () => {
279
- const rows: HistoricalMessage[] = [
280
- {
281
- id: 'u1',
282
- chatType: 'CLIENT_CHAT',
283
- createdAt: '2026-07-19T09:00:00Z',
284
- owner: { type: 'CLIENT' },
285
- messageData: [{ type: 'TEXT', text: 'visible' }],
286
- },
287
- {
288
- id: 'u2',
289
- chatType: 'ADMIN_AI_CHAT',
290
- createdAt: '2026-07-19T09:00:01Z',
291
- owner: { type: 'CLIENT' },
292
- messageData: [{ type: 'TEXT', text: 'filtered out' }],
293
- },
294
- ]
295
- expect(
296
- processHistoricalMessages(rows, { chatTypeFilter: 'CLIENT_CHAT' }).messages,
297
- ).toMatchSnapshot()
298
- })
299
- })
300
-
301
- describe('extractErrorMessages / processHistoricalMessagesWithErrors — golden', () => {
302
- it('extractErrorMessages surfaces ERROR rows as standalone error-role messages', () => {
303
- expect(extractErrorMessages(CORPUS, { assistantName: 'Mingo AI', assistantType: 'mingo' })).toMatchSnapshot()
304
- })
305
-
306
- it('processHistoricalMessagesWithErrors output parity on the same corpus (snapshot)', () => {
307
- const result = processHistoricalMessagesWithErrors(CORPUS, {
308
- assistantName: 'Mingo AI',
309
- assistantType: 'mingo',
310
- assistantAvatar: '/avatars/mingo.png',
311
- })
312
- expect({
313
- messages: result.messages,
314
- escalatedApprovals: Array.from(result.escalatedApprovals.entries()),
315
- }).toMatchSnapshot()
316
- })
317
- })
@@ -1,270 +0,0 @@
1
- /**
2
- * Phase-0 GOLDEN CHARACTERIZATION TESTS — `MessageSegmentAccumulator`.
3
- *
4
- * Pins the CURRENT segment-accumulation semantics before the stream-reader
5
- * unification. Each test drives the accumulator through a recorded event
6
- * sequence and snapshots the final segment array. Behaviors captured here
7
- * (including the implicit approval-flip on tool execution and the batch
8
- * no-downgrade rule) are the recorded baseline the future reducer must match.
9
- */
10
-
11
- import { describe, it, expect } from 'vitest'
12
- import { createMessageSegmentAccumulator } from '../message-segment-accumulator'
13
- import type { ToolExecutionSegment, PendingToolCallData } from '../../types'
14
-
15
- const executing = (
16
- execId: string | undefined,
17
- overrides: Partial<ToolExecutionSegment['data']> = {},
18
- ): ToolExecutionSegment => ({
19
- type: 'tool_execution',
20
- data: {
21
- type: 'EXECUTING_TOOL',
22
- integratedToolType: 'TACTICAL_RMM',
23
- toolFunction: 'run_script',
24
- toolTitle: 'Run cleanup script',
25
- parameters: { script: 'cleanup.sh' },
26
- ...(execId ? { toolExecutionRequestId: execId } : {}),
27
- ...overrides,
28
- },
29
- })
30
-
31
- const executed = (
32
- execId: string | undefined,
33
- overrides: Partial<ToolExecutionSegment['data']> = {},
34
- ): ToolExecutionSegment => ({
35
- type: 'tool_execution',
36
- data: {
37
- type: 'EXECUTED_TOOL',
38
- integratedToolType: 'TACTICAL_RMM',
39
- toolFunction: 'run_script',
40
- // Backend omits toolTitle on EXECUTED_TOOL — the accumulator restores it.
41
- result: 'Freed 2.3 GB',
42
- success: true,
43
- ...(execId ? { toolExecutionRequestId: execId } : {}),
44
- ...overrides,
45
- },
46
- })
47
-
48
- const batchToolCalls: PendingToolCallData[] = [
49
- {
50
- toolExecutionRequestId: 'exec-a',
51
- toolName: 'create_ticket',
52
- toolTitle: 'Create ticket',
53
- toolExplanation: 'Opens a support ticket',
54
- requiresApproval: true,
55
- approvalType: 'CLIENT',
56
- toolCallArguments: { subject: 'Printer down' },
57
- },
58
- {
59
- toolExecutionRequestId: 'exec-b',
60
- toolName: 'read_kb',
61
- requiresApproval: false,
62
- approvalType: null,
63
- toolCallArguments: null,
64
- },
65
- ]
66
-
67
- describe('MessageSegmentAccumulator — golden sequences', () => {
68
- it('coalesces consecutive text deltas into one text segment', () => {
69
- const acc = createMessageSegmentAccumulator()
70
- acc.appendText('Hello')
71
- acc.appendText(', ')
72
- acc.appendText('world')
73
- expect(acc.getSegments()).toMatchSnapshot()
74
- })
75
-
76
- it('coalesces thinking deltas, and text after thinking starts a NEW segment', () => {
77
- const acc = createMessageSegmentAccumulator()
78
- acc.appendThinking('Let me think')
79
- acc.appendThinking('… ok.')
80
- acc.appendText('Answer: ')
81
- acc.appendText('42')
82
- // A late thinking delta after text starts ANOTHER thinking segment
83
- // (append-to-last only merges into a trailing segment of the same type).
84
- acc.appendThinking('post-answer thought')
85
- expect(acc.getSegments()).toMatchSnapshot()
86
- })
87
-
88
- it('merges EXECUTING_TOOL → EXECUTED_TOOL in place by toolExecutionRequestId (title restored)', () => {
89
- const acc = createMessageSegmentAccumulator()
90
- acc.appendText('Running a cleanup now.')
91
- acc.addToolExecution(executing('exec-1'))
92
- acc.addToolExecution(executed('exec-1'))
93
- expect(acc.getSegments()).toMatchSnapshot()
94
- })
95
-
96
- it('pairs by (integratedToolType, toolFunction) when no exec id is present (older backends)', () => {
97
- const acc = createMessageSegmentAccumulator()
98
- acc.addToolExecution(executing(undefined))
99
- acc.addToolExecution(executed(undefined))
100
- expect(acc.getSegments()).toMatchSnapshot()
101
- })
102
-
103
- it('EXECUTED with no prior EXECUTING lands as a standalone completed segment', () => {
104
- const acc = createMessageSegmentAccumulator()
105
- acc.addToolExecution(executed('exec-orphan'))
106
- expect(acc.getSegments()).toMatchSnapshot()
107
- })
108
-
109
- it('CHARACTERIZATION: a LATE standalone EXECUTING after its EXECUTED pushes a NEW executing segment (no in-place downgrade, but a duplicate card appears)', () => {
110
- // The no-downgrade rule is enforced INSIDE approval batches
111
- // (applyExecutionToBatch); for standalone segments a redelivered
112
- // EXECUTING after EXECUTED does NOT downgrade the merged segment —
113
- // it appends a fresh EXECUTING segment. Recording as-is, see
114
- // unification plan.
115
- const acc = createMessageSegmentAccumulator()
116
- acc.addToolExecution(executing('exec-1'))
117
- acc.addToolExecution(executed('exec-1'))
118
- acc.addToolExecution(executing('exec-1'))
119
- expect(acc.getSegments()).toMatchSnapshot()
120
- })
121
-
122
- it('single approval request → updateApprovalStatus flips status and stamps resolvedByName only on batches', () => {
123
- const acc = createMessageSegmentAccumulator({
124
- onApprove: async () => {},
125
- onReject: async () => {},
126
- })
127
- acc.addApprovalRequest('req-1', 'systemctl restart nats', 'Restart broker', 'CLIENT')
128
- acc.updateApprovalStatus('req-1', 'approved', 'Jane Admin')
129
- expect(acc.getSegments()).toMatchSnapshot()
130
- })
131
-
132
- it('tracked (pending) approval + processApprovalResult appends a resolved segment', () => {
133
- const acc = createMessageSegmentAccumulator()
134
- acc.trackApprovalRequest('req-2', {
135
- command: 'rm -rf /tmp/cache',
136
- explanation: 'Clear caches',
137
- approvalType: 'CLIENT',
138
- })
139
- const result = acc.processApprovalResult('req-2', false, 'CLIENT')
140
- expect({
141
- segments: acc.getSegments(),
142
- pendingData: result?.pendingData ?? null,
143
- hasPendingAfter: acc.hasPendingApprovals(),
144
- }).toMatchSnapshot()
145
- })
146
-
147
- it('batch approval with per-tool executions merged into the batch (no standalone segments)', () => {
148
- const acc = createMessageSegmentAccumulator()
149
- acc.addApprovalBatch('batch-1', 'CLIENT', batchToolCalls)
150
- acc.updateApprovalStatus('batch-1', 'approved', 'Jane Admin')
151
- // Executions matching the batch's toolExecutionRequestIds merge into
152
- // `executions` instead of pushing standalone tool_execution segments.
153
- acc.addToolExecution(executing('exec-a', { toolFunction: 'create_ticket' }))
154
- acc.addToolExecution(
155
- executed('exec-a', { toolFunction: 'create_ticket', result: 'Ticket #77 created' }),
156
- )
157
- acc.addToolExecution(executing('exec-b', { toolFunction: 'read_kb' }))
158
- expect(acc.getSegments()).toMatchSnapshot()
159
- })
160
-
161
- it('batch no-downgrade rule: a redelivered EXECUTING after EXECUTED keeps the done slot', () => {
162
- const acc = createMessageSegmentAccumulator()
163
- acc.addApprovalBatch('batch-1', 'CLIENT', batchToolCalls, 'approved')
164
- acc.addToolExecution(executed('exec-a', { result: 'done!' }))
165
- // Late/redelivered EXECUTING for the same exec id — must NOT flip
166
- // the slot back to 'executing'.
167
- acc.addToolExecution(executing('exec-a'))
168
- expect(acc.getSegments()).toMatchSnapshot()
169
- })
170
-
171
- it('addApprovalBatch upserts by approvalRequestId (replay path produces ONE batch segment)', () => {
172
- const acc = createMessageSegmentAccumulator()
173
- acc.addApprovalBatch('batch-1', 'CLIENT', batchToolCalls, 'pending')
174
- acc.addApprovalBatch('batch-1', 'CLIENT', batchToolCalls, 'approved', {
175
- 'exec-a': { status: 'done', result: 'ok', success: true },
176
- }, 'Jane Admin')
177
- expect(acc.getSegments()).toMatchSnapshot()
178
- })
179
-
180
- it('implicit resolvePendingApprovalForExecution: a tool execution flips the LATEST pending single approval (NATS-observer behavior)', () => {
181
- // An observer (technician mirroring a client chat) may never receive
182
- // APPROVAL_RESULT — only the tool's EXECUTING/EXECUTED events. The
183
- // accumulator treats a tool execution as implicit approval of the most
184
- // recent still-pending single approval gate. Pinning explicitly.
185
- const acc = createMessageSegmentAccumulator()
186
- acc.addApprovalRequest('req-old', 'echo old', undefined, 'CLIENT', 'rejected')
187
- acc.addApprovalRequest('req-1', 'systemctl restart nats', undefined, 'CLIENT', 'pending')
188
- acc.addToolExecution(executing('exec-9'))
189
- expect(acc.getSegments()).toMatchSnapshot()
190
- })
191
-
192
- it('implicit approval flips ONLY the latest pending gate, earlier pending gates stay pending', () => {
193
- const acc = createMessageSegmentAccumulator()
194
- acc.addApprovalRequest('req-1', 'first', undefined, 'CLIENT', 'pending')
195
- acc.addApprovalRequest('req-2', 'second', undefined, 'CLIENT', 'pending')
196
- acc.addToolExecution(executing('exec-1'))
197
- expect(acc.getSegments()).toMatchSnapshot()
198
- })
199
-
200
- it('implicit approval does NOT touch approval_batch segments (handled by applyExecutionToBatch only)', () => {
201
- const acc = createMessageSegmentAccumulator()
202
- acc.addApprovalBatch('batch-1', 'CLIENT', batchToolCalls, 'pending')
203
- // exec id NOT in the batch → standalone segment path; batch stays pending.
204
- acc.addToolExecution(executing('exec-unrelated'))
205
- expect(acc.getSegments()).toMatchSnapshot()
206
- })
207
-
208
- it('context compaction start → complete replaces the started segment in place', () => {
209
- const acc = createMessageSegmentAccumulator()
210
- acc.appendText('Before compaction')
211
- acc.addContextCompaction()
212
- acc.completeContextCompaction('Summarized 34 messages')
213
- acc.appendText('After compaction')
214
- expect(acc.getSegments()).toMatchSnapshot()
215
- })
216
-
217
- it('completeContextCompaction with no started segment pushes a completed one', () => {
218
- const acc = createMessageSegmentAccumulator()
219
- acc.completeContextCompaction(undefined)
220
- expect(acc.getSegments()).toMatchSnapshot()
221
- })
222
-
223
- it('error segments append verbatim', () => {
224
- const acc = createMessageSegmentAccumulator()
225
- acc.appendText('partial answer')
226
- acc.addError('Agent crashed', 'boom')
227
- expect(acc.getSegments()).toMatchSnapshot()
228
- })
229
-
230
- it('flushPendingApprovals emits pending cards for every tracked-but-unresolved approval', () => {
231
- const acc = createMessageSegmentAccumulator()
232
- acc.trackApprovalRequest('req-1', { command: 'cmd-1', approvalType: 'CLIENT' })
233
- acc.trackApprovalRequest('req-2', { command: 'cmd-2', explanation: 'why', approvalType: 'ADMIN' })
234
- expect(acc.flushPendingApprovals()).toMatchSnapshot()
235
- })
236
-
237
- it('replaySegments reproduces a mixed recorded segment array (idempotent replay)', () => {
238
- const acc = createMessageSegmentAccumulator()
239
- acc.appendThinking('hmm')
240
- acc.appendText('Sure — ')
241
- acc.addToolExecution(executing('exec-1'))
242
- acc.addToolExecution(executed('exec-1'))
243
- acc.addApprovalBatch('batch-1', 'CLIENT', batchToolCalls, 'approved', {
244
- 'exec-a': { status: 'done', result: 'ok', success: true },
245
- })
246
- acc.appendText('done.')
247
- const recorded = acc.getSegments()
248
-
249
- const replayed = createMessageSegmentAccumulator().replaySegments(recorded)
250
- expect(replayed).toMatchSnapshot()
251
- })
252
-
253
- it('initializeWithState continues an incomplete message across reconnect', () => {
254
- const first = createMessageSegmentAccumulator()
255
- first.appendText('partial ')
256
- first.addToolExecution(executing('exec-1'))
257
- const state = first.getState()
258
-
259
- const resumed = createMessageSegmentAccumulator()
260
- resumed.initializeWithState({
261
- existingSegments: state.segments,
262
- pendingApprovals: state.pendingApprovals,
263
- executingTools: state.executingTools,
264
- })
265
- // The EXECUTED for the pre-reconnect EXECUTING merges into it.
266
- resumed.addToolExecution(executed('exec-1'))
267
- resumed.appendText('and the rest.')
268
- expect(resumed.getSegments()).toMatchSnapshot()
269
- })
270
- })