@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.
- package/dist/{chunk-BLZZXZNM.cjs → chunk-5USSSRAL.cjs} +26 -26
- package/dist/{chunk-BLZZXZNM.cjs.map → chunk-5USSSRAL.cjs.map} +1 -1
- package/dist/{chunk-CGNDAJ7V.js → chunk-6B27O3ZB.js} +4 -4
- package/dist/{chunk-P5JQDFRM.cjs → chunk-7IRPMNRL.cjs} +60 -60
- package/dist/chunk-7IRPMNRL.cjs.map +1 -0
- package/dist/{chunk-4XDWNAZW.cjs → chunk-DQ3EHM6G.cjs} +9 -9
- package/dist/{chunk-4XDWNAZW.cjs.map → chunk-DQ3EHM6G.cjs.map} +1 -1
- package/dist/{chunk-7KSEINAE.cjs → chunk-FTXDIDNX.cjs} +15 -15
- package/dist/{chunk-7KSEINAE.cjs.map → chunk-FTXDIDNX.cjs.map} +1 -1
- package/dist/{chunk-4R6H2U77.js → chunk-H7ETLG65.js} +4 -4
- package/dist/{chunk-LAOO7XHO.js → chunk-HWTUVLYB.js} +2 -2
- package/dist/{chunk-F2NMWV44.js → chunk-IDKDOQZL.js} +2 -2
- package/dist/{chunk-BQ7PMWLM.cjs → chunk-KIIOBK7G.cjs} +27 -28
- package/dist/chunk-KIIOBK7G.cjs.map +1 -0
- package/dist/{chunk-QO2XD3FR.js → chunk-KQGFKG6Y.js} +2 -2
- package/dist/{chunk-3N3TMZ62.cjs → chunk-L676XVP4.cjs} +7 -7
- package/dist/{chunk-3N3TMZ62.cjs.map → chunk-L676XVP4.cjs.map} +1 -1
- package/dist/{chunk-F7F43U7Q.cjs → chunk-LDAOPWXZ.cjs} +11 -11
- package/dist/{chunk-F7F43U7Q.cjs.map → chunk-LDAOPWXZ.cjs.map} +1 -1
- package/dist/{chunk-ADD3FPDG.cjs → chunk-MKLP2SOZ.cjs} +4886 -7004
- package/dist/chunk-MKLP2SOZ.cjs.map +1 -0
- package/dist/{chunk-VXJH5TDN.js → chunk-QL7ODLJA.js} +10 -10
- package/dist/chunk-QL7ODLJA.js.map +1 -0
- package/dist/{chunk-OR5AMXYN.js → chunk-R5QYMUKN.js} +2 -2
- package/dist/{chunk-REWRUV3K.js → chunk-TNLFAJPA.js} +9673 -11791
- package/dist/chunk-TNLFAJPA.js.map +1 -0
- package/dist/{chunk-XF5ROTMQ.js → chunk-U2YDR5DT.js} +2 -2
- package/dist/{chunk-PXZ7YQ5V.cjs → chunk-VTQSB6QB.cjs} +5 -5
- package/dist/{chunk-PXZ7YQ5V.cjs.map → chunk-VTQSB6QB.cjs.map} +1 -1
- package/dist/{chunk-UI7CIUAR.js → chunk-WGJPTFRH.js} +2 -2
- package/dist/{chunk-WCE66C2Z.cjs → chunk-XUNJILJT.cjs} +62 -62
- package/dist/{chunk-WCE66C2Z.cjs.map → chunk-XUNJILJT.cjs.map} +1 -1
- package/dist/{chunk-APF5QBAU.js → chunk-YQBPIUZU.js} +2 -2
- package/dist/{chunk-TA7MFVUS.cjs → chunk-YV2YA3QH.cjs} +31 -31
- package/dist/{chunk-TA7MFVUS.cjs.map → chunk-YV2YA3QH.cjs.map} +1 -1
- package/dist/{chunk-QSGZE6AZ.cjs → chunk-ZDJ4ZUQ4.cjs} +37 -37
- package/dist/{chunk-QSGZE6AZ.cjs.map → chunk-ZDJ4ZUQ4.cjs.map} +1 -1
- package/dist/{chunk-LJKZIIK4.js → chunk-ZHQQRYMB.js} +5 -6
- package/dist/chunk-ZHQQRYMB.js.map +1 -0
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chart.d.ts +1 -1
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/hooks/index.d.ts +1 -0
- package/dist/components/chat/hooks/index.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +48 -15
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +6 -0
- package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +47 -3
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -10
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.d.ts +0 -1
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +13 -21
- package/dist/components/chat/types/api.types.d.ts +81 -1
- package/dist/components/chat/types/api.types.d.ts.map +1 -1
- package/dist/components/chat/types/processing.types.d.ts +90 -2
- package/dist/components/chat/types/processing.types.d.ts.map +1 -1
- package/dist/components/chat/utils/chunk-parser.d.ts +25 -0
- package/dist/components/chat/utils/chunk-parser.d.ts.map +1 -0
- package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +6 -34
- package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
- package/dist/components/chat/utils/index.d.ts +3 -2
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts +11 -59
- package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/help-center-pages/index.cjs +20 -20
- package/dist/components/help-center-pages/index.js +11 -11
- package/dist/components/index.cjs +129 -171
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +21 -63
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/index.cjs +2 -44
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +2 -1
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +13 -55
- package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
- package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
- package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
- package/dist/index.cjs +2 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -71
- package/dist/utils/index.cjs +40 -169
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +41 -162
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
- package/package.json +1 -7
- package/src/components/chat/__tests__/chat-message-list.test.tsx +5 -293
- package/src/components/chat/chat-message-enhanced.tsx +17 -111
- package/src/components/chat/chat-message-list.tsx +113 -367
- package/src/components/chat/embeddable-chat.tsx +0 -6
- package/src/components/chat/hooks/.index.md +1 -1
- package/src/components/chat/hooks/.use-nats-chat-adapter.md +1 -1
- package/src/components/chat/hooks/.use-realtime-chunk-processor.md +50 -0
- package/src/components/chat/hooks/index.ts +1 -0
- package/src/components/chat/hooks/use-chat.ts +0 -8
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +822 -243
- package/src/components/chat/hooks/use-realtime-chunk-processor.ts +479 -0
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +666 -318
- package/src/components/chat/index.ts +0 -5
- package/src/components/chat/thinking-display.tsx +1 -1
- package/src/components/chat/types/.api.types.md +3 -1
- package/src/components/chat/types/.processing.types.md +23 -6
- package/src/components/chat/types/api.types.ts +73 -6
- package/src/components/chat/types/processing.types.ts +52 -11
- package/src/components/chat/utils/.chunk-parser.md +51 -0
- package/src/components/chat/utils/.index.md +5 -0
- package/src/components/chat/utils/chunk-parser.ts +255 -0
- package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
- package/src/components/chat/utils/index.ts +8 -5
- package/src/components/chat/utils/process-historical-messages.ts +383 -352
- package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
- package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
- package/src/components/shared/product-release/release-detail-page.tsx +4 -19
- package/src/components/ui/.simple-markdown-renderer.md +40 -0
- package/src/components/ui/index.ts +2 -1
- package/src/components/ui/release-changelog-section.tsx +1 -1
- package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
- package/src/components/ui/simple-markdown-renderer.tsx +965 -0
- package/src/components/ui/ticket-info-section.tsx +1 -1
- package/src/utils/index.ts +0 -1
- package/src/utils/markdown-section-extractor.ts +56 -41
- package/dist/chat-protocol/decode.d.ts +0 -58
- package/dist/chat-protocol/decode.d.ts.map +0 -1
- package/dist/chat-protocol/encode.d.ts +0 -44
- package/dist/chat-protocol/encode.d.ts.map +0 -1
- package/dist/chat-protocol/env-flag.d.ts +0 -35
- package/dist/chat-protocol/env-flag.d.ts.map +0 -1
- package/dist/chat-protocol/events.d.ts +0 -192
- package/dist/chat-protocol/events.d.ts.map +0 -1
- package/dist/chat-protocol/frames.d.ts +0 -206
- package/dist/chat-protocol/frames.d.ts.map +0 -1
- package/dist/chat-protocol/index.cjs +0 -493
- package/dist/chat-protocol/index.cjs.map +0 -1
- package/dist/chat-protocol/index.d.ts +0 -18
- package/dist/chat-protocol/index.d.ts.map +0 -1
- package/dist/chat-protocol/index.js +0 -477
- package/dist/chat-protocol/index.js.map +0 -1
- package/dist/chat-protocol/ip-normalize.d.ts +0 -44
- package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
- package/dist/chat-protocol/nats-decoder.d.ts +0 -26
- package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
- package/dist/chunk-ADD3FPDG.cjs.map +0 -1
- package/dist/chunk-BQ7PMWLM.cjs.map +0 -1
- package/dist/chunk-LJKZIIK4.js.map +0 -1
- package/dist/chunk-P5JQDFRM.cjs.map +0 -1
- package/dist/chunk-REWRUV3K.js.map +0 -1
- package/dist/chunk-VXJH5TDN.js.map +0 -1
- package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
- package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
- package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
- package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
- package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
- package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
- package/dist/components/chat/stream/index.d.ts +0 -17
- package/dist/components/chat/stream/index.d.ts.map +0 -1
- package/dist/components/chat/stream/message-mutations.d.ts +0 -77
- package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
- package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
- package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
- package/dist/components/ui/markdown/base-components.d.ts +0 -56
- package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
- package/dist/components/ui/markdown/engine.d.ts +0 -99
- package/dist/components/ui/markdown/engine.d.ts.map +0 -1
- package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
- package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
- package/dist/components/ui/markdown/index.d.ts +0 -18
- package/dist/components/ui/markdown/index.d.ts.map +0 -1
- package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
- package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
- package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
- package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
- package/dist/components/ui/markdown/sanitize.d.ts +0 -153
- package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
- package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
- package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
- package/dist/components/ui/markdown/streaming.d.ts +0 -78
- package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
- package/dist/components/ui/markdown/text-size.d.ts +0 -34
- package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
- package/dist/utils/markdown-fences.d.ts +0 -42
- package/dist/utils/markdown-fences.d.ts.map +0 -1
- package/dist/utils/markdown-heading-id.d.ts +0 -85
- package/dist/utils/markdown-heading-id.d.ts.map +0 -1
- package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -307
- package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -515
- package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
- package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
- package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -228
- package/src/chat-protocol/decode.ts +0 -277
- package/src/chat-protocol/encode.ts +0 -71
- package/src/chat-protocol/env-flag.ts +0 -39
- package/src/chat-protocol/events.ts +0 -228
- package/src/chat-protocol/frames.ts +0 -238
- package/src/chat-protocol/index.ts +0 -21
- package/src/chat-protocol/ip-normalize.ts +0 -146
- package/src/chat-protocol/nats-decoder.ts +0 -252
- package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
- package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -209
- package/src/components/chat/hooks/__tests__/__snapshots__/persisted-state-v1-golden.test.ts.snap +0 -297
- package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
- package/src/components/chat/hooks/__tests__/persisted-state-v1-golden.test.ts +0 -272
- package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
- package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -937
- package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -756
- package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -460
- package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -894
- package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
- package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -98
- package/src/components/chat/stream/chat-dialog-store.ts +0 -536
- package/src/components/chat/stream/chat-stream-reducer.ts +0 -1796
- package/src/components/chat/stream/delta-batcher.ts +0 -159
- package/src/components/chat/stream/index.ts +0 -55
- package/src/components/chat/stream/message-mutations.ts +0 -338
- package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
- package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -418
- package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -599
- package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -317
- package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
- package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
- package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2528
- package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -115
- package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -95
- package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -309
- package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -388
- package/src/components/ui/markdown/base-components.tsx +0 -341
- package/src/components/ui/markdown/engine.tsx +0 -315
- package/src/components/ui/markdown/heading-ids.ts +0 -239
- package/src/components/ui/markdown/index.ts +0 -49
- package/src/components/ui/markdown/mermaid-diagram.tsx +0 -291
- package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
- package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
- package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
- package/src/components/ui/markdown/sanitize.ts +0 -3499
- package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
- package/src/components/ui/markdown/streaming.ts +0 -362
- package/src/components/ui/markdown/text-size.ts +0 -106
- package/src/utils/markdown-fences.ts +0 -127
- package/src/utils/markdown-heading-id.ts +0 -348
- /package/dist/{chunk-CGNDAJ7V.js.map → chunk-6B27O3ZB.js.map} +0 -0
- /package/dist/{chunk-4R6H2U77.js.map → chunk-H7ETLG65.js.map} +0 -0
- /package/dist/{chunk-LAOO7XHO.js.map → chunk-HWTUVLYB.js.map} +0 -0
- /package/dist/{chunk-F2NMWV44.js.map → chunk-IDKDOQZL.js.map} +0 -0
- /package/dist/{chunk-QO2XD3FR.js.map → chunk-KQGFKG6Y.js.map} +0 -0
- /package/dist/{chunk-OR5AMXYN.js.map → chunk-R5QYMUKN.js.map} +0 -0
- /package/dist/{chunk-XF5ROTMQ.js.map → chunk-U2YDR5DT.js.map} +0 -0
- /package/dist/{chunk-UI7CIUAR.js.map → chunk-WGJPTFRH.js.map} +0 -0
- /package/dist/{chunk-APF5QBAU.js.map → chunk-YQBPIUZU.js.map} +0 -0
|
@@ -74,11 +74,6 @@ export * from './types'
|
|
|
74
74
|
// Chat hooks
|
|
75
75
|
export * from './hooks'
|
|
76
76
|
|
|
77
|
-
// Chat stream module — master reducer + dialog store + React wrapper
|
|
78
|
-
// (Phase 3 of the chat unification; ONE accumulation path for SSE + NATS
|
|
79
|
-
// + history replay).
|
|
80
|
-
export * from './stream'
|
|
81
|
-
|
|
82
77
|
// Chat utilities
|
|
83
78
|
export * from './utils'
|
|
84
79
|
|
|
@@ -4,7 +4,7 @@ import { forwardRef, useState } from "react"
|
|
|
4
4
|
|
|
5
5
|
import { cn } from "../../utils/cn"
|
|
6
6
|
import { DotsLoaderIcon } from "../icons-v2-generated"
|
|
7
|
-
import { SimpleMarkdownRenderer } from "../ui/
|
|
7
|
+
import { SimpleMarkdownRenderer } from "../ui/simple-markdown-renderer"
|
|
8
8
|
import { ExpandChevron } from "./expand-chevron"
|
|
9
9
|
import { useCollapsible } from "./hooks/use-collapsible"
|
|
10
10
|
import type { ThinkingDisplayProps } from "./types"
|
|
@@ -9,6 +9,7 @@ Defines TypeScript interfaces for API interactions and React hook contracts used
|
|
|
9
9
|
| `UseChunkCatchupOptions` | Configure chunk catch-up replay with optional custom fetch function |
|
|
10
10
|
| `UseNatsDialogSubscriptionOptions` | Core NATS WebSocket subscription config with reconnection backoff tuning |
|
|
11
11
|
| `UseJetStreamDialogSubscriptionOptions` | JetStream-based subscription with sequence-based resume support |
|
|
12
|
+
| `UseRealtimeChunkProcessorOptions` | Controls how streaming chunks are parsed, including approval routing and batch mode |
|
|
12
13
|
|
|
13
14
|
### Hook Return Types
|
|
14
15
|
| Interface | Purpose |
|
|
@@ -16,6 +17,7 @@ Defines TypeScript interfaces for API interactions and React hook contracts used
|
|
|
16
17
|
| `UseChunkCatchupReturn` | Exposes catchup, processing, and buffering controls |
|
|
17
18
|
| `UseNatsDialogSubscriptionReturn` | Connection state and reconnection counter |
|
|
18
19
|
| `UseJetStreamDialogSubscriptionReturn` | Connection state plus current stream sequence |
|
|
20
|
+
| `UseRealtimeChunkProcessorReturn` | Chunk processing, segment access, and approval status management |
|
|
19
21
|
|
|
20
22
|
### Callbacks
|
|
21
23
|
- **`RealtimeChunkCallbacks`** — Rich event callback map for streaming events: `onStreamStart`, `onStreamEnd`, `onSegmentsUpdate`, `onTokenUsage`, `onApprove`, `onReject`, `onEscalatedApproval`, `onApprovalResolved`, `onToolExecuted`, `onDialogClosed`, and more.
|
|
@@ -29,7 +31,7 @@ Defines TypeScript interfaces for API interactions and React hook contracts used
|
|
|
29
31
|
## Usage Example
|
|
30
32
|
|
|
31
33
|
```typescript
|
|
32
|
-
const options:
|
|
34
|
+
const options: UseRealtimeChunkProcessorOptions = {
|
|
33
35
|
callbacks: {
|
|
34
36
|
onSegmentsUpdate: (segments, meta) => {
|
|
35
37
|
if (meta?.append) appendToLastMessage(segments)
|
|
@@ -5,9 +5,13 @@ Defines TypeScript types for message processing pipeline operations, including c
|
|
|
5
5
|
|
|
6
6
|
| Export | Type | Description |
|
|
7
7
|
|--------|------|-------------|
|
|
8
|
+
| `ParsedChunkAction` | Union type | Discriminated union of all possible chunk parse results (text, tool execution, approvals, metadata, etc.) |
|
|
8
9
|
| `AccumulatorState` | Interface | Stateful container tracking message segments, pending approvals, and executing tools during stream processing |
|
|
9
10
|
| `PendingApproval` | Interface | Represents an approval request awaiting user action (command, explanation, type) |
|
|
10
11
|
| `MessageProcessingOptions` | Interface | Configuration for assistant rendering, approval callbacks, chat filtering, and batch approval UI |
|
|
12
|
+
| `ChunkProcessor` | Interface | Contract for processing raw `ChunkData` into `ParsedChunkAction` results |
|
|
13
|
+
| `ChunkProcessorOptions` | Interface | Lifecycle callbacks for chunk processing events |
|
|
14
|
+
| `MessageTransformer` | Interface | Contract for transforming raw inputs into `ProcessedMessage` objects |
|
|
11
15
|
| `StreamProcessor` | Interface | Full lifecycle control (start/stop/pause/resume/reset) for stream consumers |
|
|
12
16
|
| `StreamState` | Interface | Snapshot of stream health: active status, buffered chunks, error log, and last activity timestamp |
|
|
13
17
|
| `BufferManager` | Interface | CRUD-style contract for managing `ChunkData` buffers |
|
|
@@ -17,11 +21,29 @@ Defines TypeScript types for message processing pipeline operations, including c
|
|
|
17
21
|
|
|
18
22
|
```typescript
|
|
19
23
|
import type {
|
|
24
|
+
ParsedChunkAction,
|
|
20
25
|
AccumulatorState,
|
|
21
26
|
MessageProcessingOptions,
|
|
22
27
|
StreamState
|
|
23
28
|
} from './processing.types'
|
|
24
29
|
|
|
30
|
+
// Handling a parsed chunk action via discriminated union
|
|
31
|
+
function handleChunkAction(action: ParsedChunkAction): void {
|
|
32
|
+
switch (action.action) {
|
|
33
|
+
case 'text':
|
|
34
|
+
console.log('Received text:', action.text)
|
|
35
|
+
break
|
|
36
|
+
case 'tool_execution':
|
|
37
|
+
console.log('Tool executing:', action.segment)
|
|
38
|
+
break
|
|
39
|
+
case 'approval_batch':
|
|
40
|
+
console.log('Batch approval request:', action.requestId, action.toolCalls)
|
|
41
|
+
break
|
|
42
|
+
case 'error':
|
|
43
|
+
console.error('Processing error:', action.error, action.details)
|
|
44
|
+
break
|
|
45
|
+
}
|
|
46
|
+
}
|
|
25
47
|
|
|
26
48
|
// Initializing accumulator state
|
|
27
49
|
const state: AccumulatorState = {
|
|
@@ -43,9 +65,4 @@ const options: MessageProcessingOptions = {
|
|
|
43
65
|
logRejection(requestId)
|
|
44
66
|
}
|
|
45
67
|
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
> NOTE: the wire-chunk vocabulary now lives in `src/chat-protocol/events.ts`
|
|
49
|
-
> (`ChatStreamEvent`, produced by `decodeNatsChunk`). The old
|
|
50
|
-
> `ParsedChunkAction` union and the `ChunkProcessor` contract were deleted
|
|
51
|
-
> together with the legacy `chunk-parser`.
|
|
68
|
+
```
|
|
@@ -213,12 +213,79 @@ export interface RealtimeChunkCallbacks {
|
|
|
213
213
|
onDialogClosed?: () => void
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
216
|
+
export interface UseRealtimeChunkProcessorOptions {
|
|
217
|
+
callbacks: RealtimeChunkCallbacks
|
|
218
|
+
/**
|
|
219
|
+
* Filter approval types that should be displayed directly
|
|
220
|
+
* Others will trigger onEscalatedApproval
|
|
221
|
+
* Default: ['CLIENT']
|
|
222
|
+
*/
|
|
223
|
+
displayApprovalTypes?: string[]
|
|
224
|
+
/**
|
|
225
|
+
* Map of existing approval statuses
|
|
226
|
+
*/
|
|
227
|
+
approvalStatuses?: Record<string, ChatApprovalStatus>
|
|
228
|
+
/**
|
|
229
|
+
* Initialize accumulator with existing state from incomplete historical message
|
|
230
|
+
* Used to continue building messages across page refreshes or reconnections
|
|
231
|
+
*/
|
|
232
|
+
initialState?: {
|
|
233
|
+
/** Existing segments to continue building upon */
|
|
234
|
+
existingSegments?: MessageSegment[]
|
|
235
|
+
/** Pending approvals that haven't been resolved */
|
|
236
|
+
pendingApprovals?: Map<string, { command: string; explanation?: string; approvalType: string }>
|
|
237
|
+
/** Executing tools waiting for completion */
|
|
238
|
+
executingTools?: Map<string, ExecutingToolState>
|
|
239
|
+
/** Escalated approvals */
|
|
240
|
+
escalatedApprovals?: Map<
|
|
241
|
+
string,
|
|
242
|
+
{ command: string; explanation?: string; approvalType: string; toolCalls?: PendingToolCallData[] }
|
|
243
|
+
>
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Consumer-owned (e.g. set in `openframe-oss-tenant` chat client via the
|
|
247
|
+
* `'batch-approvals'` feature flag and forwarded here). The lib does NOT
|
|
248
|
+
* default this to a batch-on behavior — when omitted it falls back to the
|
|
249
|
+
* legacy single-card rendering.
|
|
250
|
+
*
|
|
251
|
+
* When true: `APPROVAL_REQUEST` chunks containing `toolCalls[]` are rendered
|
|
252
|
+
* as a single batch card. When false / omitted: the batch is split into N
|
|
253
|
+
* legacy approval cards (one per tool that requires approval), all sharing
|
|
254
|
+
* the same `approvalRequestId`. Tools with `requiresApproval=false` are
|
|
255
|
+
* dropped from the UI in the unfolded mode.
|
|
256
|
+
*/
|
|
257
|
+
batchApprovalsEnabled?: boolean
|
|
258
|
+
/**
|
|
259
|
+
* Engages the direct-mode barrier optimistically: once true, all AI-assistant
|
|
260
|
+
* chunks (text, thinking, tool executions, approvals, metadata, errors, etc.)
|
|
261
|
+
* are dropped and any open stream is torn down, leaving only human/control
|
|
262
|
+
* messages. A `DIRECT_MESSAGE` chunk engages the same barrier automatically
|
|
263
|
+
* regardless of this flag. Pass this from a host that already knows the dialog
|
|
264
|
+
* switched to direct mode (e.g. an optimistic mode toggle) to close the race
|
|
265
|
+
* window before the server emits the first `DIRECT_MESSAGE`.
|
|
266
|
+
*
|
|
267
|
+
* Do NOT set this when the host reconstructs history by replaying chunks
|
|
268
|
+
* through `processChunk` — a static flag would drop legitimate pre-switch AI
|
|
269
|
+
* history. Rely on the in-order `DIRECT_MESSAGE` detection instead.
|
|
270
|
+
*/
|
|
271
|
+
isDirectMode?: boolean
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export interface UseRealtimeChunkProcessorReturn {
|
|
275
|
+
/** Process a single chunk */
|
|
276
|
+
processChunk: (chunk: unknown) => void
|
|
277
|
+
/** Get current segments */
|
|
278
|
+
getSegments: () => MessageSegment[]
|
|
279
|
+
/** Reset the accumulator */
|
|
280
|
+
reset: () => void
|
|
281
|
+
/** Update approval status for a request */
|
|
282
|
+
updateApprovalStatus: (requestId: string, status: ChatApprovalStatus, resolvedByName?: string | null) => MessageSegment[]
|
|
283
|
+
/** Get pending approval requests */
|
|
284
|
+
getPendingApprovals: () => Map<
|
|
285
|
+
string,
|
|
286
|
+
{ command: string; explanation?: string; approvalType: string; toolCalls?: PendingToolCallData[] }
|
|
287
|
+
>
|
|
288
|
+
}
|
|
222
289
|
|
|
223
290
|
// ========== API Request Types ==========
|
|
224
291
|
|
|
@@ -3,14 +3,37 @@
|
|
|
3
3
|
* Contains types for message parsing, accumulation, and processing
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { MessageSegment, PendingToolCallData, ExecutingToolState } from './message.types'
|
|
6
|
+
import type { MessageSegment, ProcessedMessage, ToolExecutionSegment, TokenUsageData, PendingToolCallData, ExecutingToolState } from './message.types'
|
|
7
7
|
import type { ChatApprovalStatus, AssistantType } from './chat.types'
|
|
8
|
-
import type { ChunkData } from './network.types'
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
import type { ChunkData, NatsMessageType } from './network.types'
|
|
9
|
+
|
|
10
|
+
// ========== Parsed Chunk Result Types ==========
|
|
11
|
+
|
|
12
|
+
export type ParsedChunkAction =
|
|
13
|
+
| { action: 'message_start' }
|
|
14
|
+
| { action: 'message_end' }
|
|
15
|
+
| { action: 'error'; error: string; details?: string }
|
|
16
|
+
| { action: 'metadata'; modelDisplayName: string; modelName: string; providerName: string; contextWindow: number }
|
|
17
|
+
| { action: 'text'; text: string }
|
|
18
|
+
| { action: 'thinking'; text: string }
|
|
19
|
+
| { action: 'tool_execution'; segment: ToolExecutionSegment }
|
|
20
|
+
| { action: 'approval_request'; requestId: string; command: string; explanation?: string; approvalType: string }
|
|
21
|
+
| { action: 'approval_batch'; requestId: string; approvalType: string; toolCalls: PendingToolCallData[] }
|
|
22
|
+
| { action: 'approval_result'; requestId: string; approved: boolean; approvalType: string; resolvedByName?: string | null }
|
|
23
|
+
| {
|
|
24
|
+
action: 'message_request'
|
|
25
|
+
text: string
|
|
26
|
+
ownerType?: string
|
|
27
|
+
displayName?: string
|
|
28
|
+
userId?: string
|
|
29
|
+
contextItems?: Array<{ type: string; id: string }>
|
|
30
|
+
}
|
|
31
|
+
| { action: 'token_usage'; data: TokenUsageData }
|
|
32
|
+
| { action: 'direct_message'; text: string; ownerType?: string; displayName?: string; userId?: string }
|
|
33
|
+
| { action: 'system'; text: string }
|
|
34
|
+
| { action: 'context_compaction_start' }
|
|
35
|
+
| { action: 'context_compaction_end'; summary?: string }
|
|
36
|
+
| { action: 'dialog_closed' }
|
|
14
37
|
|
|
15
38
|
// ========== Accumulator State ==========
|
|
16
39
|
|
|
@@ -58,13 +81,31 @@ export interface MessageProcessingOptions {
|
|
|
58
81
|
batchApprovalsEnabled?: boolean
|
|
59
82
|
}
|
|
60
83
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
84
|
+
// ========== Chunk Processing Types ==========
|
|
85
|
+
|
|
86
|
+
export interface ChunkProcessor {
|
|
87
|
+
processChunk: (chunk: ChunkData, messageType: NatsMessageType) => ParsedChunkAction | null
|
|
88
|
+
reset: () => void
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ChunkProcessorOptions {
|
|
92
|
+
onMessageStart?: () => void
|
|
93
|
+
onMessageEnd?: () => void
|
|
94
|
+
onError?: (error: string, details?: string) => void
|
|
95
|
+
onText?: (text: string) => void
|
|
96
|
+
onToolExecution?: (segment: MessageSegment) => void
|
|
97
|
+
onApprovalRequest?: (data: any) => void
|
|
98
|
+
onApprovalResult?: (data: any) => void
|
|
99
|
+
onMetadata?: (data: any) => void
|
|
100
|
+
}
|
|
65
101
|
|
|
66
102
|
// ========== Message Transformation Types ==========
|
|
67
103
|
|
|
104
|
+
export interface MessageTransformer {
|
|
105
|
+
transform: (input: any) => ProcessedMessage | null
|
|
106
|
+
batch: (inputs: any[]) => ProcessedMessage[]
|
|
107
|
+
}
|
|
108
|
+
|
|
68
109
|
export interface TransformationOptions {
|
|
69
110
|
preserveOriginal?: boolean
|
|
70
111
|
mergeSegments?: boolean
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!-- source-hash: 637d22f77dbdb02b04013632095ddfdb -->
|
|
2
|
+
Utilities for parsing raw NATS message chunks into typed, structured action objects consumed by the AI message pipeline.
|
|
3
|
+
|
|
4
|
+
## Key Components
|
|
5
|
+
|
|
6
|
+
### `parseChunkToAction(chunk)`
|
|
7
|
+
Core export that maps a raw `ChunkData` object to a `ParsedChunkAction` union type. Uses a `switch` on `MESSAGE_TYPE` to handle all supported message variants:
|
|
8
|
+
|
|
9
|
+
| Action | Description |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `message_start` / `message_end` | Lifecycle control signals |
|
|
12
|
+
| `metadata` | AI model/provider info |
|
|
13
|
+
| `text` / `thinking` / `system` | Content streaming |
|
|
14
|
+
| `tool_execution` | Tool start/completion events |
|
|
15
|
+
| `approval_request` / `approval_batch` | Single or multi-tool approval flows |
|
|
16
|
+
| `approval_result` | Approval outcome |
|
|
17
|
+
| `token_usage` | Token consumption stats |
|
|
18
|
+
| `context_compaction_start/end` | Context window management |
|
|
19
|
+
| `direct_message` | Owner-attributed messages |
|
|
20
|
+
| `dialog_closed` | Session termination |
|
|
21
|
+
|
|
22
|
+
Returns `null` for unknown or malformed chunks.
|
|
23
|
+
|
|
24
|
+
### `normalizeToolCalls(raw)` *(internal)*
|
|
25
|
+
Coerces an unknown array into `PendingToolCallData[]`, safely defaulting missing fields and enforcing correct types.
|
|
26
|
+
|
|
27
|
+
### Guard Helpers
|
|
28
|
+
Lightweight boolean checks for common chunk classifications:
|
|
29
|
+
|
|
30
|
+
- `isControlChunk(chunk)` — start/end signals
|
|
31
|
+
- `isErrorChunk(chunk)` — error type
|
|
32
|
+
- `isMetadataChunk(chunk)` — AI metadata
|
|
33
|
+
- `extractTextFromChunk(chunk)` — returns text content or `null`
|
|
34
|
+
|
|
35
|
+
## Usage Example
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { parseChunkToAction, isErrorChunk } from './chunk-parser'
|
|
39
|
+
|
|
40
|
+
// Incoming NATS message payload
|
|
41
|
+
const raw = { type: 'TEXT', text: 'Hello from Mingo AI' }
|
|
42
|
+
|
|
43
|
+
if (isErrorChunk(raw)) {
|
|
44
|
+
console.error('Stream error received')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const action = parseChunkToAction(raw)
|
|
48
|
+
if (action?.action === 'text') {
|
|
49
|
+
renderText(action.text) // "Hello from Mingo AI"
|
|
50
|
+
}
|
|
51
|
+
```
|
|
@@ -5,6 +5,7 @@ Barrel export module that consolidates and re-exports all message processing, ch
|
|
|
5
5
|
|
|
6
6
|
| Category | Exports |
|
|
7
7
|
|----------|---------|
|
|
8
|
+
| **Chunk Parsing** | `parseChunkToAction`, `isControlChunk`, `isErrorChunk`, `isMetadataChunk`, `extractTextFromChunk` |
|
|
8
9
|
| **Message Accumulation** | `MessageSegmentAccumulator`, `createMessageSegmentAccumulator`, `AccumulatorCallbacks` |
|
|
9
10
|
| **Historical Messages** | `processHistoricalMessages`, `extractErrorMessages`, `processHistoricalMessagesWithErrors` |
|
|
10
11
|
| **Chat Navigation** | `handleChatNavClick`, `resolveExternalNavigation`, `decideNewTab`, `computeIsNewTab`, `buildAnchorProps` |
|
|
@@ -19,6 +20,7 @@ Barrel export module that consolidates and re-exports all message processing, ch
|
|
|
19
20
|
|
|
20
21
|
```typescript
|
|
21
22
|
import {
|
|
23
|
+
parseChunkToAction,
|
|
22
24
|
createMessageSegmentAccumulator,
|
|
23
25
|
handleChatNavClick,
|
|
24
26
|
getChatProxyAuth,
|
|
@@ -28,6 +30,9 @@ import {
|
|
|
28
30
|
getStatusColorScheme,
|
|
29
31
|
} from '@flamingo/chat-utils'
|
|
30
32
|
|
|
33
|
+
// Parse a streaming chunk from the AI response
|
|
34
|
+
const action = parseChunkToAction(rawChunk)
|
|
35
|
+
|
|
31
36
|
// Accumulate streamed message segments
|
|
32
37
|
const accumulator = createMessageSegmentAccumulator({
|
|
33
38
|
onSegmentComplete: (segment) => console.log('Segment:', segment),
|
|
@@ -0,0 +1,255 @@
|
|
|
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.EXECUTING_TOOL:
|
|
69
|
+
return {
|
|
70
|
+
action: 'tool_execution',
|
|
71
|
+
segment: {
|
|
72
|
+
type: 'tool_execution',
|
|
73
|
+
data: {
|
|
74
|
+
type: 'EXECUTING_TOOL',
|
|
75
|
+
integratedToolType: data.integratedToolType || '',
|
|
76
|
+
toolFunction: data.toolFunction || '',
|
|
77
|
+
toolTitle: typeof data.title === 'string' ? data.title : undefined,
|
|
78
|
+
parameters: data.parameters,
|
|
79
|
+
toolExecutionRequestId: typeof data.toolExecutionRequestId === 'string' ? data.toolExecutionRequestId : undefined,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
case MESSAGE_TYPE.EXECUTED_TOOL:
|
|
85
|
+
return {
|
|
86
|
+
action: 'tool_execution',
|
|
87
|
+
segment: {
|
|
88
|
+
type: 'tool_execution',
|
|
89
|
+
data: {
|
|
90
|
+
type: 'EXECUTED_TOOL',
|
|
91
|
+
integratedToolType: data.integratedToolType || '',
|
|
92
|
+
toolFunction: data.toolFunction || '',
|
|
93
|
+
toolTitle: typeof data.title === 'string' ? data.title : undefined,
|
|
94
|
+
parameters: data.parameters,
|
|
95
|
+
result: data.result,
|
|
96
|
+
success: data.success,
|
|
97
|
+
toolExecutionRequestId: typeof data.toolExecutionRequestId === 'string' ? data.toolExecutionRequestId : undefined,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case MESSAGE_TYPE.APPROVAL_REQUEST: {
|
|
103
|
+
const requestId = data.approvalRequestId || data.approval_request_id || ''
|
|
104
|
+
const approvalType = data.approvalType || 'USER'
|
|
105
|
+
const toolCalls = normalizeToolCalls(data.toolCalls)
|
|
106
|
+
|
|
107
|
+
if (toolCalls.length > 0) {
|
|
108
|
+
return {
|
|
109
|
+
action: 'approval_batch',
|
|
110
|
+
requestId,
|
|
111
|
+
approvalType,
|
|
112
|
+
toolCalls,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
action: 'approval_request',
|
|
118
|
+
requestId,
|
|
119
|
+
command: data.command || '',
|
|
120
|
+
explanation: data.explanation,
|
|
121
|
+
approvalType,
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
case MESSAGE_TYPE.APPROVAL_RESULT: {
|
|
126
|
+
// The realtime NATS chunk carries the resolver's name as `displayName`; the
|
|
127
|
+
// persisted GraphQL message exposes the same value as `resolvedByName`. Accept
|
|
128
|
+
// either so realtime and history-replay render "by {name}" identically.
|
|
129
|
+
const resolvedByName =
|
|
130
|
+
typeof data.resolvedByName === 'string'
|
|
131
|
+
? data.resolvedByName
|
|
132
|
+
: typeof data.displayName === 'string'
|
|
133
|
+
? data.displayName
|
|
134
|
+
: undefined
|
|
135
|
+
return {
|
|
136
|
+
action: 'approval_result',
|
|
137
|
+
requestId: data.approvalRequestId || data.approval_request_id || '',
|
|
138
|
+
approved: data.approved === true,
|
|
139
|
+
approvalType: data.approvalType || 'CLIENT',
|
|
140
|
+
resolvedByName,
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
case MESSAGE_TYPE.ERROR:
|
|
145
|
+
return {
|
|
146
|
+
action: 'error',
|
|
147
|
+
error: data.error || 'An error occurred',
|
|
148
|
+
details: data.details,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
case MESSAGE_TYPE.MESSAGE_REQUEST:
|
|
152
|
+
return {
|
|
153
|
+
action: 'message_request',
|
|
154
|
+
text: String(data.text || ''),
|
|
155
|
+
ownerType: typeof data.ownerType === 'string' ? data.ownerType : undefined,
|
|
156
|
+
displayName: typeof data.displayName === 'string' ? data.displayName : undefined,
|
|
157
|
+
userId: typeof data.userId === 'string' ? data.userId : undefined,
|
|
158
|
+
// Entity-context refs the user attached to this message (backend
|
|
159
|
+
// `MESSAGE_REQUEST` chunk → `contextItems: [{ type, id }]`). The wire
|
|
160
|
+
// shape carries no label; the host resolves display text + icon. `label`
|
|
161
|
+
// is REQUIRED on `ChatContextItem`, so fall back to the id (same as the
|
|
162
|
+
// historical path in `process-historical-messages.ts`) — keeps both
|
|
163
|
+
// message sources producing an identical shape.
|
|
164
|
+
contextItems: Array.isArray(data.contextItems)
|
|
165
|
+
? (data.contextItems as Array<{ type?: unknown; id?: unknown }>)
|
|
166
|
+
.filter((it) => typeof it?.type === 'string' && typeof it?.id === 'string')
|
|
167
|
+
.map((it) => ({ type: it.type as string, id: it.id as string, label: it.id as string }))
|
|
168
|
+
: undefined,
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
case MESSAGE_TYPE.TOKEN_USAGE:
|
|
172
|
+
return {
|
|
173
|
+
action: 'token_usage',
|
|
174
|
+
data: {
|
|
175
|
+
inputTokensSize: data.inputTokensSize ?? 0,
|
|
176
|
+
outputTokensSize: data.outputTokensSize ?? 0,
|
|
177
|
+
totalTokensSize: data.totalTokensSize ?? 0,
|
|
178
|
+
contextSize: data.contextSize ?? 0,
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
case MESSAGE_TYPE.CONTEXT_COMPACTION_START:
|
|
183
|
+
return { action: 'context_compaction_start' }
|
|
184
|
+
|
|
185
|
+
case MESSAGE_TYPE.CONTEXT_COMPACTION_END:
|
|
186
|
+
return {
|
|
187
|
+
action: 'context_compaction_end',
|
|
188
|
+
summary: typeof data.text === 'string' ? data.text : undefined,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
case MESSAGE_TYPE.SYSTEM:
|
|
192
|
+
if (typeof data.text === 'string') {
|
|
193
|
+
return { action: 'system', text: data.text }
|
|
194
|
+
}
|
|
195
|
+
return null
|
|
196
|
+
|
|
197
|
+
case MESSAGE_TYPE.DIRECT_MESSAGE:
|
|
198
|
+
if (typeof data.text === 'string') {
|
|
199
|
+
return {
|
|
200
|
+
action: 'direct_message',
|
|
201
|
+
text: data.text,
|
|
202
|
+
ownerType: typeof data.ownerType === 'string' ? data.ownerType : undefined,
|
|
203
|
+
displayName: typeof data.displayName === 'string' ? data.displayName : undefined,
|
|
204
|
+
userId: typeof data.userId === 'string' ? data.userId : undefined,
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return null
|
|
208
|
+
|
|
209
|
+
case MESSAGE_TYPE.DIALOG_CLOSED:
|
|
210
|
+
return { action: 'dialog_closed' }
|
|
211
|
+
|
|
212
|
+
default:
|
|
213
|
+
return null
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Check if a chunk represents a control message (start/end)
|
|
219
|
+
*/
|
|
220
|
+
export function isControlChunk(chunk: unknown): boolean {
|
|
221
|
+
if (!chunk || typeof chunk !== 'object') return false
|
|
222
|
+
const data = chunk as ChunkData
|
|
223
|
+
const type = String(data.type || '')
|
|
224
|
+
return type === MESSAGE_TYPE.MESSAGE_START || type === MESSAGE_TYPE.MESSAGE_END
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Check if a chunk represents an error
|
|
229
|
+
*/
|
|
230
|
+
export function isErrorChunk(chunk: unknown): boolean {
|
|
231
|
+
if (!chunk || typeof chunk !== 'object') return false
|
|
232
|
+
const data = chunk as ChunkData
|
|
233
|
+
return data.type === MESSAGE_TYPE.ERROR
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Check if a chunk represents metadata
|
|
238
|
+
*/
|
|
239
|
+
export function isMetadataChunk(chunk: unknown): boolean {
|
|
240
|
+
if (!chunk || typeof chunk !== 'object') return false
|
|
241
|
+
const data = chunk as ChunkData
|
|
242
|
+
return data.type === MESSAGE_TYPE.AI_METADATA
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Extract text content from a chunk if it's a text chunk
|
|
247
|
+
*/
|
|
248
|
+
export function extractTextFromChunk(chunk: unknown): string | null {
|
|
249
|
+
if (!chunk || typeof chunk !== 'object') return null
|
|
250
|
+
const data = chunk as ChunkData
|
|
251
|
+
if (data.type === MESSAGE_TYPE.TEXT && typeof data.text === 'string') {
|
|
252
|
+
return data.text
|
|
253
|
+
}
|
|
254
|
+
return null
|
|
255
|
+
}
|