@flamingo-stack/openframe-frontend-core 0.0.498-1506.4000.1 → 0.0.498

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 (290) hide show
  1. package/dist/{chunk-ZHC2BCXK.js → chunk-2OPD6KRB.js} +4 -4
  2. package/dist/{chunk-5BQWVNRS.cjs → chunk-2R25CGSO.cjs} +62 -62
  3. package/dist/{chunk-5BQWVNRS.cjs.map → chunk-2R25CGSO.cjs.map} +1 -1
  4. package/dist/{chunk-242K7LZY.cjs → chunk-4EHQEMN4.cjs} +11 -11
  5. package/dist/{chunk-242K7LZY.cjs.map → chunk-4EHQEMN4.cjs.map} +1 -1
  6. package/dist/{chunk-4KKGHPNE.cjs → chunk-4NIBKEED.cjs} +9 -9
  7. package/dist/{chunk-4KKGHPNE.cjs.map → chunk-4NIBKEED.cjs.map} +1 -1
  8. package/dist/{chunk-5QWYIPMH.js → chunk-5ZL7PA63.js} +2 -2
  9. package/dist/{chunk-3VGRZ62V.js → chunk-6GAJETAP.js} +2 -2
  10. package/dist/{chunk-EO35UHFT.cjs → chunk-A3Z63ZL5.cjs} +60 -60
  11. package/dist/chunk-A3Z63ZL5.cjs.map +1 -0
  12. package/dist/{chunk-34C2JV2C.js → chunk-G6ARA2HD.js} +2 -2
  13. package/dist/{chunk-WNXIG6YY.js → chunk-K5HHLTSG.js} +2 -2
  14. package/dist/{chunk-42NYDEHH.js → chunk-KK4M4URN.js} +2 -2
  15. package/dist/{chunk-42SMPKGY.js → chunk-MF3VJKHT.js} +2 -2
  16. package/dist/{chunk-EORFD5WB.cjs → chunk-MSB3PEPP.cjs} +15 -15
  17. package/dist/{chunk-EORFD5WB.cjs.map → chunk-MSB3PEPP.cjs.map} +1 -1
  18. package/dist/{chunk-F7XPMG25.cjs → chunk-MVORKLWX.cjs} +27 -28
  19. package/dist/chunk-MVORKLWX.cjs.map +1 -0
  20. package/dist/{chunk-D3LUKR2Y.js → chunk-OYPUQJJ2.js} +10044 -12292
  21. package/dist/chunk-OYPUQJJ2.js.map +1 -0
  22. package/dist/{chunk-62TM2RVZ.cjs → chunk-T67MZAQJ.cjs} +26 -26
  23. package/dist/{chunk-62TM2RVZ.cjs.map → chunk-T67MZAQJ.cjs.map} +1 -1
  24. package/dist/{chunk-BUBQEZ5J.js → chunk-VLWVM6ZS.js} +2 -2
  25. package/dist/{chunk-632XJ2ZT.js → chunk-VOOEX4IZ.js} +5 -6
  26. package/dist/chunk-VOOEX4IZ.js.map +1 -0
  27. package/dist/{chunk-5ZY5JM4Z.js → chunk-W4XZ3FBZ.js} +10 -10
  28. package/dist/chunk-W4XZ3FBZ.js.map +1 -0
  29. package/dist/{chunk-2LYA3RBT.cjs → chunk-XI44QDCD.cjs} +37 -37
  30. package/dist/{chunk-2LYA3RBT.cjs.map → chunk-XI44QDCD.cjs.map} +1 -1
  31. package/dist/{chunk-WZCQW4MW.js → chunk-XSNKSMB3.js} +4 -4
  32. package/dist/{chunk-J3NHQ4JB.cjs → chunk-ZBTIN7RC.cjs} +31 -31
  33. package/dist/{chunk-J3NHQ4JB.cjs.map → chunk-ZBTIN7RC.cjs.map} +1 -1
  34. package/dist/{chunk-SS3D3DHL.cjs → chunk-ZEZTITQZ.cjs} +4886 -7134
  35. package/dist/chunk-ZEZTITQZ.cjs.map +1 -0
  36. package/dist/{chunk-44C23SSC.cjs → chunk-ZHNWWFIM.cjs} +5 -5
  37. package/dist/{chunk-44C23SSC.cjs.map → chunk-ZHNWWFIM.cjs.map} +1 -1
  38. package/dist/{chunk-H6GFQ4AO.cjs → chunk-ZTE32A7C.cjs} +7 -7
  39. package/dist/{chunk-H6GFQ4AO.cjs.map → chunk-ZTE32A7C.cjs.map} +1 -1
  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/hooks/index.d.ts +1 -0
  45. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  46. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  47. package/dist/components/chat/hooks/use-chunk-catchup.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 +57 -10
  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 +93 -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 +130 -172
  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/header.d.ts.map +1 -1
  88. package/dist/components/navigation/index.cjs +2 -2
  89. package/dist/components/navigation/index.js +1 -1
  90. package/dist/components/navigation/mingo-ai-button.d.ts.map +1 -1
  91. package/dist/components/onboarding-guides/index.cjs +5 -5
  92. package/dist/components/onboarding-guides/index.js +4 -4
  93. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  94. package/dist/components/related-content/index.cjs +3 -3
  95. package/dist/components/related-content/index.js +2 -2
  96. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  97. package/dist/components/tickets/index.cjs +5 -5
  98. package/dist/components/tickets/index.js +4 -4
  99. package/dist/components/ui/index.cjs +2 -44
  100. package/dist/components/ui/index.cjs.map +1 -1
  101. package/dist/components/ui/index.d.ts +2 -1
  102. package/dist/components/ui/index.d.ts.map +1 -1
  103. package/dist/components/ui/index.js +13 -55
  104. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  105. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  106. package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
  107. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
  108. package/dist/index.cjs +2 -60
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.js +13 -71
  111. package/dist/utils/index.cjs +40 -169
  112. package/dist/utils/index.cjs.map +1 -1
  113. package/dist/utils/index.d.ts +0 -1
  114. package/dist/utils/index.d.ts.map +1 -1
  115. package/dist/utils/index.js +41 -162
  116. package/dist/utils/index.js.map +1 -1
  117. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  118. package/package.json +1 -7
  119. package/src/components/chat/__tests__/chat-message-list.test.tsx +6 -381
  120. package/src/components/chat/chat-message-enhanced.tsx +20 -122
  121. package/src/components/chat/chat-message-list.tsx +132 -409
  122. package/src/components/chat/embeddable-chat.tsx +0 -6
  123. package/src/components/chat/hooks/.index.md +33 -30
  124. package/src/components/chat/hooks/.use-nats-chat-adapter.md +55 -36
  125. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +77 -0
  126. package/src/components/chat/hooks/index.ts +1 -0
  127. package/src/components/chat/hooks/use-chat.ts +0 -8
  128. package/src/components/chat/hooks/use-chunk-catchup.ts +1 -26
  129. package/src/components/chat/hooks/use-nats-chat-adapter.ts +825 -254
  130. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +489 -0
  131. package/src/components/chat/hooks/use-sse-chat-adapter.ts +684 -380
  132. package/src/components/chat/index.ts +0 -5
  133. package/src/components/chat/thinking-display.tsx +1 -1
  134. package/src/components/chat/types/.api.types.md +49 -39
  135. package/src/components/chat/types/.processing.types.md +58 -29
  136. package/src/components/chat/types/api.types.ts +73 -6
  137. package/src/components/chat/types/processing.types.ts +53 -11
  138. package/src/components/chat/utils/.chunk-parser.md +62 -0
  139. package/src/components/chat/utils/.index.md +40 -31
  140. package/src/components/chat/utils/__tests__/process-historical-messages-approvals.test.ts +0 -61
  141. package/src/components/chat/utils/chunk-parser.ts +262 -0
  142. package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
  143. package/src/components/chat/utils/index.ts +8 -5
  144. package/src/components/chat/utils/process-historical-messages.ts +386 -358
  145. package/src/components/navigation/header.tsx +2 -1
  146. package/src/components/navigation/mingo-ai-button.tsx +4 -1
  147. package/src/components/navigation/mobile-nav-panel.tsx +5 -5
  148. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
  149. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  150. package/src/components/shared/product-release/release-detail-page.tsx +4 -19
  151. package/src/components/ui/.simple-markdown-renderer.md +52 -0
  152. package/src/components/ui/index.ts +2 -1
  153. package/src/components/ui/release-changelog-section.tsx +1 -1
  154. package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
  155. package/src/components/ui/simple-markdown-renderer.tsx +964 -0
  156. package/src/components/ui/ticket-info-section.tsx +1 -1
  157. package/src/utils/index.ts +0 -1
  158. package/src/utils/markdown-section-extractor.ts +56 -41
  159. package/dist/chat-protocol/decode.d.ts +0 -58
  160. package/dist/chat-protocol/decode.d.ts.map +0 -1
  161. package/dist/chat-protocol/encode.d.ts +0 -44
  162. package/dist/chat-protocol/encode.d.ts.map +0 -1
  163. package/dist/chat-protocol/env-flag.d.ts +0 -35
  164. package/dist/chat-protocol/env-flag.d.ts.map +0 -1
  165. package/dist/chat-protocol/events.d.ts +0 -207
  166. package/dist/chat-protocol/events.d.ts.map +0 -1
  167. package/dist/chat-protocol/frames.d.ts +0 -213
  168. package/dist/chat-protocol/frames.d.ts.map +0 -1
  169. package/dist/chat-protocol/index.cjs +0 -500
  170. package/dist/chat-protocol/index.cjs.map +0 -1
  171. package/dist/chat-protocol/index.d.ts +0 -18
  172. package/dist/chat-protocol/index.d.ts.map +0 -1
  173. package/dist/chat-protocol/index.js +0 -484
  174. package/dist/chat-protocol/index.js.map +0 -1
  175. package/dist/chat-protocol/ip-normalize.d.ts +0 -44
  176. package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
  177. package/dist/chat-protocol/nats-decoder.d.ts +0 -26
  178. package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
  179. package/dist/chunk-5ZY5JM4Z.js.map +0 -1
  180. package/dist/chunk-632XJ2ZT.js.map +0 -1
  181. package/dist/chunk-D3LUKR2Y.js.map +0 -1
  182. package/dist/chunk-EO35UHFT.cjs.map +0 -1
  183. package/dist/chunk-F7XPMG25.cjs.map +0 -1
  184. package/dist/chunk-SS3D3DHL.cjs.map +0 -1
  185. package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
  186. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
  187. package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
  188. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
  189. package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
  190. package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
  191. package/dist/components/chat/stream/index.d.ts +0 -17
  192. package/dist/components/chat/stream/index.d.ts.map +0 -1
  193. package/dist/components/chat/stream/message-mutations.d.ts +0 -77
  194. package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
  195. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
  196. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
  197. package/dist/components/ui/markdown/base-components.d.ts +0 -51
  198. package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
  199. package/dist/components/ui/markdown/engine.d.ts +0 -99
  200. package/dist/components/ui/markdown/engine.d.ts.map +0 -1
  201. package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
  202. package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
  203. package/dist/components/ui/markdown/index.d.ts +0 -18
  204. package/dist/components/ui/markdown/index.d.ts.map +0 -1
  205. package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
  206. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
  207. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
  208. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
  209. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
  210. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
  211. package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
  212. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
  213. package/dist/components/ui/markdown/sanitize.d.ts +0 -153
  214. package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
  215. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
  216. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
  217. package/dist/components/ui/markdown/streaming.d.ts +0 -78
  218. package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
  219. package/dist/components/ui/markdown/text-size.d.ts +0 -34
  220. package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
  221. package/dist/utils/markdown-fences.d.ts +0 -42
  222. package/dist/utils/markdown-fences.d.ts.map +0 -1
  223. package/dist/utils/markdown-heading-id.d.ts +0 -85
  224. package/dist/utils/markdown-heading-id.d.ts.map +0 -1
  225. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -317
  226. package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -516
  227. package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
  228. package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
  229. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -232
  230. package/src/chat-protocol/decode.ts +0 -278
  231. package/src/chat-protocol/encode.ts +0 -71
  232. package/src/chat-protocol/env-flag.ts +0 -39
  233. package/src/chat-protocol/events.ts +0 -245
  234. package/src/chat-protocol/frames.ts +0 -245
  235. package/src/chat-protocol/index.ts +0 -21
  236. package/src/chat-protocol/ip-normalize.ts +0 -146
  237. package/src/chat-protocol/nats-decoder.ts +0 -258
  238. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
  239. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -250
  240. package/src/components/chat/hooks/__tests__/__snapshots__/conversation-id-persistence-golden.test.ts.snap +0 -37
  241. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  242. package/src/components/chat/hooks/__tests__/chunk-catchup-dialog-staleness.test.ts +0 -92
  243. package/src/components/chat/hooks/__tests__/conversation-id-persistence-golden.test.ts +0 -438
  244. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
  245. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -940
  246. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -806
  247. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -467
  248. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -1248
  249. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
  250. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -105
  251. package/src/components/chat/stream/chat-dialog-store.ts +0 -536
  252. package/src/components/chat/stream/chat-stream-reducer.ts +0 -1876
  253. package/src/components/chat/stream/delta-batcher.ts +0 -168
  254. package/src/components/chat/stream/index.ts +0 -55
  255. package/src/components/chat/stream/message-mutations.ts +0 -340
  256. package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
  257. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -420
  258. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -605
  259. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -394
  260. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
  261. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
  262. package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2540
  263. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -176
  264. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -151
  265. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -354
  266. package/src/components/ui/markdown/__tests__/sanitize-render.test.tsx +0 -118
  267. package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -436
  268. package/src/components/ui/markdown/base-components.tsx +0 -360
  269. package/src/components/ui/markdown/engine.tsx +0 -315
  270. package/src/components/ui/markdown/heading-ids.ts +0 -239
  271. package/src/components/ui/markdown/index.ts +0 -49
  272. package/src/components/ui/markdown/mermaid-diagram.tsx +0 -323
  273. package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
  274. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
  275. package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
  276. package/src/components/ui/markdown/sanitize.ts +0 -3584
  277. package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
  278. package/src/components/ui/markdown/streaming.ts +0 -390
  279. package/src/components/ui/markdown/text-size.ts +0 -106
  280. package/src/utils/markdown-fences.ts +0 -127
  281. package/src/utils/markdown-heading-id.ts +0 -348
  282. /package/dist/{chunk-ZHC2BCXK.js.map → chunk-2OPD6KRB.js.map} +0 -0
  283. /package/dist/{chunk-5QWYIPMH.js.map → chunk-5ZL7PA63.js.map} +0 -0
  284. /package/dist/{chunk-3VGRZ62V.js.map → chunk-6GAJETAP.js.map} +0 -0
  285. /package/dist/{chunk-34C2JV2C.js.map → chunk-G6ARA2HD.js.map} +0 -0
  286. /package/dist/{chunk-WNXIG6YY.js.map → chunk-K5HHLTSG.js.map} +0 -0
  287. /package/dist/{chunk-42NYDEHH.js.map → chunk-KK4M4URN.js.map} +0 -0
  288. /package/dist/{chunk-42SMPKGY.js.map → chunk-MF3VJKHT.js.map} +0 -0
  289. /package/dist/{chunk-BUBQEZ5J.js.map → chunk-VLWVM6ZS.js.map} +0 -0
  290. /package/dist/{chunk-WZCQW4MW.js.map → chunk-XSNKSMB3.js.map} +0 -0
