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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/dist/chat-protocol/decode.d.ts +58 -0
  2. package/dist/chat-protocol/decode.d.ts.map +1 -0
  3. package/dist/chat-protocol/encode.d.ts +44 -0
  4. package/dist/chat-protocol/encode.d.ts.map +1 -0
  5. package/dist/chat-protocol/env-flag.d.ts +35 -0
  6. package/dist/chat-protocol/env-flag.d.ts.map +1 -0
  7. package/dist/chat-protocol/events.d.ts +196 -0
  8. package/dist/chat-protocol/events.d.ts.map +1 -0
  9. package/dist/chat-protocol/frames.d.ts +213 -0
  10. package/dist/chat-protocol/frames.d.ts.map +1 -0
  11. package/dist/chat-protocol/index.cjs +494 -0
  12. package/dist/chat-protocol/index.cjs.map +1 -0
  13. package/dist/chat-protocol/index.d.ts +18 -0
  14. package/dist/chat-protocol/index.d.ts.map +1 -0
  15. package/dist/chat-protocol/index.js +478 -0
  16. package/dist/chat-protocol/index.js.map +1 -0
  17. package/dist/chat-protocol/ip-normalize.d.ts +44 -0
  18. package/dist/chat-protocol/ip-normalize.d.ts.map +1 -0
  19. package/dist/chat-protocol/nats-decoder.d.ts +26 -0
  20. package/dist/chat-protocol/nats-decoder.d.ts.map +1 -0
  21. package/dist/{chunk-AJNDDXKC.js → chunk-4NWARV5I.js} +3 -3
  22. package/dist/{chunk-GQX6LFFA.cjs → chunk-5CJR2GZ4.cjs} +42 -42
  23. package/dist/{chunk-GQX6LFFA.cjs.map → chunk-5CJR2GZ4.cjs.map} +1 -1
  24. package/dist/{chunk-EUYIFALO.cjs → chunk-5EYRXSY5.cjs} +14 -14
  25. package/dist/{chunk-EUYIFALO.cjs.map → chunk-5EYRXSY5.cjs.map} +1 -1
  26. package/dist/{chunk-5RXKOGH6.cjs → chunk-5LMGFI4J.cjs} +7011 -4777
  27. package/dist/chunk-5LMGFI4J.cjs.map +1 -0
  28. package/dist/{chunk-KFQXO7QB.js → chunk-6GT557KN.js} +1 -1
  29. package/dist/chunk-6GT557KN.js.map +1 -0
  30. package/dist/{chunk-77DFPD35.js → chunk-BE6DK7QY.js} +12267 -10033
  31. package/dist/chunk-BE6DK7QY.js.map +1 -0
  32. package/dist/{chunk-A7IPON2V.cjs → chunk-BIKOJ4FH.cjs} +5 -5
  33. package/dist/{chunk-A7IPON2V.cjs.map → chunk-BIKOJ4FH.cjs.map} +1 -1
  34. package/dist/{chunk-HQYJINFV.js → chunk-CORIBKHG.js} +4 -4
  35. package/dist/{chunk-YEEHB4T6.cjs → chunk-CSYSYJCF.cjs} +40 -40
  36. package/dist/{chunk-YEEHB4T6.cjs.map → chunk-CSYSYJCF.cjs.map} +1 -1
  37. package/dist/{chunk-SIKCXKGB.cjs → chunk-DSDZ5T4P.cjs} +7 -7
  38. package/dist/{chunk-SIKCXKGB.cjs.map → chunk-DSDZ5T4P.cjs.map} +1 -1
  39. package/dist/{chunk-PNXNWGBY.js → chunk-GTWO5NAY.js} +2 -2
  40. package/dist/{chunk-SCCTJ2UI.js → chunk-HSACATCD.js} +4 -4
  41. package/dist/{chunk-PECGZWQR.cjs → chunk-KP5KRRD6.cjs} +3 -3
  42. package/dist/{chunk-PECGZWQR.cjs.map → chunk-KP5KRRD6.cjs.map} +1 -1
  43. package/dist/{chunk-2B6773QM.cjs → chunk-LILQJ3UZ.cjs} +1 -1
  44. package/dist/chunk-LILQJ3UZ.cjs.map +1 -0
  45. package/dist/{chunk-RZSA6MZL.cjs → chunk-NWX7MMF5.cjs} +15 -15
  46. package/dist/{chunk-RZSA6MZL.cjs.map → chunk-NWX7MMF5.cjs.map} +1 -1
  47. package/dist/{chunk-V3CNNMY3.cjs → chunk-P4WTZU6L.cjs} +18 -18
  48. package/dist/{chunk-V3CNNMY3.cjs.map → chunk-P4WTZU6L.cjs.map} +1 -1
  49. package/dist/{chunk-KLYHZRAD.js → chunk-PB3BTZDU.js} +2 -2
  50. package/dist/{chunk-FZOBQG6M.cjs → chunk-Q6E7VJ4W.cjs} +37 -36
  51. package/dist/chunk-Q6E7VJ4W.cjs.map +1 -0
  52. package/dist/{chunk-EYEIVYYF.cjs → chunk-QSCHCZL3.cjs} +7 -7
  53. package/dist/{chunk-EYEIVYYF.cjs.map → chunk-QSCHCZL3.cjs.map} +1 -1
  54. package/dist/{chunk-YJSKQ2ZV.js → chunk-RQLBHKXN.js} +3 -3
  55. package/dist/{chunk-CWQACI4Z.js → chunk-RW2LPL72.js} +2 -2
  56. package/dist/{chunk-DX6AOHNU.cjs → chunk-S2NHJDKQ.cjs} +77 -77
  57. package/dist/{chunk-DX6AOHNU.cjs.map → chunk-S2NHJDKQ.cjs.map} +1 -1
  58. package/dist/{chunk-AHDJMEEN.js → chunk-T2EGSZFN.js} +9 -8
  59. package/dist/chunk-T2EGSZFN.js.map +1 -0
  60. package/dist/{chunk-S52LJNMU.js → chunk-TKN5667N.js} +13 -13
  61. package/dist/chunk-TKN5667N.js.map +1 -0
  62. package/dist/{chunk-3BFX6HJM.js → chunk-UUYRJPGJ.js} +6 -6
  63. package/dist/{chunk-F6BYUO5U.js → chunk-VHG6AX5V.js} +3 -3
  64. package/dist/{chunk-FOQV6RCO.cjs → chunk-VQ523ORK.cjs} +29 -29
  65. package/dist/{chunk-FOQV6RCO.cjs.map → chunk-VQ523ORK.cjs.map} +1 -1
  66. package/dist/{chunk-PXF5J24T.js → chunk-XQ2B74SI.js} +2 -2
  67. package/dist/{chunk-H7JX2BG7.cjs → chunk-YHOIAA2E.cjs} +76 -76
  68. package/dist/chunk-YHOIAA2E.cjs.map +1 -0
  69. package/dist/{chunk-LLWBPPZ4.js → chunk-YZ2OIYQ3.js} +6 -6
  70. package/dist/components/case-studies/index.cjs +10 -10
  71. package/dist/components/case-studies/index.js +4 -4
  72. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  73. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  74. package/dist/components/chat/hooks/index.d.ts +0 -1
  75. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  76. package/dist/components/chat/hooks/use-chat-history-hydration.d.ts +47 -0
  77. package/dist/components/chat/hooks/use-chat-history-hydration.d.ts.map +1 -0
  78. package/dist/components/chat/hooks/use-chat.d.ts +1 -0
  79. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  80. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +15 -48
  81. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  82. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +10 -53
  83. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  84. package/dist/components/chat/index.cjs +12 -4
  85. package/dist/components/chat/index.cjs.map +1 -1
  86. package/dist/components/chat/index.d.ts +1 -0
  87. package/dist/components/chat/index.d.ts.map +1 -1
  88. package/dist/components/chat/index.js +23 -15
  89. package/dist/components/chat/stream/chat-dialog-store.d.ts +184 -0
  90. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +1 -0
  91. package/dist/components/chat/stream/chat-stream-reducer.d.ts +367 -0
  92. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -0
  93. package/dist/components/chat/stream/delta-batcher.d.ts +51 -0
  94. package/dist/components/chat/stream/delta-batcher.d.ts.map +1 -0
  95. package/dist/components/chat/stream/index.d.ts +17 -0
  96. package/dist/components/chat/stream/index.d.ts.map +1 -0
  97. package/dist/components/chat/stream/message-mutations.d.ts +77 -0
  98. package/dist/components/chat/stream/message-mutations.d.ts.map +1 -0
  99. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +22 -0
  100. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +1 -0
  101. package/dist/components/chat/types/api.types.d.ts +1 -81
  102. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  103. package/dist/components/chat/types/processing.types.d.ts +2 -90
  104. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  105. package/dist/components/chat/types/unified-chat-state.types.d.ts +5 -0
  106. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
  107. package/dist/components/chat/utils/chat-conversation-storage.d.ts +34 -0
  108. package/dist/components/chat/utils/chat-conversation-storage.d.ts.map +1 -0
  109. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +34 -6
  110. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  111. package/dist/components/chat/utils/index.d.ts +2 -3
  112. package/dist/components/chat/utils/index.d.ts.map +1 -1
  113. package/dist/components/chat/utils/process-historical-messages.d.ts +59 -11
  114. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  115. package/dist/components/contact/index.cjs +5 -5
  116. package/dist/components/contact/index.js +4 -4
  117. package/dist/components/docs/index.cjs +7 -7
  118. package/dist/components/docs/index.js +6 -6
  119. package/dist/components/embeds/index.cjs +5 -5
  120. package/dist/components/embeds/index.js +4 -4
  121. package/dist/components/faq/index.cjs +6 -6
  122. package/dist/components/faq/index.js +5 -5
  123. package/dist/components/features/index.cjs +4 -4
  124. package/dist/components/features/index.js +3 -3
  125. package/dist/components/help-center-pages/index.cjs +23 -23
  126. package/dist/components/help-center-pages/index.js +14 -14
  127. package/dist/components/index.cjs +182 -140
  128. package/dist/components/index.cjs.map +1 -1
  129. package/dist/components/index.js +66 -24
  130. package/dist/components/index.js.map +1 -1
  131. package/dist/components/navigation/index.cjs +4 -4
  132. package/dist/components/navigation/index.js +3 -3
  133. package/dist/components/onboarding-guides/index.cjs +8 -8
  134. package/dist/components/onboarding-guides/index.js +7 -7
  135. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  136. package/dist/components/related-content/index.cjs +6 -6
  137. package/dist/components/related-content/index.js +5 -5
  138. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  139. package/dist/components/tickets/index.cjs +7 -7
  140. package/dist/components/tickets/index.js +6 -6
  141. package/dist/components/ui/index.cjs +46 -4
  142. package/dist/components/ui/index.cjs.map +1 -1
  143. package/dist/components/ui/index.d.ts +1 -2
  144. package/dist/components/ui/index.d.ts.map +1 -1
  145. package/dist/components/ui/index.js +57 -15
  146. package/dist/components/ui/markdown/base-components.d.ts +51 -0
  147. package/dist/components/ui/markdown/base-components.d.ts.map +1 -0
  148. package/dist/components/ui/markdown/engine.d.ts +99 -0
  149. package/dist/components/ui/markdown/engine.d.ts.map +1 -0
  150. package/dist/components/ui/markdown/heading-ids.d.ts +65 -0
  151. package/dist/components/ui/markdown/heading-ids.d.ts.map +1 -0
  152. package/dist/components/ui/markdown/index.d.ts +18 -0
  153. package/dist/components/ui/markdown/index.d.ts.map +1 -0
  154. package/dist/components/ui/markdown/mermaid-diagram.d.ts +79 -0
  155. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +1 -0
  156. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +14 -0
  157. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +1 -0
  158. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +40 -0
  159. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +1 -0
  160. package/dist/components/ui/markdown/rich/shortcodes.d.ts +8 -0
  161. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +1 -0
  162. package/dist/components/ui/markdown/sanitize.d.ts +153 -0
  163. package/dist/components/ui/markdown/sanitize.d.ts.map +1 -0
  164. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +23 -0
  165. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +1 -0
  166. package/dist/components/ui/markdown/streaming.d.ts +78 -0
  167. package/dist/components/ui/markdown/streaming.d.ts.map +1 -0
  168. package/dist/components/ui/markdown/text-size.d.ts +34 -0
  169. package/dist/components/ui/markdown/text-size.d.ts.map +1 -0
  170. package/dist/contexts/chat-runtime-context.d.ts +8 -0
  171. package/dist/contexts/chat-runtime-context.d.ts.map +1 -1
  172. package/dist/contexts/index.cjs +2 -2
  173. package/dist/contexts/index.js +1 -1
  174. package/dist/hooks/index.cjs +3 -3
  175. package/dist/hooks/index.js +2 -2
  176. package/dist/index.cjs +62 -4
  177. package/dist/index.cjs.map +1 -1
  178. package/dist/index.js +73 -15
  179. package/dist/utils/index.cjs +169 -40
  180. package/dist/utils/index.cjs.map +1 -1
  181. package/dist/utils/index.d.ts +1 -0
  182. package/dist/utils/index.d.ts.map +1 -1
  183. package/dist/utils/index.js +162 -41
  184. package/dist/utils/index.js.map +1 -1
  185. package/dist/utils/markdown-fences.d.ts +42 -0
  186. package/dist/utils/markdown-fences.d.ts.map +1 -0
  187. package/dist/utils/markdown-heading-id.d.ts +85 -0
  188. package/dist/utils/markdown-heading-id.d.ts.map +1 -0
  189. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  190. package/package.json +7 -1
  191. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +307 -0
  192. package/src/chat-protocol/__tests__/chat-protocol.test.ts +516 -0
  193. package/src/chat-protocol/__tests__/env-flag.test.ts +52 -0
  194. package/src/chat-protocol/__tests__/ip-normalize.test.ts +136 -0
  195. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +228 -0
  196. package/src/chat-protocol/decode.ts +278 -0
  197. package/src/chat-protocol/encode.ts +71 -0
  198. package/src/chat-protocol/env-flag.ts +39 -0
  199. package/src/chat-protocol/events.ts +232 -0
  200. package/src/chat-protocol/frames.ts +245 -0
  201. package/src/chat-protocol/index.ts +21 -0
  202. package/src/chat-protocol/ip-normalize.ts +146 -0
  203. package/src/chat-protocol/nats-decoder.ts +252 -0
  204. package/src/components/chat/__tests__/chat-message-list.test.tsx +293 -5
  205. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +207 -0
  206. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +209 -0
  207. package/src/components/chat/chat-message-enhanced.tsx +111 -17
  208. package/src/components/chat/chat-message-list.tsx +358 -109
  209. package/src/components/chat/embeddable-chat.tsx +6 -0
  210. package/src/components/chat/hooks/.index.md +30 -33
  211. package/src/components/chat/hooks/.use-nats-chat-adapter.md +36 -55
  212. package/src/components/chat/hooks/__tests__/__snapshots__/conversation-id-persistence-golden.test.ts.snap +37 -0
  213. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  214. package/src/components/chat/hooks/__tests__/conversation-id-persistence-golden.test.ts +438 -0
  215. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +318 -0
  216. package/src/components/chat/hooks/index.ts +0 -1
  217. package/src/components/chat/hooks/use-chat-history-hydration.ts +142 -0
  218. package/src/components/chat/hooks/use-chat.ts +20 -0
  219. package/src/components/chat/hooks/use-nats-chat-adapter.ts +243 -823
  220. package/src/components/chat/hooks/use-sse-chat-adapter.ts +417 -774
  221. package/src/components/chat/index.ts +5 -0
  222. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +940 -0
  223. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +756 -0
  224. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +460 -0
  225. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +894 -0
  226. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +255 -0
  227. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +98 -0
  228. package/src/components/chat/stream/chat-dialog-store.ts +536 -0
  229. package/src/components/chat/stream/chat-stream-reducer.ts +1796 -0
  230. package/src/components/chat/stream/delta-batcher.ts +159 -0
  231. package/src/components/chat/stream/index.ts +55 -0
  232. package/src/components/chat/stream/message-mutations.ts +338 -0
  233. package/src/components/chat/stream/use-chat-stream-reducer.ts +126 -0
  234. package/src/components/chat/thinking-display.tsx +1 -1
  235. package/src/components/chat/types/.api.types.md +39 -49
  236. package/src/components/chat/types/.processing.types.md +29 -58
  237. package/src/components/chat/types/api.types.ts +6 -73
  238. package/src/components/chat/types/processing.types.ts +11 -52
  239. package/src/components/chat/types/unified-chat-state.types.ts +6 -0
  240. package/src/components/chat/utils/.index.md +31 -40
  241. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +420 -0
  242. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +605 -0
  243. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +317 -0
  244. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +270 -0
  245. package/src/components/chat/utils/chat-conversation-storage.ts +83 -0
  246. package/src/components/chat/utils/extract-incomplete-message-state.ts +63 -5
  247. package/src/components/chat/utils/index.ts +5 -8
  248. package/src/components/chat/utils/process-historical-messages.ts +352 -384
  249. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +22 -4
  250. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  251. package/src/components/shared/product-release/release-detail-page.tsx +19 -4
  252. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +2420 -0
  253. package/src/components/ui/__tests__/markdown-parity.test.tsx +2528 -0
  254. package/src/components/ui/index.ts +1 -2
  255. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +115 -0
  256. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +95 -0
  257. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +309 -0
  258. package/src/components/ui/markdown/__tests__/streaming.test.tsx +388 -0
  259. package/src/components/ui/markdown/base-components.tsx +360 -0
  260. package/src/components/ui/markdown/engine.tsx +315 -0
  261. package/src/components/ui/markdown/heading-ids.ts +239 -0
  262. package/src/components/ui/markdown/index.ts +49 -0
  263. package/src/components/ui/markdown/mermaid-diagram.tsx +291 -0
  264. package/src/components/ui/markdown/rich/embed-overrides.tsx +199 -0
  265. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +184 -0
  266. package/src/components/ui/markdown/rich/shortcodes.ts +170 -0
  267. package/src/components/ui/markdown/sanitize.ts +3499 -0
  268. package/src/components/ui/markdown/simple-markdown-renderer.tsx +28 -0
  269. package/src/components/ui/markdown/streaming.ts +362 -0
  270. package/src/components/ui/markdown/text-size.ts +106 -0
  271. package/src/components/ui/release-changelog-section.tsx +1 -1
  272. package/src/components/ui/ticket-info-section.tsx +1 -1
  273. package/src/contexts/chat-runtime-context.tsx +8 -0
  274. package/src/utils/index.ts +1 -0
  275. package/src/utils/markdown-fences.ts +127 -0
  276. package/src/utils/markdown-heading-id.ts +348 -0
  277. package/src/utils/markdown-section-extractor.ts +41 -56
  278. package/dist/chunk-2B6773QM.cjs.map +0 -1
  279. package/dist/chunk-5RXKOGH6.cjs.map +0 -1
  280. package/dist/chunk-77DFPD35.js.map +0 -1
  281. package/dist/chunk-AHDJMEEN.js.map +0 -1
  282. package/dist/chunk-FZOBQG6M.cjs.map +0 -1
  283. package/dist/chunk-H7JX2BG7.cjs.map +0 -1
  284. package/dist/chunk-KFQXO7QB.js.map +0 -1
  285. package/dist/chunk-S52LJNMU.js.map +0 -1
  286. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +0 -6
  287. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +0 -1
  288. package/dist/components/chat/utils/chunk-parser.d.ts +0 -25
  289. package/dist/components/chat/utils/chunk-parser.d.ts.map +0 -1
  290. package/dist/components/ui/rich-markdown-renderer.d.ts +0 -34
  291. package/dist/components/ui/rich-markdown-renderer.d.ts.map +0 -1
  292. package/dist/components/ui/simple-markdown-renderer.d.ts +0 -73
  293. package/dist/components/ui/simple-markdown-renderer.d.ts.map +0 -1
  294. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +0 -77
  295. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +0 -479
  296. package/src/components/chat/utils/.chunk-parser.md +0 -62
  297. package/src/components/chat/utils/chunk-parser.ts +0 -256
  298. package/src/components/ui/.simple-markdown-renderer.md +0 -52
  299. package/src/components/ui/rich-markdown-renderer.tsx +0 -1223
  300. package/src/components/ui/simple-markdown-renderer.tsx +0 -964
  301. /package/dist/{chunk-AJNDDXKC.js.map → chunk-4NWARV5I.js.map} +0 -0
  302. /package/dist/{chunk-HQYJINFV.js.map → chunk-CORIBKHG.js.map} +0 -0
  303. /package/dist/{chunk-PNXNWGBY.js.map → chunk-GTWO5NAY.js.map} +0 -0
  304. /package/dist/{chunk-SCCTJ2UI.js.map → chunk-HSACATCD.js.map} +0 -0
  305. /package/dist/{chunk-KLYHZRAD.js.map → chunk-PB3BTZDU.js.map} +0 -0
  306. /package/dist/{chunk-YJSKQ2ZV.js.map → chunk-RQLBHKXN.js.map} +0 -0
  307. /package/dist/{chunk-CWQACI4Z.js.map → chunk-RW2LPL72.js.map} +0 -0
  308. /package/dist/{chunk-3BFX6HJM.js.map → chunk-UUYRJPGJ.js.map} +0 -0
  309. /package/dist/{chunk-F6BYUO5U.js.map → chunk-VHG6AX5V.js.map} +0 -0
  310. /package/dist/{chunk-PXF5J24T.js.map → chunk-XQ2B74SI.js.map} +0 -0
  311. /package/dist/{chunk-LLWBPPZ4.js.map → chunk-YZ2OIYQ3.js.map} +0 -0
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Pending-turn + hidden-row contracts.
3
+ *
4
+ * Two reader-visible defects this pins against:
5
+ *
6
+ * 1. Approving a tool call minted an author-label row with NO body
7
+ * ("Michael Assraf:" then nothing). The approval decision is
8
+ * out-of-band metadata, so the reducer must not materialize a user
9
+ * row for it at all — fixing it at render would leave dead state.
10
+ * 2. While the model was thinking, the transcript showed a second,
11
+ * empty "Mingo:" row ABOVE the footer progress indicator — two
12
+ * owners for one pending turn, and an `aria-live` log announcing a
13
+ * bare "Mingo". Exactly one affordance must be present.
14
+ *
15
+ * Plus the two idioms that must SURVIVE both fixes: a hidden row that
16
+ * carries real text (auto-continuation directive) stays in state while
17
+ * never rendering, and the SYSTEM name-only row still renders.
18
+ */
19
+
20
+ import { render } from '@testing-library/react'
21
+ import { describe, expect, it, vi } from 'vitest'
22
+ import { createChatStreamReducer } from '../stream/chat-stream-reducer'
23
+ import {
24
+ AUTO_CONTINUATION_DIRECTIVE_PREFIX,
25
+ buildAutoContinuationDirective,
26
+ } from '../utils/auto-continuation-directive'
27
+ import type { Message } from '../types/message.types'
28
+
29
+ // ─── Render harness (mirrors chat-message-list.test.tsx) ────────────────────
30
+
31
+ const scrollToBottom = vi.fn()
32
+ const stopScroll = vi.fn()
33
+
34
+ function makeRef() {
35
+ const fn = ((el: HTMLElement | null) => {
36
+ ;(fn as { current: HTMLElement | null }).current = el
37
+ }) as ((el: HTMLElement | null) => void) & { current: HTMLElement | null }
38
+ fn.current = null
39
+ return fn
40
+ }
41
+
42
+ vi.mock('use-stick-to-bottom', () => ({
43
+ useStickToBottom: () => ({
44
+ scrollRef: makeRef(),
45
+ contentRef: makeRef(),
46
+ scrollToBottom,
47
+ stopScroll,
48
+ }),
49
+ }))
50
+
51
+ // Row stub that renders the author label the way the real component does
52
+ // (`Name:`), so "labeled row with no body" is directly assertable.
53
+ vi.mock('../chat-message-enhanced', () => ({
54
+ ChatMessageEnhanced: ({ name, content }: { name?: string; content: unknown }) => (
55
+ <div data-testid="row">
56
+ <span data-testid="row-name">{name ?? ''}</span>
57
+ <span data-testid="row-body">
58
+ {typeof content === 'string'
59
+ ? content
60
+ : Array.isArray(content)
61
+ ? content
62
+ .map((s) => (s && (s as { type?: string }).type === 'text' ? (s as { text: string }).text : '[seg]'))
63
+ .join('')
64
+ : ''}
65
+ </span>
66
+ </div>
67
+ ),
68
+ }))
69
+
70
+ import { ChatMessageList } from '../chat-message-list'
71
+
72
+ class ObserverStub {
73
+ observe() {}
74
+ unobserve() {}
75
+ disconnect() {}
76
+ }
77
+ vi.stubGlobal('IntersectionObserver', ObserverStub)
78
+ vi.stubGlobal('ResizeObserver', ObserverStub)
79
+
80
+ const names = (c: HTMLElement) =>
81
+ Array.from(c.querySelectorAll('[data-testid="row-name"]')).map((n) => n.textContent)
82
+ const bodies = (c: HTMLElement) =>
83
+ Array.from(c.querySelectorAll('[data-testid="row-body"]')).map((n) => n.textContent)
84
+
85
+ // ─── State-level contracts ─────────────────────────────────────────────────
86
+
87
+ describe('approval sends mint no visible user row', () => {
88
+ it('beginSseSend with empty text pushes only the assistant placeholder', () => {
89
+ const r = createChatStreamReducer({ transport: 'sse' })
90
+ // What `cardApprove` triggers: ('', { hidden: true, approvalAction }).
91
+ r.beginSseSend({ text: '', hidden: true, assistantName: 'Mingo AI' })
92
+
93
+ expect(r.state.messages).toHaveLength(1)
94
+ expect(r.state.messages[0].role).toBe('assistant')
95
+ expect(r.state.messages.some((m) => m.role === 'user')).toBe(false)
96
+ expect(r.state.streamingPhase).toBe('thinking')
97
+ })
98
+
99
+ it('pushOptimisticSend with empty text likewise mints no user row', () => {
100
+ const r = createChatStreamReducer({ transport: 'nats' })
101
+ r.pushOptimisticSend('', true)
102
+
103
+ expect(r.state.messages).toHaveLength(1)
104
+ expect(r.state.messages[0].role).toBe('assistant')
105
+ })
106
+
107
+ it('a normal send still mints the user row', () => {
108
+ const r = createChatStreamReducer({ transport: 'sse' })
109
+ r.beginSseSend({ text: 'hello', assistantName: 'Mingo AI' })
110
+
111
+ expect(r.state.messages).toHaveLength(2)
112
+ expect(r.state.messages[0]).toMatchObject({ role: 'user', content: 'hello' })
113
+ expect(r.state.messages[0].hidden).toBeUndefined()
114
+ })
115
+ })
116
+
117
+ describe('hidden rows that carry text', () => {
118
+ it('an auto-continuation directive IS state (the model sees it) but is flagged hidden', () => {
119
+ const directive = buildAutoContinuationDirective('create_ticket', { ticketId: '42' })
120
+ expect(directive.startsWith(AUTO_CONTINUATION_DIRECTIVE_PREFIX)).toBe(true)
121
+
122
+ const r = createChatStreamReducer({ transport: 'sse' })
123
+ r.beginSseSend({ text: directive, hidden: true, assistantName: 'Mingo AI' })
124
+
125
+ const userRow = r.state.messages.find((m) => m.role === 'user')
126
+ expect(userRow?.content).toBe(directive)
127
+ expect(userRow?.hidden).toBe(true)
128
+ })
129
+
130
+ it('never renders — the raw directive text must not reach the transcript', () => {
131
+ const directive = buildAutoContinuationDirective('create_ticket', { ticketId: '42' })
132
+ const messages: Message[] = [
133
+ { id: 'u1', role: 'user', name: 'Michael Assraf', content: 'my laptop is dead' },
134
+ { id: 'h1', role: 'user', name: 'Michael Assraf', content: directive, hidden: true },
135
+ { id: 'a1', role: 'assistant', name: 'Mingo', content: 'Opened a ticket.' },
136
+ ]
137
+ const { container } = render(<ChatMessageList dialogId="d" messages={messages} />)
138
+
139
+ expect(container.textContent).not.toContain(AUTO_CONTINUATION_DIRECTIVE_PREFIX)
140
+ expect(bodies(container)).toEqual(['my laptop is dead', 'Opened a ticket.'])
141
+ })
142
+ })
143
+
144
+ // ─── Render-level contracts ────────────────────────────────────────────────
145
+
146
+ describe('a thinking turn has exactly ONE pending affordance', () => {
147
+ const pending: Message[] = [
148
+ { id: 'u1', role: 'user', name: 'Michael Assraf', content: 'what is broken?' },
149
+ { id: 'a1', role: 'assistant', name: 'Mingo', content: '', segments: [] },
150
+ ]
151
+
152
+ it('does not render the empty labeled assistant row while typing', () => {
153
+ const { container } = render(
154
+ <ChatMessageList dialogId="d" messages={pending} isTyping />,
155
+ )
156
+ // The bare "Mingo" label must be gone from the transcript entirely —
157
+ // removed from the DOM, not visually hidden (the list is an aria-live
158
+ // log; a zero-height node would still be announced).
159
+ expect(names(container)).toEqual(['Michael Assraf'])
160
+ expect(bodies(container)).toEqual(['what is broken?'])
161
+ // …and the single remaining owner is the polite status indicator.
162
+ expect(container.querySelectorAll('[role="status"]')).toHaveLength(1)
163
+ })
164
+
165
+ it('renders the assistant row as soon as it carries text', () => {
166
+ const withText: Message[] = [
167
+ pending[0],
168
+ { id: 'a1', role: 'assistant', name: 'Mingo', content: [{ type: 'text', text: 'Chec' }] },
169
+ ]
170
+ const { container } = render(
171
+ <ChatMessageList dialogId="d" messages={withText} isTyping />,
172
+ )
173
+ expect(names(container)).toEqual(['Michael Assraf', 'Mingo'])
174
+ })
175
+
176
+ it('renders the assistant row when it carries a NON-text segment (tool call)', () => {
177
+ const withTool: Message[] = [
178
+ pending[0],
179
+ {
180
+ id: 'a1',
181
+ role: 'assistant',
182
+ name: 'Mingo',
183
+ content: [
184
+ { type: 'tool_execution', toolExecutionRequestId: 'e1', status: 'executing' },
185
+ ] as Message['content'],
186
+ },
187
+ ]
188
+ const { container } = render(
189
+ <ChatMessageList dialogId="d" messages={withTool} isTyping />,
190
+ )
191
+ expect(names(container)).toEqual(['Michael Assraf', 'Mingo'])
192
+ })
193
+
194
+ it('renders a completed empty-ish assistant row when NOT typing', () => {
195
+ const { container } = render(<ChatMessageList dialogId="d" messages={pending} />)
196
+ expect(names(container)).toEqual(['Michael Assraf', 'Mingo'])
197
+ })
198
+ })
199
+
200
+ describe('the SYSTEM name-only row is a legitimate label-without-body', () => {
201
+ it('still renders', () => {
202
+ const messages: Message[] = [
203
+ { id: 'u1', role: 'user', name: 'Michael Assraf', content: 'hi' },
204
+ { id: 's1', role: 'user', name: 'Technician joined', content: '', authorType: 'system' },
205
+ ]
206
+ const { container } = render(<ChatMessageList dialogId="d" messages={messages} isTyping />)
207
+ expect(names(container)).toContain('Technician joined')
208
+ })
209
+ })
@@ -1,6 +1,6 @@
1
1
  "use client"
