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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/{chunk-BLZZXZNM.cjs → chunk-5USSSRAL.cjs} +26 -26
  2. package/dist/{chunk-BLZZXZNM.cjs.map → chunk-5USSSRAL.cjs.map} +1 -1
  3. package/dist/{chunk-CGNDAJ7V.js → chunk-6B27O3ZB.js} +4 -4
  4. package/dist/{chunk-P5JQDFRM.cjs → chunk-7IRPMNRL.cjs} +60 -60
  5. package/dist/chunk-7IRPMNRL.cjs.map +1 -0
  6. package/dist/{chunk-4XDWNAZW.cjs → chunk-DQ3EHM6G.cjs} +9 -9
  7. package/dist/{chunk-4XDWNAZW.cjs.map → chunk-DQ3EHM6G.cjs.map} +1 -1
  8. package/dist/{chunk-7KSEINAE.cjs → chunk-FTXDIDNX.cjs} +15 -15
  9. package/dist/{chunk-7KSEINAE.cjs.map → chunk-FTXDIDNX.cjs.map} +1 -1
  10. package/dist/{chunk-4R6H2U77.js → chunk-H7ETLG65.js} +4 -4
  11. package/dist/{chunk-LAOO7XHO.js → chunk-HWTUVLYB.js} +2 -2
  12. package/dist/{chunk-F2NMWV44.js → chunk-IDKDOQZL.js} +2 -2
  13. package/dist/{chunk-BQ7PMWLM.cjs → chunk-KIIOBK7G.cjs} +27 -28
  14. package/dist/chunk-KIIOBK7G.cjs.map +1 -0
  15. package/dist/{chunk-QO2XD3FR.js → chunk-KQGFKG6Y.js} +2 -2
  16. package/dist/{chunk-3N3TMZ62.cjs → chunk-L676XVP4.cjs} +7 -7
  17. package/dist/{chunk-3N3TMZ62.cjs.map → chunk-L676XVP4.cjs.map} +1 -1
  18. package/dist/{chunk-F7F43U7Q.cjs → chunk-LDAOPWXZ.cjs} +11 -11
  19. package/dist/{chunk-F7F43U7Q.cjs.map → chunk-LDAOPWXZ.cjs.map} +1 -1
  20. package/dist/{chunk-ADD3FPDG.cjs → chunk-MKLP2SOZ.cjs} +4886 -7004
  21. package/dist/chunk-MKLP2SOZ.cjs.map +1 -0
  22. package/dist/{chunk-VXJH5TDN.js → chunk-QL7ODLJA.js} +10 -10
  23. package/dist/chunk-QL7ODLJA.js.map +1 -0
  24. package/dist/{chunk-OR5AMXYN.js → chunk-R5QYMUKN.js} +2 -2
  25. package/dist/{chunk-REWRUV3K.js → chunk-TNLFAJPA.js} +9673 -11791
  26. package/dist/chunk-TNLFAJPA.js.map +1 -0
  27. package/dist/{chunk-XF5ROTMQ.js → chunk-U2YDR5DT.js} +2 -2
  28. package/dist/{chunk-PXZ7YQ5V.cjs → chunk-VTQSB6QB.cjs} +5 -5
  29. package/dist/{chunk-PXZ7YQ5V.cjs.map → chunk-VTQSB6QB.cjs.map} +1 -1
  30. package/dist/{chunk-UI7CIUAR.js → chunk-WGJPTFRH.js} +2 -2
  31. package/dist/{chunk-WCE66C2Z.cjs → chunk-XUNJILJT.cjs} +62 -62
  32. package/dist/{chunk-WCE66C2Z.cjs.map → chunk-XUNJILJT.cjs.map} +1 -1
  33. package/dist/{chunk-APF5QBAU.js → chunk-YQBPIUZU.js} +2 -2
  34. package/dist/{chunk-TA7MFVUS.cjs → chunk-YV2YA3QH.cjs} +31 -31
  35. package/dist/{chunk-TA7MFVUS.cjs.map → chunk-YV2YA3QH.cjs.map} +1 -1
  36. package/dist/{chunk-QSGZE6AZ.cjs → chunk-ZDJ4ZUQ4.cjs} +37 -37
  37. package/dist/{chunk-QSGZE6AZ.cjs.map → chunk-ZDJ4ZUQ4.cjs.map} +1 -1
  38. package/dist/{chunk-LJKZIIK4.js → chunk-ZHQQRYMB.js} +5 -6
  39. package/dist/chunk-ZHQQRYMB.js.map +1 -0
  40. package/dist/components/case-studies/index.cjs +8 -8
  41. package/dist/components/case-studies/index.js +2 -2
  42. package/dist/components/chart.d.ts +1 -1
  43. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  44. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  45. package/dist/components/chat/hooks/index.d.ts +1 -0
  46. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  47. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  48. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +48 -15
  49. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  50. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +6 -0
  51. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -0
  52. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +47 -3
  53. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  54. package/dist/components/chat/index.cjs +2 -10
  55. package/dist/components/chat/index.cjs.map +1 -1
  56. package/dist/components/chat/index.d.ts +0 -1
  57. package/dist/components/chat/index.d.ts.map +1 -1
  58. package/dist/components/chat/index.js +13 -21
  59. package/dist/components/chat/types/api.types.d.ts +81 -1
  60. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  61. package/dist/components/chat/types/processing.types.d.ts +90 -2
  62. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  63. package/dist/components/chat/utils/chunk-parser.d.ts +25 -0
  64. package/dist/components/chat/utils/chunk-parser.d.ts.map +1 -0
  65. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +6 -34
  66. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  67. package/dist/components/chat/utils/index.d.ts +3 -2
  68. package/dist/components/chat/utils/index.d.ts.map +1 -1
  69. package/dist/components/chat/utils/process-historical-messages.d.ts +11 -59
  70. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  71. package/dist/components/contact/index.cjs +3 -3
  72. package/dist/components/contact/index.js +2 -2
  73. package/dist/components/docs/index.cjs +5 -5
  74. package/dist/components/docs/index.js +4 -4
  75. package/dist/components/embeds/index.cjs +3 -3
  76. package/dist/components/embeds/index.js +2 -2
  77. package/dist/components/faq/index.cjs +3 -3
  78. package/dist/components/faq/index.js +2 -2
  79. package/dist/components/features/index.cjs +2 -2
  80. package/dist/components/features/index.js +1 -1
  81. package/dist/components/help-center-pages/index.cjs +20 -20
  82. package/dist/components/help-center-pages/index.js +11 -11
  83. package/dist/components/index.cjs +129 -171
  84. package/dist/components/index.cjs.map +1 -1
  85. package/dist/components/index.js +21 -63
  86. package/dist/components/index.js.map +1 -1
  87. package/dist/components/navigation/index.cjs +2 -2
  88. package/dist/components/navigation/index.js +1 -1
  89. package/dist/components/onboarding-guides/index.cjs +5 -5
  90. package/dist/components/onboarding-guides/index.js +4 -4
  91. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  92. package/dist/components/related-content/index.cjs +3 -3
  93. package/dist/components/related-content/index.js +2 -2
  94. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  95. package/dist/components/tickets/index.cjs +5 -5
  96. package/dist/components/tickets/index.js +4 -4
  97. package/dist/components/ui/index.cjs +2 -44
  98. package/dist/components/ui/index.cjs.map +1 -1
  99. package/dist/components/ui/index.d.ts +2 -1
  100. package/dist/components/ui/index.d.ts.map +1 -1
  101. package/dist/components/ui/index.js +13 -55
  102. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  103. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  104. package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
  105. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
  106. package/dist/index.cjs +2 -60
  107. package/dist/index.cjs.map +1 -1
  108. package/dist/index.js +13 -71
  109. package/dist/utils/index.cjs +40 -169
  110. package/dist/utils/index.cjs.map +1 -1
  111. package/dist/utils/index.d.ts +0 -1
  112. package/dist/utils/index.d.ts.map +1 -1
  113. package/dist/utils/index.js +41 -162
  114. package/dist/utils/index.js.map +1 -1
  115. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  116. package/package.json +1 -7
  117. package/src/components/chat/__tests__/chat-message-list.test.tsx +5 -293
  118. package/src/components/chat/chat-message-enhanced.tsx +17 -111
  119. package/src/components/chat/chat-message-list.tsx +113 -367
  120. package/src/components/chat/embeddable-chat.tsx +0 -6
  121. package/src/components/chat/hooks/.index.md +1 -1
  122. package/src/components/chat/hooks/.use-nats-chat-adapter.md +1 -1
  123. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +50 -0
  124. package/src/components/chat/hooks/index.ts +1 -0
  125. package/src/components/chat/hooks/use-chat.ts +0 -8
  126. package/src/components/chat/hooks/use-nats-chat-adapter.ts +822 -243
  127. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +479 -0
  128. package/src/components/chat/hooks/use-sse-chat-adapter.ts +666 -318
  129. package/src/components/chat/index.ts +0 -5
  130. package/src/components/chat/thinking-display.tsx +1 -1
  131. package/src/components/chat/types/.api.types.md +3 -1
  132. package/src/components/chat/types/.processing.types.md +23 -6
  133. package/src/components/chat/types/api.types.ts +73 -6
  134. package/src/components/chat/types/processing.types.ts +52 -11
  135. package/src/components/chat/utils/.chunk-parser.md +51 -0
  136. package/src/components/chat/utils/.index.md +5 -0
  137. package/src/components/chat/utils/chunk-parser.ts +255 -0
  138. package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
  139. package/src/components/chat/utils/index.ts +8 -5
  140. package/src/components/chat/utils/process-historical-messages.ts +383 -352
  141. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
  142. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  143. package/src/components/shared/product-release/release-detail-page.tsx +4 -19
  144. package/src/components/ui/.simple-markdown-renderer.md +40 -0
  145. package/src/components/ui/index.ts +2 -1
  146. package/src/components/ui/release-changelog-section.tsx +1 -1
  147. package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
  148. package/src/components/ui/simple-markdown-renderer.tsx +965 -0
  149. package/src/components/ui/ticket-info-section.tsx +1 -1
  150. package/src/utils/index.ts +0 -1
  151. package/src/utils/markdown-section-extractor.ts +56 -41
  152. package/dist/chat-protocol/decode.d.ts +0 -58
  153. package/dist/chat-protocol/decode.d.ts.map +0 -1
  154. package/dist/chat-protocol/encode.d.ts +0 -44
  155. package/dist/chat-protocol/encode.d.ts.map +0 -1
  156. package/dist/chat-protocol/env-flag.d.ts +0 -35
  157. package/dist/chat-protocol/env-flag.d.ts.map +0 -1
  158. package/dist/chat-protocol/events.d.ts +0 -192
  159. package/dist/chat-protocol/events.d.ts.map +0 -1
  160. package/dist/chat-protocol/frames.d.ts +0 -206
  161. package/dist/chat-protocol/frames.d.ts.map +0 -1
  162. package/dist/chat-protocol/index.cjs +0 -493
  163. package/dist/chat-protocol/index.cjs.map +0 -1
  164. package/dist/chat-protocol/index.d.ts +0 -18
  165. package/dist/chat-protocol/index.d.ts.map +0 -1
  166. package/dist/chat-protocol/index.js +0 -477
  167. package/dist/chat-protocol/index.js.map +0 -1
  168. package/dist/chat-protocol/ip-normalize.d.ts +0 -44
  169. package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
  170. package/dist/chat-protocol/nats-decoder.d.ts +0 -26
  171. package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
  172. package/dist/chunk-ADD3FPDG.cjs.map +0 -1
  173. package/dist/chunk-BQ7PMWLM.cjs.map +0 -1
  174. package/dist/chunk-LJKZIIK4.js.map +0 -1
  175. package/dist/chunk-P5JQDFRM.cjs.map +0 -1
  176. package/dist/chunk-REWRUV3K.js.map +0 -1
  177. package/dist/chunk-VXJH5TDN.js.map +0 -1
  178. package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
  179. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
  180. package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
  181. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
  182. package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
  183. package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
  184. package/dist/components/chat/stream/index.d.ts +0 -17
  185. package/dist/components/chat/stream/index.d.ts.map +0 -1
  186. package/dist/components/chat/stream/message-mutations.d.ts +0 -77
  187. package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
  188. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
  189. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
  190. package/dist/components/ui/markdown/base-components.d.ts +0 -56
  191. package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
  192. package/dist/components/ui/markdown/engine.d.ts +0 -99
  193. package/dist/components/ui/markdown/engine.d.ts.map +0 -1
  194. package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
  195. package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
  196. package/dist/components/ui/markdown/index.d.ts +0 -18
  197. package/dist/components/ui/markdown/index.d.ts.map +0 -1
  198. package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
  199. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
  200. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
  201. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
  202. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
  203. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
  204. package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
  205. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
  206. package/dist/components/ui/markdown/sanitize.d.ts +0 -153
  207. package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
  208. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
  209. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
  210. package/dist/components/ui/markdown/streaming.d.ts +0 -78
  211. package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
  212. package/dist/components/ui/markdown/text-size.d.ts +0 -34
  213. package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
  214. package/dist/utils/markdown-fences.d.ts +0 -42
  215. package/dist/utils/markdown-fences.d.ts.map +0 -1
  216. package/dist/utils/markdown-heading-id.d.ts +0 -85
  217. package/dist/utils/markdown-heading-id.d.ts.map +0 -1
  218. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -307
  219. package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -515
  220. package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
  221. package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
  222. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -228
  223. package/src/chat-protocol/decode.ts +0 -277
  224. package/src/chat-protocol/encode.ts +0 -71
  225. package/src/chat-protocol/env-flag.ts +0 -39
  226. package/src/chat-protocol/events.ts +0 -228
  227. package/src/chat-protocol/frames.ts +0 -238
  228. package/src/chat-protocol/index.ts +0 -21
  229. package/src/chat-protocol/ip-normalize.ts +0 -146
  230. package/src/chat-protocol/nats-decoder.ts +0 -252
  231. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
  232. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -209
  233. package/src/components/chat/hooks/__tests__/__snapshots__/persisted-state-v1-golden.test.ts.snap +0 -297
  234. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  235. package/src/components/chat/hooks/__tests__/persisted-state-v1-golden.test.ts +0 -272
  236. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
  237. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -937
  238. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -756
  239. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -460
  240. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -894
  241. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
  242. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -98
  243. package/src/components/chat/stream/chat-dialog-store.ts +0 -536
  244. package/src/components/chat/stream/chat-stream-reducer.ts +0 -1796
  245. package/src/components/chat/stream/delta-batcher.ts +0 -159
  246. package/src/components/chat/stream/index.ts +0 -55
  247. package/src/components/chat/stream/message-mutations.ts +0 -338
  248. package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
  249. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -418
  250. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -599
  251. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -317
  252. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
  253. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
  254. package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2528
  255. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -115
  256. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -95
  257. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -309
  258. package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -388
  259. package/src/components/ui/markdown/base-components.tsx +0 -341
  260. package/src/components/ui/markdown/engine.tsx +0 -315
  261. package/src/components/ui/markdown/heading-ids.ts +0 -239
  262. package/src/components/ui/markdown/index.ts +0 -49
  263. package/src/components/ui/markdown/mermaid-diagram.tsx +0 -291
  264. package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
  265. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
  266. package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
  267. package/src/components/ui/markdown/sanitize.ts +0 -3499
  268. package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
  269. package/src/components/ui/markdown/streaming.ts +0 -362
  270. package/src/components/ui/markdown/text-size.ts +0 -106
  271. package/src/utils/markdown-fences.ts +0 -127
  272. package/src/utils/markdown-heading-id.ts +0 -348
  273. /package/dist/{chunk-CGNDAJ7V.js.map → chunk-6B27O3ZB.js.map} +0 -0
  274. /package/dist/{chunk-4R6H2U77.js.map → chunk-H7ETLG65.js.map} +0 -0
  275. /package/dist/{chunk-LAOO7XHO.js.map → chunk-HWTUVLYB.js.map} +0 -0
  276. /package/dist/{chunk-F2NMWV44.js.map → chunk-IDKDOQZL.js.map} +0 -0
  277. /package/dist/{chunk-QO2XD3FR.js.map → chunk-KQGFKG6Y.js.map} +0 -0
  278. /package/dist/{chunk-OR5AMXYN.js.map → chunk-R5QYMUKN.js.map} +0 -0
  279. /package/dist/{chunk-XF5ROTMQ.js.map → chunk-U2YDR5DT.js.map} +0 -0
  280. /package/dist/{chunk-UI7CIUAR.js.map → chunk-WGJPTFRH.js.map} +0 -0
  281. /package/dist/{chunk-APF5QBAU.js.map → chunk-YQBPIUZU.js.map} +0 -0
