@flamingo-stack/openframe-frontend-core 0.0.429-snapshot.20260715222543 → 0.0.429
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-KDVGC6EG.cjs → chunk-2LJA3ABH.cjs} +37 -37
- package/dist/{chunk-KDVGC6EG.cjs.map → chunk-2LJA3ABH.cjs.map} +1 -1
- package/dist/{chunk-3XWBE3SM.js → chunk-2WJ25MTA.js} +4 -4
- package/dist/{chunk-3AWPRVFM.js → chunk-4VODJPTB.js} +2 -2
- package/dist/{chunk-TYANQCZA.js → chunk-62L7S7HQ.js} +166 -269
- package/dist/chunk-62L7S7HQ.js.map +1 -0
- package/dist/{chunk-FYMD7CCA.cjs → chunk-7MJTM6QT.cjs} +7 -7
- package/dist/{chunk-FYMD7CCA.cjs.map → chunk-7MJTM6QT.cjs.map} +1 -1
- package/dist/{chunk-A6JKKKIF.js → chunk-7PA4B6SD.js} +4 -4
- package/dist/{chunk-TDITU4KW.js → chunk-B3FBMRHQ.js} +2 -2
- package/dist/{chunk-CTY37UUO.cjs → chunk-B3Y47C2U.cjs} +59 -59
- package/dist/{chunk-CTY37UUO.cjs.map → chunk-B3Y47C2U.cjs.map} +1 -1
- package/dist/{chunk-WQN4B6CM.cjs → chunk-BN3V465H.cjs} +15 -15
- package/dist/{chunk-WQN4B6CM.cjs.map → chunk-BN3V465H.cjs.map} +1 -1
- package/dist/{chunk-WQR7H56P.cjs → chunk-CCL6JEMS.cjs} +62 -62
- package/dist/{chunk-WQR7H56P.cjs.map → chunk-CCL6JEMS.cjs.map} +1 -1
- package/dist/{chunk-CJOFXDTK.cjs → chunk-CRGH6TV6.cjs} +26 -26
- package/dist/{chunk-CJOFXDTK.cjs.map → chunk-CRGH6TV6.cjs.map} +1 -1
- package/dist/{chunk-Q7SYPXUX.cjs → chunk-E4PKZNR7.cjs} +11 -11
- package/dist/{chunk-Q7SYPXUX.cjs.map → chunk-E4PKZNR7.cjs.map} +1 -1
- package/dist/{chunk-ZUP2ZKS6.cjs → chunk-GGJUXN6Z.cjs} +9 -9
- package/dist/{chunk-ZUP2ZKS6.cjs.map → chunk-GGJUXN6Z.cjs.map} +1 -1
- package/dist/{chunk-2ELINEWQ.js → chunk-GMR5AA3C.js} +2 -2
- package/dist/{chunk-AY5TBDWZ.js → chunk-KHKB5RY2.js} +2 -2
- package/dist/{chunk-S7UXICHB.js → chunk-MAYEJ3NY.js} +2 -2
- package/dist/{chunk-NZBQGODM.js → chunk-NYISC4Z3.js} +2 -2
- package/dist/{chunk-D4K53CES.cjs → chunk-OLGFIDZY.cjs} +26 -26
- package/dist/{chunk-D4K53CES.cjs.map → chunk-OLGFIDZY.cjs.map} +1 -1
- package/dist/{chunk-3OKVH6FW.js → chunk-RTOVYU4D.js} +4 -4
- package/dist/{chunk-67LZDLIO.js → chunk-TJ4HJ3KX.js} +2 -2
- package/dist/{chunk-FL4IOCYH.cjs → chunk-WXKFFVGC.cjs} +5 -5
- package/dist/{chunk-FL4IOCYH.cjs.map → chunk-WXKFFVGC.cjs.map} +1 -1
- package/dist/{chunk-PP5KNHMK.cjs → chunk-XDBD6BJN.cjs} +215 -318
- package/dist/chunk-XDBD6BJN.cjs.map +1 -0
- package/dist/{chunk-IMOJWQDR.js → chunk-Y2TW664W.js} +4 -4
- package/dist/{chunk-374KFDET.cjs → chunk-YGITDP6O.cjs} +31 -31
- package/dist/{chunk-374KFDET.cjs.map → chunk-YGITDP6O.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/hooks/index.d.ts +0 -1
- package/dist/components/chat/hooks/index.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +1 -10
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -12
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +1 -11
- package/dist/components/chat/utils/index.d.ts +0 -1
- package/dist/components/chat/utils/index.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/board/index.d.ts +2 -2
- package/dist/components/features/board/index.d.ts.map +1 -1
- package/dist/components/features/board/ticket-card.d.ts +2 -22
- package/dist/components/features/board/ticket-card.d.ts.map +1 -1
- package/dist/components/features/index.cjs +2 -6
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.js +1 -5
- 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 +128 -142
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +9 -23
- 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/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/index.cjs +2 -12
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +1 -11
- package/dist/index.cjs +2 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -15
- package/package.json +1 -1
- package/src/components/chat/hooks/index.ts +0 -1
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +0 -23
- package/src/components/chat/utils/index.ts +0 -2
- package/src/components/features/board/index.ts +2 -2
- package/src/components/features/board/ticket-card.tsx +64 -108
- package/dist/chunk-PP5KNHMK.cjs.map +0 -1
- package/dist/chunk-TYANQCZA.js.map +0 -1
- package/dist/components/chat/hooks/use-scripted-stream.d.ts +0 -3
- package/dist/components/chat/hooks/use-scripted-stream.d.ts.map +0 -1
- package/dist/components/chat/utils/scripted-stream.d.ts +0 -38
- package/dist/components/chat/utils/scripted-stream.d.ts.map +0 -1
- package/src/components/chat/hooks/use-scripted-stream.ts +0 -69
- package/src/components/chat/utils/scripted-stream.ts +0 -111
- /package/dist/{chunk-3XWBE3SM.js.map → chunk-2WJ25MTA.js.map} +0 -0
- /package/dist/{chunk-3AWPRVFM.js.map → chunk-4VODJPTB.js.map} +0 -0
- /package/dist/{chunk-A6JKKKIF.js.map → chunk-7PA4B6SD.js.map} +0 -0
- /package/dist/{chunk-TDITU4KW.js.map → chunk-B3FBMRHQ.js.map} +0 -0
- /package/dist/{chunk-2ELINEWQ.js.map → chunk-GMR5AA3C.js.map} +0 -0
- /package/dist/{chunk-AY5TBDWZ.js.map → chunk-KHKB5RY2.js.map} +0 -0
- /package/dist/{chunk-S7UXICHB.js.map → chunk-MAYEJ3NY.js.map} +0 -0
- /package/dist/{chunk-NZBQGODM.js.map → chunk-NYISC4Z3.js.map} +0 -0
- /package/dist/{chunk-3OKVH6FW.js.map → chunk-RTOVYU4D.js.map} +0 -0
- /package/dist/{chunk-67LZDLIO.js.map → chunk-TJ4HJ3KX.js.map} +0 -0
- /package/dist/{chunk-IMOJWQDR.js.map → chunk-Y2TW664W.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-scripted-stream.d.ts","sourceRoot":"","sources":["../../../../src/components/chat/hooks/use-scripted-stream.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAQ3D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,UAAO,GAAG,WAAW,CAwCvG"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scripted-conversation replay — turn a stored `HistoricalMessage[]` into ordered
|
|
3
|
-
* "mock SSE" playback frames that animate a chat surface exactly like the live
|
|
4
|
-
* NATS/SSE stream (a `thinking` pause → assistant text token-by-token → tool /
|
|
5
|
-
* approval segments popping in → `idle`), just replayed from a script instead of
|
|
6
|
-
* a network stream.
|
|
7
|
-
*
|
|
8
|
-
* Lives in the lib (not a host) so any consumer — marketing hero demos, docs,
|
|
9
|
-
* onboarding tours — can drive a `previewMode` `EmbeddableChat` or a
|
|
10
|
-
* `ChatMessageList` from a canned conversation without re-implementing the
|
|
11
|
-
* streaming cadence. Pair with {@link useScriptedStream} (the playback clock).
|
|
12
|
-
*/
|
|
13
|
-
import type { HistoricalMessage, MessageData, StreamingPhase } from '../types';
|
|
14
|
-
/** Normalize the single-or-array `messageData` to an array (empty when absent). */
|
|
15
|
-
export declare function normalizeHistoricalMessageData(md: HistoricalMessage['messageData']): MessageData[];
|
|
16
|
-
/** A message the user authored carries an `owner`; assistant turns have none —
|
|
17
|
-
* drives whether a turn streams (assistant) or lands at once (user). */
|
|
18
|
-
export declare function isHistoricalUserTurn(m: HistoricalMessage): boolean;
|
|
19
|
-
/** One rendered step of the mocked stream. */
|
|
20
|
-
export interface StreamFrame {
|
|
21
|
-
/** The partial message list to show at this step. */
|
|
22
|
-
messages: HistoricalMessage[];
|
|
23
|
-
phase: StreamingPhase;
|
|
24
|
-
/** The chat "typing" indicator (up during the `thinking` pause). */
|
|
25
|
-
typing: boolean;
|
|
26
|
-
/** Hold time (ms) before advancing to the next frame. */
|
|
27
|
-
delayMs: number;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Expand a message list into ordered playback frames reproducing the live
|
|
31
|
-
* stream: each user turn lands whole; each assistant turn first shows a
|
|
32
|
-
* `thinking` indicator, then streams its text token-by-token, then pops any
|
|
33
|
-
* tool / approval segments. Frame COUNT for a given prefix is deterministic, so
|
|
34
|
-
* a host that appends a continuation (e.g. after an Approve) resumes seamlessly
|
|
35
|
-
* from where it paused — the shared prefix's frames are unchanged.
|
|
36
|
-
*/
|
|
37
|
-
export declare function buildStreamFrames(messages: HistoricalMessage[]): StreamFrame[];
|
|
38
|
-
//# sourceMappingURL=scripted-stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scripted-stream.d.ts","sourceRoot":"","sources":["../../../../src/components/chat/utils/scripted-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9E,mFAAmF;AACnF,wBAAgB,8BAA8B,CAAC,EAAE,EAAE,iBAAiB,CAAC,aAAa,CAAC,GAAG,WAAW,EAAE,CAElG;AAED;yEACyE;AACzE,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAElE;AAKD,8CAA8C;AAC9C,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,QAAQ,EAAE,iBAAiB,EAAE,CAAA;IAC7B,KAAK,EAAE,cAAc,CAAA;IACrB,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAA;IACf,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAA;CAChB;AAgBD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,WAAW,EAAE,CAgD9E"}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Playback clock for {@link buildStreamFrames}: advance through pre-built
|
|
5
|
-
* scripted frames like a live chat stream — each frame holds for its own
|
|
6
|
-
* `delayMs`, then the next reveals, parking on the last. Surface-agnostic: the
|
|
7
|
-
* caller maps `frame.messages` to its own chat shape and reads `frame.phase` /
|
|
8
|
-
* `frame.typing`.
|
|
9
|
-
*
|
|
10
|
-
* `resetKey` restarts playback from the top when a NEW conversation is selected
|
|
11
|
-
* (identity change) — NOT when the SAME conversation grows (e.g. an Approve
|
|
12
|
-
* appends its continuation), which must resume from where it paused. Because the
|
|
13
|
-
* frame list's shared prefix is deterministic, keeping the index across a grow
|
|
14
|
-
* resumes seamlessly into the appended frames.
|
|
15
|
-
*
|
|
16
|
-
* `prefers-reduced-motion` (or `enabled === false`) jumps straight to the final
|
|
17
|
-
* frame (everything revealed, idle).
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { useEffect, useState } from 'react'
|
|
21
|
-
import type { StreamFrame } from '../utils/scripted-stream'
|
|
22
|
-
|
|
23
|
-
const EMPTY_FRAME: StreamFrame = { messages: [], phase: 'idle', typing: false, delayMs: 0 }
|
|
24
|
-
|
|
25
|
-
function prefersReducedMotion(): boolean {
|
|
26
|
-
return typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function useScriptedStream(frames: StreamFrame[], resetKey: unknown, enabled = true): StreamFrame {
|
|
30
|
-
const [index, setIndex] = useState(0)
|
|
31
|
-
const [reducedMotion, setReducedMotion] = useState(false)
|
|
32
|
-
|
|
33
|
-
// Restart from the top on a new conversation, synchronously during render
|
|
34
|
-
// (React's "adjust state on prop change" pattern) so the previous stream's
|
|
35
|
-
// last frame never flashes before the reset effect runs.
|
|
36
|
-
const [prevKey, setPrevKey] = useState(resetKey)
|
|
37
|
-
if (resetKey !== prevKey) {
|
|
38
|
-
setPrevKey(resetKey)
|
|
39
|
-
setIndex(0)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
setReducedMotion(prefersReducedMotion())
|
|
44
|
-
const mq = window.matchMedia?.('(prefers-reduced-motion: reduce)')
|
|
45
|
-
if (!mq) return
|
|
46
|
-
const onChange = () => setReducedMotion(mq.matches)
|
|
47
|
-
mq.addEventListener('change', onChange)
|
|
48
|
-
return () => mq.removeEventListener('change', onChange)
|
|
49
|
-
}, [])
|
|
50
|
-
|
|
51
|
-
const playing = enabled && !reducedMotion && frames.length > 0
|
|
52
|
-
const lastIndex = Math.max(0, frames.length - 1)
|
|
53
|
-
|
|
54
|
-
// Advance one frame after the current frame's hold. When `frames` grows (an
|
|
55
|
-
// Approve appends more), this effect re-runs and, if we were parked on the old
|
|
56
|
-
// last frame, schedules the next — resuming the stream. `frames[index]` is
|
|
57
|
-
// clamped because a shrink (a shorter new conversation before the reset lands)
|
|
58
|
-
// could momentarily leave `index` past the end.
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (!playing || index >= lastIndex) return
|
|
61
|
-
const current = frames[Math.min(index, lastIndex)] ?? EMPTY_FRAME
|
|
62
|
-
const t = setTimeout(() => setIndex((i) => Math.min(i + 1, lastIndex)), current.delayMs)
|
|
63
|
-
return () => clearTimeout(t)
|
|
64
|
-
}, [index, frames, playing, lastIndex])
|
|
65
|
-
|
|
66
|
-
if (frames.length === 0) return EMPTY_FRAME
|
|
67
|
-
if (!playing) return frames[lastIndex]
|
|
68
|
-
return frames[Math.min(index, lastIndex)] ?? EMPTY_FRAME
|
|
69
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scripted-conversation replay — turn a stored `HistoricalMessage[]` into ordered
|
|
3
|
-
* "mock SSE" playback frames that animate a chat surface exactly like the live
|
|
4
|
-
* NATS/SSE stream (a `thinking` pause → assistant text token-by-token → tool /
|
|
5
|
-
* approval segments popping in → `idle`), just replayed from a script instead of
|
|
6
|
-
* a network stream.
|
|
7
|
-
*
|
|
8
|
-
* Lives in the lib (not a host) so any consumer — marketing hero demos, docs,
|
|
9
|
-
* onboarding tours — can drive a `previewMode` `EmbeddableChat` or a
|
|
10
|
-
* `ChatMessageList` from a canned conversation without re-implementing the
|
|
11
|
-
* streaming cadence. Pair with {@link useScriptedStream} (the playback clock).
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type { HistoricalMessage, MessageData, StreamingPhase } from '../types'
|
|
15
|
-
|
|
16
|
-
/** Normalize the single-or-array `messageData` to an array (empty when absent). */
|
|
17
|
-
export function normalizeHistoricalMessageData(md: HistoricalMessage['messageData']): MessageData[] {
|
|
18
|
-
return Array.isArray(md) ? md : md ? [md] : []
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** A message the user authored carries an `owner`; assistant turns have none —
|
|
22
|
-
* drives whether a turn streams (assistant) or lands at once (user). */
|
|
23
|
-
export function isHistoricalUserTurn(m: HistoricalMessage): boolean {
|
|
24
|
-
return !!m.owner
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const isTextSegment = (d: MessageData): d is MessageData & { type: 'TEXT'; text: string } =>
|
|
28
|
-
(d as { type?: string })?.type === 'TEXT' && typeof (d as { text?: unknown }).text === 'string'
|
|
29
|
-
|
|
30
|
-
/** One rendered step of the mocked stream. */
|
|
31
|
-
export interface StreamFrame {
|
|
32
|
-
/** The partial message list to show at this step. */
|
|
33
|
-
messages: HistoricalMessage[]
|
|
34
|
-
phase: StreamingPhase
|
|
35
|
-
/** The chat "typing" indicator (up during the `thinking` pause). */
|
|
36
|
-
typing: boolean
|
|
37
|
-
/** Hold time (ms) before advancing to the next frame. */
|
|
38
|
-
delayMs: number
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Playback cadence. Assistant turns "think" then stream token-by-token; user
|
|
42
|
-
// turns land at once. Tuned to read like a real chat without dragging.
|
|
43
|
-
const THINK_MS = 550
|
|
44
|
-
const TOKEN_MS = 55 // per word revealed while streaming text
|
|
45
|
-
const USER_MS = 480 // dwell on a user turn before the reply starts thinking
|
|
46
|
-
const SEGMENT_MS = 340 // a tool / approval card pops in
|
|
47
|
-
const POST_MS = 240 // dwell after a completed assistant turn
|
|
48
|
-
|
|
49
|
-
/** Split text into tokens that KEEP surrounding whitespace, so re-joining a
|
|
50
|
-
* prefix reproduces the original spacing exactly (`"a b"` → `["a ", "b"]`). */
|
|
51
|
-
function tokenize(text: string): string[] {
|
|
52
|
-
return text.match(/\s*\S+\s*/g) ?? (text ? [text] : [])
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Expand a message list into ordered playback frames reproducing the live
|
|
57
|
-
* stream: each user turn lands whole; each assistant turn first shows a
|
|
58
|
-
* `thinking` indicator, then streams its text token-by-token, then pops any
|
|
59
|
-
* tool / approval segments. Frame COUNT for a given prefix is deterministic, so
|
|
60
|
-
* a host that appends a continuation (e.g. after an Approve) resumes seamlessly
|
|
61
|
-
* from where it paused — the shared prefix's frames are unchanged.
|
|
62
|
-
*/
|
|
63
|
-
export function buildStreamFrames(messages: HistoricalMessage[]): StreamFrame[] {
|
|
64
|
-
const frames: StreamFrame[] = []
|
|
65
|
-
const revealed: HistoricalMessage[] = []
|
|
66
|
-
const push = (msgs: HistoricalMessage[], phase: StreamingPhase, typing: boolean, delayMs: number) =>
|
|
67
|
-
frames.push({ messages: msgs.slice(), phase, typing, delayMs })
|
|
68
|
-
|
|
69
|
-
messages.forEach((msg) => {
|
|
70
|
-
if (isHistoricalUserTurn(msg)) {
|
|
71
|
-
revealed.push(msg)
|
|
72
|
-
push(revealed, 'idle', false, USER_MS)
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Assistant turn: a `thinking` pause, then stream this turn's segments in
|
|
77
|
-
// order. The pause is emitted ONLY when there is already content to show
|
|
78
|
-
// (`revealed.length > 0`) — an empty first frame would hand the surface a
|
|
79
|
-
// zero-message list, flashing its empty state before the opening line.
|
|
80
|
-
if (revealed.length > 0) push(revealed, 'thinking', true, THINK_MS)
|
|
81
|
-
|
|
82
|
-
const segs = normalizeHistoricalMessageData(msg.messageData)
|
|
83
|
-
const built: MessageData[] = []
|
|
84
|
-
const emit = () => push([...revealed, { ...msg, messageData: [...built] }], 'streaming', false, 0)
|
|
85
|
-
|
|
86
|
-
segs.forEach((seg) => {
|
|
87
|
-
if (isTextSegment(seg)) {
|
|
88
|
-
const tokens = tokenize(seg.text)
|
|
89
|
-
let acc = ''
|
|
90
|
-
built.push({ ...seg, text: '' })
|
|
91
|
-
tokens.forEach((tok) => {
|
|
92
|
-
acc += tok
|
|
93
|
-
built[built.length - 1] = { ...seg, text: acc }
|
|
94
|
-
push([...revealed, { ...msg, messageData: [...built] }], 'streaming', false, TOKEN_MS)
|
|
95
|
-
})
|
|
96
|
-
built[built.length - 1] = { ...seg }
|
|
97
|
-
} else {
|
|
98
|
-
// Tool / approval segment: pops in fully.
|
|
99
|
-
built.push(seg)
|
|
100
|
-
emit()
|
|
101
|
-
frames[frames.length - 1].delayMs = SEGMENT_MS
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
revealed.push(msg)
|
|
106
|
-
push(revealed, 'idle', false, POST_MS)
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
if (frames.length === 0) push(revealed, 'idle', false, 0)
|
|
110
|
-
return frames
|
|
111
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|