@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import React, { forwardRef, memo, useMemo, useRef } from "react"
|
|
3
|
+
import React, { forwardRef, memo, useEffect, useMemo, useRef } from "react"
|
|
4
4
|
import { cn } from "../../utils/cn"
|
|
5
5
|
import { isToday } from "../../utils/date-utils"
|
|
6
6
|
import { formatDate, formatTime } from "../../utils/format-date"
|
|
@@ -12,7 +12,7 @@ import { ErrorMessageDisplay } from "./error-message-display"
|
|
|
12
12
|
import { ContextCompactionDisplay } from "./context-compaction-display"
|
|
13
13
|
import { ThinkingDisplay } from "./thinking-display"
|
|
14
14
|
import { GuideDisplay } from "./guide-display"
|
|
15
|
-
import { SimpleMarkdownRenderer } from "../ui/simple-markdown-renderer"
|
|
15
|
+
import { SimpleMarkdownRenderer } from "../ui/markdown/simple-markdown-renderer"
|
|
16
16
|
import type { ChatRef } from "./chat-ref.types"
|
|
17
17
|
import { remarkCardLinks } from "./remark-card-links"
|
|
18
18
|
import { remarkMentionChips } from "./remark-mention-chips"
|
|
@@ -164,9 +164,9 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
164
164
|
| { kind: 'text'; text: string }
|
|
165
165
|
| { kind: 'block'; key: string; node: React.ReactNode }
|
|
166
166
|
const partsBySegment = new Map<number, SegmentPart[]>()
|
|
167
|
-
if (!render) return { inlineByKey, partsBySegment }
|
|
168
|
-
const cache = renderedCardNodeCache.current
|
|
169
167
|
const usedKeys = new Set<string>()
|
|
168
|
+
if (!render) return { inlineByKey, partsBySegment, usedKeys }
|
|
169
|
+
const cache = renderedCardNodeCache.current
|
|
170
170
|
// Card keys already emitted as a hoisted block (`b-<key>`). The same
|
|
171
171
|
// marker can legitimately appear twice in one message (LLM references
|
|
172
172
|
// the same entity twice); we hoist the FIRST occurrence and skip the
|
|
@@ -281,20 +281,99 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
281
281
|
partsBySegment.set(segIdx, parts)
|
|
282
282
|
}
|
|
283
283
|
})
|
|
284
|
-
|
|
285
|
-
// grow unbounded as a long message's markers change.
|
|
286
|
-
if (cache.size > usedKeys.size) {
|
|
287
|
-
for (const k of cache.keys()) {
|
|
288
|
-
if (!usedKeys.has(k)) cache.delete(k)
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return { inlineByKey, partsBySegment }
|
|
284
|
+
return { inlineByKey, partsBySegment, usedKeys }
|
|
292
285
|
}, [hasMarkerSupport, chatRefs, renderEntityCard, segments])
|
|
293
286
|
|
|
287
|
+
// Drop cached nodes for markers no longer present so the cache can't grow
|
|
288
|
+
// unbounded as a long message's markers change. Deliberately an EFFECT,
|
|
289
|
+
// not part of the memo above: pruning is a mutation, and doing it in the
|
|
290
|
+
// render phase is non-idempotent (StrictMode's double-invoke, or a render
|
|
291
|
+
// React throws away, would evict nodes the committed tree still uses and
|
|
292
|
+
// remount the cards it was built to preserve).
|
|
293
|
+
useEffect(() => {
|
|
294
|
+
const cache = renderedCardNodeCache.current
|
|
295
|
+
const usedKeys = renderingPlan?.usedKeys
|
|
296
|
+
if (!usedKeys) return
|
|
297
|
+
if (cache.size <= usedKeys.size) return
|
|
298
|
+
for (const k of [...cache.keys()]) {
|
|
299
|
+
if (!usedKeys.has(k)) cache.delete(k)
|
|
300
|
+
}
|
|
301
|
+
}, [renderingPlan])
|
|
302
|
+
|
|
303
|
+
// The plan is read through a REF inside the `<a>` override, not captured
|
|
304
|
+
// in the override's closure. `renderingPlan` is rebuilt on every text
|
|
305
|
+
// delta (its `segments` dep is a fresh array per delta), so depending on
|
|
306
|
+
// it here would give `cardComponentOverrides` a new identity every token
|
|
307
|
+
// — which re-creates the markdown engine's `components` memo and defeats
|
|
308
|
+
// its per-block `StreamingBlockRenderer` memoization for the WHOLE
|
|
309
|
+
// message, on every token. The ref keeps the override identity stable
|
|
310
|
+
// while still reading the current plan at call time.
|
|
311
|
+
const renderingPlanRef = useRef(renderingPlan)
|
|
312
|
+
renderingPlanRef.current = renderingPlan
|
|
313
|
+
const chatRefsRef = useRef(chatRefs)
|
|
314
|
+
chatRefsRef.current = chatRefs
|
|
315
|
+
|
|
316
|
+
// Ref-SET token. The override reads `chatRefsRef` at CALL time, but the
|
|
317
|
+
// markdown engine memoizes completed blocks on the override map's
|
|
318
|
+
// identity — so on a COMPLETED (no longer streaming) message, a ref that
|
|
319
|
+
// resolves late would never be re-read: nothing else about the renderer's
|
|
320
|
+
// props changes, the engine's memo bails, and the pill stays stuck on its
|
|
321
|
+
// fallback (`refMatch.title`, or the raw cardId) forever. Streaming is
|
|
322
|
+
// covered because `card://` blocks are excluded from the block cache; the
|
|
323
|
+
// completed path has no other escape.
|
|
324
|
+
//
|
|
325
|
+
// The token fingerprints VALUES, not just the key set: a later refs frame
|
|
326
|
+
// REPLACES the whole map for a send index, and the enrichment case that
|
|
327
|
+
// matters most — a `title` going from the raw cardId to the resolved
|
|
328
|
+
// document title — keeps the key set IDENTICAL. A key-only token would be
|
|
329
|
+
// unchanged, the override map would keep its identity, the engine's
|
|
330
|
+
// completed-block memo would bail, and the pill would stay on its fallback
|
|
331
|
+
// forever. Every `ChatRef` field is included because the host's
|
|
332
|
+
// `renderEntityCard` receives the whole ref and may render any of them.
|
|
333
|
+
//
|
|
334
|
+
// Still STABLE per text delta (the refs map doesn't change while tokens
|
|
335
|
+
// stream), and the cost is one pass over a handful of refs per CHANGED
|
|
336
|
+
// `chatRefs` identity — the dep list is unchanged.
|
|
337
|
+
//
|
|
338
|
+
// Fields are joined by `JSON.stringify`, NOT by a separator character.
|
|
339
|
+
// `title`, `preview` and `url` are free-form HOST strings, so any
|
|
340
|
+
// delimiter we pick is one the data may also contain: joined with a plain
|
|
341
|
+
// space, `title: 'a b'` + empty `url` fingerprints identically to
|
|
342
|
+
// `title: 'a'` + `url: 'b'`, silently reintroducing the stale-pill memo
|
|
343
|
+
// bail this token exists to fix. (An earlier revision used a literal NUL
|
|
344
|
+
// byte as the separator: collision-free in practice, but it made the
|
|
345
|
+
// source file itself binary to grep and diff tooling.) `JSON.stringify`
|
|
346
|
+
// escapes every field, so no value can forge a boundary.
|
|
347
|
+
//
|
|
348
|
+
// Caveat worth stating: `JSON.stringify` on `metadata` is key-ORDER
|
|
349
|
+
// dependent: two structurally equal objects built in different insertion
|
|
350
|
+
// orders fingerprint differently. Acceptable here because every refs map
|
|
351
|
+
// arrives from ONE decoder with a fixed field order, and the failure mode
|
|
352
|
+
// is a redundant re-render, never a stale pill.
|
|
353
|
+
const refsKey = useMemo(
|
|
354
|
+
() =>
|
|
355
|
+
Object.entries(chatRefs ?? {})
|
|
356
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
357
|
+
.map(([k, v]) =>
|
|
358
|
+
JSON.stringify([
|
|
359
|
+
k,
|
|
360
|
+
v.type,
|
|
361
|
+
v.sourceRepo ?? null,
|
|
362
|
+
v.id,
|
|
363
|
+
v.title,
|
|
364
|
+
v.url ?? null,
|
|
365
|
+
v.targetPlatform ?? null,
|
|
366
|
+
v.date ?? null,
|
|
367
|
+
v.preview ?? null,
|
|
368
|
+
v.metadata ?? null,
|
|
369
|
+
]),
|
|
370
|
+
)
|
|
371
|
+
.join('|'),
|
|
372
|
+
[chatRefs],
|
|
373
|
+
)
|
|
374
|
+
|
|
294
375
|
const cardComponentOverrides = useMemo(() => {
|
|
295
376
|
if (!hasMarkerSupport && !hasMentionSupport) return undefined
|
|
296
|
-
const refs = chatRefs ?? {}
|
|
297
|
-
const inlineByKey = renderingPlan?.inlineByKey
|
|
298
377
|
return {
|
|
299
378
|
// Override `<a>` to detect `card://` URLs emitted by `remarkCardLinks`.
|
|
300
379
|
// The render result was pre-computed in `renderingPlan` so block-level
|
|
@@ -322,7 +401,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
322
401
|
const cardType = stripped.slice(0, sepIdx)
|
|
323
402
|
const cardId = stripped.slice(sepIdx + 1)
|
|
324
403
|
const key = `${cardType}:${cardId}`
|
|
325
|
-
const inline = inlineByKey
|
|
404
|
+
const inline = renderingPlanRef.current?.inlineByKey.get(key)
|
|
326
405
|
if (inline != null) return inline
|
|
327
406
|
// Three fallback cases — keep them DISTINCT, never blur them
|
|
328
407
|
// together. Mixing them up (which the old code did by reaching
|
|
@@ -346,7 +425,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
346
425
|
// title from an unrelated ref — that hides the bug and
|
|
347
426
|
// deceives the reader into thinking they're looking at
|
|
348
427
|
// a real card.
|
|
349
|
-
const refMatch: ChatRef | undefined =
|
|
428
|
+
const refMatch: ChatRef | undefined = chatRefsRef.current?.[key]
|
|
350
429
|
if (refMatch) {
|
|
351
430
|
return <span className="text-ods-text-primary">{refMatch.title}</span>
|
|
352
431
|
}
|
|
@@ -388,7 +467,13 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
388
467
|
)
|
|
389
468
|
},
|
|
390
469
|
}
|
|
391
|
-
|
|
470
|
+
// DEPS ARE DELIBERATELY MINIMAL — every one of them is stable across a
|
|
471
|
+
// streaming turn (booleans + host-stable fn/component identities, both
|
|
472
|
+
// enforced by this file's `memo` comparator). The rendering plan and the
|
|
473
|
+
// refs MAP are read through refs above precisely so they do NOT appear
|
|
474
|
+
// here; `refsKey` is the one ref-derived dep, and it only moves when the
|
|
475
|
+
// ref set OR any ref VALUE does (see its definition).
|
|
476
|
+
}, [hasMarkerSupport, hasMentionSupport, renderMention, NavLinkAnchor, refsKey])
|
|
392
477
|
|
|
393
478
|
/**
|
|
394
479
|
* Body of a markdown-bearing segment (`text` / `guide`).
|
|
@@ -403,8 +488,13 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
403
488
|
* end). Stable React keys come from the card key (block) and chunk position
|
|
404
489
|
* (text); streaming token-by-token reuses the same React instances so
|
|
405
490
|
* `<Video>` doesn't remount mid-play.
|
|
491
|
+
*
|
|
492
|
+
* `isStreaming` opts the segment into the markdown engine's streaming path
|
|
493
|
+
* (atomic-block memoization + fence tail-completion + aria-live). Only the
|
|
494
|
+
* actively streaming segment gets it, and within a marker-split segment
|
|
495
|
+
* only the LAST text chunk — the earlier chunks are already final.
|
|
406
496
|
*/
|
|
407
|
-
const renderSegmentBody = (segIndex: number, text: string) => {
|
|
497
|
+
const renderSegmentBody = (segIndex: number, text: string, isStreaming: boolean) => {
|
|
408
498
|
const parts = renderingPlan?.partsBySegment.get(segIndex)
|
|
409
499
|
if (!parts || parts.length === 0) {
|
|
410
500
|
return (
|
|
@@ -413,6 +503,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
413
503
|
textSize="compact"
|
|
414
504
|
additionalRemarkPlugins={cardRemarkPlugins}
|
|
415
505
|
componentOverrides={cardComponentOverrides}
|
|
506
|
+
streaming={isStreaming}
|
|
416
507
|
/>
|
|
417
508
|
)
|
|
418
509
|
}
|
|
@@ -425,6 +516,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
425
516
|
textSize="compact"
|
|
426
517
|
additionalRemarkPlugins={cardRemarkPlugins}
|
|
427
518
|
componentOverrides={cardComponentOverrides}
|
|
519
|
+
streaming={isStreaming && pIdx === parts.length - 1}
|
|
428
520
|
/>
|
|
429
521
|
)
|
|
430
522
|
}
|
|
@@ -539,6 +631,12 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
539
631
|
{/* Message segments — hidden for system messages without content */}
|
|
540
632
|
{(!isSystem || segments.length > 0) && <div className="flex flex-col gap-2">
|
|
541
633
|
{segments.map((segment, index) => {
|
|
634
|
+
// The engine's streaming path (atomic-block memoization +
|
|
635
|
+
// fence tail-completion + aria-live) applies ONLY to the
|
|
636
|
+
// actively streaming segment: last segment of a message that
|
|
637
|
+
// is still typing. On completion `isTyping` flips false and
|
|
638
|
+
// the engine does one authoritative whole-document parse.
|
|
639
|
+
const segmentIsStreaming = index === segments.length - 1 && !!isTyping
|
|
542
640
|
if (segment.type === 'text') {
|
|
543
641
|
return (
|
|
544
642
|
<div
|
|
@@ -548,11 +646,15 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
548
646
|
isError ? "text-ods-error" : "text-ods-text-primary",
|
|
549
647
|
)}
|
|
550
648
|
>
|
|
551
|
-
{renderSegmentBody(index, segment.text)}
|
|
649
|
+
{renderSegmentBody(index, segment.text, segmentIsStreaming)}
|
|
552
650
|
</div>
|
|
553
651
|
)
|
|
554
652
|
} else if (segment.type === 'guide') {
|
|
555
|
-
return
|
|
653
|
+
return (
|
|
654
|
+
<GuideDisplay key={index}>
|
|
655
|
+
{renderSegmentBody(index, segment.text, segmentIsStreaming)}
|
|
656
|
+
</GuideDisplay>
|
|
657
|
+
)
|
|
556
658
|
} else if (segment.type === 'tool_execution') {
|
|
557
659
|
return (
|
|
558
660
|
<ToolExecutionDisplay
|