@flamingo-stack/openframe-frontend-core 0.0.508 → 0.0.509
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/chat-protocol/decode.d.ts +58 -0
- package/dist/chat-protocol/decode.d.ts.map +1 -0
- package/dist/chat-protocol/encode.d.ts +44 -0
- package/dist/chat-protocol/encode.d.ts.map +1 -0
- package/dist/chat-protocol/env-flag.d.ts +35 -0
- package/dist/chat-protocol/env-flag.d.ts.map +1 -0
- package/dist/chat-protocol/events.d.ts +216 -0
- package/dist/chat-protocol/events.d.ts.map +1 -0
- package/dist/chat-protocol/frames.d.ts +213 -0
- package/dist/chat-protocol/frames.d.ts.map +1 -0
- package/dist/chat-protocol/index.cjs +506 -0
- package/dist/chat-protocol/index.cjs.map +1 -0
- package/dist/chat-protocol/index.d.ts +18 -0
- package/dist/chat-protocol/index.d.ts.map +1 -0
- package/dist/chat-protocol/index.js +490 -0
- package/dist/chat-protocol/index.js.map +1 -0
- package/dist/chat-protocol/ip-normalize.d.ts +44 -0
- package/dist/chat-protocol/ip-normalize.d.ts.map +1 -0
- package/dist/chat-protocol/nats-decoder.d.ts +26 -0
- package/dist/chat-protocol/nats-decoder.d.ts.map +1 -0
- package/dist/{chunk-3SQ5KXHQ.cjs → chunk-2T4GTV25.cjs} +9 -9
- package/dist/{chunk-3SQ5KXHQ.cjs.map → chunk-2T4GTV25.cjs.map} +1 -1
- package/dist/{chunk-CWAOV2FK.cjs → chunk-3CGZPAGR.cjs} +3 -3
- package/dist/{chunk-CWAOV2FK.cjs.map → chunk-3CGZPAGR.cjs.map} +1 -1
- package/dist/{chunk-TLMJHMXJ.js → chunk-3QSR22IC.js} +12 -12
- package/dist/chunk-3QSR22IC.js.map +1 -0
- package/dist/{chunk-TWYNR4TZ.cjs → chunk-4G5TLHJD.cjs} +7141 -4799
- package/dist/chunk-4G5TLHJD.cjs.map +1 -0
- package/dist/{chunk-ADPMHWOE.js → chunk-72XAID7Y.js} +4 -4
- package/dist/{chunk-PAGKRNWK.js → chunk-7WZHBQ4J.js} +2 -2
- package/dist/{chunk-OCEKO5CW.js → chunk-AEELJC4N.js} +12106 -9764
- package/dist/chunk-AEELJC4N.js.map +1 -0
- package/dist/{chunk-Z42BGM6Q.cjs → chunk-BT2WWDFP.cjs} +5 -5
- package/dist/{chunk-Z42BGM6Q.cjs.map → chunk-BT2WWDFP.cjs.map} +1 -1
- package/dist/{chunk-7LEL3RIX.cjs → chunk-C7OY3PQP.cjs} +11 -11
- package/dist/{chunk-7LEL3RIX.cjs.map → chunk-C7OY3PQP.cjs.map} +1 -1
- package/dist/{chunk-RHGGEKPQ.cjs → chunk-CIOLOQKQ.cjs} +4 -4
- package/dist/{chunk-RHGGEKPQ.cjs.map → chunk-CIOLOQKQ.cjs.map} +1 -1
- package/dist/{chunk-TSZHM74B.js → chunk-DC2TKS7C.js} +2 -2
- package/dist/{chunk-M2GOR3XQ.cjs → chunk-DYPYR7FR.cjs} +87 -87
- package/dist/{chunk-M2GOR3XQ.cjs.map → chunk-DYPYR7FR.cjs.map} +1 -1
- package/dist/{chunk-I64ABCDX.js → chunk-I2B6X77L.js} +2 -2
- package/dist/{chunk-NIZDKTGL.cjs → chunk-K5MSCMDK.cjs} +37 -37
- package/dist/{chunk-NIZDKTGL.cjs.map → chunk-K5MSCMDK.cjs.map} +1 -1
- package/dist/{chunk-DTYRYB2N.js → chunk-K6QTZ7CZ.js} +2 -2
- package/dist/{chunk-4LTMXDUS.js → chunk-KBN7PMFT.js} +2 -2
- package/dist/{chunk-TBMV7I5N.js → chunk-KXZO2WZX.js} +2 -2
- package/dist/{chunk-QTYZMP6D.cjs → chunk-LBAKLT6T.cjs} +62 -62
- package/dist/chunk-LBAKLT6T.cjs.map +1 -0
- package/dist/{chunk-KEBYLU3U.js → chunk-LFUPI7VX.js} +2 -2
- package/dist/{chunk-LDTR4IVZ.cjs → chunk-M37PBG4N.cjs} +31 -31
- package/dist/{chunk-LDTR4IVZ.cjs.map → chunk-M37PBG4N.cjs.map} +1 -1
- package/dist/{chunk-WA7RR64F.js → chunk-PO5O654H.js} +6 -5
- package/dist/chunk-PO5O654H.js.map +1 -0
- package/dist/{chunk-WK4N5VBX.cjs → chunk-QJJISLPA.cjs} +28 -27
- package/dist/chunk-QJJISLPA.cjs.map +1 -0
- package/dist/{chunk-2F44PLTV.cjs → chunk-T7MCSA55.cjs} +26 -26
- package/dist/{chunk-2F44PLTV.cjs.map → chunk-T7MCSA55.cjs.map} +1 -1
- package/dist/{chunk-WJQHJD7J.js → chunk-TWSKTJHW.js} +2 -2
- package/dist/{chunk-ZSQHZYCO.cjs → chunk-UQDMJ6DH.cjs} +13 -13
- package/dist/{chunk-ZSQHZYCO.cjs.map → chunk-UQDMJ6DH.cjs.map} +1 -1
- package/dist/{chunk-TZRUCD56.js → chunk-V3ZAAFE3.js} +5 -5
- package/dist/{chunk-LRGHJPET.js → chunk-XGIFOHKE.js} +2 -2
- package/dist/{chunk-POOMO3PA.cjs → chunk-YQEPRYT5.cjs} +7 -7
- package/dist/{chunk-POOMO3PA.cjs.map → chunk-YQEPRYT5.cjs.map} +1 -1
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- 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 +0 -1
- 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-chunk-catchup.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +15 -48
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +10 -57
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +10 -2
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.d.ts +1 -0
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +21 -13
- package/dist/components/chat/stream/chat-dialog-store.d.ts +184 -0
- package/dist/components/chat/stream/chat-dialog-store.d.ts.map +1 -0
- package/dist/components/chat/stream/chat-stream-reducer.d.ts +380 -0
- package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -0
- package/dist/components/chat/stream/delta-batcher.d.ts +51 -0
- package/dist/components/chat/stream/delta-batcher.d.ts.map +1 -0
- package/dist/components/chat/stream/index.d.ts +17 -0
- package/dist/components/chat/stream/index.d.ts.map +1 -0
- package/dist/components/chat/stream/message-mutations.d.ts +77 -0
- package/dist/components/chat/stream/message-mutations.d.ts.map +1 -0
- package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +22 -0
- package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +1 -0
- package/dist/components/chat/types/api.types.d.ts +1 -81
- package/dist/components/chat/types/api.types.d.ts.map +1 -1
- package/dist/components/chat/types/processing.types.d.ts +2 -93
- package/dist/components/chat/types/processing.types.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +15 -0
- package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
- package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +34 -6
- package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
- package/dist/components/chat/utils/history-merge.d.ts.map +1 -1
- package/dist/components/chat/utils/index.d.ts +2 -3
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts +59 -11
- 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 +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +174 -132
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +65 -23
- package/dist/components/index.js.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +34 -34
- package/dist/components/meeting-scheduler/index.js +3 -3
- 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 +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/index.cjs +44 -2
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +1 -2
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +55 -13
- package/dist/components/ui/markdown/base-components.d.ts +51 -0
- package/dist/components/ui/markdown/base-components.d.ts.map +1 -0
- package/dist/components/ui/markdown/engine.d.ts +99 -0
- package/dist/components/ui/markdown/engine.d.ts.map +1 -0
- package/dist/components/ui/markdown/heading-ids.d.ts +65 -0
- package/dist/components/ui/markdown/heading-ids.d.ts.map +1 -0
- package/dist/components/ui/markdown/index.d.ts +18 -0
- package/dist/components/ui/markdown/index.d.ts.map +1 -0
- package/dist/components/ui/markdown/mermaid-diagram.d.ts +79 -0
- package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +1 -0
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts +14 -0
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +1 -0
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +40 -0
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +1 -0
- package/dist/components/ui/markdown/rich/shortcodes.d.ts +8 -0
- package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +1 -0
- package/dist/components/ui/markdown/sanitize.d.ts +153 -0
- package/dist/components/ui/markdown/sanitize.d.ts.map +1 -0
- package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +23 -0
- package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +1 -0
- package/dist/components/ui/markdown/streaming.d.ts +78 -0
- package/dist/components/ui/markdown/streaming.d.ts.map +1 -0
- package/dist/components/ui/markdown/text-size.d.ts +34 -0
- package/dist/components/ui/markdown/text-size.d.ts.map +1 -0
- package/dist/index.cjs +60 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +71 -13
- package/dist/utils/index.cjs +169 -40
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +162 -41
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/markdown-fences.d.ts +42 -0
- package/dist/utils/markdown-fences.d.ts.map +1 -0
- package/dist/utils/markdown-heading-id.d.ts +85 -0
- package/dist/utils/markdown-heading-id.d.ts.map +1 -0
- package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
- package/package.json +7 -1
- package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +319 -0
- package/src/chat-protocol/__tests__/chat-protocol.test.ts +516 -0
- package/src/chat-protocol/__tests__/env-flag.test.ts +52 -0
- package/src/chat-protocol/__tests__/ip-normalize.test.ts +136 -0
- package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +237 -0
- package/src/chat-protocol/decode.ts +278 -0
- package/src/chat-protocol/encode.ts +71 -0
- package/src/chat-protocol/env-flag.ts +39 -0
- package/src/chat-protocol/events.ts +254 -0
- package/src/chat-protocol/frames.ts +245 -0
- package/src/chat-protocol/index.ts +21 -0
- package/src/chat-protocol/ip-normalize.ts +146 -0
- package/src/chat-protocol/nats-decoder.ts +264 -0
- package/src/components/chat/.chat-message-list.md +10 -6
- package/src/components/chat/__tests__/chat-message-list.test.tsx +450 -9
- package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +207 -0
- package/src/components/chat/__tests__/chat-pending-turn.test.tsx +250 -0
- package/src/components/chat/chat-message-enhanced.tsx +122 -20
- package/src/components/chat/chat-message-list.tsx +515 -133
- package/src/components/chat/embeddable-chat.tsx +6 -0
- package/src/components/chat/hooks/.index.md +30 -33
- package/src/components/chat/hooks/.use-nats-chat-adapter.md +36 -55
- package/src/components/chat/hooks/__tests__/__snapshots__/conversation-id-persistence-golden.test.ts.snap +37 -0
- package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
- package/src/components/chat/hooks/__tests__/chunk-catchup-dialog-staleness.test.ts +92 -0
- package/src/components/chat/hooks/__tests__/conversation-id-persistence-golden.test.ts +438 -0
- package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +318 -0
- package/src/components/chat/hooks/index.ts +0 -1
- package/src/components/chat/hooks/use-chat.ts +8 -0
- package/src/components/chat/hooks/use-chunk-catchup.ts +26 -1
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +254 -825
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +380 -684
- package/src/components/chat/index.ts +5 -0
- package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +944 -0
- package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +806 -0
- package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +467 -0
- package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +1330 -0
- package/src/components/chat/stream/__tests__/delta-batcher.test.ts +255 -0
- package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +105 -0
- package/src/components/chat/stream/chat-dialog-store.ts +536 -0
- package/src/components/chat/stream/chat-stream-reducer.ts +1928 -0
- package/src/components/chat/stream/delta-batcher.ts +168 -0
- package/src/components/chat/stream/index.ts +55 -0
- package/src/components/chat/stream/message-mutations.ts +340 -0
- package/src/components/chat/stream/use-chat-stream-reducer.ts +126 -0
- package/src/components/chat/thinking-display.tsx +1 -1
- package/src/components/chat/types/.api.types.md +39 -49
- package/src/components/chat/types/.processing.types.md +29 -58
- package/src/components/chat/types/.unified-chat-state.types.md +2 -2
- package/src/components/chat/types/api.types.ts +6 -73
- package/src/components/chat/types/processing.types.ts +11 -53
- package/src/components/chat/types/unified-chat-state.types.ts +16 -0
- package/src/components/chat/utils/.extract-incomplete-message-state.md +21 -3
- package/src/components/chat/utils/.history-merge.md +44 -3
- package/src/components/chat/utils/.index.md +31 -40
- package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +420 -0
- package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +605 -0
- package/src/components/chat/utils/__tests__/extract-incomplete-message-state.test.ts +106 -0
- package/src/components/chat/utils/__tests__/history-merge.test.ts +160 -0
- package/src/components/chat/utils/__tests__/process-historical-messages-approvals.test.ts +61 -0
- package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +394 -0
- package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +270 -0
- package/src/components/chat/utils/extract-incomplete-message-state.ts +93 -6
- package/src/components/chat/utils/history-merge.ts +85 -5
- package/src/components/chat/utils/index.ts +5 -8
- package/src/components/chat/utils/process-historical-messages.ts +361 -385
- package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +22 -4
- package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
- package/src/components/shared/product-release/release-detail-page.tsx +19 -4
- package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +2420 -0
- package/src/components/ui/__tests__/markdown-parity.test.tsx +2540 -0
- package/src/components/ui/index.ts +1 -2
- package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +176 -0
- package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +151 -0
- package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +354 -0
- package/src/components/ui/markdown/__tests__/sanitize-render.test.tsx +118 -0
- package/src/components/ui/markdown/__tests__/streaming.test.tsx +436 -0
- package/src/components/ui/markdown/base-components.tsx +360 -0
- package/src/components/ui/markdown/engine.tsx +315 -0
- package/src/components/ui/markdown/heading-ids.ts +239 -0
- package/src/components/ui/markdown/index.ts +49 -0
- package/src/components/ui/markdown/mermaid-diagram.tsx +323 -0
- package/src/components/ui/markdown/rich/embed-overrides.tsx +199 -0
- package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +184 -0
- package/src/components/ui/markdown/rich/shortcodes.ts +170 -0
- package/src/components/ui/markdown/sanitize.ts +3584 -0
- package/src/components/ui/markdown/simple-markdown-renderer.tsx +28 -0
- package/src/components/ui/markdown/streaming.ts +390 -0
- package/src/components/ui/markdown/text-size.ts +106 -0
- package/src/components/ui/release-changelog-section.tsx +1 -1
- package/src/components/ui/ticket-info-section.tsx +1 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/markdown-fences.ts +127 -0
- package/src/utils/markdown-heading-id.ts +348 -0
- package/src/utils/markdown-section-extractor.ts +41 -56
- package/dist/chunk-OCEKO5CW.js.map +0 -1
- package/dist/chunk-QTYZMP6D.cjs.map +0 -1
- package/dist/chunk-TLMJHMXJ.js.map +0 -1
- package/dist/chunk-TWYNR4TZ.cjs.map +0 -1
- package/dist/chunk-WA7RR64F.js.map +0 -1
- package/dist/chunk-WK4N5VBX.cjs.map +0 -1
- package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +0 -6
- package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +0 -1
- package/dist/components/chat/utils/chunk-parser.d.ts +0 -25
- package/dist/components/chat/utils/chunk-parser.d.ts.map +0 -1
- package/dist/components/ui/rich-markdown-renderer.d.ts +0 -34
- package/dist/components/ui/rich-markdown-renderer.d.ts.map +0 -1
- package/dist/components/ui/simple-markdown-renderer.d.ts +0 -73
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +0 -1
- package/src/components/chat/hooks/.use-realtime-chunk-processor.md +0 -77
- package/src/components/chat/hooks/use-realtime-chunk-processor.ts +0 -489
- package/src/components/chat/utils/.chunk-parser.md +0 -62
- package/src/components/chat/utils/chunk-parser.ts +0 -262
- package/src/components/ui/.simple-markdown-renderer.md +0 -52
- package/src/components/ui/rich-markdown-renderer.tsx +0 -1223
- package/src/components/ui/simple-markdown-renderer.tsx +0 -964
- /package/dist/{chunk-ADPMHWOE.js.map → chunk-72XAID7Y.js.map} +0 -0
- /package/dist/{chunk-PAGKRNWK.js.map → chunk-7WZHBQ4J.js.map} +0 -0
- /package/dist/{chunk-TSZHM74B.js.map → chunk-DC2TKS7C.js.map} +0 -0
- /package/dist/{chunk-I64ABCDX.js.map → chunk-I2B6X77L.js.map} +0 -0
- /package/dist/{chunk-DTYRYB2N.js.map → chunk-K6QTZ7CZ.js.map} +0 -0
- /package/dist/{chunk-4LTMXDUS.js.map → chunk-KBN7PMFT.js.map} +0 -0
- /package/dist/{chunk-TBMV7I5N.js.map → chunk-KXZO2WZX.js.map} +0 -0
- /package/dist/{chunk-KEBYLU3U.js.map → chunk-LFUPI7VX.js.map} +0 -0
- /package/dist/{chunk-WJQHJD7J.js.map → chunk-TWSKTJHW.js.map} +0 -0
- /package/dist/{chunk-TZRUCD56.js.map → chunk-V3ZAAFE3.js.map} +0 -0
- /package/dist/{chunk-LRGHJPET.js.map → chunk-XGIFOHKE.js.map} +0 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GOLDEN CHARACTERIZATION TESTS — the NATS kernel of
|
|
3
|
+
* `createChatStreamReducer`, driven through `decodeNatsChunk`.
|
|
4
|
+
*
|
|
5
|
+
* Originally written against the `useRealtimeChunkProcessor` compat hook
|
|
6
|
+
* (Phase 0 of the chat unification). That wrapper was deleted once every
|
|
7
|
+
* consumer moved to the reducer; the behavioral spec it pinned is far too
|
|
8
|
+
* valuable to lose, so the suite was RETARGETED at the reducer itself. The
|
|
9
|
+
* recorded snapshots are byte-identical to the wrapper-era ones — the only
|
|
10
|
+
* thing that changed is who dispatches the effects.
|
|
11
|
+
*
|
|
12
|
+
* `dispatch()` below replicates the deleted wrapper's effect→callback
|
|
13
|
+
* forwarding verbatim (including the `segments-after-approval-result`
|
|
14
|
+
* conditional), so the logs remain a 1:1 record of the legacy
|
|
15
|
+
* `RealtimeChunkCallbacks` contract. Do NOT "fix" behaviors captured here.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { describe, it, expect } from 'vitest'
|
|
19
|
+
import { decodeNatsChunk } from '../../../../chat-protocol/nats-decoder'
|
|
20
|
+
import {
|
|
21
|
+
createChatStreamReducer,
|
|
22
|
+
type ChatStreamReducer,
|
|
23
|
+
type InitializeExtras,
|
|
24
|
+
} from '../chat-stream-reducer'
|
|
25
|
+
import type { ChatApprovalStatus, RealtimeChunkCallbacks } from '../../types'
|
|
26
|
+
|
|
27
|
+
type EventLog = Array<Record<string, unknown>>
|
|
28
|
+
|
|
29
|
+
/** Build a full callback set that records every invocation into `log`. */
|
|
30
|
+
function makeRecordingCallbacks(log: EventLog): RealtimeChunkCallbacks {
|
|
31
|
+
return {
|
|
32
|
+
onStreamStart: () => log.push({ event: 'onStreamStart' }),
|
|
33
|
+
onStreamEnd: () => log.push({ event: 'onStreamEnd' }),
|
|
34
|
+
onMetadata: (metadata) => log.push({ event: 'onMetadata', metadata }),
|
|
35
|
+
onSegmentsUpdate: (segments, metadata) =>
|
|
36
|
+
log.push({ event: 'onSegmentsUpdate', segments, metadata }),
|
|
37
|
+
onError: (error, details) => log.push({ event: 'onError', error, details }),
|
|
38
|
+
onUserMessage: (text, metadata) => log.push({ event: 'onUserMessage', text, metadata }),
|
|
39
|
+
onTokenUsage: (data) => log.push({ event: 'onTokenUsage', data }),
|
|
40
|
+
onDirectMessage: (text, metadata) => log.push({ event: 'onDirectMessage', text, metadata }),
|
|
41
|
+
onSystemMessage: (text, metadata) => log.push({ event: 'onSystemMessage', text, metadata }),
|
|
42
|
+
// Block bodies, not concise ones: `log.push` returns a number, so a
|
|
43
|
+
// concise async arrow is `() => Promise<number>` and does not satisfy the
|
|
44
|
+
// declared `(requestId?: string) => void | Promise<void>`.
|
|
45
|
+
onApprove: async () => {
|
|
46
|
+
log.push({ event: 'onApprove' })
|
|
47
|
+
},
|
|
48
|
+
onReject: async () => {
|
|
49
|
+
log.push({ event: 'onReject' })
|
|
50
|
+
},
|
|
51
|
+
onEscalatedApproval: (requestId, data) =>
|
|
52
|
+
log.push({ event: 'onEscalatedApproval', requestId, data }),
|
|
53
|
+
onEscalatedApprovalResult: (requestId, approved, data) =>
|
|
54
|
+
log.push({ event: 'onEscalatedApprovalResult', requestId, approved, data }),
|
|
55
|
+
onApprovalResolved: (requestId, status, approvalType, resolvedByName) =>
|
|
56
|
+
log.push({ event: 'onApprovalResolved', requestId, status, approvalType, resolvedByName }),
|
|
57
|
+
onToolExecuted: (segment) => log.push({ event: 'onToolExecuted', segment }),
|
|
58
|
+
onAgentBusy: () => log.push({ event: 'onAgentBusy' }),
|
|
59
|
+
onDialogClosed: () => log.push({ event: 'onDialogClosed' }),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface SetupOptions {
|
|
64
|
+
callbacks?: RealtimeChunkCallbacks
|
|
65
|
+
batchApprovalsEnabled?: boolean
|
|
66
|
+
displayApprovalTypes?: string[]
|
|
67
|
+
approvalStatuses?: Record<string, ChatApprovalStatus>
|
|
68
|
+
isDirectMode?: boolean
|
|
69
|
+
initialState?: InitializeExtras
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function setup(options: SetupOptions = {}) {
|
|
73
|
+
const log: EventLog = []
|
|
74
|
+
const callbacks = options.callbacks ?? makeRecordingCallbacks(log)
|
|
75
|
+
|
|
76
|
+
const reducer: ChatStreamReducer = createChatStreamReducer({
|
|
77
|
+
transport: 'nats',
|
|
78
|
+
batchApprovalsEnabled: options.batchApprovalsEnabled,
|
|
79
|
+
displayApprovalTypes: options.displayApprovalTypes,
|
|
80
|
+
approvalStatuses: options.approvalStatuses,
|
|
81
|
+
isDirectMode: options.isDirectMode,
|
|
82
|
+
crossMessageToolRouting: !!callbacks.onToolExecuted,
|
|
83
|
+
callbacks: {
|
|
84
|
+
onApprove: (id) => callbacks.onApprove?.(id),
|
|
85
|
+
onReject: (id) => callbacks.onReject?.(id),
|
|
86
|
+
},
|
|
87
|
+
onEffect: ({ name, args }) => {
|
|
88
|
+
const cbs = callbacks as Record<string, ((...a: unknown[]) => void) | undefined>
|
|
89
|
+
// Legacy conditional: the cumulative post-APPROVAL_RESULT emit fires
|
|
90
|
+
// only when the consumer did NOT wire onApprovalResolved.
|
|
91
|
+
if (name === 'segments-after-approval-result') {
|
|
92
|
+
if (!cbs.onApprovalResolved) cbs.onSegmentsUpdate?.(...args)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
cbs[name]?.(...args)
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// The wrapper initialized from `initialState` in a mount effect.
|
|
100
|
+
if (options.initialState) reducer.initializeWithState(null, options.initialState)
|
|
101
|
+
|
|
102
|
+
const feed = (chunks: unknown[]) => {
|
|
103
|
+
for (const chunk of chunks) {
|
|
104
|
+
const event = decodeNatsChunk(chunk)
|
|
105
|
+
if (event) reducer.apply(event)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { log, reducer, feed }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const EXECUTING = {
|
|
112
|
+
type: 'EXECUTING_TOOL',
|
|
113
|
+
integratedToolType: 'TACTICAL_RMM',
|
|
114
|
+
toolFunction: 'run_script',
|
|
115
|
+
title: 'Run cleanup script',
|
|
116
|
+
parameters: { script: 'cleanup.sh' },
|
|
117
|
+
toolExecutionRequestId: 'exec-1',
|
|
118
|
+
}
|
|
119
|
+
const EXECUTED = {
|
|
120
|
+
type: 'EXECUTED_TOOL',
|
|
121
|
+
integratedToolType: 'TACTICAL_RMM',
|
|
122
|
+
toolFunction: 'run_script',
|
|
123
|
+
result: 'Freed 2.3 GB',
|
|
124
|
+
success: true,
|
|
125
|
+
toolExecutionRequestId: 'exec-1',
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
describe('chat stream reducer — legacy chunk-processor golden event logs', () => {
|
|
129
|
+
it('normal turn: start → metadata → text ×3 → token usage → end', () => {
|
|
130
|
+
const { log, feed } = setup()
|
|
131
|
+
feed([
|
|
132
|
+
{ type: 'MESSAGE_START' },
|
|
133
|
+
{
|
|
134
|
+
type: 'AI_METADATA',
|
|
135
|
+
modelDisplayName: 'Claude Sonnet',
|
|
136
|
+
modelName: 'claude-sonnet-x',
|
|
137
|
+
providerName: 'anthropic',
|
|
138
|
+
contextWindow: 200000,
|
|
139
|
+
},
|
|
140
|
+
{ type: 'TEXT', text: 'Hello' },
|
|
141
|
+
{ type: 'TEXT', text: ', ' },
|
|
142
|
+
{ type: 'TEXT', text: 'world' },
|
|
143
|
+
{
|
|
144
|
+
type: 'TOKEN_USAGE',
|
|
145
|
+
inputTokensSize: 100,
|
|
146
|
+
outputTokensSize: 20,
|
|
147
|
+
totalTokensSize: 120,
|
|
148
|
+
contextSize: 180000,
|
|
149
|
+
},
|
|
150
|
+
{ type: 'MESSAGE_END' },
|
|
151
|
+
])
|
|
152
|
+
expect(log).toMatchSnapshot()
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('streamSeq on content chunks is threaded into onSegmentsUpdate metadata', () => {
|
|
156
|
+
const { log, feed } = setup()
|
|
157
|
+
feed([
|
|
158
|
+
{ type: 'MESSAGE_START' },
|
|
159
|
+
{ type: 'TEXT', text: 'seq-stamped', streamSeq: 7 },
|
|
160
|
+
{ type: 'MESSAGE_END' },
|
|
161
|
+
])
|
|
162
|
+
expect(log).toMatchSnapshot()
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('cold start (no MESSAGE_START ever): text emits CUMULATIVE segments (no append flag)', () => {
|
|
166
|
+
const { log, feed } = setup()
|
|
167
|
+
feed([
|
|
168
|
+
{ type: 'TEXT', text: 'cold ' },
|
|
169
|
+
{ type: 'TEXT', text: 'start' },
|
|
170
|
+
])
|
|
171
|
+
expect(log).toMatchSnapshot()
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('post-MESSAGE_END continuation: text/thinking emit DELTA segments with append:true', () => {
|
|
175
|
+
const { log, feed } = setup()
|
|
176
|
+
feed([
|
|
177
|
+
{ type: 'MESSAGE_START' },
|
|
178
|
+
{ type: 'TEXT', text: 'in-stream' },
|
|
179
|
+
{ type: 'MESSAGE_END' },
|
|
180
|
+
{ type: 'TEXT', text: 'post-end text' },
|
|
181
|
+
{ type: 'THINKING', text: 'post-end thinking' },
|
|
182
|
+
])
|
|
183
|
+
expect(log).toMatchSnapshot()
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('tool execution OUTSIDE a message window: onAgentBusy + cross-message onToolExecuted (accumulator skipped)', () => {
|
|
187
|
+
const { log, feed } = setup()
|
|
188
|
+
// No MESSAGE_START — approved commands execute between the approval
|
|
189
|
+
// bubble's MESSAGE_END and the continuation stream.
|
|
190
|
+
feed([EXECUTING, EXECUTED])
|
|
191
|
+
expect(log).toMatchSnapshot()
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('tool execution IN-stream: accumulator-driven segment updates, onToolExecuted NOT fired', () => {
|
|
195
|
+
const { log, feed } = setup()
|
|
196
|
+
feed([
|
|
197
|
+
{ type: 'MESSAGE_START' },
|
|
198
|
+
{ type: 'TEXT', text: 'Running now. ' },
|
|
199
|
+
EXECUTING,
|
|
200
|
+
EXECUTED,
|
|
201
|
+
{ type: 'MESSAGE_END' },
|
|
202
|
+
])
|
|
203
|
+
expect(log).toMatchSnapshot()
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('approval request (displayed) → approval result: in-message flip + onApprovalResolved', () => {
|
|
207
|
+
const { log, feed } = setup()
|
|
208
|
+
feed([
|
|
209
|
+
{ type: 'MESSAGE_START' },
|
|
210
|
+
{
|
|
211
|
+
type: 'APPROVAL_REQUEST',
|
|
212
|
+
approvalRequestId: 'req-1',
|
|
213
|
+
approvalType: 'CLIENT',
|
|
214
|
+
command: 'systemctl restart nats',
|
|
215
|
+
explanation: 'Restart the broker',
|
|
216
|
+
},
|
|
217
|
+
{ type: 'MESSAGE_END' },
|
|
218
|
+
{
|
|
219
|
+
type: 'APPROVAL_RESULT',
|
|
220
|
+
approvalRequestId: 'req-1',
|
|
221
|
+
approved: true,
|
|
222
|
+
approvalType: 'CLIENT',
|
|
223
|
+
displayName: 'Jane Admin',
|
|
224
|
+
},
|
|
225
|
+
])
|
|
226
|
+
// CHARACTERIZATION: because onApprovalResolved IS wired, the result
|
|
227
|
+
// does NOT emit onSegmentsUpdate — only the cross-message callback.
|
|
228
|
+
expect(log).toMatchSnapshot()
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('approval result WITHOUT onApprovalResolved wired: emits cumulative onSegmentsUpdate instead', () => {
|
|
232
|
+
const log: EventLog = []
|
|
233
|
+
const callbacks = makeRecordingCallbacks(log)
|
|
234
|
+
delete callbacks.onApprovalResolved
|
|
235
|
+
const { feed } = setup({ callbacks })
|
|
236
|
+
feed([
|
|
237
|
+
{ type: 'MESSAGE_START' },
|
|
238
|
+
{
|
|
239
|
+
type: 'APPROVAL_REQUEST',
|
|
240
|
+
approvalRequestId: 'req-1',
|
|
241
|
+
approvalType: 'CLIENT',
|
|
242
|
+
command: 'reboot',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
type: 'APPROVAL_RESULT',
|
|
246
|
+
approvalRequestId: 'req-1',
|
|
247
|
+
approved: false,
|
|
248
|
+
approvalType: 'CLIENT',
|
|
249
|
+
},
|
|
250
|
+
])
|
|
251
|
+
expect(log).toMatchSnapshot()
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it('escalated approval (type not displayed) → onEscalatedApproval, then result appends resolved card', () => {
|
|
255
|
+
const { log, feed, reducer } = setup() // displayApprovalTypes defaults to ['CLIENT']
|
|
256
|
+
feed([
|
|
257
|
+
{ type: 'MESSAGE_START' },
|
|
258
|
+
{
|
|
259
|
+
type: 'APPROVAL_REQUEST',
|
|
260
|
+
approvalRequestId: 'req-adm',
|
|
261
|
+
approvalType: 'ADMIN',
|
|
262
|
+
command: 'drop database prod',
|
|
263
|
+
},
|
|
264
|
+
{ type: 'MESSAGE_END' },
|
|
265
|
+
{
|
|
266
|
+
type: 'APPROVAL_RESULT',
|
|
267
|
+
approvalRequestId: 'req-adm',
|
|
268
|
+
approved: true,
|
|
269
|
+
approvalType: 'ADMIN',
|
|
270
|
+
},
|
|
271
|
+
])
|
|
272
|
+
expect({
|
|
273
|
+
log,
|
|
274
|
+
pendingAfter: Array.from(reducer.getPendingEscalated().entries()),
|
|
275
|
+
}).toMatchSnapshot()
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it('batch approval (batchApprovalsEnabled default ON): one batch segment, executions merge into it', () => {
|
|
279
|
+
const { log, feed } = setup()
|
|
280
|
+
feed([
|
|
281
|
+
{ type: 'MESSAGE_START' },
|
|
282
|
+
{
|
|
283
|
+
type: 'APPROVAL_REQUEST',
|
|
284
|
+
approvalRequestId: 'batch-1',
|
|
285
|
+
approvalType: 'CLIENT',
|
|
286
|
+
toolCalls: [
|
|
287
|
+
{
|
|
288
|
+
toolExecutionRequestId: 'exec-a',
|
|
289
|
+
toolName: 'create_ticket',
|
|
290
|
+
toolTitle: 'Create ticket',
|
|
291
|
+
requiresApproval: true,
|
|
292
|
+
approvalType: 'CLIENT',
|
|
293
|
+
toolCallArguments: { subject: 'Printer down' },
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
toolExecutionRequestId: 'exec-b',
|
|
297
|
+
toolName: 'read_kb',
|
|
298
|
+
requiresApproval: false,
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
type: 'APPROVAL_RESULT',
|
|
304
|
+
approvalRequestId: 'batch-1',
|
|
305
|
+
approved: true,
|
|
306
|
+
displayName: 'Alice Client',
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
type: 'EXECUTING_TOOL',
|
|
310
|
+
integratedToolType: 'PSA',
|
|
311
|
+
toolFunction: 'create_ticket',
|
|
312
|
+
toolExecutionRequestId: 'exec-a',
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
type: 'EXECUTED_TOOL',
|
|
316
|
+
integratedToolType: 'PSA',
|
|
317
|
+
toolFunction: 'create_ticket',
|
|
318
|
+
result: 'Ticket #77 created',
|
|
319
|
+
success: true,
|
|
320
|
+
toolExecutionRequestId: 'exec-a',
|
|
321
|
+
},
|
|
322
|
+
{ type: 'MESSAGE_END' },
|
|
323
|
+
])
|
|
324
|
+
expect(log).toMatchSnapshot()
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
it('batch approval with batchApprovalsEnabled:false unfolds into legacy cards (requiresApproval only)', () => {
|
|
328
|
+
const { log, feed } = setup({ batchApprovalsEnabled: false })
|
|
329
|
+
feed([
|
|
330
|
+
{ type: 'MESSAGE_START' },
|
|
331
|
+
{
|
|
332
|
+
type: 'APPROVAL_REQUEST',
|
|
333
|
+
approvalRequestId: 'batch-1',
|
|
334
|
+
approvalType: 'CLIENT',
|
|
335
|
+
toolCalls: [
|
|
336
|
+
{
|
|
337
|
+
toolExecutionRequestId: 'exec-a',
|
|
338
|
+
toolName: 'create_ticket',
|
|
339
|
+
toolTitle: 'Create ticket',
|
|
340
|
+
requiresApproval: true,
|
|
341
|
+
toolCallArguments: { subject: 'Printer down' },
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
toolExecutionRequestId: 'exec-b',
|
|
345
|
+
toolName: 'read_kb',
|
|
346
|
+
requiresApproval: false,
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
},
|
|
350
|
+
{ type: 'MESSAGE_END' },
|
|
351
|
+
])
|
|
352
|
+
expect(log).toMatchSnapshot()
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
it('CHARACTERIZATION duplicate/out-of-order: redelivered EXECUTING after EXECUTED in-stream appends a NEW executing segment (no dedup)', () => {
|
|
356
|
+
// The reducer does no duplicate suppression for standalone tool
|
|
357
|
+
// segments — dedup only exists inside approval batches (no-downgrade
|
|
358
|
+
// rule). Recording actual behavior, see unification plan.
|
|
359
|
+
const { log, feed } = setup()
|
|
360
|
+
feed([
|
|
361
|
+
{ type: 'MESSAGE_START' },
|
|
362
|
+
EXECUTING,
|
|
363
|
+
EXECUTED,
|
|
364
|
+
EXECUTING, // redelivered
|
|
365
|
+
{ type: 'MESSAGE_END' },
|
|
366
|
+
])
|
|
367
|
+
expect(log).toMatchSnapshot()
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
it('error chunk: segment append + onError with JSON-extracted message', () => {
|
|
371
|
+
const { log, feed } = setup()
|
|
372
|
+
feed([
|
|
373
|
+
{ type: 'MESSAGE_START' },
|
|
374
|
+
{ type: 'TEXT', text: 'partial' },
|
|
375
|
+
{ type: 'ERROR', error: 'Agent crashed', details: '{"error":{"message":"boom"}}' },
|
|
376
|
+
{ type: 'ERROR', error: 'Plain details', details: 'not-json' },
|
|
377
|
+
])
|
|
378
|
+
expect(log).toMatchSnapshot()
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
it('user echo / system / direct-message / dialog-closed routing', () => {
|
|
382
|
+
const { log, feed } = setup()
|
|
383
|
+
feed([
|
|
384
|
+
{
|
|
385
|
+
type: 'MESSAGE_REQUEST',
|
|
386
|
+
text: 'open a ticket',
|
|
387
|
+
ownerType: 'CLIENT',
|
|
388
|
+
displayName: 'Alice',
|
|
389
|
+
userId: 'user-42',
|
|
390
|
+
streamSeq: 3,
|
|
391
|
+
contextItems: [{ type: 'device', id: 'dev-1' }],
|
|
392
|
+
},
|
|
393
|
+
{ type: 'SYSTEM', text: 'User joined the chat', streamSeq: 4 },
|
|
394
|
+
{
|
|
395
|
+
type: 'DIRECT_MESSAGE',
|
|
396
|
+
text: 'Human here now',
|
|
397
|
+
ownerType: 'ADMIN',
|
|
398
|
+
displayName: 'Jane Admin',
|
|
399
|
+
userId: 'admin-7',
|
|
400
|
+
streamSeq: 5,
|
|
401
|
+
},
|
|
402
|
+
{ type: 'DIALOG_CLOSED' },
|
|
403
|
+
])
|
|
404
|
+
expect(log).toMatchSnapshot()
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it('direct-mode barrier: after a DIRECT_MESSAGE, AI chunks are dropped with a one-shot teardown', () => {
|
|
408
|
+
const { log, feed } = setup()
|
|
409
|
+
feed([
|
|
410
|
+
{ type: 'MESSAGE_START' },
|
|
411
|
+
{ type: 'TEXT', text: 'ai text before takeover' },
|
|
412
|
+
{ type: 'DIRECT_MESSAGE', text: 'Human takeover', ownerType: 'ADMIN' },
|
|
413
|
+
// AI chunks now dropped; first one triggers the teardown (onStreamEnd).
|
|
414
|
+
{ type: 'TEXT', text: 'dropped ai text' },
|
|
415
|
+
{ type: 'TEXT', text: 'also dropped' },
|
|
416
|
+
// Allowlisted chunks still flow.
|
|
417
|
+
{ type: 'SYSTEM', text: 'still visible' },
|
|
418
|
+
{ type: 'DIRECT_MESSAGE', text: 'second human message' },
|
|
419
|
+
])
|
|
420
|
+
expect(log).toMatchSnapshot()
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
it('context compaction outside a stream emits append+isCompacting metadata; inside a stream it is cumulative', () => {
|
|
424
|
+
const { log, feed } = setup()
|
|
425
|
+
feed([
|
|
426
|
+
// standalone (no open stream)
|
|
427
|
+
{ type: 'CONTEXT_COMPACTION_START' },
|
|
428
|
+
{ type: 'CONTEXT_COMPACTION_END', text: 'Summarized 12 messages' },
|
|
429
|
+
])
|
|
430
|
+
const standaloneLog = [...log]
|
|
431
|
+
log.length = 0
|
|
432
|
+
feed([
|
|
433
|
+
{ type: 'MESSAGE_START' },
|
|
434
|
+
{ type: 'CONTEXT_COMPACTION_START' },
|
|
435
|
+
{ type: 'CONTEXT_COMPACTION_END', text: 'Mid-stream summary' },
|
|
436
|
+
{ type: 'MESSAGE_END' },
|
|
437
|
+
])
|
|
438
|
+
expect({ standalone: standaloneLog, inStream: log }).toMatchSnapshot()
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
it('reset() clears accumulator + stream flags so the next dialog cold-starts cumulative', () => {
|
|
442
|
+
const { log, feed, reducer } = setup()
|
|
443
|
+
feed([
|
|
444
|
+
{ type: 'MESSAGE_START' },
|
|
445
|
+
{ type: 'TEXT', text: 'dialog one' },
|
|
446
|
+
{ type: 'MESSAGE_END' },
|
|
447
|
+
])
|
|
448
|
+
reducer.reset()
|
|
449
|
+
log.length = 0
|
|
450
|
+
feed([{ type: 'TEXT', text: 'dialog two cold start' }])
|
|
451
|
+
expect(log).toMatchSnapshot()
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
it('initialState resume: continuation chunks after resume take the post-stream append path', () => {
|
|
455
|
+
const { log } = setup({
|
|
456
|
+
initialState: {
|
|
457
|
+
existingSegments: [{ type: 'text', text: 'restored partial ' }],
|
|
458
|
+
escalatedApprovals: new Map([
|
|
459
|
+
['req-esc', { command: 'escalated cmd', approvalType: 'ADMIN' }],
|
|
460
|
+
]),
|
|
461
|
+
},
|
|
462
|
+
})
|
|
463
|
+
// initializeWithState replays escalated approvals via onEscalatedApproval
|
|
464
|
+
// and marks hasEverStreamed=true.
|
|
465
|
+
expect(log).toMatchSnapshot()
|
|
466
|
+
})
|
|
467
|
+
})
|