@flamingo-stack/openframe-frontend-core 0.0.490-1506.3944.1 → 0.0.490

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 (293) hide show
  1. package/dist/{chunk-5CJR2GZ4.cjs → chunk-2MKUHJ3O.cjs} +31 -31
  2. package/dist/{chunk-5CJR2GZ4.cjs.map → chunk-2MKUHJ3O.cjs.map} +1 -1
  3. package/dist/{chunk-S2NHJDKQ.cjs → chunk-3IEVA5AO.cjs} +62 -62
  4. package/dist/{chunk-S2NHJDKQ.cjs.map → chunk-3IEVA5AO.cjs.map} +1 -1
  5. package/dist/{chunk-GTWO5NAY.js → chunk-6CFFISUC.js} +2 -2
  6. package/dist/{chunk-VHG6AX5V.js → chunk-6CJ2K7BD.js} +2 -2
  7. package/dist/{chunk-4NWARV5I.js → chunk-6QK3ONDD.js} +2 -2
  8. package/dist/{chunk-YHOIAA2E.cjs → chunk-7I42V2OD.cjs} +60 -60
  9. package/dist/chunk-7I42V2OD.cjs.map +1 -0
  10. package/dist/{chunk-T2EGSZFN.js → chunk-AIRNG27G.js} +5 -6
  11. package/dist/chunk-AIRNG27G.js.map +1 -0
  12. package/dist/{chunk-NWX7MMF5.cjs → chunk-AW63ET2A.cjs} +15 -15
  13. package/dist/{chunk-NWX7MMF5.cjs.map → chunk-AW63ET2A.cjs.map} +1 -1
  14. package/dist/{chunk-TKN5667N.js → chunk-BZMOEWWS.js} +10 -10
  15. package/dist/chunk-BZMOEWWS.js.map +1 -0
  16. package/dist/{chunk-DSDZ5T4P.cjs → chunk-D5LQMRPU.cjs} +5 -5
  17. package/dist/{chunk-DSDZ5T4P.cjs.map → chunk-D5LQMRPU.cjs.map} +1 -1
  18. package/dist/{chunk-CORIBKHG.js → chunk-EGXCWZYP.js} +2 -2
  19. package/dist/{chunk-5EYRXSY5.cjs → chunk-EJQUYZXF.cjs} +9 -9
  20. package/dist/{chunk-5EYRXSY5.cjs.map → chunk-EJQUYZXF.cjs.map} +1 -1
  21. package/dist/{chunk-P4WTZU6L.cjs → chunk-FY5XAW3H.cjs} +11 -11
  22. package/dist/{chunk-P4WTZU6L.cjs.map → chunk-FY5XAW3H.cjs.map} +1 -1
  23. package/dist/{chunk-VQ523ORK.cjs → chunk-GMPYR3MX.cjs} +26 -26
  24. package/dist/{chunk-VQ523ORK.cjs.map → chunk-GMPYR3MX.cjs.map} +1 -1
  25. package/dist/{chunk-QSCHCZL3.cjs → chunk-GUTYUMGV.cjs} +7 -7
  26. package/dist/{chunk-QSCHCZL3.cjs.map → chunk-GUTYUMGV.cjs.map} +1 -1
  27. package/dist/{chunk-Q6E7VJ4W.cjs → chunk-IEZ3YBAP.cjs} +27 -28
  28. package/dist/chunk-IEZ3YBAP.cjs.map +1 -0
  29. package/dist/{chunk-HSACATCD.js → chunk-MPYDX5WX.js} +2 -2
  30. package/dist/{chunk-RQLBHKXN.js → chunk-NGEFYPY7.js} +2 -2
  31. package/dist/{chunk-BE6DK7QY.js → chunk-OQIMH2WQ.js} +8985 -11081
  32. package/dist/chunk-OQIMH2WQ.js.map +1 -0
  33. package/dist/{chunk-CSYSYJCF.cjs → chunk-UZZT65PQ.cjs} +37 -37
  34. package/dist/{chunk-CSYSYJCF.cjs.map → chunk-UZZT65PQ.cjs.map} +1 -1
  35. package/dist/{chunk-YZ2OIYQ3.js → chunk-VDZO6IDR.js} +4 -4
  36. package/dist/{chunk-UUYRJPGJ.js → chunk-VL2YMDPH.js} +4 -4
  37. package/dist/{chunk-5LMGFI4J.cjs → chunk-VUXNXWOQ.cjs} +4946 -7042
  38. package/dist/chunk-VUXNXWOQ.cjs.map +1 -0
  39. package/dist/{chunk-XQ2B74SI.js → chunk-WLM3F3WU.js} +2 -2
  40. package/dist/components/case-studies/index.cjs +8 -8
  41. package/dist/components/case-studies/index.js +2 -2
  42. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  43. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  44. package/dist/components/chat/guide-display.d.ts +14 -0
  45. package/dist/components/chat/guide-display.d.ts.map +1 -0
  46. package/dist/components/chat/hooks/index.d.ts +1 -0
  47. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  48. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  49. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +48 -15
  50. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  51. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +6 -0
  52. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -0
  53. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +57 -10
  54. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  55. package/dist/components/chat/index.cjs +2 -8
  56. package/dist/components/chat/index.cjs.map +1 -1
  57. package/dist/components/chat/index.d.ts +1 -1
  58. package/dist/components/chat/index.d.ts.map +1 -1
  59. package/dist/components/chat/index.js +15 -21
  60. package/dist/components/chat/types/api.types.d.ts +81 -1
  61. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  62. package/dist/components/chat/types/component.types.d.ts +6 -0
  63. package/dist/components/chat/types/component.types.d.ts.map +1 -1
  64. package/dist/components/chat/types/message.types.d.ts +15 -2
  65. package/dist/components/chat/types/message.types.d.ts.map +1 -1
  66. package/dist/components/chat/types/processing.types.d.ts +93 -2
  67. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  68. package/dist/components/chat/utils/chunk-parser.d.ts +25 -0
  69. package/dist/components/chat/utils/chunk-parser.d.ts.map +1 -0
  70. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +6 -34
  71. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  72. package/dist/components/chat/utils/index.d.ts +3 -2
  73. package/dist/components/chat/utils/index.d.ts.map +1 -1
  74. package/dist/components/chat/utils/message-segment-accumulator.d.ts +5 -0
  75. package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
  76. package/dist/components/chat/utils/process-historical-messages.d.ts +11 -59
  77. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  78. package/dist/components/contact/index.cjs +3 -3
  79. package/dist/components/contact/index.js +2 -2
  80. package/dist/components/docs/index.cjs +5 -5
  81. package/dist/components/docs/index.js +4 -4
  82. package/dist/components/embeds/index.cjs +3 -3
  83. package/dist/components/embeds/index.js +2 -2
  84. package/dist/components/faq/index.cjs +3 -3
  85. package/dist/components/faq/index.js +2 -2
  86. package/dist/components/features/index.cjs +2 -2
  87. package/dist/components/features/index.js +1 -1
  88. package/dist/components/help-center-pages/index.cjs +20 -20
  89. package/dist/components/help-center-pages/index.js +11 -11
  90. package/dist/components/index.cjs +130 -170
  91. package/dist/components/index.cjs.map +1 -1
  92. package/dist/components/index.js +23 -63
  93. package/dist/components/index.js.map +1 -1
  94. package/dist/components/navigation/index.cjs +2 -2
  95. package/dist/components/navigation/index.js +1 -1
  96. package/dist/components/onboarding-guides/index.cjs +5 -5
  97. package/dist/components/onboarding-guides/index.js +4 -4
  98. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  99. package/dist/components/related-content/index.cjs +3 -3
  100. package/dist/components/related-content/index.js +2 -2
  101. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  102. package/dist/components/tickets/index.cjs +5 -5
  103. package/dist/components/tickets/index.js +4 -4
  104. package/dist/components/ui/index.cjs +2 -42
  105. package/dist/components/ui/index.cjs.map +1 -1
  106. package/dist/components/ui/index.d.ts +2 -1
  107. package/dist/components/ui/index.d.ts.map +1 -1
  108. package/dist/components/ui/index.js +15 -55
  109. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  110. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  111. package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
  112. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
  113. package/dist/index.cjs +2 -58
  114. package/dist/index.cjs.map +1 -1
  115. package/dist/index.js +15 -71
  116. package/dist/utils/index.cjs +40 -169
  117. package/dist/utils/index.cjs.map +1 -1
  118. package/dist/utils/index.d.ts +0 -1
  119. package/dist/utils/index.d.ts.map +1 -1
  120. package/dist/utils/index.js +41 -162
  121. package/dist/utils/index.js.map +1 -1
  122. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  123. package/package.json +1 -7
  124. package/src/components/chat/__tests__/chat-message-list.test.tsx +5 -293
  125. package/src/components/chat/chat-message-enhanced.tsx +80 -163
  126. package/src/components/chat/chat-message-list.tsx +109 -358
  127. package/src/components/chat/embeddable-chat.tsx +0 -6
  128. package/src/components/chat/guide-display.tsx +44 -0
  129. package/src/components/chat/hooks/.index.md +33 -30
  130. package/src/components/chat/hooks/.use-nats-chat-adapter.md +55 -36
  131. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +77 -0
  132. package/src/components/chat/hooks/index.ts +1 -0
  133. package/src/components/chat/hooks/use-chat.ts +0 -8
  134. package/src/components/chat/hooks/use-nats-chat-adapter.ts +825 -243
  135. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +489 -0
  136. package/src/components/chat/hooks/use-sse-chat-adapter.ts +684 -380
  137. package/src/components/chat/index.ts +1 -5
  138. package/src/components/chat/thinking-display.tsx +1 -1
  139. package/src/components/chat/types/.api.types.md +49 -39
  140. package/src/components/chat/types/.processing.types.md +58 -29
  141. package/src/components/chat/types/api.types.ts +73 -6
  142. package/src/components/chat/types/component.types.ts +9 -0
  143. package/src/components/chat/types/message.types.ts +17 -1
  144. package/src/components/chat/types/processing.types.ts +53 -11
  145. package/src/components/chat/utils/.chunk-parser.md +62 -0
  146. package/src/components/chat/utils/.index.md +40 -31
  147. package/src/components/chat/utils/chunk-parser.ts +262 -0
  148. package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
  149. package/src/components/chat/utils/index.ts +8 -5
  150. package/src/components/chat/utils/message-segment-accumulator.ts +19 -0
  151. package/src/components/chat/utils/process-historical-messages.ts +390 -352
  152. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
  153. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  154. package/src/components/shared/product-release/release-detail-page.tsx +4 -19
  155. package/src/components/ui/.simple-markdown-renderer.md +52 -0
  156. package/src/components/ui/index.ts +2 -1
  157. package/src/components/ui/release-changelog-section.tsx +1 -1
  158. package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
  159. package/src/components/ui/simple-markdown-renderer.tsx +964 -0
  160. package/src/components/ui/ticket-info-section.tsx +1 -1
  161. package/src/stories/ChatMessageEnhanced.stories.tsx +48 -1
  162. package/src/utils/index.ts +0 -1
  163. package/src/utils/markdown-section-extractor.ts +56 -41
  164. package/dist/chat-protocol/decode.d.ts +0 -58
  165. package/dist/chat-protocol/decode.d.ts.map +0 -1
  166. package/dist/chat-protocol/encode.d.ts +0 -44
  167. package/dist/chat-protocol/encode.d.ts.map +0 -1
  168. package/dist/chat-protocol/env-flag.d.ts +0 -35
  169. package/dist/chat-protocol/env-flag.d.ts.map +0 -1
  170. package/dist/chat-protocol/events.d.ts +0 -196
  171. package/dist/chat-protocol/events.d.ts.map +0 -1
  172. package/dist/chat-protocol/frames.d.ts +0 -213
  173. package/dist/chat-protocol/frames.d.ts.map +0 -1
  174. package/dist/chat-protocol/index.cjs +0 -494
  175. package/dist/chat-protocol/index.cjs.map +0 -1
  176. package/dist/chat-protocol/index.d.ts +0 -18
  177. package/dist/chat-protocol/index.d.ts.map +0 -1
  178. package/dist/chat-protocol/index.js +0 -478
  179. package/dist/chat-protocol/index.js.map +0 -1
  180. package/dist/chat-protocol/ip-normalize.d.ts +0 -44
  181. package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
  182. package/dist/chat-protocol/nats-decoder.d.ts +0 -26
  183. package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
  184. package/dist/chunk-5LMGFI4J.cjs.map +0 -1
  185. package/dist/chunk-BE6DK7QY.js.map +0 -1
  186. package/dist/chunk-Q6E7VJ4W.cjs.map +0 -1
  187. package/dist/chunk-T2EGSZFN.js.map +0 -1
  188. package/dist/chunk-TKN5667N.js.map +0 -1
  189. package/dist/chunk-YHOIAA2E.cjs.map +0 -1
  190. package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
  191. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
  192. package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
  193. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
  194. package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
  195. package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
  196. package/dist/components/chat/stream/index.d.ts +0 -17
  197. package/dist/components/chat/stream/index.d.ts.map +0 -1
  198. package/dist/components/chat/stream/message-mutations.d.ts +0 -77
  199. package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
  200. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
  201. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
  202. package/dist/components/ui/markdown/base-components.d.ts +0 -51
  203. package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
  204. package/dist/components/ui/markdown/engine.d.ts +0 -99
  205. package/dist/components/ui/markdown/engine.d.ts.map +0 -1
  206. package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
  207. package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
  208. package/dist/components/ui/markdown/index.d.ts +0 -18
  209. package/dist/components/ui/markdown/index.d.ts.map +0 -1
  210. package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
  211. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
  212. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
  213. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
  214. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
  215. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
  216. package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
  217. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
  218. package/dist/components/ui/markdown/sanitize.d.ts +0 -153
  219. package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
  220. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
  221. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
  222. package/dist/components/ui/markdown/streaming.d.ts +0 -78
  223. package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
  224. package/dist/components/ui/markdown/text-size.d.ts +0 -34
  225. package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
  226. package/dist/utils/markdown-fences.d.ts +0 -42
  227. package/dist/utils/markdown-fences.d.ts.map +0 -1
  228. package/dist/utils/markdown-heading-id.d.ts +0 -85
  229. package/dist/utils/markdown-heading-id.d.ts.map +0 -1
  230. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -307
  231. package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -516
  232. package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
  233. package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
  234. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -228
  235. package/src/chat-protocol/decode.ts +0 -278
  236. package/src/chat-protocol/encode.ts +0 -71
  237. package/src/chat-protocol/env-flag.ts +0 -39
  238. package/src/chat-protocol/events.ts +0 -232
  239. package/src/chat-protocol/frames.ts +0 -245
  240. package/src/chat-protocol/index.ts +0 -21
  241. package/src/chat-protocol/ip-normalize.ts +0 -146
  242. package/src/chat-protocol/nats-decoder.ts +0 -252
  243. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
  244. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -209
  245. package/src/components/chat/hooks/__tests__/__snapshots__/conversation-id-persistence-golden.test.ts.snap +0 -37
  246. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  247. package/src/components/chat/hooks/__tests__/conversation-id-persistence-golden.test.ts +0 -438
  248. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
  249. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -940
  250. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -756
  251. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -460
  252. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -894
  253. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
  254. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -98
  255. package/src/components/chat/stream/chat-dialog-store.ts +0 -536
  256. package/src/components/chat/stream/chat-stream-reducer.ts +0 -1796
  257. package/src/components/chat/stream/delta-batcher.ts +0 -159
  258. package/src/components/chat/stream/index.ts +0 -55
  259. package/src/components/chat/stream/message-mutations.ts +0 -338
  260. package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
  261. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -420
  262. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -605
  263. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -317
  264. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
  265. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
  266. package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2528
  267. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -115
  268. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -95
  269. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -309
  270. package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -388
  271. package/src/components/ui/markdown/base-components.tsx +0 -360
  272. package/src/components/ui/markdown/engine.tsx +0 -315
  273. package/src/components/ui/markdown/heading-ids.ts +0 -239
  274. package/src/components/ui/markdown/index.ts +0 -49
  275. package/src/components/ui/markdown/mermaid-diagram.tsx +0 -291
  276. package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
  277. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
  278. package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
  279. package/src/components/ui/markdown/sanitize.ts +0 -3499
  280. package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
  281. package/src/components/ui/markdown/streaming.ts +0 -362
  282. package/src/components/ui/markdown/text-size.ts +0 -106
  283. package/src/utils/markdown-fences.ts +0 -127
  284. package/src/utils/markdown-heading-id.ts +0 -348
  285. /package/dist/{chunk-GTWO5NAY.js.map → chunk-6CFFISUC.js.map} +0 -0
  286. /package/dist/{chunk-VHG6AX5V.js.map → chunk-6CJ2K7BD.js.map} +0 -0
  287. /package/dist/{chunk-4NWARV5I.js.map → chunk-6QK3ONDD.js.map} +0 -0
  288. /package/dist/{chunk-CORIBKHG.js.map → chunk-EGXCWZYP.js.map} +0 -0
  289. /package/dist/{chunk-HSACATCD.js.map → chunk-MPYDX5WX.js.map} +0 -0
  290. /package/dist/{chunk-RQLBHKXN.js.map → chunk-NGEFYPY7.js.map} +0 -0
  291. /package/dist/{chunk-YZ2OIYQ3.js.map → chunk-VDZO6IDR.js.map} +0 -0
  292. /package/dist/{chunk-UUYRJPGJ.js.map → chunk-VL2YMDPH.js.map} +0 -0
  293. /package/dist/{chunk-XQ2B74SI.js.map → chunk-WLM3F3WU.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
- })