( aiMessageId: string, setMessages: SetMessagesFn, )
| 29 | export const DEFAULT_FLUSH_INTERVAL_MS = 100 |
| 30 | |
| 31 | export const createMessageUpdater = ( |
| 32 | aiMessageId: string, |
| 33 | setMessages: SetMessagesFn, |
| 34 | ): MessageUpdater => { |
| 35 | const updateAiMessage = (updater: (msg: ChatMessage) => ChatMessage) => { |
| 36 | setMessages((prev) => |
| 37 | prev.map((msg) => (msg.id === aiMessageId ? updater(msg) : msg)), |
| 38 | ) |
| 39 | } |
| 40 | |
| 41 | const updateAiMessageBlocks = ( |
| 42 | blockUpdater: (blocks: ContentBlock[]) => ContentBlock[], |
| 43 | ) => { |
| 44 | updateAiMessage((msg) => ({ |
| 45 | ...msg, |
| 46 | blocks: blockUpdater(msg.blocks ?? []), |
| 47 | })) |
| 48 | } |
| 49 | |
| 50 | const addBlock = (block: ContentBlock) => { |
| 51 | updateAiMessage((msg) => ({ |
| 52 | ...msg, |
| 53 | blocks: [...(msg.blocks ?? []), block], |
| 54 | })) |
| 55 | } |
| 56 | |
| 57 | const markComplete = (metadata?: Partial<ChatMessage>) => { |
| 58 | updateAiMessage((msg) => { |
| 59 | const { metadata: messageMetadata, ...rest } = metadata ?? {} |
| 60 | |
| 61 | // Mark native reasoning blocks as complete by setting thinkingOpen = false |
| 62 | // This ensures thinking blocks auto-collapse when the message finishes |
| 63 | // Check for thinkingOpen !== false to handle both true (native) and undefined (legacy) |
| 64 | const updatedBlocks = msg.blocks?.map((block) => { |
| 65 | if ( |
| 66 | block.type === 'text' && |
| 67 | (block as TextContentBlock).textType === 'reasoning' && |
| 68 | (block as TextContentBlock).thinkingOpen !== false |
| 69 | ) { |
| 70 | return { ...block, thinkingOpen: false } as ContentBlock |
| 71 | } |
| 72 | return block |
| 73 | }) |
| 74 | |
| 75 | const nextMessage: ChatMessage = { |
| 76 | ...msg, |
| 77 | isComplete: true, |
| 78 | ...(updatedBlocks && { blocks: updatedBlocks }), |
| 79 | ...rest, |
| 80 | } |
| 81 | |
| 82 | if (messageMetadata) { |
| 83 | nextMessage.metadata = { |
| 84 | ...(msg.metadata ?? {}), |
| 85 | ...messageMetadata, |
| 86 | } |
| 87 | } |
| 88 |
no outgoing calls