2
2
 
3
- import React, { forwardRef, memo, useMemo, useRef } from "react"
3
+ import React, { forwardRef, memo, useEffect, useMemo, useRef } from "react"
4
4
  import { cn } from "../../utils/cn"
5
5
  import { isToday } from "../../utils/date-utils"
6
6
  import { formatDate, formatTime } from "../../utils/format-date"
@@ -11,7 +11,7 @@ import { ApprovalBatchMessage } from "./approval-batch-message"
11
11
  import { ErrorMessageDisplay } from "./error-message-display"
12
12
  import { ContextCompactionDisplay } from "./context-compaction-display"
13
13
  import { ThinkingDisplay } from "./thinking-display"
14
- import { SimpleMarkdownRenderer } from "../ui/simple-markdown-renderer"
14
+ import { SimpleMarkdownRenderer } from "../ui/markdown/simple-markdown-renderer"
15
15
  import type { ChatRef } from "./chat-ref.types"
16
16
  import { remarkCardLinks } from "./remark-card-links"
17
17
  import { remarkMentionChips } from "./remark-mention-chips"
@@ -163,9 +163,9 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
163
163
  | { kind: 'text'; text: string }
164
164
  | { kind: 'block'; key: string; node: React.ReactNode }
165
165
  const partsBySegment = new Map<number, SegmentPart[]>()
