Skip to content

Commit 2470658

Browse files
pandemieMaxLeiterjridgewell
authoredAug 31, 2023
handle partial chunks in react getStreamedResponse (vercel#524)
Co-authored-by: Max Leiter <max.leiter@vercel.com> Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
1 parent ec4bfa0 commit 2470658

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed
 

‎.changeset/popular-badgers-applaud.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'ai': patch
3+
---
4+
5+
ai/react: fix: handle partial chunks in react getStreamedResponse

‎docs/pages/docs/api-reference/use-chat.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ Options passed to `useChat`:
109109
[
110110
'sendExtraMessageFields',
111111
'boolean',
112-
'An optional boolean that determines whether to send extra fields you\'ve added to `messages`. Defaults to `false` and only the `content` and `role` fields will be sent to the API endpoint.'
112+
"An optional boolean that determines whether to send extra fields you've added to `messages`. Defaults to `false` and only the `content` and `role` fields will be sent to the API endpoint."
113113
]
114114
]}
115115
/>

‎packages/core/react/use-chat.ts

+27-3
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,39 @@ const getStreamedResponse = async (
156156
}
157157

158158
const prefixMap: PrefixMap = {}
159+
const NEWLINE = '\n'.charCodeAt(0)
160+
let chunks: Uint8Array[] = []
161+
let totalLength = 0
159162

160163
if (isComplexMode) {
161164
while (true) {
162-
const { done, value } = await reader.read()
163-
if (done) {
165+
const { value } = await reader.read()
166+
if (value) {
167+
chunks.push(value)
168+
totalLength += value.length
169+
if (value[value.length - 1] !== NEWLINE) {
170+
// if the last character is not a newline, we have not read the whole JSON value
171+
continue
172+
}
173+
}
174+
175+
if (chunks.length === 0) {
176+
// we have reached the end of the stream
164177
break
165178
}
179+
180+
// concatenate all the chunks into a single Uint8Array
181+
let concatenatedChunks = new Uint8Array(totalLength)
182+
let offset = 0
183+
for (const chunk of chunks) {
184+
concatenatedChunks.set(chunk, offset)
185+
offset += chunk.length
186+
}
187+
chunks.length = 0
188+
totalLength = 0
189+
166190
// Update the chat state with the new message tokens.
167-
const lines = decode(value)
191+
const lines = decode(concatenatedChunks)
168192
if (typeof lines === 'string') {
169193
throw new Error(
170194
'Invalid response format. Complex mode was set but the response is a string. This should never happen.'

0 commit comments

Comments
 (0)
Please sign in to comment.