@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,460 +0,0 @@
1
- /**
2
- * GOLDEN CHARACTERIZATION TESTS — the NATS kernel of
3
- * `createChatStreamReducer`, driven through `decodeNatsChunk`.
4
- *
5
- * Originally written against the `useRealtimeChunkProcessor` compat hook
6
- * (Phase 0 of the chat unification). That wrapper was deleted once every
7
- * consumer moved to the reducer; the behavioral spec it pinned is far too
8
- * valuable to lose, so the suite was RETARGETED at the reducer itself. The
9
- * recorded snapshots are byte-identical to the wrapper-era ones — the only
10
- * thing that changed is who dispatches the effects.
11
- *
12
- * `dispatch()` below replicates the deleted wrapper's effect→callback
13
- * forwarding verbatim (including the `segments-after-approval-result`
14
- * conditional), so the logs remain a 1:1 record of the legacy
15
- * `RealtimeChunkCallbacks` contract. Do NOT "fix" behaviors captured here.
16
- */
17
-
18
- import { describe, it, expect } from 'vitest'
19
- import { decodeNatsChunk } from '../../../../chat-protocol/nats-decoder'
20
- import {
21
- createChatStreamReducer,
22
- type ChatStreamReducer,
23
- type InitializeExtras,
24
- } from '../chat-stream-reducer'
25
- import type { ChatApprovalStatus, RealtimeChunkCallbacks } from '../../types'
26
-
27
- type EventLog = Array<Record<string, unknown>>
28
-
29
- /** Build a full callback set that records every invocation into `log`. */
30
- function makeRecordingCallbacks(log: EventLog): RealtimeChunkCallbacks {
31
- return {
32
- onStreamStart: () => log.push({ event: 'onStreamStart' }),
33
- onStreamEnd: () => log.push({ event: 'onStreamEnd' }),
34
- onMetadata: (metadata) => log.push({ event: 'onMetadata', metadata }),
35
- onSegmentsUpdate: (segments, metadata) =>
36
- log.push({ event: 'onSegmentsUpdate', segments, metadata }),
37
- onError: (error, details) => log.push({ event: 'onError', error, details }),
38
- onUserMessage: (text, metadata) => log.push({ event: 'onUserMessage', text, metadata }),
39
- onTokenUsage: (data) => log.push({ event: 'onTokenUsage', data }),
40
- onDirectMessage: (text, metadata) => log.push({ event: 'onDirectMessage', text, metadata }),
41
- onSystemMessage: (text, metadata) => log.push({ event: 'onSystemMessage', text, metadata }),
42
- onApprove: async () => log.push({ event: 'onApprove' }),
43
- onReject: async () => log.push({ event: 'onReject' }),
44
- onEscalatedApproval: (requestId, data) =>
45
- log.push({ event: 'onEscalatedApproval', requestId, data }),
46
- onEscalatedApprovalResult: (requestId, approved, data) =>
47
- log.push({ event: 'onEscalatedApprovalResult', requestId, approved, data }),
48
- onApprovalResolved: (requestId, status, approvalType, resolvedByName) =>
49
- log.push({ event: 'onApprovalResolved', requestId, status, approvalType, resolvedByName }),
50
- onToolExecuted: (segment) => log.push({ event: 'onToolExecuted', segment }),
51
- onAgentBusy: () => log.push({ event: 'onAgentBusy' }),
52
- onDialogClosed: () => log.push({ event: 'onDialogClosed' }),
53
- }
54
- }
55
-
56
- interface SetupOptions {
57
- callbacks?: RealtimeChunkCallbacks
58
- batchApprovalsEnabled?: boolean
59
- displayApprovalTypes?: string[]
60
- approvalStatuses?: Record<string, ChatApprovalStatus>
61
- isDirectMode?: boolean
62
- initialState?: InitializeExtras
63
- }
64
-
65
- function setup(options: SetupOptions = {}) {
66
- const log: EventLog = []
67
- const callbacks = options.callbacks ?? makeRecordingCallbacks(log)
68
-
69
- const reducer: ChatStreamReducer = createChatStreamReducer({
70
- transport: 'nats',
71
- batchApprovalsEnabled: options.batchApprovalsEnabled,
72
- displayApprovalTypes: options.displayApprovalTypes,
73
- approvalStatuses: options.approvalStatuses,
74
- isDirectMode: options.isDirectMode,
75
- crossMessageToolRouting: !!callbacks.onToolExecuted,
76
- callbacks: {
77
- onApprove: (id) => callbacks.onApprove?.(id),
78
- onReject: (id) => callbacks.onReject?.(id),
79
- },
80
- onEffect: ({ name, args }) => {
81
- const cbs = callbacks as Record<string, ((...a: unknown[]) => void) | undefined>
82
- // Legacy conditional: the cumulative post-APPROVAL_RESULT emit fires
83
- // only when the consumer did NOT wire onApprovalResolved.
84
- if (name === 'segments-after-approval-result') {
85
- if (!cbs.onApprovalResolved) cbs.onSegmentsUpdate?.(...args)
86
- return
87
- }
88
- cbs[name]?.(...args)
89
- },
90
- })
91
-
92
- // The wrapper initialized from `initialState` in a mount effect.
93
- if (options.initialState) reducer.initializeWithState(null, options.initialState)
94
-
95
- const feed = (chunks: unknown[]) => {
96
- for (const chunk of chunks) {
97
- const event = decodeNatsChunk(chunk)
98
- if (event) reducer.apply(event)
99
- }
100
- }
101
- return { log, reducer, feed }
102
- }
103
-
104
- const EXECUTING = {
105
- type: 'EXECUTING_TOOL',
106
- integratedToolType: 'TACTICAL_RMM',
107
- toolFunction: 'run_script',
108
- title: 'Run cleanup script',
109
- parameters: { script: 'cleanup.sh' },
110
- toolExecutionRequestId: 'exec-1',
111
- }
112
- const EXECUTED = {
113
- type: 'EXECUTED_TOOL',
114
- integratedToolType: 'TACTICAL_RMM',
115
- toolFunction: 'run_script',
116
- result: 'Freed 2.3 GB',
117
- success: true,
118
- toolExecutionRequestId: 'exec-1',
119
- }
120
-
121
- describe('chat stream reducer — legacy chunk-processor golden event logs', () => {
122
- it('normal turn: start → metadata → text ×3 → token usage → end', () => {
123
- const { log, feed } = setup()
124
- feed([
125
- { type: 'MESSAGE_START' },
126
- {
127
- type: 'AI_METADATA',
128
- modelDisplayName: 'Claude Sonnet',
129
- modelName: 'claude-sonnet-x',
130
- providerName: 'anthropic',
131
- contextWindow: 200000,
132
- },
133
- { type: 'TEXT', text: 'Hello' },
134
- { type: 'TEXT', text: ', ' },
135
- { type: 'TEXT', text: 'world' },
136
- {
137
- type: 'TOKEN_USAGE',
138
- inputTokensSize: 100,
139
- outputTokensSize: 20,
140
- totalTokensSize: 120,
141
- contextSize: 180000,
142
- },
143
- { type: 'MESSAGE_END' },
144
- ])
145
- expect(log).toMatchSnapshot()
146
- })
147
-
148
- it('streamSeq on content chunks is threaded into onSegmentsUpdate metadata', () => {
149
- const { log, feed } = setup()
150
- feed([
151
- { type: 'MESSAGE_START' },
152
- { type: 'TEXT', text: 'seq-stamped', streamSeq: 7 },
153
- { type: 'MESSAGE_END' },
154
- ])
155
- expect(log).toMatchSnapshot()
156
- })
157
-
158
- it('cold start (no MESSAGE_START ever): text emits CUMULATIVE segments (no append flag)', () => {
159
- const { log, feed } = setup()
160
- feed([
161
- { type: 'TEXT', text: 'cold ' },
162
- { type: 'TEXT', text: 'start' },
163
- ])
164
- expect(log).toMatchSnapshot()
165
- })
166
-
167
- it('post-MESSAGE_END continuation: text/thinking emit DELTA segments with append:true', () => {
168
- const { log, feed } = setup()
169
- feed([
170
- { type: 'MESSAGE_START' },
171
- { type: 'TEXT', text: 'in-stream' },
172
- { type: 'MESSAGE_END' },
173
- { type: 'TEXT', text: 'post-end text' },
174
- { type: 'THINKING', text: 'post-end thinking' },
175
- ])
176
- expect(log).toMatchSnapshot()
177
- })
178
-
179
- it('tool execution OUTSIDE a message window: onAgentBusy + cross-message onToolExecuted (accumulator skipped)', () => {
180
- const { log, feed } = setup()
181
- // No MESSAGE_START — approved commands execute between the approval
182
- // bubble's MESSAGE_END and the continuation stream.
183
- feed([EXECUTING, EXECUTED])
184
- expect(log).toMatchSnapshot()
185
- })
186
-
187
- it('tool execution IN-stream: accumulator-driven segment updates, onToolExecuted NOT fired', () => {
188
- const { log, feed } = setup()
189
- feed([
190
- { type: 'MESSAGE_START' },
191
- { type: 'TEXT', text: 'Running now. ' },
192
- EXECUTING,
193
- EXECUTED,
194
- { type: 'MESSAGE_END' },
195
- ])
196
- expect(log).toMatchSnapshot()
197
- })
198
-
199
- it('approval request (displayed) → approval result: in-message flip + onApprovalResolved', () => {
200
- const { log, feed } = setup()
201
- feed([
202
- { type: 'MESSAGE_START' },
203
- {
204
- type: 'APPROVAL_REQUEST',
205
- approvalRequestId: 'req-1',
206
- approvalType: 'CLIENT',
207
- command: 'systemctl restart nats',
208
- explanation: 'Restart the broker',
209
- },
210
- { type: 'MESSAGE_END' },
211
- {
212
- type: 'APPROVAL_RESULT',
213
- approvalRequestId: 'req-1',
214
- approved: true,
215
- approvalType: 'CLIENT',
216
- displayName: 'Jane Admin',
217
- },
218
- ])
219
- // CHARACTERIZATION: because onApprovalResolved IS wired, the result
220
- // does NOT emit onSegmentsUpdate — only the cross-message callback.
221
- expect(log).toMatchSnapshot()
222
- })
223
-
224
- it('approval result WITHOUT onApprovalResolved wired: emits cumulative onSegmentsUpdate instead', () => {
225
- const log: EventLog = []
226
- const callbacks = makeRecordingCallbacks(log)
227
- delete callbacks.onApprovalResolved
228
- const { feed } = setup({ callbacks })
229
- feed([
230
- { type: 'MESSAGE_START' },
231
- {
232
- type: 'APPROVAL_REQUEST',
233
- approvalRequestId: 'req-1',
234
- approvalType: 'CLIENT',
235
- command: 'reboot',
236
- },
237
- {
238
- type: 'APPROVAL_RESULT',
239
- approvalRequestId: 'req-1',
240
- approved: false,
241
- approvalType: 'CLIENT',
242
- },
243
- ])
244
- expect(log).toMatchSnapshot()
245
- })
246
-
247
- it('escalated approval (type not displayed) → onEscalatedApproval, then result appends resolved card', () => {
248
- const { log, feed, reducer } = setup() // displayApprovalTypes defaults to ['CLIENT']
249
- feed([
250
- { type: 'MESSAGE_START' },
251
- {
252
- type: 'APPROVAL_REQUEST',
253
- approvalRequestId: 'req-adm',
254
- approvalType: 'ADMIN',
255
- command: 'drop database prod',
256
- },
257
- { type: 'MESSAGE_END' },
258
- {
259
- type: 'APPROVAL_RESULT',
260
- approvalRequestId: 'req-adm',
261
- approved: true,
262
- approvalType: 'ADMIN',
263
- },
264
- ])
265
- expect({
266
- log,
267
- pendingAfter: Array.from(reducer.getPendingEscalated().entries()),
268
- }).toMatchSnapshot()
269
- })
270
-
271
- it('batch approval (batchApprovalsEnabled default ON): one batch segment, executions merge into it', () => {
272
- const { log, feed } = setup()
273
- feed([
274
- { type: 'MESSAGE_START' },
275
- {
276
- type: 'APPROVAL_REQUEST',
277
- approvalRequestId: 'batch-1',
278
- approvalType: 'CLIENT',
279
- toolCalls: [
280
- {
281
- toolExecutionRequestId: 'exec-a',
282
- toolName: 'create_ticket',
283
- toolTitle: 'Create ticket',
284
- requiresApproval: true,
285
- approvalType: 'CLIENT',
286
- toolCallArguments: { subject: 'Printer down' },
287
- },
288
- {
289
- toolExecutionRequestId: 'exec-b',
290
- toolName: 'read_kb',
291
- requiresApproval: false,
292
- },
293
- ],
294
- },
295
- {
296
- type: 'APPROVAL_RESULT',
297
- approvalRequestId: 'batch-1',
298
- approved: true,
299
- displayName: 'Alice Client',
300
- },
301
- {
302
- type: 'EXECUTING_TOOL',
303
- integratedToolType: 'PSA',
304
- toolFunction: 'create_ticket',
305
- toolExecutionRequestId: 'exec-a',
306
- },
307
- {
308
- type: 'EXECUTED_TOOL',
309
- integratedToolType: 'PSA',
310
- toolFunction: 'create_ticket',
311
- result: 'Ticket #77 created',
312
- success: true,
313
- toolExecutionRequestId: 'exec-a',
314
- },
315
- { type: 'MESSAGE_END' },
316
- ])
317
- expect(log).toMatchSnapshot()
318
- })
319
-
320
- it('batch approval with batchApprovalsEnabled:false unfolds into legacy cards (requiresApproval only)', () => {
321
- const { log, feed } = setup({ batchApprovalsEnabled: false })
322
- feed([
323
- { type: 'MESSAGE_START' },
324
- {
325
- type: 'APPROVAL_REQUEST',
326
- approvalRequestId: 'batch-1',
327
- approvalType: 'CLIENT',
328
- toolCalls: [
329
- {
330
- toolExecutionRequestId: 'exec-a',
331
- toolName: 'create_ticket',
332
- toolTitle: 'Create ticket',
333
- requiresApproval: true,
334
- toolCallArguments: { subject: 'Printer down' },
335
- },
336
- {
337
- toolExecutionRequestId: 'exec-b',
338
- toolName: 'read_kb',
339
- requiresApproval: false,
340
- },
341
- ],
342
- },
343
- { type: 'MESSAGE_END' },
344
- ])
345
- expect(log).toMatchSnapshot()
346
- })
347
-
348
- it('CHARACTERIZATION duplicate/out-of-order: redelivered EXECUTING after EXECUTED in-stream appends a NEW executing segment (no dedup)', () => {
349
- // The reducer does no duplicate suppression for standalone tool
350
- // segments — dedup only exists inside approval batches (no-downgrade
351
- // rule). Recording actual behavior, see unification plan.
352
- const { log, feed } = setup()
353
- feed([
354
- { type: 'MESSAGE_START' },
355
- EXECUTING,
356
- EXECUTED,
357
- EXECUTING, // redelivered
358
- { type: 'MESSAGE_END' },
359
- ])
360
- expect(log).toMatchSnapshot()
361
- })
362
-
363
- it('error chunk: segment append + onError with JSON-extracted message', () => {
364
- const { log, feed } = setup()
365
- feed([
366
- { type: 'MESSAGE_START' },
367
- { type: 'TEXT', text: 'partial' },
368
- { type: 'ERROR', error: 'Agent crashed', details: '{"error":{"message":"boom"}}' },
369
- { type: 'ERROR', error: 'Plain details', details: 'not-json' },
370
- ])
371
- expect(log).toMatchSnapshot()
372
- })
373
-
374
- it('user echo / system / direct-message / dialog-closed routing', () => {
375
- const { log, feed } = setup()
376
- feed([
377
- {
378
- type: 'MESSAGE_REQUEST',
379
- text: 'open a ticket',
380
- ownerType: 'CLIENT',
381
- displayName: 'Alice',
382
- userId: 'user-42',
383
- streamSeq: 3,
384
- contextItems: [{ type: 'device', id: 'dev-1' }],
385
- },
386
- { type: 'SYSTEM', text: 'User joined the chat', streamSeq: 4 },
387
- {
388
- type: 'DIRECT_MESSAGE',
389
- text: 'Human here now',
390
- ownerType: 'ADMIN',
391
- displayName: 'Jane Admin',
392
- userId: 'admin-7',
393
- streamSeq: 5,
394
- },
395
- { type: 'DIALOG_CLOSED' },
396
- ])
397
- expect(log).toMatchSnapshot()
398
- })
399
-
400
- it('direct-mode barrier: after a DIRECT_MESSAGE, AI chunks are dropped with a one-shot teardown', () => {
401
- const { log, feed } = setup()
402
- feed([
403
- { type: 'MESSAGE_START' },
404
- { type: 'TEXT', text: 'ai text before takeover' },
405
- { type: 'DIRECT_MESSAGE', text: 'Human takeover', ownerType: 'ADMIN' },
406
- // AI chunks now dropped; first one triggers the teardown (onStreamEnd).
407
- { type: 'TEXT', text: 'dropped ai text' },
408
- { type: 'TEXT', text: 'also dropped' },
409
- // Allowlisted chunks still flow.
410
- { type: 'SYSTEM', text: 'still visible' },
411
- { type: 'DIRECT_MESSAGE', text: 'second human message' },
412
- ])
413
- expect(log).toMatchSnapshot()
414
- })
415
-
416
- it('context compaction outside a stream emits append+isCompacting metadata; inside a stream it is cumulative', () => {
417
- const { log, feed } = setup()
418
- feed([
419
- // standalone (no open stream)
420
- { type: 'CONTEXT_COMPACTION_START' },
421
- { type: 'CONTEXT_COMPACTION_END', text: 'Summarized 12 messages' },
422
- ])
423
- const standaloneLog = [...log]
424
- log.length = 0
425
- feed([
426
- { type: 'MESSAGE_START' },
427
- { type: 'CONTEXT_COMPACTION_START' },
428
- { type: 'CONTEXT_COMPACTION_END', text: 'Mid-stream summary' },
429
- { type: 'MESSAGE_END' },
430
- ])
431
- expect({ standalone: standaloneLog, inStream: log }).toMatchSnapshot()
432
- })
433
-
434
- it('reset() clears accumulator + stream flags so the next dialog cold-starts cumulative', () => {
435
- const { log, feed, reducer } = setup()
436
- feed([
437
- { type: 'MESSAGE_START' },
438
- { type: 'TEXT', text: 'dialog one' },
439
- { type: 'MESSAGE_END' },
440
- ])
441
- reducer.reset()
442
- log.length = 0
443
- feed([{ type: 'TEXT', text: 'dialog two cold start' }])
444
- expect(log).toMatchSnapshot()
445
- })
446
-
447
- it('initialState resume: continuation chunks after resume take the post-stream append path', () => {
448
- const { log } = setup({
449
- initialState: {
450
- existingSegments: [{ type: 'text', text: 'restored partial ' }],
451
- escalatedApprovals: new Map([
452
- ['req-esc', { command: 'escalated cmd', approvalType: 'ADMIN' }],
453
- ]),
454
- },
455
- })
456
- // initializeWithState replays escalated approvals via onEscalatedApproval
457
- // and marks hasEverStreamed=true.
458
- expect(log).toMatchSnapshot()
459
- })
460
- })