| 424 | |
| 425 | return new ReadableStream<Uint8Array>({ |
| 426 | async start(controller) { |
| 427 | const reader = response.body?.getReader() |
| 428 | if (!reader) { |
| 429 | controller.close() |
| 430 | return |
| 431 | } |
| 432 | |
| 433 | const decoder = new TextDecoder() |
| 434 | let buffer = '' |
| 435 | |
| 436 | try { |
| 437 | while (true) { |
| 438 | const { done, value } = await reader.read() |
| 439 | if (done) { |
| 440 | break |
| 441 | } |
| 442 | |
| 443 | buffer += decoder.decode(value, { stream: true }) |
| 444 | const lines = buffer.split('\n') |
| 445 | buffer = lines.pop() || '' |
| 446 | |
| 447 | for (const line of lines) { |
| 448 | const trimmed = line.trim() |
| 449 | if (!trimmed) { |
| 450 | continue |
| 451 | } |
| 452 | |
| 453 | if (trimmed.startsWith('event:')) { |
| 454 | activeEventType = trimmed.slice(6).trim() |
| 455 | continue |
| 456 | } |
| 457 | |
| 458 | if (!trimmed.startsWith('data:')) { |
| 459 | continue |
| 460 | } |
| 461 | |
| 462 | const data = trimmed.slice(5).trim() |
| 463 | if (data === '[DONE]') { |
| 464 | continue |
| 465 | } |
| 466 | |
| 467 | let event: Record<string, unknown> |
| 468 | try { |
| 469 | event = JSON.parse(data) |
| 470 | } catch (error) { |
| 471 | logger.debug('Skipping non-JSON response stream chunk', { |
| 472 | data: data.slice(0, 200), |
| 473 | error, |
| 474 | }) |
| 475 | continue |
| 476 | } |
| 477 | |
| 478 | const eventType = event?.type ?? activeEventType |
| 479 | |
| 480 | if ( |
| 481 | eventType === 'response.error' || |
| 482 | eventType === 'error' || |
| 483 | eventType === 'response.failed' |