(params: {
aiMessageId: string
timerController: SendMessageTimerController
setMessages: (updater: (messages: ChatMessage[]) => ChatMessage[]) => void
streamRefs: StreamController
abortControllerRef: MutableRefObject<AbortController | null>
setStreamStatus: (status: StreamStatus) => void
setCanProcessQueue: (can: boolean) => void
isQueuePausedRef?: MutableRefObject<boolean>
isProcessingQueueRef?: MutableRefObject<boolean>
updateChainInProgress: (value: boolean) => void
setIsRetrying: (value: boolean) => void
setStreamingAgents: (updater: (prev: Set<string>) => Set<string>) => void
})
| 257 | } |
| 258 | |
| 259 | export const setupStreamingContext = (params: { |
| 260 | aiMessageId: string |
| 261 | timerController: SendMessageTimerController |
| 262 | setMessages: (updater: (messages: ChatMessage[]) => ChatMessage[]) => void |
| 263 | streamRefs: StreamController |
| 264 | abortControllerRef: MutableRefObject<AbortController | null> |
| 265 | setStreamStatus: (status: StreamStatus) => void |
| 266 | setCanProcessQueue: (can: boolean) => void |
| 267 | isQueuePausedRef?: MutableRefObject<boolean> |
| 268 | isProcessingQueueRef?: MutableRefObject<boolean> |
| 269 | updateChainInProgress: (value: boolean) => void |
| 270 | setIsRetrying: (value: boolean) => void |
| 271 | setStreamingAgents: (updater: (prev: Set<string>) => Set<string>) => void |
| 272 | }) => { |
| 273 | const { |
| 274 | timerController, |
| 275 | setMessages, |
| 276 | streamRefs, |
| 277 | abortControllerRef, |
| 278 | setStreamStatus, |
| 279 | setCanProcessQueue, |
| 280 | isQueuePausedRef, |
| 281 | isProcessingQueueRef, |
| 282 | updateChainInProgress, |
| 283 | setIsRetrying, |
| 284 | setStreamingAgents, |
| 285 | } = params |
| 286 | const { aiMessageId } = params |
| 287 | |
| 288 | streamRefs.reset() |
| 289 | timerController.start(aiMessageId) |
| 290 | const updater = createBatchedMessageUpdater(aiMessageId, setMessages) |
| 291 | // Clear any previous UI-only error on this message when starting a new run |
| 292 | updater.clearUserError() |
| 293 | const hasReceivedContentRef = { current: false } |
| 294 | const abortController = new AbortController() |
| 295 | abortControllerRef.current = abortController |
| 296 | |
| 297 | abortController.signal.addEventListener('abort', () => { |
| 298 | // Abort means the user stopped streaming; update UI with an interruption notice. |
| 299 | // Release the chain lock immediately so new messages can be sent directly instead |
| 300 | // of being queued. The minor trade-off is that if the user sends a new message |
| 301 | // before client.run() resolves, it may use stale previousRunStateRef. This is |
| 302 | // acceptable because: (1) the user explicitly cancelled, and (2) client.run() |
| 303 | // will update previousRunStateRef when it eventually resolves, so subsequent |
| 304 | // runs will have the full state. |
| 305 | streamRefs.setters.setWasAbortedByUser(true) |
| 306 | setIsRetrying(false) |
| 307 | timerController.stop('aborted') |
| 308 | |
| 309 | // Update stream status so the UI reflects cancellation visually |
| 310 | setStreamStatus('idle') |
| 311 | |
| 312 | // Clear streaming agents so cancelled status displays correctly in UI |
| 313 | setStreamingAgents(() => new Set()) |
| 314 | |
| 315 | // Release chain lock and queue state so new messages are sent directly |
| 316 | updateChainInProgress(false) |
no test coverage detected