@@ -1,467 +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
- // Block bodies, not concise ones: `log.push` returns a number, so a
43
- // concise async arrow is `() => Promise<number>` and does not satisfy the
44
- // declared `(requestId?: string) => void | Promise<void>`.
45
- onApprove: async () => {
46
- log.push({ event: 'onApprove' })
47
- },
48
- onReject: async () => {
49
- log.push({ event: 'onReject' })
50
- },
51
- onEscalatedApproval: (requestId, data) =>
52
- log.push({ event: 'onEscalatedApproval', requestId, data }),
53
- onEscalatedApprovalResult: (requestId, approved, data) =>
54
- log.push({ event: 'onEscalatedApprovalResult', requestId, approved, data }),
55
- onApprovalResolved: (requestId, status, approvalType, resolvedByName) =>
56
- log.push({ event: 'onApprovalResolved', requestId, status, approvalType, resolvedByName }),
57
- onToolExecuted: (segment) => log.push({ event: 'onToolExecuted', segment }),
58
- onAgentBusy: () => log.push({ event: 'onAgentBusy' }),
59
- onDialogClosed: () => log.push({ event: 'onDialogClosed' }),
60
- }
61
- }
62
-
63
- interface SetupOptions {
64
- callbacks?: RealtimeChunkCallbacks
65
- batchApprovalsEnabled?: boolean
66
- displayApprovalTypes?: string[]
67
- approvalStatuses?: Record<string, ChatApprovalStatus>
68
- isDirectMode?: boolean
69
- initialState?: InitializeExtras
70
- }
71
-
72
- function setup(options: SetupOptions = {}) {
73
- const log: EventLog = []
74
- const callbacks = options.callbacks ?? makeRecordingCallbacks(log)
75
-
76
- const reducer: ChatStreamReducer = createChatStreamReducer({
77
- transport: 'nats',
78
- batchApprovalsEnabled: options.batchApprovalsEnabled,
79
- displayApprovalTypes: options.displayApprovalTypes,
80
- approvalStatuses: options.approvalStatuses,
81
- isDirectMode: options.isDirectMode,
82
- crossMessageToolRouting: !!callbacks.onToolExecuted,
83
- callbacks: {
84
- onApprove: (id) => callbacks.onApprove?.(id),
85
- onReject: (id) => callbacks.onReject?.(id),
86
- },
87
- onEffect: ({ name, args }) => {
88
- const cbs = callbacks as Record<string, ((...a: unknown[]) => void) | undefined>
89
- // Legacy conditional: the cumulative post-APPROVAL_RESULT emit fires
90
- // only when the consumer did NOT wire onApprovalResolved.
91
- if (name === 'segments-after-approval-result') {
92
- if (!cbs.onApprovalResolved) cbs.onSegmentsUpdate?.(...args)
93
- return
94
- }
95
- cbs[name]?.(...args)
96
- },
97
- })
98
-
99
- // The wrapper initialized from `initialState` in a mount effect.
100
- if (options.initialState) reducer.initializeWithState(null, options.initialState)
101
-
102
- const feed = (chunks: unknown[]) => {
103
- for (const chunk of chunks) {
104
- const event = decodeNatsChunk(chunk)
105
- if (event) reducer.apply(event)
106
- }
107
- }
108
- return { log, reducer, feed }
109
- }
110
-
111
- const EXECUTING = {
112
- type: 'EXECUTING_TOOL',
113
- integratedToolType: 'TACTICAL_RMM',
114
- toolFunction: 'run_script',
115
- title: 'Run cleanup script',
116
- parameters: { script: 'cleanup.sh' },
117
- toolExecutionRequestId: 'exec-1',
118
- }
119
- const EXECUTED = {
120
- type: 'EXECUTED_TOOL',
121
- integratedToolType: 'TACTICAL_RMM',
122
- toolFunction: 'run_script',
123
- result: 'Freed 2.3 GB',
124
- success: true,
125
- toolExecutionRequestId: 'exec-1',
126
- }
127
-
128
- describe('chat stream reducer — legacy chunk-processor golden event logs', () => {
129
- it('normal turn: start → metadata → text ×3 → token usage → end', () => {
130
- const { log, feed } = setup()
131
- feed([
132
- { type: 'MESSAGE_START' },
133
- {
134
- type: 'AI_METADATA',
135
- modelDisplayName: 'Claude Sonnet',
136
- modelName: 'claude-sonnet-x',
137
- providerName: 'anthropic',
138
- contextWindow: 200000,
139
- },
140
- { type: 'TEXT', text: 'Hello' },
141
- { type: 'TEXT', text: ', ' },
142
- { type: 'TEXT', text: 'world' },
143
- {
144
- type: 'TOKEN_USAGE',
145
- inputTokensSize: 100,
146
- outputTokensSize: 20,
147
- totalTokensSize: 120,
148
- contextSize: 180000,
149
- },
150
- { type: 'MESSAGE_END' },
151
- ])
152
- expect(log).toMatchSnapshot()
153
- })
154
-
155
- it('streamSeq on content chunks is threaded into onSegmentsUpdate metadata', () => {
156
- const { log, feed } = setup()
157
- feed([
158
- { type: 'MESSAGE_START' },
159
- { type: 'TEXT', text: 'seq-stamped', streamSeq: 7 },
160
- { type: 'MESSAGE_END' },
161
- ])
162
- expect(log).toMatchSnapshot()
163
- })
164
-
165
- it('cold start (no MESSAGE_START ever): text emits CUMULATIVE segments (no append flag)', () => {
166
- const { log, feed } = setup()
167
- feed([
168
- { type: 'TEXT', text: 'cold ' },
169
- { type: 'TEXT', text: 'start' },
170
- ])
171
- expect(log).toMatchSnapshot()
172
- })
173
-
174
- it('post-MESSAGE_END continuation: text/thinking emit DELTA segments with append:true', () => {
175
- const { log, feed } = setup()
176
- feed([
177
- { type: 'MESSAGE_START' },
178
- { type: 'TEXT', text: 'in-stream' },
179
- { type: 'MESSAGE_END' },
180
- { type: 'TEXT', text: 'post-end text' },
181
- { type: 'THINKING', text: 'post-end thinking' },
182
- ])
183
- expect(log).toMatchSnapshot()
184
- })
185
-
186
- it('tool execution OUTSIDE a message window: onAgentBusy + cross-message onToolExecuted (accumulator skipped)', () => {
187
- const { log, feed } = setup()
188
- // No MESSAGE_START — approved commands execute between the approval
189
- // bubble's MESSAGE_END and the continuation stream.
190
- feed([EXECUTING, EXECUTED])
191
- expect(log).toMatchSnapshot()
192
- })
193
-
194
- it('tool execution IN-stream: accumulator-driven segment updates, onToolExecuted NOT fired', () => {
195
- const { log, feed } = setup()
196
- feed([
197
- { type: 'MESSAGE_START' },
198
- { type: 'TEXT', text: 'Running now. ' },
199
- EXECUTING,
200
- EXECUTED,
201
- { type: 'MESSAGE_END' },
202
- ])
203
- expect(log).toMatchSnapshot()
204
- })
205
-
206
- it('approval request (displayed) → approval result: in-message flip + onApprovalResolved', () => {
207
- const { log, feed } = setup()
208
- feed([
209
- { type: 'MESSAGE_START' },
210
- {
211
- type: 'APPROVAL_REQUEST',
212
- approvalRequestId: 'req-1',
213
- approvalType: 'CLIENT',
214
- command: 'systemctl restart nats',
215
- explanation: 'Restart the broker',
216
- },
217
- { type: 'MESSAGE_END' },
218
- {
219
- type: 'APPROVAL_RESULT',
220
- approvalRequestId: 'req-1',
221
- approved: true,
222
- approvalType: 'CLIENT',
223
- displayName: 'Jane Admin',
224
- },
225
- ])
226
- // CHARACTERIZATION: because onApprovalResolved IS wired, the result
227
- // does NOT emit onSegmentsUpdate — only the cross-message callback.
228
- expect(log).toMatchSnapshot()
229
- })
230
-
231
- it('approval result WITHOUT onApprovalResolved wired: emits cumulative onSegmentsUpdate instead', () => {
232
- const log: EventLog = []
233
- const callbacks = makeRecordingCallbacks(log)
234
- delete callbacks.onApprovalResolved
235
- const { feed } = setup({ callbacks })
236
- feed([
237
- { type: 'MESSAGE_START' },
238
- {
239
- type: 'APPROVAL_REQUEST',
240
- approvalRequestId: 'req-1',
241
- approvalType: 'CLIENT',
242
- command: 'reboot',
243
- },
244
- {
245
- type: 'APPROVAL_RESULT',
246
- approvalRequestId: 'req-1',
247
- approved: false,
248
- approvalType: 'CLIENT',
249
- },
250
- ])
251
- expect(log).toMatchSnapshot()
252
- })
253
-
254
- it('escalated approval (type not displayed) → onEscalatedApproval, then result appends resolved card', () => {
255
- const { log, feed, reducer } = setup() // displayApprovalTypes defaults to ['CLIENT']
256
- feed([
257
- { type: 'MESSAGE_START' },
258
- {
259
- type: 'APPROVAL_REQUEST',
260
- approvalRequestId: 'req-adm',
261
- approvalType: 'ADMIN',
262
- command: 'drop database prod',
263
- },
264
- { type: 'MESSAGE_END' },
265
- {
266
- type: 'APPROVAL_RESULT',
267
- approvalRequestId: 'req-adm',
268
- approved: true,
269
- approvalType: 'ADMIN',
270
- },
271
- ])
272
- expect({
273
- log,
274
- pendingAfter: Array.from(reducer.getPendingEscalated().entries()),
275
- }).toMatchSnapshot()
276
- })
277
-
278
- it('batch approval (batchApprovalsEnabled default ON): one batch segment, executions merge into it', () => {
279
- const { log, feed } = setup()
280
- feed([
281
- { type: 'MESSAGE_START' },
282
- {
283
- type: 'APPROVAL_REQUEST',
284
- approvalRequestId: 'batch-1',
285
- approvalType: 'CLIENT',
286
- toolCalls: [
287
- {
288
- toolExecutionRequestId: 'exec-a',
289
- toolName: 'create_ticket',
290
- toolTitle: 'Create ticket',
291
- requiresApproval: true,
292
- approvalType: 'CLIENT',
293
- toolCallArguments: { subject: 'Printer down' },
294
- },
295
- {
296
- toolExecutionRequestId: 'exec-b',
297
- toolName: 'read_kb',
298
- requiresApproval: false,
299
- },
300
- ],
301
- },
302
- {
303
- type: 'APPROVAL_RESULT',
304
- approvalRequestId: 'batch-1',
305
- approved: true,
306
- displayName: 'Alice Client',
307
- },
308
- {
309
- type: 'EXECUTING_TOOL',
310
- integratedToolType: 'PSA',
311
- toolFunction: 'create_ticket',
312
- toolExecutionRequestId: 'exec-a',
313
- },
314
- {
315
- type: 'EXECUTED_TOOL',
316
- integratedToolType: 'PSA',
317
- toolFunction: 'create_ticket',
318
- result: 'Ticket #77 created',
319
- success: true,
320
- toolExecutionRequestId: 'exec-a',
321
- },
322
- { type: 'MESSAGE_END' },
323
- ])
324
- expect(log).toMatchSnapshot()
325
- })
326
-
327
- it('batch approval with batchApprovalsEnabled:false unfolds into legacy cards (requiresApproval only)', () => {
328
- const { log, feed } = setup({ batchApprovalsEnabled: false })
329
- feed([
330
- { type: 'MESSAGE_START' },
331
- {
332
- type: 'APPROVAL_REQUEST',
333
- approvalRequestId: 'batch-1',
334
- approvalType: 'CLIENT',
335
- toolCalls: [
336
- {
337
- toolExecutionRequestId: 'exec-a',
338
- toolName: 'create_ticket',
339
- toolTitle: 'Create ticket',
340
- requiresApproval: true,
341
- toolCallArguments: { subject: 'Printer down' },
342
- },
343
- {
344
- toolExecutionRequestId: 'exec-b',
345
- toolName: 'read_kb',
346
- requiresApproval: false,
347
- },
348
- ],
349
- },
350
- { type: 'MESSAGE_END' },
351
- ])
352
- expect(log).toMatchSnapshot()
353
- })
354
-
355
- it('CHARACTERIZATION duplicate/out-of-order: redelivered EXECUTING after EXECUTED in-stream appends a NEW executing segment (no dedup)', () => {
356
- // The reducer does no duplicate suppression for standalone tool
357
- // segments — dedup only exists inside approval batches (no-downgrade
358
- // rule). Recording actual behavior, see unification plan.
359
- const { log, feed } = setup()
360
- feed([
361
- { type: 'MESSAGE_START' },
362
- EXECUTING,
363
- EXECUTED,
364
- EXECUTING, // redelivered
365
- { type: 'MESSAGE_END' },
366
- ])
367
- expect(log).toMatchSnapshot()
368
- })
369
-
370
- it('error chunk: segment append + onError with JSON-extracted message', () => {
371
- const { log, feed } = setup()
372
- feed([
373
- { type: 'MESSAGE_START' },
374
- { type: 'TEXT', text: 'partial' },
375
- { type: 'ERROR', error: 'Agent crashed', details: '{"error":{"message":"boom"}}' },
376
- { type: 'ERROR', error: 'Plain details', details: 'not-json' },
377
- ])
378
- expect(log).toMatchSnapshot()
379
- })
380
-
381
- it('user echo / system / direct-message / dialog-closed routing', () => {
382
- const { log, feed } = setup()
383
- feed([
384
- {
385
- type: 'MESSAGE_REQUEST',
386
- text: 'open a ticket',
387
- ownerType: 'CLIENT',
388
- displayName: 'Alice',
389
- userId: 'user-42',
390
- streamSeq: 3,
391
- contextItems: [{ type: 'device', id: 'dev-1' }],
392
- },
393
- { type: 'SYSTEM', text: 'User joined the chat', streamSeq: 4 },
394
- {
395
- type: 'DIRECT_MESSAGE',
396
- text: 'Human here now',
397
- ownerType: 'ADMIN',
398
- displayName: 'Jane Admin',
399
- userId: 'admin-7',
400
- streamSeq: 5,
401
- },
402
- { type: 'DIALOG_CLOSED' },
403
- ])
404
- expect(log).toMatchSnapshot()
405
- })
406
-
407
- it('direct-mode barrier: after a DIRECT_MESSAGE, AI chunks are dropped with a one-shot teardown', () => {
408
- const { log, feed } = setup()
409
- feed([
410
- { type: 'MESSAGE_START' },
411
- { type: 'TEXT', text: 'ai text before takeover' },
412
- { type: 'DIRECT_MESSAGE', text: 'Human takeover', ownerType: 'ADMIN' },
413
- // AI chunks now dropped; first one triggers the teardown (onStreamEnd).
414
- { type: 'TEXT', text: 'dropped ai text' },
415
- { type: 'TEXT', text: 'also dropped' },
416
- // Allowlisted chunks still flow.
417
- { type: 'SYSTEM', text: 'still visible' },
418
- { type: 'DIRECT_MESSAGE', text: 'second human message' },
419
- ])
420
- expect(log).toMatchSnapshot()
421
- })
422
-
423
- it('context compaction outside a stream emits append+isCompacting metadata; inside a stream it is cumulative', () => {
424
- const { log, feed } = setup()
425
- feed([
426
- // standalone (no open stream)
427
- { type: 'CONTEXT_COMPACTION_START' },
428
- { type: 'CONTEXT_COMPACTION_END', text: 'Summarized 12 messages' },
429
- ])
430
- const standaloneLog = [...log]
431
- log.length = 0
432
- feed([
433
- { type: 'MESSAGE_START' },
434
- { type: 'CONTEXT_COMPACTION_START' },
435
- { type: 'CONTEXT_COMPACTION_END', text: 'Mid-stream summary' },
436
- { type: 'MESSAGE_END' },
437
- ])
438
- expect({ standalone: standaloneLog, inStream: log }).toMatchSnapshot()
439
- })
440
-
441
- it('reset() clears accumulator + stream flags so the next dialog cold-starts cumulative', () => {
442
- const { log, feed, reducer } = setup()
443
- feed([
444
- { type: 'MESSAGE_START' },
445
- { type: 'TEXT', text: 'dialog one' },
446
- { type: 'MESSAGE_END' },
447
- ])
448
- reducer.reset()
449
- log.length = 0
450
- feed([{ type: 'TEXT', text: 'dialog two cold start' }])
451
- expect(log).toMatchSnapshot()
452
- })
453
-
454
- it('initialState resume: continuation chunks after resume take the post-stream append path', () => {
455
- const { log } = setup({
456
- initialState: {
457
- existingSegments: [{ type: 'text', text: 'restored partial ' }],
458
- escalatedApprovals: new Map([
459
- ['req-esc', { command: 'escalated cmd', approvalType: 'ADMIN' }],
460
- ]),
461
- },
462
- })
463
- // initializeWithState replays escalated approvals via onEscalatedApproval
464
- // and marks hasEverStreamed=true.
465
- expect(log).toMatchSnapshot()
466
- })
467
- })