166
- if (!render) return { inlineByKey, partsBySegment }
167
- const cache = renderedCardNodeCache.current
168
166
  const usedKeys = new Set<string>()
167
+ if (!render) return { inlineByKey, partsBySegment, usedKeys }
168
+ const cache = renderedCardNodeCache.current
169
169
  // Card keys already emitted as a hoisted block (`b-<key>`). The same
170
170
  // marker can legitimately appear twice in one message (LLM references
171
171
  // the same entity twice); we hoist the FIRST occurrence and skip the
@@ -275,20 +275,99 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
275
275
  partsBySegment.set(segIdx, parts)
276
276
  }
277
277
  })
278
- // Drop cached nodes for markers no longer present so the cache can't
279
- // grow unbounded as a long message's markers change.
280
- if (cache.size > usedKeys.size) {
281
- for (const k of cache.keys()) {
282
- if (!usedKeys.has(k)) cache.delete(k)
283
- }
284
- }
285
- return { inlineByKey, partsBySegment }
278
+ return { inlineByKey, partsBySegment, usedKeys }
286
279
  }, [hasMarkerSupport, chatRefs, renderEntityCard, segments])
287
280
 
281
+ // Drop cached nodes for markers no longer present so the cache can't grow
282
+ // unbounded as a long message's markers change. Deliberately an EFFECT,
283
+ // not part of the memo above: pruning is a mutation, and doing it in the
284
+ // render phase is non-idempotent (StrictMode's double-invoke, or a render
285
+ // React throws away, would evict nodes the committed tree still uses and
286
+ // remount the cards it was built to preserve).
287
+ useEffect(() => {
288
+ const cache = renderedCardNodeCache.current
289
+ const usedKeys = renderingPlan?.usedKeys
290
+ if (!usedKeys) return
291
+ if (cache.size <= usedKeys.size) return
292
+ for (const k of [...cache.keys()]) {
293
+ if (!usedKeys.has(k)) cache.delete(k)
294
+ }
295
+ }, [renderingPlan])
296
+
297
+ // The plan is read through a REF inside the `<a>` override, not captured
298
+ // in the override's closure. `renderingPlan` is rebuilt on every text
299
+ // delta (its `segments` dep is a fresh array per delta), so depending on
300
+ // it here would give `cardComponentOverrides` a new identity every token
301
+ // — which re-creates the markdown engine's `components` memo and defeats
302
+ // its per-block `StreamingBlockRenderer` memoization for the WHOLE
303
+ // message, on every token. The ref keeps the override identity stable
304
+ // while still reading the current plan at call time.
305
+ const renderingPlanRef = useRef(renderingPlan)
306
+ renderingPlanRef.current = renderingPlan
307
+ const chatRefsRef = useRef(chatRefs)
308
+ chatRefsRef.current = chatRefs
309
+
310
+ // Ref-SET token. The override reads `chatRefsRef` at CALL time, but the
311
+ // markdown engine memoizes completed blocks on the override map's
312
+ // identity — so on a COMPLETED (no longer streaming) message, a ref that
313
+ // resolves late would never be re-read: nothing else about the renderer's
314
+ // props changes, the engine's memo bails, and the pill stays stuck on its
315
+ // fallback (`refMatch.title`, or the raw cardId) forever. Streaming is
316
+ // covered because `card://` blocks are excluded from the block cache; the
317
+ // completed path has no other escape.
318
+ //
319
+ // The token fingerprints VALUES, not just the key set: a later refs frame
320
+ // REPLACES the whole map for a send index, and the enrichment case that
321
+ // matters most — a `title` going from the raw cardId to the resolved
322
+ // document title — keeps the key set IDENTICAL. A key-only token would be
323
+ // unchanged, the override map would keep its identity, the engine's
324
+ // completed-block memo would bail, and the pill would stay on its fallback
325
+ // forever. Every `ChatRef` field is included because the host's
326
+ // `renderEntityCard` receives the whole ref and may render any of them.
327
+ //
328
+ // Still STABLE per text delta (the refs map doesn't change while tokens
329
+ // stream), and the cost is one pass over a handful of refs per CHANGED
330
+ // `chatRefs` identity — the dep list is unchanged.
331
+ //
332
+ // Fields are joined by `JSON.stringify`, NOT by a separator character.
333
+ // `title`, `preview` and `url` are free-form HOST strings, so any
334
+ // delimiter we pick is one the data may also contain: joined with a plain
335
+ // space, `title: 'a b'` + empty `url` fingerprints identically to
336
+ // `title: 'a'` + `url: 'b'`, silently reintroducing the stale-pill memo
337
+ // bail this token exists to fix. (An earlier revision used a literal NUL
338
+ // byte as the separator: collision-free in practice, but it made the
339
+ // source file itself binary to grep and diff tooling.) `JSON.stringify`
340
+ // escapes every field, so no value can forge a boundary.
341
+ //
342
+ // Caveat worth stating: `JSON.stringify` on `metadata` is key-ORDER
343
+ // dependent: two structurally equal objects built in different insertion
344
+ // orders fingerprint differently. Acceptable here because every refs map
345
+ // arrives from ONE decoder with a fixed field order, and the failure mode
346
+ // is a redundant re-render, never a stale pill.
347
+ const refsKey = useMemo(
348
+ () =>
349
+ Object.entries(chatRefs ?? {})
350
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
351
+ .map(([k, v]) =>
352
+ JSON.stringify([
353
+ k,
354
+ v.type,
355
+ v.sourceRepo ?? null,
356
+ v.id,
357
+ v.title,
358
+ v.url ?? null,
359
+ v.targetPlatform ?? null,
360
+ v.date ?? null,
361
+ v.preview ?? null,
362
+ v.metadata ?? null,
363
+ ]),
364
+ )
365
+ .join('|'),
366
+ [chatRefs],
367
+ )
368
+
288
369
  const cardComponentOverrides = useMemo(() => {
289
370
  if (!hasMarkerSupport && !hasMentionSupport) return undefined
290
- const refs = chatRefs ?? {}
291
- const inlineByKey = renderingPlan?.inlineByKey
292
371
  return {
293
372
  // Override `<a>` to detect `card://` URLs emitted by `remarkCardLinks`.
294
373
  // The render result was pre-computed in `renderingPlan` so block-level
@@ -316,7 +395,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
316
395
  const cardType = stripped.slice(0, sepIdx)
317
396
  const cardId = stripped.slice(sepIdx + 1)
318
397
  const key = `${cardType}:${cardId}`
319
- const inline = inlineByKey?.get(key)
398
+ const inline = renderingPlanRef.current?.inlineByKey.get(key)
320
399
  if (inline != null) return inline
321
400
  // Three fallback cases — keep them DISTINCT, never blur them
322
401
  // together. Mixing them up (which the old code did by reaching
@@ -340,7 +419,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
340
419
  // title from an unrelated ref — that hides the bug and
341
420
  // deceives the reader into thinking they're looking at
342
421
  // a real card.
343
- const refMatch: ChatRef | undefined = refs[key]
422
+ const refMatch: ChatRef | undefined = chatRefsRef.current?.[key]
344
423
  if (refMatch) {
345
424
  return <span className="text-ods-text-primary">{refMatch.title}</span>
346
425
  }
@@ -382,7 +461,13 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
382
461
  )
383
462
  },
384
463
  }