@@ -1,209 +0,0 @@
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,297 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`PersistedChatState v1 — golden rehydration (migration contract) > rehydration round-trips: the persist callback re-saves an equivalent v1 blob 1`] = `
4
- {
5
- "messages": [
6
- {
7
- "content": "open a ticket for the broken printer",
8
- "id": "user-1752915600000",
9
- "name": "You",
10
- "role": "user",
11
- "timestamp": "2026-07-19T09:00:00.000Z",
12
- },
13
- {
14
- "content": [
15
- {
16
- "text": "I'll open a ticket for you.",
17
- "type": "text",
18
- },
19
- {
20
- "data": {
21
- "approvalType": "create_ticket",
22
- "command": "Create ticket",
23
- "fields": [
24
- {
25
- "label": "Subject",
26
- "value": "Broken printer",
27
- },
28
- {
29
- "label": "Priority",
30
- "value": "High",
31
- },
32
- ],
33
- "requestId": "prop-1",
34
- },
35
- "status": "approved",
36
- "type": "approval_request",
37
- },
38
- ],
39
- "id": "assistant-1752915600000",
40
- "name": "Mingo AI",
41
- "role": "assistant",
42
- "timestamp": "2026-07-19T09:00:05.000Z",
43
- },
44
- {
45
- "content": "",
46
- "hidden": true,
47
- "id": "user-1752915610000",
48
- "name": "You",
49
- "role": "user",
50
- "timestamp": "2026-07-19T09:00:10.000Z",
51
- },
52
- {
53
- "chatRefs": {
54
- "ticket:77": {
55
- "id": "77",
56
- "metadata": {
57
- "status": "OPEN",
58
- },
59
- "title": "Broken printer",
60
- "type": "ticket",
61
- "url": null,
62
- },
63
- },
64
- "content": [
65
- {
66
- "text": "✅ Approved — ticket created: [card://ticket:77]
67
-
68
- Now, to triage faster: which floor is the printer on?",
69
- "type": "text",
70
- },
71
- ],
72
- "id": "assistant-1752915610000",
73
- "name": "Mingo AI",
74
- "role": "assistant",
75
- "timestamp": "2026-07-19T09:00:12.000Z",
76
- },
77
- {
78
- "content": "[internal-auto-continuation] The user just approved create_ticket (ticket #77). Ask diagnostic follow-ups.",
79
- "hidden": true,
80
- "id": "user-1752915612000",
81
- "name": "You",
82
- "role": "user",
83
- "timestamp": "2026-07-19T09:00:12.500Z",
84
- },
85
- {
86
- "content": [
87
- {
88
- "text": "Also: is the printer showing any error code on its display?",
89
- "type": "text",
90
- },
91
- ],
92
- "id": "assistant-1752915613000",
93
- "name": "Mingo AI",
94
- "role": "assistant",
95
- "timestamp": "2026-07-19T09:00:13.000Z",
96
- },
97
- {
98
- "content": "what is the pricing?",
99
- "id": "user-1752915700000",
100
- "name": "You",
101
- "role": "user",
102
- "timestamp": "2026-07-19T09:01:40.000Z",
103
- },
104
- {
105
- "content": [
106
- {
107
- "text": "Checking pricing docs…",
108
- "type": "thinking",
109
- },
110
- {
111
- "text": "Pricing starts at $99/month per site.",
112
- "type": "text",
113
- },
114
- ],
115
- "id": "assistant-1752915700000",
116
- "name": "Mingo AI",
117
- "role": "assistant",
118
- "timestamp": "2026-07-19T09:01:45.000Z",
119
- },
120
- ],
121
- "refs": [
122
- [
123
- 0,
124
- {
125
- "ticket:77": {
126
- "id": "77",
127
- "metadata": {
128
- "status": "OPEN",
129
- },
130
- "title": "Broken printer",
131
- "type": "ticket",
132
- "url": null,
133
- },
134
- },
135
- ],
136
- ],
137
- "sendCount": 2,
138
- "sources": [
139
- [
140
- 1,
141
- [
142
- {
143
- "documentType": "markdown",
144
- "index": 1,
145
- "name": "Pricing overview",
146
- "path": "docs/pricing.md",
147
- "sourceRepo": "markdown",
148
- },
149
- ],
150
- ],
151
- ],
152
- }
153
- `;
154
-
155
- exports[`PersistedChatState v1 — golden rehydration (migration contract) > restores messages / refs / sources from a hand-crafted v1 blob (snapshot) 1`] = `
156
- {
157
- "isLoading": false,
158
- "messages": [
159
- {
160
- "content": "open a ticket for the broken printer",
161
- "id": "user-1752915600000",
162
- "role": "user",
163
- },
164
- {
165
- "chatRefs": {
166
- "ticket:77": {
167
- "id": "77",
168
- "metadata": {
169
- "status": "OPEN",
170
- },
171
- "title": "Broken printer",
172
- "type": "ticket",
173
- "url": null,
174
- },
175
- },
176
- "content": "I'll open a ticket for you.",
177
- "id": "assistant-1752915600000",
178
- "role": "assistant",
179
- "segments": [
180
- {
181
- "text": "I'll open a ticket for you.",
182
- "type": "text",
183
- },
184
- {
185
- "data": {
186
- "approvalType": "create_ticket",
187
- "command": "Create ticket",
188
- "fields": [
189
- {
190
- "label": "Subject",
191
- "value": "Broken printer",
192
- },
193
- {
194
- "label": "Priority",
195
- "value": "High",
196
- },
197
- ],
198
- "requestId": "prop-1",
199
- },
200
- "status": "approved",
201
- "type": "approval_request",
202
- },
203
- ],
204
- },
205
- {
206
- "content": "",
207
- "hidden": true,
208
- "id": "user-1752915610000",
209
- "role": "user",
210
- },
211
- {
212
- "chatRefs": {
213
- "ticket:77": {
214
- "id": "77",
215
- "metadata": {
216
- "status": "OPEN",
217
- },
218
- "title": "Broken printer",
219
- "type": "ticket",
220
- "url": null,
221
- },
222
- },
223
- "content": "✅ Approved — ticket created: [card://ticket:77]
224
-
225
- Now, to triage faster: which floor is the printer on?",
226
- "id": "assistant-1752915610000",
227
- "role": "assistant",
228
- "segments": [
229
- {
230
- "text": "✅ Approved — ticket created: [card://ticket:77]
231
-
232
- Now, to triage faster: which floor is the printer on?",
233
- "type": "text",
234
- },
235
- ],
236
- },
237
- {
238
- "content": "[internal-auto-continuation] The user just approved create_ticket (ticket #77). Ask diagnostic follow-ups.",
239
- "hidden": true,
240
- "id": "user-1752915612000",
241
- "role": "user",
242
- },
243
- {
244
- "chatRefs": {
245
- "ticket:77": {
246
- "id": "77",
247
- "metadata": {
248
- "status": "OPEN",
249
- },
250
- "title": "Broken printer",
251
- "type": "ticket",
252
- "url": null,
253
- },
254
- },
255
- "content": "Also: is the printer showing any error code on its display?",
256
- "id": "assistant-1752915613000",
257
- "role": "assistant",
258
- "segments": [
259
- {
260
- "text": "Also: is the printer showing any error code on its display?",
261
- "type": "text",
262
- },
263
- ],
264
- },
265
- {
266
- "content": "what is the pricing?",
267
- "id": "user-1752915700000",
268
- "role": "user",
269
- },
270
- {
271
- "content": "Pricing starts at $99/month per site.",
272
- "id": "assistant-1752915700000",
273
- "role": "assistant",
274
- "segments": [
275
- {
276
- "text": "Checking pricing docs…",
277
- "type": "thinking",
278
- },
279
- {
280
- "text": "Pricing starts at $99/month per site.",
281
- "type": "text",
282
- },
283
- ],
284
- "sources": [
285
- {
286
- "documentType": "markdown",
287
- "index": 1,
288
- "name": "Pricing overview",
289
- "path": "docs/pricing.md",
290
- "sourceRepo": "markdown",
291
- },
292
- ],
293
- },
294
- ],
295
- "streamingPhase": "idle",
296
- }
297
- `;