@adminide-stack/yantra-mobile 12.0.69-alpha.18 → 12.0.69-alpha.19

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.
@@ -1 +1 @@
1
- {"version":3,"file":"useCdecliChannel.js","sources":["../../src/hooks/useCdecliChannel.ts"],"sourcesContent":["/**\n * useCdecliChannel — wires the cdecli-serve messenger-gateway channel into the mobile chat UI.\n *\n * Kept in sync with `packages-modules/account/browser/src/hooks/useCdecliChannel.ts`.\n * When the CDeCLI channel is connected:\n * - `sendMessage(text, chatId, media)` calls `gatewaySendMessage`\n * - `MessengerStreamDelta` subscription delivers streaming chunks via `onChunk`\n * - `GatewayInboundMessageByChannel` delivers the final reply via `onComplete`\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { AppState } from 'react-native';\nimport { useApolloClient } from '@apollo/client';\nimport { isConnectorReply } from 'common';\nimport { quickReplyViaBrain } from '../services/brainQuickReply';\nimport { MESSENGER_ACTIVE_STREAM_QUERY, stripModelCostHeader } from './messengerStream';\nimport {\n CHAT_RUN_TIMEOUT_TEXT,\n CDECLI_MAX_RUN_MS,\n EMPTY_CHAT_RESPONSE_TEXT,\n resolveAssistantReply,\n} from '../features/chat/emptyChatResponse';\nimport { isFastLaneRunId, splitPreResponse } from '../features/chat/preResponse';\nimport {\n useGatewaySendMessageMutation,\n useGatewayInboundMessageByChannelSubscription,\n useMessengerStreamDeltaSubscription,\n} from 'common/graphql';\n\n// `error?: undefined` on the success arm keeps `result.error` reachable on the\n// union: with strictNullChecks off (repo-wide), TS will not narrow the\n// discriminated union after an `if (result.ok) continue`.\nexport type SteerResult = { ok: true; error?: undefined } | { ok: false; error: string };\n\nexport interface CdecliChannelCallbacks {\n onChunk: (text: string) => void;\n /**\n * A fast provisional answer from `yantra-brain` or `CDECLI_FAST_LANE=pre`.\n * Shown as a Quick answer strip — never the main bubble. Pass the full\n * text so far (not a delta). Do not pass `''` to hide it when the agent\n * starts; web keeps the strip beside the agent reply.\n */\n onQuickReply?: (text: string) => void;\n /**\n * The agent started a new run (typically after the fast lane). Clear the\n * main bubble so the agent's tokens do not append onto the provisional\n * article.\n */\n onStreamRestart?: () => void;\n onComplete: (text: string) => void;\n onError: (error: string) => void;\n}\n\nexport function isNoActiveSessionError(message: string): boolean {\n return /no active session/i.test(message);\n}\n\n/**\n * Idle window, not a total budget. The timer is re-armed on every streamed\n * delta (a turn that is actively streaming is not stuck), and paused while the\n * app is backgrounded (iOS suspends the WebSocket + throttles JS timers, so a\n * wall-clock timer would otherwise fire a false \"did not respond\" the instant\n * the app returns to the foreground). It fires only after this much CONTINUOUS\n * silence with the app in the foreground.\n */\nconst CDECLI_RESPONSE_TIMEOUT_MS = 300_000;\n\nexport function useCdecliChannel(\n isConnected: boolean,\n accountId: string,\n channelId: string | undefined,\n callbacks: CdecliChannelCallbacks,\n model?: string,\n skill?: string,\n) {\n const [sendMutation] = useGatewaySendMessageMutation();\n const cbRef = useRef(callbacks);\n cbRef.current = callbacks;\n\n const pendingRef = useRef<{ text: string; sentAt: number; chatId: string } | null>(null);\n const hasReceivedDeltasRef = useRef(false);\n const reconnectedStreamRef = useRef(false);\n const streamCompletedRef = useRef(false);\n const accumulatedLenRef = useRef(0);\n const lastRunIdRef = useRef<string | null>(null);\n const apolloClient = useApolloClient();\n const seededChannelRef = useRef<string | null>(null);\n const quickReplyShownRef = useRef(false);\n\n /**\n * Forward newly-accumulated stream text. Shared by live deltas and the\n * mount-time resume seed so neither gaps nor double-delivery happen when\n * the user leaves Chat for history and comes back mid-turn.\n */\n const ingestAccumulatedText = useCallback((accumulated: string, asFastLane = false) => {\n const stripped = stripModelCostHeader(accumulated);\n const { preResponse, text: fullText } = splitPreResponse(stripped);\n if (preResponse) {\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(preResponse);\n }\n if (asFastLane) {\n const fast = (preResponse || fullText).trim();\n if (fast) {\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(fast);\n }\n return;\n }\n const newChunk = fullText.substring(accumulatedLenRef.current);\n accumulatedLenRef.current = fullText.length;\n if (newChunk) cbRef.current.onChunk(newChunk);\n }, []);\n // Identity of the current turn for the brain race. A counter, not a\n // timestamp: two sends can share a millisecond, and a timestamp would then\n // let a brain answer for a superseded turn paint over the live one.\n const turnSeqRef = useRef(0);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const maxRunTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const runStartedAtRef = useRef<number | null>(null);\n const stoppingRef = useRef(false);\n\n const streamSkip = !channelId;\n const streamChannelId = channelId || accountId;\n\n const clearRunTimers = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n if (maxRunTimerRef.current) {\n clearTimeout(maxRunTimerRef.current);\n maxRunTimerRef.current = null;\n }\n }, []);\n\n const stopTurn = useCallback(\n (reason: 'idle' | 'max-run') => {\n const pending = pendingRef.current;\n if (!pending || stoppingRef.current) return;\n stoppingRef.current = true;\n const chatId = pending.chatId;\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n streamCompletedRef.current = true;\n runStartedAtRef.current = null;\n clearRunTimers();\n void sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text: '',\n metadata: { cancel: true },\n },\n },\n }).catch(() => {\n /* local stop still lands a standard reply */\n });\n cbRef.current.onComplete(reason === 'max-run' ? CHAT_RUN_TIMEOUT_TEXT : EMPTY_CHAT_RESPONSE_TEXT);\n stoppingRef.current = false;\n },\n [accountId, clearRunTimers, sendMutation],\n );\n\n /** (Re)start the idle timer for the in-flight turn. No-op if none pending. */\n const armTimeout = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (!pendingRef.current) {\n timeoutRef.current = null;\n return;\n }\n timeoutRef.current = setTimeout(() => stopTurn('idle'), CDECLI_RESPONSE_TIMEOUT_MS);\n }, [stopTurn]);\n\n /** Hard 2-minute cap from send start — still-streaming turns are cancelled too. */\n const armMaxRun = useCallback(() => {\n if (maxRunTimerRef.current) clearTimeout(maxRunTimerRef.current);\n const started = runStartedAtRef.current;\n if (!pendingRef.current || started == null) {\n maxRunTimerRef.current = null;\n return;\n }\n const remaining = CDECLI_MAX_RUN_MS - (Date.now() - started);\n maxRunTimerRef.current = setTimeout(() => stopTurn('max-run'), Math.max(0, remaining));\n }, [stopTurn]);\n\n // Pause JS timers in the background; on resume re-arm from wall-clock start\n // so a 2-minute run that finished while away is stopped immediately.\n useEffect(() => {\n const sub = AppState.addEventListener('change', (next) => {\n if (next === 'active') {\n if (pendingRef.current && !streamCompletedRef.current) {\n armTimeout();\n armMaxRun();\n }\n } else {\n clearRunTimers();\n }\n });\n return () => sub.remove();\n }, [armMaxRun, armTimeout, clearRunTimers]);\n\n useMessengerStreamDeltaSubscription({\n variables: { channelId: streamChannelId },\n skip: streamSkip,\n onData: ({ data }) => {\n const delta = data?.data?.messengerStreamDelta;\n if (!delta) return;\n\n if (delta.isFinal) return;\n\n const prevRunId = lastRunIdRef.current;\n if (delta.runId && delta.runId !== prevRunId) {\n accumulatedLenRef.current = 0;\n // Fast-lane run (`fast-…`) then agent (`serve-…`): start a fresh\n // bubble instead of appending the agent onto the provisional article.\n if (prevRunId && !isFastLaneRunId(delta.runId)) {\n cbRef.current.onStreamRestart?.();\n }\n }\n if (delta.runId) lastRunIdRef.current = delta.runId;\n\n if (streamCompletedRef.current) return;\n\n // Pick up a turn that kept running after the user left Chat for history.\n if (!pendingRef.current) {\n if (!reconnectedStreamRef.current) {\n reconnectedStreamRef.current = true;\n accumulatedLenRef.current = 0;\n }\n }\n\n hasReceivedDeltasRef.current = true;\n armTimeout();\n ingestAccumulatedText(delta.text ?? '', isFastLaneRunId(delta.runId));\n },\n onError: (err) => {\n console.error('[useCdecliChannel] stream delta subscription error:', err);\n },\n });\n\n // Seed the in-flight reply when Chat remounts (history → chat) mid-stream.\n useEffect(() => {\n if (streamSkip || !streamChannelId) return undefined;\n if (seededChannelRef.current === streamChannelId) return undefined;\n seededChannelRef.current = streamChannelId;\n accumulatedLenRef.current = 0;\n streamCompletedRef.current = false;\n reconnectedStreamRef.current = false;\n lastRunIdRef.current = null;\n\n let cancelled = false;\n apolloClient\n .query({\n query: MESSENGER_ACTIVE_STREAM_QUERY,\n variables: { channelId: streamChannelId },\n fetchPolicy: 'network-only',\n errorPolicy: 'all',\n })\n .then(({ data }) => {\n if (cancelled) return;\n const snapshot = data?.messengerActiveStream as\n | { runId?: string; text?: string; isFinal?: boolean }\n | null\n | undefined;\n if (!snapshot?.text || snapshot.isFinal) return;\n if (streamCompletedRef.current) return;\n if (accumulatedLenRef.current > 0) return;\n reconnectedStreamRef.current = true;\n hasReceivedDeltasRef.current = true;\n if (snapshot.runId) lastRunIdRef.current = snapshot.runId;\n ingestAccumulatedText(snapshot.text);\n })\n .catch(() => {\n /* pre-#701 backend or transient failure — live deltas self-heal */\n });\n return () => {\n cancelled = true;\n };\n }, [streamChannelId, streamSkip, apolloClient, ingestAccumulatedText]);\n\n useGatewayInboundMessageByChannelSubscription({\n variables: { channelId: streamChannelId },\n skip: streamSkip,\n onData: ({ data }) => {\n const msg = data?.data?.gatewayInboundMessageByChannel;\n if (!msg) return;\n if (streamCompletedRef.current) return;\n const sanitizedText = stripModelCostHeader(msg.text ?? '');\n const { preResponse, text: finalText } = splitPreResponse(sanitizedText);\n if (preResponse) cbRef.current.onQuickReply?.(preResponse);\n // Fast-lane-only inbound: keep waiting for the agent complete.\n if (msg.text && !finalText.trim() && preResponse) return;\n if (!finalText.trim() && !pendingRef.current && !hasReceivedDeltasRef.current) return;\n\n if (finalText.trim() && !hasReceivedDeltasRef.current) {\n cbRef.current.onChunk(finalText);\n }\n\n cbRef.current.onComplete(resolveAssistantReply(finalText));\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = true;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n },\n onError: (err) => {\n console.error('[useCdecliChannel] subscription error:', err);\n cbRef.current.onError(err.message || 'CDeCLI subscription error');\n },\n });\n\n const sendMessage = useCallback(\n async (\n text: string,\n chatId = 'messenger',\n media: Array<{ type: string; url: string; data?: string; mimeType?: string; filename?: string }> = [],\n ): Promise<boolean> => {\n if (!isConnected) return false;\n\n pendingRef.current = { text, sentAt: Date.now(), chatId };\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n quickReplyShownRef.current = false;\n\n // Ask the brain the same question in parallel with the send. On a cold\n // first turn the agent can take minutes before its first delta; the\n // brain answers in seconds. Its reply is painted only if nothing real\n // has arrived yet, and is replaced in place the moment it does. Fire\n // and forget: a brain failure changes nothing about the turn.\n // Never run it for media turns — the brain only sees `text`, so\n // \"what is this\" + a photo becomes a generic \"what are you referring to\".\n // Nor for a connect card's `[CONNECTOR_CONNECTED:…]` / `[CONNECTOR_DECLINED:…]`\n // reply: it answers the agent's parked request and asks nothing, so a brain\n // \"answer\" would paint a bogus bubble over the agent's real follow-up.\n const turn = ++turnSeqRef.current;\n if (media.length === 0 && !isConnectorReply(text)) {\n void quickReplyViaBrain(text).then((answer) => {\n if (!answer) return;\n // Stale if the turn moved on, or the agent already spoke.\n if (turnSeqRef.current !== turn || !pendingRef.current) return;\n if (hasReceivedDeltasRef.current || streamCompletedRef.current) return;\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(answer);\n });\n }\n\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n ...(media.length > 0 ? { media: media as never } : {}),\n ...(model || skill\n ? { metadata: { ...(model && { model }), ...(skill && { skill }) } }\n : {}),\n },\n },\n });\n\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI send failed';\n cbRef.current.onError(errMsg);\n pendingRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n return false;\n }\n\n runStartedAtRef.current = Date.now();\n armTimeout();\n armMaxRun();\n\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n cbRef.current.onError(msg);\n pendingRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n return false;\n }\n },\n [isConnected, accountId, channelId, sendMutation, model, skill, armTimeout, armMaxRun, clearRunTimers],\n );\n\n useEffect(\n () => () => {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n },\n [clearRunTimers],\n );\n\n /**\n * Inject a follow-up into the turn that is currently streaming.\n * Same `gatewaySendMessage` mutation with `metadata.steer = true` (browser\n * `useCdecliChannel.steer`). Do NOT reset streaming refs: the existing\n * delta subscription must keep running.\n *\n * \"Cannot steer: no active session\" is an expected race before cdecli has\n * started the turn. Callers should queue and retry; do not `console.error`\n * (that pops the RN LogBox and looks like a crash).\n */\n const steer = useCallback(\n async (text: string, chatId = 'messenger'): Promise<SteerResult> => {\n if (!isConnected) return { ok: false, error: 'CDeCLI is not connected.' };\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n metadata: { steer: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI steer failed';\n if (!isNoActiveSessionError(errMsg)) {\n console.warn('[useCdecliChannel] steer failed:', errMsg);\n }\n return { ok: false, error: errMsg };\n }\n return { ok: true };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn('[useCdecliChannel] steer mutation error:', msg);\n return { ok: false, error: msg };\n }\n },\n [isConnected, accountId, sendMutation],\n );\n\n /**\n * Abort the in-flight turn. `metadata.cancel = true` maps to\n * `POST /v1/chat/cancel` on cdecli-serve (browser parity).\n */\n const cancel = useCallback(\n async (chatId = 'messenger'): Promise<boolean> => {\n if (!isConnected) return false;\n pendingRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text: '',\n metadata: { cancel: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI cancel failed';\n // Trash-clear / greet flows cancel with nothing running — expected.\n if (!isNoActiveSessionError(errMsg)) {\n console.warn('[useCdecliChannel] cancel failed:', errMsg);\n }\n return false;\n }\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliChannel] cancel mutation error:', msg);\n return false;\n }\n },\n [isConnected, accountId, sendMutation, clearRunTimers],\n );\n\n return { sendMessage, steer, cancel };\n}\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"useCdecliChannel.js","sources":["../../src/hooks/useCdecliChannel.ts"],"sourcesContent":["/**\n * useCdecliChannel — wires the cdecli-serve messenger-gateway channel into the mobile chat UI.\n *\n * Kept in sync with `packages-modules/account/browser/src/hooks/useCdecliChannel.ts`.\n * When the CDeCLI channel is connected:\n * - `sendMessage(text, chatId, media)` calls `gatewaySendMessage`\n * - `MessengerStreamDelta` subscription delivers streaming chunks via `onChunk`\n * - `GatewayInboundMessageByChannel` delivers the final reply via `onComplete`\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { AppState } from 'react-native';\nimport { useApolloClient } from '@apollo/client';\nimport { isConnectorReply } from 'common';\nimport { quickReplyViaBrain } from '../services/brainQuickReply';\nimport { MESSENGER_ACTIVE_STREAM_QUERY, stripModelCostHeader } from './messengerStream';\nimport {\n CHAT_RUN_TIMEOUT_TEXT,\n CDECLI_MAX_RUN_MS,\n EMPTY_CHAT_RESPONSE_TEXT,\n resolveAssistantReply,\n} from '../features/chat/emptyChatResponse';\nimport { isFastLaneRunId, splitPreResponse } from '../features/chat/preResponse';\nimport {\n useGatewaySendMessageMutation,\n useGatewayInboundMessageByChannelSubscription,\n useMessengerStreamDeltaSubscription,\n} from 'common/graphql';\n\n// `error?: undefined` on the success arm keeps `result.error` reachable on the\n// union: with strictNullChecks off (repo-wide), TS will not narrow the\n// discriminated union after an `if (result.ok) continue`.\nexport type SteerResult = { ok: true; error?: undefined } | { ok: false; error: string };\n\n/**\n * What became of a message sent while a turn was running:\n * - `queued`: the gateway queued it for the agent, which answers it when the\n * running turn ends. `id` cancels it (`cancelQueued`).\n * - `answered`: the gateway answered it on the spot (a status question) with a\n * notice that arrives through `onNotice`.\n * - `started`: the running turn had already ended, so the agent took it right\n * away; its answer arrives as a follow-up.\n */\nexport type QueuedSendResult =\n | { status: 'queued'; id: string; error?: undefined }\n | { status: 'answered' | 'started'; id?: undefined; error?: undefined }\n | { status: 'failed'; id?: undefined; error: string };\n\n/** The gateway's send-result ids for a message it queued or answered itself. */\nconst QUEUED_EXTERNAL_ID_PREFIX = 'handoff-queued-';\nconst STATUS_EXTERNAL_ID_PREFIX = 'handoff-status-';\n/** Messages from the gateway itself (a status answer, a long-wait report). */\nconst GATEWAY_NOTICE_ID_PREFIX = 'handoff-';\n\nexport interface CdecliChannelCallbacks {\n onChunk: (text: string) => void;\n /**\n * A fast provisional answer from `yantra-brain` or `CDECLI_FAST_LANE=pre`.\n * Shown as a Quick answer strip — never the main bubble. Pass the full\n * text so far (not a delta). Do not pass `''` to hide it when the agent\n * starts; web keeps the strip beside the agent reply.\n */\n onQuickReply?: (text: string) => void;\n /**\n * The agent started a new run (typically after the fast lane). Clear the\n * main bubble so the agent's tokens do not append onto the provisional\n * article.\n */\n onStreamRestart?: () => void;\n onComplete: (text: string) => void;\n onError: (error: string) => void;\n /**\n * A message from the gateway about queued work (a status answer, a\n * long-wait report) that arrived while a reply is still streaming. It is\n * shown beside that reply and does NOT end it.\n */\n onNotice?: (text: string) => void;\n}\n\nexport function isNoActiveSessionError(message: string): boolean {\n return /no active session/i.test(message);\n}\n\n/**\n * Idle window, not a total budget. The timer is re-armed on every streamed\n * delta (a turn that is actively streaming is not stuck), and paused while the\n * app is backgrounded (iOS suspends the WebSocket + throttles JS timers, so a\n * wall-clock timer would otherwise fire a false \"did not respond\" the instant\n * the app returns to the foreground). It fires only after this much CONTINUOUS\n * silence with the app in the foreground.\n */\nconst CDECLI_RESPONSE_TIMEOUT_MS = 300_000;\n\nexport function useCdecliChannel(\n isConnected: boolean,\n accountId: string,\n channelId: string | undefined,\n callbacks: CdecliChannelCallbacks,\n model?: string,\n skill?: string,\n) {\n const [sendMutation] = useGatewaySendMessageMutation();\n const cbRef = useRef(callbacks);\n cbRef.current = callbacks;\n\n const pendingRef = useRef<{ text: string; sentAt: number; chatId: string } | null>(null);\n const hasReceivedDeltasRef = useRef(false);\n const reconnectedStreamRef = useRef(false);\n const streamCompletedRef = useRef(false);\n const accumulatedLenRef = useRef(0);\n const lastRunIdRef = useRef<string | null>(null);\n const apolloClient = useApolloClient();\n const seededChannelRef = useRef<string | null>(null);\n const quickReplyShownRef = useRef(false);\n /**\n * The run the last finished turn streamed on. After a turn ends the agent\n * can still speak with no send behind it - the gateway runs a request it\n * queued while the agent was busy and follows up with the answer. That\n * arrives as a NEW run (or a new final message) and must open a round of\n * its own; a late delta from THIS run must not.\n */\n const completedRunIdRef = useRef<string | null>(null);\n /** Final messages already delivered, so a redelivery never paints twice. */\n const deliveredInboundRef = useRef<string[]>([]);\n\n /**\n * Forward newly-accumulated stream text. Shared by live deltas and the\n * mount-time resume seed so neither gaps nor double-delivery happen when\n * the user leaves Chat for history and comes back mid-turn.\n */\n const ingestAccumulatedText = useCallback((accumulated: string, asFastLane = false) => {\n const stripped = stripModelCostHeader(accumulated);\n const { preResponse, text: fullText } = splitPreResponse(stripped);\n if (preResponse) {\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(preResponse);\n }\n if (asFastLane) {\n const fast = (preResponse || fullText).trim();\n if (fast) {\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(fast);\n }\n return;\n }\n const newChunk = fullText.substring(accumulatedLenRef.current);\n accumulatedLenRef.current = fullText.length;\n if (newChunk) cbRef.current.onChunk(newChunk);\n }, []);\n // Identity of the current turn for the brain race. A counter, not a\n // timestamp: two sends can share a millisecond, and a timestamp would then\n // let a brain answer for a superseded turn paint over the live one.\n const turnSeqRef = useRef(0);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const maxRunTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const runStartedAtRef = useRef<number | null>(null);\n const stoppingRef = useRef(false);\n\n const streamSkip = !channelId;\n const streamChannelId = channelId || accountId;\n\n const clearRunTimers = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n if (maxRunTimerRef.current) {\n clearTimeout(maxRunTimerRef.current);\n maxRunTimerRef.current = null;\n }\n }, []);\n\n const stopTurn = useCallback(\n (reason: 'idle' | 'max-run') => {\n const pending = pendingRef.current;\n if (!pending || stoppingRef.current) return;\n stoppingRef.current = true;\n const chatId = pending.chatId;\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n streamCompletedRef.current = true;\n completedRunIdRef.current = lastRunIdRef.current;\n runStartedAtRef.current = null;\n clearRunTimers();\n void sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text: '',\n metadata: { cancel: true },\n },\n },\n }).catch(() => {\n /* local stop still lands a standard reply */\n });\n cbRef.current.onComplete(reason === 'max-run' ? CHAT_RUN_TIMEOUT_TEXT : EMPTY_CHAT_RESPONSE_TEXT);\n stoppingRef.current = false;\n },\n [accountId, clearRunTimers, sendMutation],\n );\n\n /** (Re)start the idle timer for the in-flight turn. No-op if none pending. */\n const armTimeout = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (!pendingRef.current) {\n timeoutRef.current = null;\n return;\n }\n timeoutRef.current = setTimeout(() => stopTurn('idle'), CDECLI_RESPONSE_TIMEOUT_MS);\n }, [stopTurn]);\n\n /** Hard 2-minute cap from send start — still-streaming turns are cancelled too. */\n const armMaxRun = useCallback(() => {\n if (maxRunTimerRef.current) clearTimeout(maxRunTimerRef.current);\n const started = runStartedAtRef.current;\n if (!pendingRef.current || started == null) {\n maxRunTimerRef.current = null;\n return;\n }\n const remaining = CDECLI_MAX_RUN_MS - (Date.now() - started);\n maxRunTimerRef.current = setTimeout(() => stopTurn('max-run'), Math.max(0, remaining));\n }, [stopTurn]);\n\n // Pause JS timers in the background; on resume re-arm from wall-clock start\n // so a 2-minute run that finished while away is stopped immediately.\n useEffect(() => {\n const sub = AppState.addEventListener('change', (next) => {\n if (next === 'active') {\n if (pendingRef.current && !streamCompletedRef.current) {\n armTimeout();\n armMaxRun();\n }\n } else {\n clearRunTimers();\n }\n });\n return () => sub.remove();\n }, [armMaxRun, armTimeout, clearRunTimers]);\n\n useMessengerStreamDeltaSubscription({\n variables: { channelId: streamChannelId },\n skip: streamSkip,\n onData: ({ data }) => {\n const delta = data?.data?.messengerStreamDelta;\n if (!delta) return;\n\n if (delta.isFinal) return;\n\n // A new run after the turn finished, with no send behind it, is the\n // agent following up. Open a round for it rather than drop it until\n // the user happens to send again.\n if (\n streamCompletedRef.current &&\n delta.runId &&\n delta.runId !== completedRunIdRef.current &&\n !isFastLaneRunId(delta.runId)\n ) {\n streamCompletedRef.current = false;\n hasReceivedDeltasRef.current = false;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n }\n\n const prevRunId = lastRunIdRef.current;\n if (delta.runId && delta.runId !== prevRunId) {\n accumulatedLenRef.current = 0;\n // Fast-lane run (`fast-…`) then agent (`serve-…`): start a fresh\n // bubble instead of appending the agent onto the provisional article.\n if (prevRunId && !isFastLaneRunId(delta.runId)) {\n cbRef.current.onStreamRestart?.();\n }\n }\n if (delta.runId) lastRunIdRef.current = delta.runId;\n\n if (streamCompletedRef.current) return;\n\n // Pick up a turn that kept running after the user left Chat for history.\n if (!pendingRef.current) {\n if (!reconnectedStreamRef.current) {\n reconnectedStreamRef.current = true;\n accumulatedLenRef.current = 0;\n }\n }\n\n hasReceivedDeltasRef.current = true;\n armTimeout();\n ingestAccumulatedText(delta.text ?? '', isFastLaneRunId(delta.runId));\n },\n onError: (err) => {\n console.error('[useCdecliChannel] stream delta subscription error:', err);\n },\n });\n\n // Seed the in-flight reply when Chat remounts (history → chat) mid-stream.\n useEffect(() => {\n if (streamSkip || !streamChannelId) return undefined;\n if (seededChannelRef.current === streamChannelId) return undefined;\n seededChannelRef.current = streamChannelId;\n accumulatedLenRef.current = 0;\n streamCompletedRef.current = false;\n reconnectedStreamRef.current = false;\n lastRunIdRef.current = null;\n\n let cancelled = false;\n apolloClient\n .query({\n query: MESSENGER_ACTIVE_STREAM_QUERY,\n variables: { channelId: streamChannelId },\n fetchPolicy: 'network-only',\n errorPolicy: 'all',\n })\n .then(({ data }) => {\n if (cancelled) return;\n const snapshot = data?.messengerActiveStream as\n | { runId?: string; text?: string; isFinal?: boolean }\n | null\n | undefined;\n if (!snapshot?.text || snapshot.isFinal) return;\n if (streamCompletedRef.current) return;\n if (accumulatedLenRef.current > 0) return;\n reconnectedStreamRef.current = true;\n hasReceivedDeltasRef.current = true;\n if (snapshot.runId) lastRunIdRef.current = snapshot.runId;\n ingestAccumulatedText(snapshot.text);\n })\n .catch(() => {\n /* pre-#701 backend or transient failure — live deltas self-heal */\n });\n return () => {\n cancelled = true;\n };\n }, [streamChannelId, streamSkip, apolloClient, ingestAccumulatedText]);\n\n useGatewayInboundMessageByChannelSubscription({\n variables: { channelId: streamChannelId },\n skip: streamSkip,\n onData: ({ data }) => {\n const msg = data?.data?.gatewayInboundMessageByChannel;\n if (!msg) return;\n const externalId = msg.externalId ?? '';\n if (externalId && deliveredInboundRef.current.includes(externalId)) return;\n const sanitizedText = stripModelCostHeader(msg.text ?? '');\n const { preResponse, text: finalText } = splitPreResponse(sanitizedText);\n // The gateway speaking about queued work (a status answer, a\n // long-wait report) while a reply is still on its way belongs beside\n // that reply. Taken as the round's final message it would cut the\n // reply off, and the rest of its stream would be dropped.\n if (\n externalId.startsWith(GATEWAY_NOTICE_ID_PREFIX) &&\n finalText.trim() &&\n !streamCompletedRef.current &&\n (pendingRef.current || hasReceivedDeltasRef.current)\n ) {\n deliveredInboundRef.current = [...deliveredInboundRef.current.slice(-49), externalId];\n cbRef.current.onNotice?.(finalText.trim());\n return;\n }\n if (streamCompletedRef.current) {\n // A final message after the turn finished that did not stream -\n // e.g. the gateway's word on a message it queued, or a queued\n // request's answer - is a follow-up of its own. Only a message\n // this hook has not delivered yet can be one.\n if (!externalId || !finalText.trim()) return;\n streamCompletedRef.current = false;\n hasReceivedDeltasRef.current = false;\n accumulatedLenRef.current = 0;\n }\n if (preResponse) cbRef.current.onQuickReply?.(preResponse);\n // Fast-lane-only inbound: keep waiting for the agent complete.\n if (msg.text && !finalText.trim() && preResponse) return;\n if (!finalText.trim() && !pendingRef.current && !hasReceivedDeltasRef.current) return;\n\n if (finalText.trim() && !hasReceivedDeltasRef.current) {\n cbRef.current.onChunk(finalText);\n }\n\n cbRef.current.onComplete(resolveAssistantReply(finalText));\n if (externalId) deliveredInboundRef.current = [...deliveredInboundRef.current.slice(-49), externalId];\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = true;\n completedRunIdRef.current = lastRunIdRef.current;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n },\n onError: (err) => {\n console.error('[useCdecliChannel] subscription error:', err);\n cbRef.current.onError(err.message || 'CDeCLI subscription error');\n },\n });\n\n const sendMessage = useCallback(\n async (\n text: string,\n chatId = 'messenger',\n media: Array<{ type: string; url: string; data?: string; mimeType?: string; filename?: string }> = [],\n ): Promise<boolean> => {\n if (!isConnected) return false;\n\n pendingRef.current = { text, sentAt: Date.now(), chatId };\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n quickReplyShownRef.current = false;\n\n // Ask the brain the same question in parallel with the send. On a cold\n // first turn the agent can take minutes before its first delta; the\n // brain answers in seconds. Its reply is painted only if nothing real\n // has arrived yet, and is replaced in place the moment it does. Fire\n // and forget: a brain failure changes nothing about the turn.\n // Never run it for media turns — the brain only sees `text`, so\n // \"what is this\" + a photo becomes a generic \"what are you referring to\".\n // Nor for a connect card's `[CONNECTOR_CONNECTED:…]` / `[CONNECTOR_DECLINED:…]`\n // reply: it answers the agent's parked request and asks nothing, so a brain\n // \"answer\" would paint a bogus bubble over the agent's real follow-up.\n const turn = ++turnSeqRef.current;\n if (media.length === 0 && !isConnectorReply(text)) {\n void quickReplyViaBrain(text).then((answer) => {\n if (!answer) return;\n // Stale if the turn moved on, or the agent already spoke.\n if (turnSeqRef.current !== turn || !pendingRef.current) return;\n if (hasReceivedDeltasRef.current || streamCompletedRef.current) return;\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(answer);\n });\n }\n\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n ...(media.length > 0 ? { media: media as never } : {}),\n ...(model || skill\n ? { metadata: { ...(model && { model }), ...(skill && { skill }) } }\n : {}),\n },\n },\n });\n\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI send failed';\n cbRef.current.onError(errMsg);\n pendingRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n return false;\n }\n\n runStartedAtRef.current = Date.now();\n armTimeout();\n armMaxRun();\n\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n cbRef.current.onError(msg);\n pendingRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n return false;\n }\n },\n [isConnected, accountId, channelId, sendMutation, model, skill, armTimeout, armMaxRun, clearRunTimers],\n );\n\n useEffect(\n () => () => {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n runStartedAtRef.current = null;\n clearRunTimers();\n },\n [clearRunTimers],\n );\n\n /**\n * Inject a follow-up into the turn that is currently streaming.\n * Same `gatewaySendMessage` mutation with `metadata.steer = true` (browser\n * `useCdecliChannel.steer`). Do NOT reset streaming refs: the existing\n * delta subscription must keep running.\n *\n * \"Cannot steer: no active session\" is an expected race before cdecli has\n * started the turn. Callers should queue and retry; do not `console.error`\n * (that pops the RN LogBox and looks like a crash).\n */\n const steer = useCallback(\n async (text: string, chatId = 'messenger'): Promise<SteerResult> => {\n if (!isConnected) return { ok: false, error: 'CDeCLI is not connected.' };\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n metadata: { steer: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI steer failed';\n if (!isNoActiveSessionError(errMsg)) {\n console.warn('[useCdecliChannel] steer failed:', errMsg);\n }\n return { ok: false, error: errMsg };\n }\n return { ok: true };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn('[useCdecliChannel] steer mutation error:', msg);\n return { ok: false, error: msg };\n }\n },\n [isConnected, accountId, sendMutation],\n );\n\n /**\n * Send a message while a turn is running. The gateway queues it for the\n * agent, which answers it when the running turn ends - the way Claude Code\n * and Cursor queue a message typed mid-turn. `queueAware` tells the gateway\n * this client shows the queue itself, so no \"Got it\" reply comes back.\n *\n * Unlike `sendMessage` this touches none of the in-flight round's refs: the\n * running reply keeps streaming, and the queued message's answer arrives\n * later as a follow-up round of its own.\n */\n const sendQueued = useCallback(\n async (\n text: string,\n chatId = 'messenger',\n media: Array<{ type: string; url: string; data?: string; mimeType?: string; filename?: string }> = [],\n ): Promise<QueuedSendResult> => {\n if (!isConnected) return { status: 'failed', error: 'CDeCLI is not connected.' };\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n ...(media.length > 0 ? { media: media as never } : {}),\n metadata: { queueAware: true, ...(model && { model }), ...(skill && { skill }) },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) return { status: 'failed', error: payload?.error || 'CDeCLI send failed' };\n const externalId = payload.externalId ?? '';\n if (externalId.startsWith(QUEUED_EXTERNAL_ID_PREFIX)) {\n return { status: 'queued', id: externalId.slice(QUEUED_EXTERNAL_ID_PREFIX.length) };\n }\n if (externalId.startsWith(STATUS_EXTERNAL_ID_PREFIX)) return { status: 'answered' };\n return { status: 'started' };\n } catch (err) {\n return { status: 'failed', error: err instanceof Error ? err.message : String(err) };\n }\n },\n [isConnected, accountId, sendMutation, model, skill],\n );\n\n /** Take one queued message back before the agent gets to it. */\n const cancelQueued = useCallback(\n async (id: string, chatId = 'messenger'): Promise<SteerResult> => {\n if (!isConnected) return { ok: false, error: 'CDeCLI is not connected.' };\n try {\n const result = await sendMutation({\n variables: {\n input: { channelType: 'cdecli-serve', accountId, chatId, text: '', metadata: { dequeue: id } },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n return payload?.success\n ? { ok: true }\n : { ok: false, error: payload?.error || 'Could not cancel that message.' };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n },\n [isConnected, accountId, sendMutation],\n );\n\n /**\n * Abort the in-flight turn. `metadata.cancel = true` maps to\n * `POST /v1/chat/cancel` on cdecli-serve (browser parity).\n */\n const cancel = useCallback(\n async (chatId = 'messenger'): Promise<boolean> => {\n if (!isConnected) return false;\n pendingRef.current = null;\n runStartedAtRef.current = null;\n // The stopped run is over for this client: a delta it still emits\n // must not reopen as a follow-up. The next run (a queued message the\n // agent now takes) does, since its runId differs.\n if (hasReceivedDeltasRef.current || lastRunIdRef.current) {\n streamCompletedRef.current = true;\n completedRunIdRef.current = lastRunIdRef.current;\n hasReceivedDeltasRef.current = false;\n }\n clearRunTimers();\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text: '',\n metadata: { cancel: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI cancel failed';\n // Trash-clear / greet flows cancel with nothing running — expected.\n if (!isNoActiveSessionError(errMsg)) {\n console.warn('[useCdecliChannel] cancel failed:', errMsg);\n }\n return false;\n }\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliChannel] cancel mutation error:', msg);\n return false;\n }\n },\n [isConnected, accountId, sendMutation, clearRunTimers],\n );\n\n return { sendMessage, sendQueued, cancelQueued, steer, cancel };\n}\n"],"names":["_a"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import {useState,useRef,useCallback,useEffect,useMemo,useSyncExternalStore}from'react';import {useCreateAccountChatFileUploadLinksMutation,useCreateAccountChatFileDownloadLinksMutation}from'common/graphql';import {markChannelHistoryRunning,useChatMutations,useChatMessages,clearChannelHistoryRunning,patchChannelHistoryPreview}from'./useChatApi.js';import {useCdecliChannel,isNoActiveSessionError}from'./useCdecliChannel.js';import {usePrerequisiteIds}from'./usePrerequisiteIds.js';import {isAgentJwtRejected,shouldInlineGatewayMediaForHostedAgent}from'./systemTokenJwt.js';import {config}from'../config/env-config.js';import {queueGatewayMessage,MAX_QUEUED_MESSAGES,dropQueuedGatewayMessage,queuedGatewayMessages,subscribeQueuedGatewayMessages,restoreQueuedGatewayMessages,clearQueuedGatewayMessages}from'../services/queuedGatewayMessages.js';import {isImageAttachment}from'../features/attachments/isImageAttachment.js';import {buildGatewayMedia,buildGatewayMediaPreferUrls}from'../features/attachments/buildGatewayMedia.js';import {preserveAttachmentPreviews}from'../features/attachments/preserveAttachmentPreviews.js';import {releasePreviewBytes}from'../features/attachments/releasePreviewBytes.js';import {resolveAssistantReply}from'../features/chat/emptyChatResponse.js';import {appendOrReplaceAssistant,mergeOptimisticGatewayMessages,collapseConsecutiveAssistants}from'../state/chatThreadMerge.js';var __defProp = Object.defineProperty;
1
+ import {useState,useRef,useCallback,useEffect,useMemo,useSyncExternalStore}from'react';import {useCreateAccountChatFileUploadLinksMutation,useCreateAccountChatFileDownloadLinksMutation}from'common/graphql';import {markChannelHistoryRunning,useChatMutations,useChatMessages,clearChannelHistoryRunning,patchChannelHistoryPreview}from'./useChatApi.js';import {useCdecliChannel}from'./useCdecliChannel.js';import {usePrerequisiteIds}from'./usePrerequisiteIds.js';import {isAgentJwtRejected,shouldInlineGatewayMediaForHostedAgent}from'./systemTokenJwt.js';import {config}from'../config/env-config.js';import {queueGatewayMessage,MAX_QUEUED_MESSAGES,dropQueuedGatewayMessage,queuedGatewayMessages,subscribeQueuedGatewayMessages,restoreQueuedGatewayMessages,clearQueuedGatewayMessages}from'../services/queuedGatewayMessages.js';import {isImageAttachment}from'../features/attachments/isImageAttachment.js';import {buildGatewayMedia,buildGatewayMediaPreferUrls}from'../features/attachments/buildGatewayMedia.js';import {preserveAttachmentPreviews}from'../features/attachments/preserveAttachmentPreviews.js';import {releasePreviewBytes}from'../features/attachments/releasePreviewBytes.js';import {resolveAssistantReply}from'../features/chat/emptyChatResponse.js';import {appendOrReplaceAssistant,appendFollowUpAssistant,mergeOptimisticGatewayMessages,collapseConsecutiveAssistants}from'../state/chatThreadMerge.js';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -63,10 +63,9 @@ function useChatStream(sessionId, routing = {
63
63
  const [isStreaming, setIsStreaming] = useState(false);
64
64
  const [error, setError] = useState(null);
65
65
  const isSendingRef = useRef(false);
66
- const pendingSteersRef = useRef([]);
67
- const sessionLiveRef = useRef(false);
68
- const flushPendingSteersRef = useRef(async () => {
69
- });
66
+ const [queuedFollowUps, setQueuedFollowUps] = useState([]);
67
+ const queuedFollowUpsRef = useRef([]);
68
+ const [queueNotice, setQueueNotice] = useState(null);
70
69
  const sendMessageRef = useRef(async () => "failed");
71
70
  const [cdecliStreamOverrideId, setCdecliStreamOverrideId] = useState(void 0);
72
71
  const userMsgForSaveRef = useRef(null);
@@ -74,6 +73,7 @@ function useChatStream(sessionId, routing = {
74
73
  const sessionIdRef = useRef(sessionId);
75
74
  sessionIdRef.current = sessionId || cdecliStreamOverrideId || null;
76
75
  const cdecliRoundHandledRef = useRef(false);
76
+ const followUpRoundRef = useRef(false);
77
77
  const authRetryUsedRef = useRef(false);
78
78
  const recoveringAuthRef = useRef(false);
79
79
  const routingRef = useRef(routing);
@@ -124,7 +124,8 @@ function useChatStream(sessionId, routing = {
124
124
  clearPendingStream();
125
125
  saveSessionIdRef.current = null;
126
126
  userMsgForSaveRef.current = null;
127
- sessionLiveRef.current = false;
127
+ followUpRoundRef.current = false;
128
+ setQueueNotice(null);
128
129
  setResponse("");
129
130
  setQuickReply("");
130
131
  setIsLoading(false);
@@ -143,6 +144,7 @@ function useChatStream(sessionId, routing = {
143
144
  onChunk: (text) => {
144
145
  if (!isSendingRef.current) {
145
146
  isSendingRef.current = true;
147
+ followUpRoundRef.current = true;
146
148
  cdecliRoundHandledRef.current = false;
147
149
  saveSessionIdRef.current = sessionIdRef.current;
148
150
  setIsLoading(true);
@@ -150,23 +152,30 @@ function useChatStream(sessionId, routing = {
150
152
  setError(null);
151
153
  const sid = sessionIdRef.current;
152
154
  if (sid) markChannelHistoryRunning(sid, text);
155
+ const started = queuedFollowUpsRef.current;
156
+ if (started.length > 0) {
157
+ queuedFollowUpsRef.current = [];
158
+ setQueuedFollowUps([]);
159
+ setMessages((prev) => [...prev, ...started.map((q) => ({
160
+ role: "user",
161
+ content: q.text,
162
+ attachments: q.attachments
163
+ }))]);
164
+ }
153
165
  }
154
166
  pendingStreamRef.current += text;
155
- if (!sessionLiveRef.current) {
156
- sessionLiveRef.current = true;
157
- void flushPendingSteersRef.current();
158
- }
159
167
  if (streamFlushTimerRef.current == null) {
160
168
  streamFlushTimerRef.current = setTimeout(flushPendingStream, 50);
161
169
  }
162
170
  },
163
171
  // The brain's provisional answer is the WHOLE reply-so-far, not a chunk:
164
172
  // it is set outright, and set to '' when the real stream supersedes it.
165
- // It deliberately does not mark the session live - steers wait for the
166
- // agent, which is the only side that can act on them.
167
173
  onQuickReply: (text) => {
168
174
  setQuickReply(text);
169
175
  },
176
+ onNotice: (text) => {
177
+ setQueueNotice(text);
178
+ },
170
179
  onStreamRestart: () => {
171
180
  clearPendingStream();
172
181
  pendingStreamRef.current = "";
@@ -183,7 +192,6 @@ function useChatStream(sessionId, routing = {
183
192
  if (await tryRecoverAndResendRef.current(text)) return;
184
193
  if (cdecliRoundHandledRef.current) return;
185
194
  cdecliRoundHandledRef.current = true;
186
- pendingSteersRef.current = [];
187
195
  setError(isAgentJwtRejected(text) ? text : "CDeCLI agent error. Check gateway status and server-side LLM configuration.");
188
196
  finalizeCdecliRound(isAgentJwtRejected(text) ? void 0 : text);
189
197
  })();
@@ -194,15 +202,16 @@ function useChatStream(sessionId, routing = {
194
202
  const reply = resolveAssistantReply(text);
195
203
  const sid = saveSessionIdRef.current;
196
204
  const um = userMsgForSaveRef.current;
197
- const leftover = pendingSteersRef.current;
198
- pendingSteersRef.current = [];
205
+ const followUp = followUpRoundRef.current;
199
206
  saveSessionIdRef.current = null;
200
207
  userMsgForSaveRef.current = null;
201
- sessionLiveRef.current = false;
202
- setMessages((prev) => appendOrReplaceAssistant(prev, {
208
+ followUpRoundRef.current = false;
209
+ setQueueNotice(null);
210
+ const assistant = {
203
211
  role: "assistant",
204
212
  content: reply
205
- }));
213
+ };
214
+ setMessages((prev) => followUp ? appendFollowUpAssistant(prev, assistant) : appendOrReplaceAssistant(prev, assistant));
206
215
  const previewSid = sid || sessionIdRef.current;
207
216
  if (previewSid) {
208
217
  clearChannelHistoryRunning(previewSid);
@@ -241,13 +250,6 @@ function useChatStream(sessionId, routing = {
241
250
  console.error("[useChatStream] saveMessages (cdecli):", e);
242
251
  });
243
252
  }
244
- if (leftover.length > 0) {
245
- const [first, ...rest] = leftover;
246
- pendingSteersRef.current = rest;
247
- queueMicrotask(() => {
248
- void sendMessageRef.current(first, void 0, sid, true);
249
- });
250
- }
251
253
  },
252
254
  onError: (err) => {
253
255
  if (cdecliRoundHandledRef.current) return;
@@ -255,7 +257,6 @@ function useChatStream(sessionId, routing = {
255
257
  if (await tryRecoverAndResendRef.current(err)) return;
256
258
  if (cdecliRoundHandledRef.current) return;
257
259
  cdecliRoundHandledRef.current = true;
258
- pendingSteersRef.current = [];
259
260
  setError(err || "CDeCLI stream error.");
260
261
  finalizeCdecliRound(resolveAssistantReply(""));
261
262
  })();
@@ -263,29 +264,14 @@ function useChatStream(sessionId, routing = {
263
264
  }), [saveMessages, accountUserId, finalizeCdecliRound, flushPendingStream, clearPendingStream]);
264
265
  const {
265
266
  sendMessage: sendCdecliMessage,
266
- steer: steerCdecliMessage,
267
+ sendQueued: sendQueuedCdecli,
268
+ cancelQueued: cancelQueuedCdecli,
267
269
  cancel: cancelCdecliTurn
268
270
  } = useCdecliChannel(routing.channelConnected, routing.accountId, streamChannelId, cdecliCallbacks);
269
- const flushPendingSteers = useCallback(async () => {
270
- if (!sessionLiveRef.current || !isSendingRef.current) return;
271
- const sid = saveSessionIdRef.current;
272
- if (!sid) return;
273
- while (pendingSteersRef.current.length > 0 && sessionLiveRef.current && isSendingRef.current) {
274
- const next = pendingSteersRef.current[0];
275
- const result = await steerCdecliMessage(next, sid);
276
- if (result.ok) {
277
- pendingSteersRef.current.shift();
278
- continue;
279
- }
280
- if (isNoActiveSessionError(result.error)) {
281
- return;
282
- }
283
- pendingSteersRef.current.shift();
284
- setError(result.error || "Could not send follow-up. Try again.");
285
- return;
286
- }
287
- }, [steerCdecliMessage]);
288
- flushPendingSteersRef.current = flushPendingSteers;
271
+ const setQueue = useCallback((next) => {
272
+ queuedFollowUpsRef.current = next;
273
+ setQueuedFollowUps(next);
274
+ }, []);
289
275
  useEffect(() => {
290
276
  if (sessionId && cdecliStreamOverrideId && sessionId === cdecliStreamOverrideId) {
291
277
  setCdecliStreamOverrideId(void 0);
@@ -295,9 +281,10 @@ function useChatStream(sessionId, routing = {
295
281
  const prevSid = lastHydratedSessionIdRef.current;
296
282
  if (prevSid && sessionId && prevSid !== sessionId && isSendingRef.current) {
297
283
  clearPendingStream();
298
- pendingSteersRef.current = [];
284
+ setQueue([]);
285
+ setQueueNotice(null);
299
286
  isSendingRef.current = false;
300
- sessionLiveRef.current = false;
287
+ followUpRoundRef.current = false;
301
288
  cdecliRoundHandledRef.current = false;
302
289
  saveSessionIdRef.current = null;
303
290
  userMsgForSaveRef.current = null;
@@ -356,7 +343,7 @@ function useChatStream(sessionId, routing = {
356
343
  setQuickReply("");
357
344
  }
358
345
  }
359
- }, [sessionId, backendMessages, backendMessagesLoaded, clearPendingStream]);
346
+ }, [sessionId, backendMessages, backendMessagesLoaded, clearPendingStream, setQueue]);
360
347
  const sendMessage = useCallback(async (content, attachments, sessionIdOverride, alreadyVisible = false, queuedId = void 0) => {
361
348
  var _a;
362
349
  if (!content.trim() && !(attachments == null ? void 0 : attachments.length)) return "failed";
@@ -394,15 +381,30 @@ function useChatStream(sessionId, routing = {
394
381
  setError("Missing chat session id.");
395
382
  return "failed";
396
383
  }
397
- if (!alreadyVisible) setMessages((prev) => [...prev, userMessage]);
398
- setError(null);
399
- pendingSteersRef.current = [...pendingSteersRef.current, sendText];
384
+ const media2 = (attachments == null ? void 0 : attachments.length) ? buildGatewayMedia(attachments, {
385
+ includeData: true
386
+ }) : [];
387
+ const outcome = await sendQueuedCdecli(sendText, effectiveSessionId, media2);
388
+ if (outcome.status === "failed") {
389
+ setError(outcome.error || "Could not send the message. Try again.");
390
+ return "failed";
391
+ }
400
392
  if (queuedId) dropQueuedGatewayMessage(queuedId);
401
- void flushPendingSteers();
393
+ setError(null);
394
+ if (outcome.status === "queued") {
395
+ setQueue([...queuedFollowUpsRef.current, {
396
+ id: outcome.id,
397
+ text: sendText,
398
+ attachments: releasePreviewBytes(attachments)
399
+ }]);
400
+ if (alreadyVisible) setMessages((prev) => withoutTrailingUserMessage(prev, sendText));
401
+ } else if (!alreadyVisible) {
402
+ setMessages((prev) => [...prev, userMessage]);
403
+ }
402
404
  return "sent";
403
405
  }
404
406
  isSendingRef.current = true;
405
- sessionLiveRef.current = false;
407
+ followUpRoundRef.current = false;
406
408
  ignoreHydrationRef.current = false;
407
409
  if (effectiveSessionId && sendText) {
408
410
  titlePatchedChannelsRef.current.add(effectiveSessionId);
@@ -492,7 +494,7 @@ function useChatStream(sessionId, routing = {
492
494
  }
493
495
  if (ok && queuedId) dropQueuedGatewayMessage(queuedId);
494
496
  return ok ? "sent" : "failed";
495
- }, [sessionId, sendCdecliMessage, patchChannelTitle, flushPendingSteers, createAccountChatFileUploadLinksMutation, createAccountChatFileDownloadLinksMutation]);
497
+ }, [sessionId, sendCdecliMessage, patchChannelTitle, sendQueuedCdecli, setQueue, createAccountChatFileUploadLinksMutation, createAccountChatFileDownloadLinksMutation]);
496
498
  sendMessageRef.current = sendMessage;
497
499
  const queuedChannelId = sessionId || cdecliStreamOverrideId || null;
498
500
  const queuedSnapshot = useCallback(() => queuedGatewayMessages(queuedChannelId, routing.accountId), [queuedChannelId, routing.accountId]);
@@ -566,8 +568,6 @@ function useChatStream(sessionId, routing = {
566
568
  const cancel = useCallback(() => {
567
569
  var _a;
568
570
  clearPendingStream();
569
- pendingSteersRef.current = [];
570
- sessionLiveRef.current = false;
571
571
  const sid = (_a = saveSessionIdRef.current) != null ? _a : sessionId;
572
572
  void cancelCdecliTurn(sid != null ? sid : "messenger");
573
573
  if (!cdecliRoundHandledRef.current) {
@@ -578,10 +578,8 @@ function useChatStream(sessionId, routing = {
578
578
  const clearMessages = useCallback(() => {
579
579
  var _a;
580
580
  clearPendingStream();
581
- pendingSteersRef.current = [];
582
- const hadActiveTurn = isSendingRef.current || sessionLiveRef.current;
581
+ const hadActiveTurn = isSendingRef.current;
583
582
  const sid = (_a = saveSessionIdRef.current) != null ? _a : sessionId;
584
- sessionLiveRef.current = false;
585
583
  isSendingRef.current = false;
586
584
  cdecliRoundHandledRef.current = true;
587
585
  saveSessionIdRef.current = null;
@@ -591,6 +589,9 @@ function useChatStream(sessionId, routing = {
591
589
  }
592
590
  ignoreHydrationRef.current = true;
593
591
  if (sid) clearQueuedGatewayMessages(sid);
592
+ for (const queued of queuedFollowUpsRef.current) void cancelQueuedCdecli(queued.id, sid != null ? sid : "messenger");
593
+ setQueue([]);
594
+ setQueueNotice(null);
594
595
  setMessages([]);
595
596
  setResponse("");
596
597
  setQuickReply("");
@@ -598,7 +599,20 @@ function useChatStream(sessionId, routing = {
598
599
  setIsLoading(false);
599
600
  setIsStreaming(false);
600
601
  if (sid) clearChannelHistoryRunning(sid);
601
- }, [cancelCdecliTurn, clearPendingStream, sessionId]);
602
+ }, [cancelCdecliTurn, cancelQueuedCdecli, clearPendingStream, sessionId, setQueue]);
603
+ const cancelQueuedFollowUp = useCallback(async (id) => {
604
+ const sid = sessionIdRef.current;
605
+ if (!sid) return;
606
+ const result = await cancelQueuedCdecli(id, sid);
607
+ if (result.ok) {
608
+ setQueue(queuedFollowUpsRef.current.filter((q) => q.id !== id));
609
+ } else {
610
+ setError(result.error || "Could not cancel that message.");
611
+ }
612
+ }, [cancelQueuedCdecli, setQueue]);
613
+ const sendQueuedNow = useCallback(() => {
614
+ if (isSendingRef.current) cancel();
615
+ }, [cancel]);
602
616
  const messagesLoading = !!sessionId && backendMessagesLoading && !backendMessagesLoaded;
603
617
  return {
604
618
  messages,
@@ -608,12 +622,18 @@ function useChatStream(sessionId, routing = {
608
622
  isLoading,
609
623
  isStreaming,
610
624
  messagesLoading,
611
- hasMessages: messages.length > 0 || !!response || !!quickReply || queuedMessages.length > 0,
625
+ hasMessages: messages.length > 0 || !!response || !!quickReply || queuedMessages.length > 0 || queuedFollowUps.length > 0,
612
626
  /** Turns waiting on the gateway, oldest first. Rendered as queued bubbles. */
613
627
  queuedMessages,
614
628
  /** Send the queue now (the notice's retry), independent of the reconnect edge. */
615
629
  flushQueuedMessages,
616
630
  discardQueuedMessages,
631
+ /** Sent while the agent was busy and queued for it, oldest first. */
632
+ queuedFollowUps,
633
+ /** The gateway's latest word on the running work, while it runs. */
634
+ queueNotice,
635
+ cancelQueuedFollowUp,
636
+ sendQueuedNow,
617
637
  sendMessage,
618
638
  cancel,
619
639
  clearMessages