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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/dist/{chunk-5CJR2GZ4.cjs → chunk-2MKUHJ3O.cjs} +31 -31
  2. package/dist/{chunk-5CJR2GZ4.cjs.map → chunk-2MKUHJ3O.cjs.map} +1 -1
  3. package/dist/{chunk-S2NHJDKQ.cjs → chunk-3IEVA5AO.cjs} +62 -62
  4. package/dist/{chunk-S2NHJDKQ.cjs.map → chunk-3IEVA5AO.cjs.map} +1 -1
  5. package/dist/{chunk-GTWO5NAY.js → chunk-6CFFISUC.js} +2 -2
  6. package/dist/{chunk-VHG6AX5V.js → chunk-6CJ2K7BD.js} +2 -2
  7. package/dist/{chunk-4NWARV5I.js → chunk-6QK3ONDD.js} +2 -2
  8. package/dist/{chunk-YHOIAA2E.cjs → chunk-7I42V2OD.cjs} +60 -60
  9. package/dist/chunk-7I42V2OD.cjs.map +1 -0
  10. package/dist/{chunk-T2EGSZFN.js → chunk-AIRNG27G.js} +5 -6
  11. package/dist/chunk-AIRNG27G.js.map +1 -0
  12. package/dist/{chunk-NWX7MMF5.cjs → chunk-AW63ET2A.cjs} +15 -15
  13. package/dist/{chunk-NWX7MMF5.cjs.map → chunk-AW63ET2A.cjs.map} +1 -1
  14. package/dist/{chunk-TKN5667N.js → chunk-BZMOEWWS.js} +10 -10
  15. package/dist/chunk-BZMOEWWS.js.map +1 -0
  16. package/dist/{chunk-DSDZ5T4P.cjs → chunk-D5LQMRPU.cjs} +5 -5
  17. package/dist/{chunk-DSDZ5T4P.cjs.map → chunk-D5LQMRPU.cjs.map} +1 -1
  18. package/dist/{chunk-CORIBKHG.js → chunk-EGXCWZYP.js} +2 -2
  19. package/dist/{chunk-5EYRXSY5.cjs → chunk-EJQUYZXF.cjs} +9 -9
  20. package/dist/{chunk-5EYRXSY5.cjs.map → chunk-EJQUYZXF.cjs.map} +1 -1
  21. package/dist/{chunk-P4WTZU6L.cjs → chunk-FY5XAW3H.cjs} +11 -11
  22. package/dist/{chunk-P4WTZU6L.cjs.map → chunk-FY5XAW3H.cjs.map} +1 -1
  23. package/dist/{chunk-VQ523ORK.cjs → chunk-GMPYR3MX.cjs} +26 -26
  24. package/dist/{chunk-VQ523ORK.cjs.map → chunk-GMPYR3MX.cjs.map} +1 -1
  25. package/dist/{chunk-QSCHCZL3.cjs → chunk-GUTYUMGV.cjs} +7 -7
  26. package/dist/{chunk-QSCHCZL3.cjs.map → chunk-GUTYUMGV.cjs.map} +1 -1
  27. package/dist/{chunk-Q6E7VJ4W.cjs → chunk-IEZ3YBAP.cjs} +27 -28
  28. package/dist/chunk-IEZ3YBAP.cjs.map +1 -0
  29. package/dist/{chunk-HSACATCD.js → chunk-MPYDX5WX.js} +2 -2
  30. package/dist/{chunk-RQLBHKXN.js → chunk-NGEFYPY7.js} +2 -2
  31. package/dist/{chunk-BE6DK7QY.js → chunk-OQIMH2WQ.js} +8985 -11081
  32. package/dist/chunk-OQIMH2WQ.js.map +1 -0
  33. package/dist/{chunk-CSYSYJCF.cjs → chunk-UZZT65PQ.cjs} +37 -37
  34. package/dist/{chunk-CSYSYJCF.cjs.map → chunk-UZZT65PQ.cjs.map} +1 -1
  35. package/dist/{chunk-YZ2OIYQ3.js → chunk-VDZO6IDR.js} +4 -4
  36. package/dist/{chunk-UUYRJPGJ.js → chunk-VL2YMDPH.js} +4 -4
  37. package/dist/{chunk-5LMGFI4J.cjs → chunk-VUXNXWOQ.cjs} +4946 -7042
  38. package/dist/chunk-VUXNXWOQ.cjs.map +1 -0
  39. package/dist/{chunk-XQ2B74SI.js → chunk-WLM3F3WU.js} +2 -2
  40. package/dist/components/case-studies/index.cjs +8 -8
  41. package/dist/components/case-studies/index.js +2 -2
  42. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  43. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  44. package/dist/components/chat/guide-display.d.ts +14 -0
  45. package/dist/components/chat/guide-display.d.ts.map +1 -0
  46. package/dist/components/chat/hooks/index.d.ts +1 -0
  47. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  48. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  49. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +48 -15
  50. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  51. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +6 -0
  52. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -0
  53. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +57 -10
  54. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  55. package/dist/components/chat/index.cjs +2 -8
  56. package/dist/components/chat/index.cjs.map +1 -1
  57. package/dist/components/chat/index.d.ts +1 -1
  58. package/dist/components/chat/index.d.ts.map +1 -1
  59. package/dist/components/chat/index.js +15 -21
  60. package/dist/components/chat/types/api.types.d.ts +81 -1
  61. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  62. package/dist/components/chat/types/component.types.d.ts +6 -0
  63. package/dist/components/chat/types/component.types.d.ts.map +1 -1
  64. package/dist/components/chat/types/message.types.d.ts +15 -2
  65. package/dist/components/chat/types/message.types.d.ts.map +1 -1
  66. package/dist/components/chat/types/processing.types.d.ts +93 -2
  67. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  68. package/dist/components/chat/utils/chunk-parser.d.ts +25 -0
  69. package/dist/components/chat/utils/chunk-parser.d.ts.map +1 -0
  70. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +6 -34
  71. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  72. package/dist/components/chat/utils/index.d.ts +3 -2
  73. package/dist/components/chat/utils/index.d.ts.map +1 -1
  74. package/dist/components/chat/utils/message-segment-accumulator.d.ts +5 -0
  75. package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
  76. package/dist/components/chat/utils/process-historical-messages.d.ts +11 -59
  77. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  78. package/dist/components/contact/index.cjs +3 -3
  79. package/dist/components/contact/index.js +2 -2
  80. package/dist/components/docs/index.cjs +5 -5
  81. package/dist/components/docs/index.js +4 -4
  82. package/dist/components/embeds/index.cjs +3 -3
  83. package/dist/components/embeds/index.js +2 -2
  84. package/dist/components/faq/index.cjs +3 -3
  85. package/dist/components/faq/index.js +2 -2
  86. package/dist/components/features/index.cjs +2 -2
  87. package/dist/components/features/index.js +1 -1
  88. package/dist/components/help-center-pages/index.cjs +20 -20
  89. package/dist/components/help-center-pages/index.js +11 -11
  90. package/dist/components/index.cjs +130 -170
  91. package/dist/components/index.cjs.map +1 -1
  92. package/dist/components/index.js +23 -63
  93. package/dist/components/index.js.map +1 -1
  94. package/dist/components/navigation/index.cjs +2 -2
  95. package/dist/components/navigation/index.js +1 -1
  96. package/dist/components/onboarding-guides/index.cjs +5 -5
  97. package/dist/components/onboarding-guides/index.js +4 -4
  98. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  99. package/dist/components/related-content/index.cjs +3 -3
  100. package/dist/components/related-content/index.js +2 -2
  101. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  102. package/dist/components/tickets/index.cjs +5 -5
  103. package/dist/components/tickets/index.js +4 -4
  104. package/dist/components/ui/index.cjs +2 -42
  105. package/dist/components/ui/index.cjs.map +1 -1
  106. package/dist/components/ui/index.d.ts +2 -1
  107. package/dist/components/ui/index.d.ts.map +1 -1
  108. package/dist/components/ui/index.js +15 -55
  109. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  110. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  111. package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
  112. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
  113. package/dist/index.cjs +2 -58
  114. package/dist/index.cjs.map +1 -1
  115. package/dist/index.js +15 -71
  116. package/dist/utils/index.cjs +40 -169
  117. package/dist/utils/index.cjs.map +1 -1
  118. package/dist/utils/index.d.ts +0 -1
  119. package/dist/utils/index.d.ts.map +1 -1
  120. package/dist/utils/index.js +41 -162
  121. package/dist/utils/index.js.map +1 -1
  122. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  123. package/package.json +1 -7
  124. package/src/components/chat/__tests__/chat-message-list.test.tsx +5 -293
  125. package/src/components/chat/chat-message-enhanced.tsx +80 -163
  126. package/src/components/chat/chat-message-list.tsx +109 -358
  127. package/src/components/chat/embeddable-chat.tsx +0 -6
  128. package/src/components/chat/guide-display.tsx +44 -0
  129. package/src/components/chat/hooks/.index.md +33 -30
  130. package/src/components/chat/hooks/.use-nats-chat-adapter.md +55 -36
  131. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +77 -0
  132. package/src/components/chat/hooks/index.ts +1 -0
  133. package/src/components/chat/hooks/use-chat.ts +0 -8
  134. package/src/components/chat/hooks/use-nats-chat-adapter.ts +825 -243
  135. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +489 -0
  136. package/src/components/chat/hooks/use-sse-chat-adapter.ts +684 -380
  137. package/src/components/chat/index.ts +1 -5
  138. package/src/components/chat/thinking-display.tsx +1 -1
  139. package/src/components/chat/types/.api.types.md +49 -39
  140. package/src/components/chat/types/.processing.types.md +58 -29
  141. package/src/components/chat/types/api.types.ts +73 -6
  142. package/src/components/chat/types/component.types.ts +9 -0
  143. package/src/components/chat/types/message.types.ts +17 -1
  144. package/src/components/chat/types/processing.types.ts +53 -11
  145. package/src/components/chat/utils/.chunk-parser.md +62 -0
  146. package/src/components/chat/utils/.index.md +40 -31
  147. package/src/components/chat/utils/chunk-parser.ts +262 -0
  148. package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
  149. package/src/components/chat/utils/index.ts +8 -5
  150. package/src/components/chat/utils/message-segment-accumulator.ts +19 -0
  151. package/src/components/chat/utils/process-historical-messages.ts +390 -352
  152. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
  153. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  154. package/src/components/shared/product-release/release-detail-page.tsx +4 -19
  155. package/src/components/ui/.simple-markdown-renderer.md +52 -0
  156. package/src/components/ui/index.ts +2 -1
  157. package/src/components/ui/release-changelog-section.tsx +1 -1
  158. package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
  159. package/src/components/ui/simple-markdown-renderer.tsx +964 -0
  160. package/src/components/ui/ticket-info-section.tsx +1 -1
  161. package/src/stories/ChatMessageEnhanced.stories.tsx +48 -1
  162. package/src/utils/index.ts +0 -1
  163. package/src/utils/markdown-section-extractor.ts +56 -41
  164. package/dist/chat-protocol/decode.d.ts +0 -58
  165. package/dist/chat-protocol/decode.d.ts.map +0 -1
  166. package/dist/chat-protocol/encode.d.ts +0 -44
  167. package/dist/chat-protocol/encode.d.ts.map +0 -1
  168. package/dist/chat-protocol/env-flag.d.ts +0 -35
  169. package/dist/chat-protocol/env-flag.d.ts.map +0 -1
  170. package/dist/chat-protocol/events.d.ts +0 -196
  171. package/dist/chat-protocol/events.d.ts.map +0 -1
  172. package/dist/chat-protocol/frames.d.ts +0 -213
  173. package/dist/chat-protocol/frames.d.ts.map +0 -1
  174. package/dist/chat-protocol/index.cjs +0 -494
  175. package/dist/chat-protocol/index.cjs.map +0 -1
  176. package/dist/chat-protocol/index.d.ts +0 -18
  177. package/dist/chat-protocol/index.d.ts.map +0 -1
  178. package/dist/chat-protocol/index.js +0 -478
  179. package/dist/chat-protocol/index.js.map +0 -1
  180. package/dist/chat-protocol/ip-normalize.d.ts +0 -44
  181. package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
  182. package/dist/chat-protocol/nats-decoder.d.ts +0 -26
  183. package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
  184. package/dist/chunk-5LMGFI4J.cjs.map +0 -1
  185. package/dist/chunk-BE6DK7QY.js.map +0 -1
  186. package/dist/chunk-Q6E7VJ4W.cjs.map +0 -1
  187. package/dist/chunk-T2EGSZFN.js.map +0 -1
  188. package/dist/chunk-TKN5667N.js.map +0 -1
  189. package/dist/chunk-YHOIAA2E.cjs.map +0 -1
  190. package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
  191. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
  192. package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
  193. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
  194. package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
  195. package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
  196. package/dist/components/chat/stream/index.d.ts +0 -17
  197. package/dist/components/chat/stream/index.d.ts.map +0 -1
  198. package/dist/components/chat/stream/message-mutations.d.ts +0 -77
  199. package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
  200. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
  201. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
  202. package/dist/components/ui/markdown/base-components.d.ts +0 -51
  203. package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
  204. package/dist/components/ui/markdown/engine.d.ts +0 -99
  205. package/dist/components/ui/markdown/engine.d.ts.map +0 -1
  206. package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
  207. package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
  208. package/dist/components/ui/markdown/index.d.ts +0 -18
  209. package/dist/components/ui/markdown/index.d.ts.map +0 -1
  210. package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
  211. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
  212. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
  213. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
  214. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
  215. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
  216. package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
  217. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
  218. package/dist/components/ui/markdown/sanitize.d.ts +0 -153
  219. package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
  220. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
  221. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
  222. package/dist/components/ui/markdown/streaming.d.ts +0 -78
  223. package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
  224. package/dist/components/ui/markdown/text-size.d.ts +0 -34
  225. package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
  226. package/dist/utils/markdown-fences.d.ts +0 -42
  227. package/dist/utils/markdown-fences.d.ts.map +0 -1
  228. package/dist/utils/markdown-heading-id.d.ts +0 -85
  229. package/dist/utils/markdown-heading-id.d.ts.map +0 -1
  230. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -307
  231. package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -516
  232. package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
  233. package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
  234. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -228
  235. package/src/chat-protocol/decode.ts +0 -278
  236. package/src/chat-protocol/encode.ts +0 -71
  237. package/src/chat-protocol/env-flag.ts +0 -39
  238. package/src/chat-protocol/events.ts +0 -232
  239. package/src/chat-protocol/frames.ts +0 -245
  240. package/src/chat-protocol/index.ts +0 -21
  241. package/src/chat-protocol/ip-normalize.ts +0 -146
  242. package/src/chat-protocol/nats-decoder.ts +0 -252
  243. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
  244. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -209
  245. package/src/components/chat/hooks/__tests__/__snapshots__/conversation-id-persistence-golden.test.ts.snap +0 -37
  246. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  247. package/src/components/chat/hooks/__tests__/conversation-id-persistence-golden.test.ts +0 -438
  248. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
  249. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -940
  250. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -756
  251. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -460
  252. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -894
  253. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
  254. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -98
  255. package/src/components/chat/stream/chat-dialog-store.ts +0 -536
  256. package/src/components/chat/stream/chat-stream-reducer.ts +0 -1796
  257. package/src/components/chat/stream/delta-batcher.ts +0 -159
  258. package/src/components/chat/stream/index.ts +0 -55
  259. package/src/components/chat/stream/message-mutations.ts +0 -338
  260. package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
  261. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -420
  262. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -605
  263. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -317
  264. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
  265. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
  266. package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2528
  267. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -115
  268. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -95
  269. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -309
  270. package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -388
  271. package/src/components/ui/markdown/base-components.tsx +0 -360
  272. package/src/components/ui/markdown/engine.tsx +0 -315
  273. package/src/components/ui/markdown/heading-ids.ts +0 -239
  274. package/src/components/ui/markdown/index.ts +0 -49
  275. package/src/components/ui/markdown/mermaid-diagram.tsx +0 -291
  276. package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
  277. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
  278. package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
  279. package/src/components/ui/markdown/sanitize.ts +0 -3499
  280. package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
  281. package/src/components/ui/markdown/streaming.ts +0 -362
  282. package/src/components/ui/markdown/text-size.ts +0 -106
  283. package/src/utils/markdown-fences.ts +0 -127
  284. package/src/utils/markdown-heading-id.ts +0 -348
  285. /package/dist/{chunk-GTWO5NAY.js.map → chunk-6CFFISUC.js.map} +0 -0
  286. /package/dist/{chunk-VHG6AX5V.js.map → chunk-6CJ2K7BD.js.map} +0 -0
  287. /package/dist/{chunk-4NWARV5I.js.map → chunk-6QK3ONDD.js.map} +0 -0
  288. /package/dist/{chunk-CORIBKHG.js.map → chunk-EGXCWZYP.js.map} +0 -0
  289. /package/dist/{chunk-HSACATCD.js.map → chunk-MPYDX5WX.js.map} +0 -0
  290. /package/dist/{chunk-RQLBHKXN.js.map → chunk-NGEFYPY7.js.map} +0 -0
  291. /package/dist/{chunk-YZ2OIYQ3.js.map → chunk-VDZO6IDR.js.map} +0 -0
  292. /package/dist/{chunk-UUYRJPGJ.js.map → chunk-VL2YMDPH.js.map} +0 -0
  293. /package/dist/{chunk-XQ2B74SI.js.map → chunk-WLM3F3WU.js.map} +0 -0
@@ -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
@@ -139,6 +139,22 @@ export class MessageSegmentAccumulator {
139
139
  return this.getSegments()
140
140
  }
141
141
 
142
+ /**
143
+ * Append guide text to the current message.
144
+ * If the last segment is guide, append to it; otherwise start a new guide segment.
145
+ */
146
+ appendGuide(text: string): MessageSegment[] {
147
+ const lastSegment = this.segments[this.segments.length - 1]
148
+
149
+ if (lastSegment && lastSegment.type === 'guide') {
150
+ this.segments[this.segments.length - 1] = { type: 'guide', text: lastSegment.text + text }
151
+ } else {
152
+ this.segments.push({ type: 'guide', text })
153
+ }
154
+
155
+ return this.getSegments()
156
+ }
157
+
142
158
  /**
143
159
  * Add a tool execution segment.
144
160
  *
@@ -516,6 +532,9 @@ export class MessageSegmentAccumulator {
516
532
  case 'thinking':
517
533
  if (segment.text) this.appendThinking(segment.text)
518
534
  break
535
+ case 'guide':
536
+ if (segment.text) this.appendGuide(segment.text)
537
+ break
519
538
  case 'tool_execution':
520
539
  this.addToolExecution(segment)
521
540
  break