Skip to content

Commit ec33b97

Browse files
committed
fix(sdk): preserve stream backpressure when tapping chat chunks
Tap the response stream with a TransformStream instead of an async generator. The generator forced ensureReadableStream down its eager-drain wrapper, which enqueues without honoring desiredSize (dropping backpressure to the model stream) and never propagates consumer cancel to the source. piping through a TransformStream keeps the ReadableStream pass-through, so native backpressure and stop/cancel propagation are retained. Also stamp an id on a recovered partial that lacks one, matching the success path.
1 parent 882364a commit ec33b97

1 file changed

Lines changed: 16 additions & 15 deletions

File tree

  • packages/trigger-sdk/src/v3

packages/trigger-sdk/src/v3/ai.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7949,6 +7949,9 @@ function chatAgent<
79497949
partialResponse = undefined;
79507950
partialIdx = -1;
79517951
}
7952+
if (partialResponse && !partialResponse.id) {
7953+
partialResponse = { ...partialResponse, id: generateMessageId() } as TUIMessage;
7954+
}
79527955
const erroredUIMessagesWithPartial: TUIMessage[] = !partialResponse
79537956
? erroredUIMessages
79547957
: partialIdx === -1
@@ -8982,28 +8985,26 @@ export type PipeAndCaptureResult = {
89828985
* can return, and propagates a source error to the consumer after buffering
89838986
* whatever streamed first. See {@link pipeChatAndCapture} for why.
89848987
*/
8985-
async function* tapUIMessageChunks(
8988+
function tapUIMessageChunks(
89868989
source: AsyncIterable<unknown> | ReadableStream<unknown>,
89878990
buffer: UIMessageChunk[]
8988-
): AsyncGenerator<unknown> {
8991+
): ReadableStream<unknown> | AsyncGenerator<unknown> {
89898992
if (isReadableStream(source)) {
8990-
const reader = source.getReader();
8991-
try {
8992-
while (true) {
8993-
const { done, value } = await reader.read();
8994-
if (done) break;
8995-
buffer.push(value as UIMessageChunk);
8996-
yield value;
8997-
}
8998-
} finally {
8999-
reader.releaseLock();
9000-
}
9001-
} else {
8993+
return source.pipeThrough(
8994+
new TransformStream<unknown, unknown>({
8995+
transform(chunk, controller) {
8996+
buffer.push(chunk as UIMessageChunk);
8997+
controller.enqueue(chunk);
8998+
},
8999+
})
9000+
);
9001+
}
9002+
return (async function* () {
90029003
for await (const chunk of source) {
90039004
buffer.push(chunk as UIMessageChunk);
90049005
yield chunk;
90059006
}
9006-
}
9007+
})();
90079008
}
90089009

90099010
/**

0 commit comments

Comments
 (0)