385
- }, [hasMarkerSupport, hasMentionSupport, renderMention, chatRefs, renderingPlan, NavLinkAnchor])
464
+ // DEPS ARE DELIBERATELY MINIMAL every one of them is stable across a
465
+ // streaming turn (booleans + host-stable fn/component identities, both
466
+ // enforced by this file's `memo` comparator). The rendering plan and the
467
+ // refs MAP are read through refs above precisely so they do NOT appear
468
+ // here; `refsKey` is the one ref-derived dep, and it only moves when the
469
+ // ref set OR any ref VALUE does (see its definition).
470
+ }, [hasMarkerSupport, hasMentionSupport, renderMention, NavLinkAnchor, refsKey])
386
471
 
387
472
  const getAvatarProps = () => {
388
473
  const displayName = name || (isUser ? "User" : assistantType === 'mingo' ? "Mingo" : "Fae")
@@ -493,6 +578,13 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
493
578
  "min-w-0 w-full break-words text-h4",
494
579
  isError ? "text-ods-error" : "text-ods-text-primary",
495
580
  )
581
+ // The engine's streaming path (atomic-block memoization +
582
+ // fence tail-completion + aria-live) applies ONLY to the
583
+ // actively streaming segment: last segment of a message
584
+ // that is still typing. On completion `isTyping` flips
585
+ // false and the engine does one authoritative
586
+ // whole-document parse.
587
+ const segmentIsStreaming = index === segments.length - 1 && !!isTyping
496
588
  // No block markers in this segment → single
497
589
  // SimpleMarkdownRenderer call (existing behaviour
498
590
  // preserved for the vast majority of messages).
@@ -504,6 +596,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
504
596
  textSize="compact"
505
597
  additionalRemarkPlugins={cardRemarkPlugins}
506
598
  componentOverrides={cardComponentOverrides}
599
+ streaming={segmentIsStreaming}
507
600
  />
508
601
  </div>
509
602
  )
@@ -531,6 +624,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
531
624
  textSize="compact"
532
625
  additionalRemarkPlugins={cardRemarkPlugins}
533
626
  componentOverrides={cardComponentOverrides}
627
+ streaming={segmentIsStreaming && pIdx === parts.length - 1}
534
628
  />
535
629
  )
536
630
  }