@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
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Utilities for parsing NATS chunks into structured actions
3
+ */
4
+
5
+ import { MESSAGE_TYPE, type ChunkData, type ParsedChunkAction, type ToolExecutionSegment, type PendingToolCallData } from '../types'
6
+
7
+ function normalizeToolCalls(raw: unknown): PendingToolCallData[] {
8
+ if (!Array.isArray(raw)) return []
9
+ return raw
10
+ .filter((item): item is Record<string, any> => !!item && typeof item === 'object')
11
+ .map((item) => ({
12
+ toolExecutionRequestId: String(item.toolExecutionRequestId ?? ''),
13
+ toolName: String(item.toolName ?? ''),
14
+ toolTitle: typeof item.toolTitle === 'string' ? item.toolTitle : undefined,
15
+ toolExplanation: typeof item.toolExplanation === 'string' ? item.toolExplanation : undefined,
16
+ toolType: typeof item.toolType === 'string' ? item.toolType : undefined,
17
+ requiresApproval: item.requiresApproval === true,
18
+ approvalType: typeof item.approvalType === 'string' ? item.approvalType : null,
19
+ toolCallArguments:
20
+ item.toolCallArguments && typeof item.toolCallArguments === 'object'
21
+ ? (item.toolCallArguments as Record<string, any>)
22
+ : null,
23
+ }))
24
+ }
25
+
26
+ /**
27
+ * Parse a raw NATS chunk into a structured action
28
+ */
29
+ export function parseChunkToAction(chunk: unknown): ParsedChunkAction | null {
30
+ if (!chunk || typeof chunk !== 'object') return null
31
+
32
+ const data = chunk as ChunkData
33
+ const type = String(data.type || '')
34
+
35
+ switch (type) {
36
+ case MESSAGE_TYPE.MESSAGE_START:
37
+ return { action: 'message_start' }
38
+
39
+ case MESSAGE_TYPE.MESSAGE_END:
40
+ return { action: 'message_end' }
41
+
42
+ case MESSAGE_TYPE.AI_METADATA: {
43
+ const providerName = data.providerName || data.provider
44
+ if (typeof data.modelName === 'string' && typeof providerName === 'string') {
45
+ return {
46
+ action: 'metadata',
47
+ modelDisplayName: data.modelDisplayName,
48
+ modelName: data.modelName,
49
+ providerName,
50
+ contextWindow: typeof data.contextWindow === 'number' ? data.contextWindow : 0,
51
+ }
52
+ }
53
+ return null
54
+ }
55
+
56
+ case MESSAGE_TYPE.TEXT:
57
+ if (typeof data.text === 'string') {
58
+ return { action: 'text', text: data.text }
59
+ }
60
+ return null
61
+
62
+ case MESSAGE_TYPE.THINKING:
63
+ if (typeof data.text === 'string') {
64
+ return { action: 'thinking', text: data.text }
65
+ }
66
+ return null
67
+
68
+ case MESSAGE_TYPE.GUIDE:
69
+ if (typeof data.text === 'string') {
70
+ return { action: 'guide', text: data.text }
71
+ }
72
+ return null
73
+
74
+ case MESSAGE_TYPE.EXECUTING_TOOL:
75
+ return {
76
+ action: 'tool_execution',
77
+ segment: {
78
+ type: 'tool_execution',
79
+ data: {
80
+ type: 'EXECUTING_TOOL',
81
+ integratedToolType: data.integratedToolType || '',
82
+ toolFunction: data.toolFunction || '',
83
+ toolTitle: typeof data.title === 'string' ? data.title : undefined,
84
+ toolExplanation: typeof data.toolExplanation === 'string' ? data.toolExplanation : undefined,
85
+ parameters: data.parameters,
86
+ toolExecutionRequestId: typeof data.toolExecutionRequestId === 'string' ? data.toolExecutionRequestId : undefined,
87
+ }
88
+ }
89
+ }
90
+
91
+ case MESSAGE_TYPE.EXECUTED_TOOL:
92
+ return {
93
+ action: 'tool_execution',
94
+ segment: {
95
+ type: 'tool_execution',
96
+ data: {
97
+ type: 'EXECUTED_TOOL',
98
+ integratedToolType: data.integratedToolType || '',
99
+ toolFunction: data.toolFunction || '',
100
+ toolTitle: typeof data.title === 'string' ? data.title : undefined,
101
+ parameters: data.parameters,
102
+ result: data.result,
103
+ success: data.success,
104
+ toolExecutionRequestId: typeof data.toolExecutionRequestId === 'string' ? data.toolExecutionRequestId : undefined,
105
+ }
106
+ }
107
+ }
108
+
109
+ case MESSAGE_TYPE.APPROVAL_REQUEST: {
110
+ const requestId = data.approvalRequestId || data.approval_request_id || ''
111
+ const approvalType = data.approvalType || 'USER'
112
+ const toolCalls = normalizeToolCalls(data.toolCalls)
113
+
114
+ if (toolCalls.length > 0) {
115
+ return {
116
+ action: 'approval_batch',
117
+ requestId,
118
+ approvalType,
119
+ toolCalls,
120
+ }
121
+ }
122
+
123
+ return {
124
+ action: 'approval_request',
125
+ requestId,
126
+ command: data.command || '',
127
+ explanation: data.explanation,
128
+ approvalType,
129
+ }
130
+ }
131
+
132
+ case MESSAGE_TYPE.APPROVAL_RESULT: {
133
+ // The realtime NATS chunk carries the resolver's name as `displayName`; the
134
+ // persisted GraphQL message exposes the same value as `resolvedByName`. Accept
135
+ // either so realtime and history-replay render "by {name}" identically.
136
+ const resolvedByName =
137
+ typeof data.resolvedByName === 'string'
138
+ ? data.resolvedByName
139
+ : typeof data.displayName === 'string'
140
+ ? data.displayName
141
+ : undefined
142
+ return {
143
+ action: 'approval_result',
144
+ requestId: data.approvalRequestId || data.approval_request_id || '',
145
+ approved: data.approved === true,
146
+ approvalType: data.approvalType || 'CLIENT',
147
+ resolvedByName,
148
+ }
149
+ }
150
+
151
+ case MESSAGE_TYPE.ERROR:
152
+ return {
153
+ action: 'error',
154
+ error: data.error || 'An error occurred',
155
+ details: data.details,
156
+ }
157
+
158
+ case MESSAGE_TYPE.MESSAGE_REQUEST:
159
+ return {
160
+ action: 'message_request',
161
+ text: String(data.text || ''),
162
+ ownerType: typeof data.ownerType === 'string' ? data.ownerType : undefined,
163
+ displayName: typeof data.displayName === 'string' ? data.displayName : undefined,
164
+ userId: typeof data.userId === 'string' ? data.userId : undefined,
165
+ // Entity-context refs the user attached to this message (backend
166
+ // `MESSAGE_REQUEST` chunk → `contextItems: [{ type, id }]`). The wire
167
+ // shape carries no label; the host resolves display text + icon. `label`
168
+ // is REQUIRED on `ChatContextItem`, so fall back to the id (same as the
169
+ // historical path in `process-historical-messages.ts`) — keeps both
170
+ // message sources producing an identical shape.
171
+ contextItems: Array.isArray(data.contextItems)
172
+ ? (data.contextItems as Array<{ type?: unknown; id?: unknown }>)
173
+ .filter((it) => typeof it?.type === 'string' && typeof it?.id === 'string')
174
+ .map((it) => ({ type: it.type as string, id: it.id as string, label: it.id as string }))
175
+ : undefined,
176
+ }
177
+
178
+ case MESSAGE_TYPE.TOKEN_USAGE:
179
+ return {
180
+ action: 'token_usage',
181
+ data: {
182
+ inputTokensSize: data.inputTokensSize ?? 0,
183
+ outputTokensSize: data.outputTokensSize ?? 0,
184
+ totalTokensSize: data.totalTokensSize ?? 0,
185
+ contextSize: data.contextSize ?? 0,
186
+ },
187
+ }
188
+
189
+ case MESSAGE_TYPE.CONTEXT_COMPACTION_START:
190
+ return { action: 'context_compaction_start' }
191
+
192
+ case MESSAGE_TYPE.CONTEXT_COMPACTION_END:
193
+ return {
194
+ action: 'context_compaction_end',
195
+ summary: typeof data.text === 'string' ? data.text : undefined,
196
+ }
197
+
198
+ case MESSAGE_TYPE.SYSTEM:
199
+ if (typeof data.text === 'string') {
200
+ return { action: 'system', text: data.text }
201
+ }
202
+ return null
203
+
204
+ case MESSAGE_TYPE.DIRECT_MESSAGE:
205
+ if (typeof data.text === 'string') {
206
+ return {
207
+ action: 'direct_message',
208
+ text: data.text,
209
+ ownerType: typeof data.ownerType === 'string' ? data.ownerType : undefined,
210
+ displayName: typeof data.displayName === 'string' ? data.displayName : undefined,
211
+ userId: typeof data.userId === 'string' ? data.userId : undefined,
212
+ }
213
+ }
214
+ return null
215
+
216
+ case MESSAGE_TYPE.DIALOG_CLOSED:
217
+ return { action: 'dialog_closed' }
218
+
219
+ default:
220
+ return null
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Check if a chunk represents a control message (start/end)
226
+ */
227
+ export function isControlChunk(chunk: unknown): boolean {
228
+ if (!chunk || typeof chunk !== 'object') return false
229
+ const data = chunk as ChunkData
230
+ const type = String(data.type || '')
231
+ return type === MESSAGE_TYPE.MESSAGE_START || type === MESSAGE_TYPE.MESSAGE_END
232
+ }
233
+
234
+ /**
235
+ * Check if a chunk represents an error
236
+ */
237
+ export function isErrorChunk(chunk: unknown): boolean {
238
+ if (!chunk || typeof chunk !== 'object') return false
239
+ const data = chunk as ChunkData
240
+ return data.type === MESSAGE_TYPE.ERROR
241
+ }
242
+
243
+ /**
244
+ * Check if a chunk represents metadata
245
+ */
246
+ export function isMetadataChunk(chunk: unknown): boolean {
247
+ if (!chunk || typeof chunk !== 'object') return false
248
+ const data = chunk as ChunkData
249
+ return data.type === MESSAGE_TYPE.AI_METADATA
250
+ }
251
+
252
+ /**
253
+ * Extract text content from a chunk if it's a text chunk
254
+ */
255
+ export function extractTextFromChunk(chunk: unknown): string | null {
256
+ if (!chunk || typeof chunk !== 'object') return null
257
+ const data = chunk as ChunkData
258
+ if (data.type === MESSAGE_TYPE.TEXT && typeof data.text === 'string') {
259
+ return data.text
260
+ }
261
+ return null
262
+ }
@@ -9,18 +9,6 @@ import type {
9
9
  PendingApproval,
10
10
  ExecutingToolState,
11
11
  } from '../types'
12
- import type { InitializeExtras } from '../stream/chat-stream-reducer'
13
-
14
- /**
15
- * What the realtime accumulator needs to RESUME an unfinished turn.
16
- *
17
- * DERIVED, not restated: this is exactly the reducer's `InitializeExtras`
18
- * minus `escalatedApprovals` (which only the live stream can produce — it has
19
- * no historical representation to extract). Hosts pass the result straight
20
- * into `reducer.initializeWithState(messages, extras)`, so the two must not
21
- * drift; a structural coincidence is not a contract.
22
- */
23
- export type IncompleteMessageState = Omit<InitializeExtras, 'escalatedApprovals'>
24
12
 
25
13
  /**
26
14
  * Extract incomplete message state from the last historical assistant message
@@ -28,7 +16,11 @@ export type IncompleteMessageState = Omit<InitializeExtras, 'escalatedApprovals'
28
16
  */
29
17
  export function extractIncompleteMessageState(
30
18
  lastMessage: ProcessedMessage | undefined
31
- ): IncompleteMessageState | undefined {
19
+ ): {
20
+ existingSegments?: MessageSegment[]
21
+ pendingApprovals?: Map<string, PendingApproval>
22
+ executingTools?: Map<string, ExecutingToolState>
23
+ } | undefined {
32
24
  if (!lastMessage || lastMessage.role !== 'assistant' || typeof lastMessage.content === 'string') {
33
25
  return undefined
34
26
  }
@@ -100,54 +92,4 @@ export function extractIncompleteMessageState(
100
92
  pendingApprovals: pendingApprovals.size > 0 ? pendingApprovals : undefined,
101
93
  executingTools: executingTools.size > 0 ? executingTools : undefined,
102
94
  }
103
- }
104
-
105
- /**
106
- * THREAD-level generalization of `extractIncompleteMessageState`: given a
107
- * processed thread, look at the TRAILING RUN of consecutive assistant
108
- * messages (not just the very last row), flatten it to one segment list, and
109
- * ask the single-message extractor whether that tail is unfinished.
110
- *
111
- * Why the run and not the last row: the backend can split one logical turn
112
- * across several assistant messages (a preamble bubble, then the approval
113
- * card, then the continuation). The unfinished artifact — a pending approval,
114
- * an EXECUTING_TOOL with no result, an open compaction — can therefore sit in
115
- * an EARLIER bubble of the same trailing run, and a last-row-only check
116
- * reports "complete" while the turn is very much still in flight.
117
- *
118
- * SSOT for every "is the tail incomplete?" question — the NATS adapter (which
119
- * used to inline the single-row check) and hosts replaying a stored thread
120
- * both call this instead of re-deriving the walk.
121
- *
122
- * A trailing non-assistant row (user / error) means the last turn closed →
123
- * `undefined`.
124
- */
125
- export function extractIncompleteTailState(
126
- messages: readonly ProcessedMessage[] | undefined,
127
- ): IncompleteMessageState | undefined {
128
- if (!messages || messages.length === 0) return undefined
129
-
130
- // Walk back over the trailing consecutive assistant run.
131
- let start = messages.length
132
- while (start > 0 && messages[start - 1]?.role === 'assistant') start -= 1
133
- if (start === messages.length) return undefined
134
-
135
- const segments: MessageSegment[] = []
136
- for (let i = start; i < messages.length; i += 1) {
137
- const content = messages[i]?.content
138
- // A string-content assistant row is a plain-text bubble with nothing to
139
- // resume; skip it rather than aborting — a later row in the same run may
140
- // still hold the unfinished segment.
141
- if (Array.isArray(content)) segments.push(...(content as MessageSegment[]))
142
- }
143
- if (segments.length === 0) return undefined
144
-
145
- // Reuse the single-message extractor verbatim by handing it a synthetic
146
- // assistant row carrying the flattened run — one incompleteness rule set,
147
- // not two.
148
- return extractIncompleteMessageState({
149
- ...messages[messages.length - 1],
150
- role: 'assistant',
151
- content: segments,
152
- } as ProcessedMessage)
153
95
  }
@@ -3,9 +3,14 @@
3
3
  * Export all utilities for processing chat messages
4
4
  */
5
5
 
6
- // NOTE: NATS chunk parsing lives in `chat-protocol/nats-decoder`
7
- // (`decodeNatsChunk`) — the legacy `chunk-parser` module was deleted once the
8
- // reducer became the single reading path.
6
+ // Chunk parsing utilities
7
+ export {
8
+ parseChunkToAction,
9
+ isControlChunk,
10
+ isErrorChunk,
11
+ isMetadataChunk,
12
+ extractTextFromChunk,
13
+ } from './chunk-parser'
9
14
 
10
15
  // Segment accumulator
11
16
  export {
@@ -19,13 +24,11 @@ export {
19
24
  processHistoricalMessages,
20
25
  extractErrorMessages,
21
26
  processHistoricalMessagesWithErrors,
22
- decodeHistoricalMessageData,
23
27
  } from './process-historical-messages'
24
28
 
25
29
  // Incomplete message state extraction
26
30
  export {
27
31
  extractIncompleteMessageState,
28
- extractIncompleteTailState,
29
32
  } from './extract-incomplete-message-state'
30
33
 
31
34
  // History <-> realtime reconciliation