MCPcopy Create free account
hub / github.com/TanStack/ai / processConverseStream

Function processConverseStream

packages/ai-bedrock/src/converse/stream-processor.ts:61–309  ·  view source on GitHub ↗
(
  stream: AsyncIterable<ConverseStreamOutput>,
  newMessageId: () => string,
  lifecycle: { threadId?: string; parentRunId?: string; model?: string } = {},
)

Source from the content-addressed store, hash-verified

59 * previous behaviour (fresh `threadId`, no `parentRunId`).
60 */
61export async function* processConverseStream(
62 stream: AsyncIterable<ConverseStreamOutput>,
63 newMessageId: () => string,
64 lifecycle: { threadId?: string; parentRunId?: string; model?: string } = {},
65): AsyncIterable<StreamChunk> {
66 const runId = newMessageId()
67 const threadId = lifecycle.threadId ?? newMessageId()
68 const { parentRunId, model } = lifecycle
69 const messageId = newMessageId()
70
71 let hasEmittedRunStarted = false
72
73 // Text lifecycle
74 let accumulatedContent = ''
75 let hasEmittedTextMessageStart = false
76
77 // Reasoning lifecycle
78 let reasoningMessageId: string | undefined
79 let hasClosedReasoning = false
80
81 // Tool-call lifecycle, keyed by Converse contentBlockIndex. Converse opens a
82 // tool-use block with `contentBlockStart`, streams arg fragments via
83 // `contentBlockDelta`, and closes it with `contentBlockStop`.
84 const toolCallsByIndex = new Map<
85 number,
86 { id: string; name: string; started: boolean }
87 >()
88
89 // Usage + finish-reason are captured during iteration and folded into the
90 // single terminal RUN_FINISHED, matching openai-base's deferred-finish
91 // contract (usage may arrive after the finish signal).
92 let usage:
93 | { promptTokens: number; completionTokens: number; totalTokens: number }
94 | undefined
95 let finishReason: NonNullable<RunFinishedEvent['finishReason']> | undefined
96
97 // Lazily emit RUN_STARTED exactly once, before the first content event.
98 function* ensureRunStarted(): Generator<StreamChunk> {
99 if (hasEmittedRunStarted) return
100 hasEmittedRunStarted = true
101 yield {
102 type: EventType.RUN_STARTED,
103 runId,
104 threadId,
105 parentRunId,
106 ...(model && { model }),
107 timestamp: Date.now(),
108 }
109 }
110
111 // Close an open reasoning message before text/tool content begins, mirroring
112 // openai-base which always emits REASONING_MESSAGE_END before TEXT_MESSAGE_START.
113 function* closeReasoning(): Generator<StreamChunk> {
114 if (reasoningMessageId && !hasClosedReasoning) {
115 hasClosedReasoning = true
116 yield {
117 type: EventType.REASONING_MESSAGE_END,
118 messageId: reasoningMessageId,

Callers 4

chatStreamMethod · 0.90
collectFunction · 0.90
drainFunction · 0.90

Calls 7

ensureRunStartedFunction · 0.85
nowMethod · 0.80
closeReasoningFunction · 0.70
setMethod · 0.65
getMethod · 0.65
deleteMethod · 0.65

Tested by 2

collectFunction · 0.72
drainFunction · 0.72