( responseBody: string | undefined, )
| 1256 | // Takes raw HTTP response data and turns it into an OpenAI ChatCompletion object, regardless of whether |
| 1257 | // it's a streaming or non-streaming response |
| 1258 | async function parseOpenAIResponse( |
| 1259 | responseBody: string | undefined, |
| 1260 | ): Promise<ChatCompletion | undefined> { |
| 1261 | // Check if it's a streaming response (Server-Sent Events format) |
| 1262 | if (responseBody?.startsWith("data:")) { |
| 1263 | const lines = responseBody |
| 1264 | .split("\n") |
| 1265 | .filter((line) => line.startsWith("data:") && !line.includes("[DONE]")); |
| 1266 | const chunks = lines.map( |
| 1267 | (line) => JSON.parse(line.slice(5)) as ChatCompletionChunk, |
| 1268 | ); |
| 1269 | |
| 1270 | // Convert the sequence of chunks into a final ChatCompletion object |
| 1271 | // TODO: Do we need to apply fixCAPIStreamingToolCalling normalization here? |
| 1272 | const readableStream = new ReadableStream({ |
| 1273 | async start(controller) { |
| 1274 | for (const chunk of chunks) { |
| 1275 | controller.enqueue( |
| 1276 | new TextEncoder().encode(JSON.stringify(chunk) + "\n"), |
| 1277 | ); |
| 1278 | } |
| 1279 | controller.close(); |
| 1280 | }, |
| 1281 | }); |
| 1282 | |
| 1283 | return await ChatCompletionStream.fromReadableStream( |
| 1284 | readableStream, |
| 1285 | ).finalChatCompletion(); |
| 1286 | } else if (responseBody) { |
| 1287 | return JSON.parse(responseBody) as ChatCompletion; |
| 1288 | } |
| 1289 | } |
| 1290 | |
| 1291 | // Checks if requestMessages is a prefix of savedMessages, |
| 1292 | // and returns the index of the next assistant message if found. |
no test coverage detected
searching dependent graphs…