| 398 | } |
| 399 | |
| 400 | const transformResponse = async (response: Response) => { |
| 401 | if (!response.ok && response.status === 400) { |
| 402 | try { |
| 403 | const errorData = await response.clone().json() |
| 404 | const errorMessage = String(errorData.message || errorData.error || "") |
| 405 | if (errorMessage.toLowerCase().includes("conversation complete")) { |
| 406 | return new Response( |
| 407 | JSON.stringify({ |
| 408 | choices: [{ finish_reason: "stop", message: { content: "", role: "assistant" } }], |
| 409 | }), |
| 410 | { status: 200, headers: new Headers({ "content-type": "application/json" }) }, |
| 411 | ) |
| 412 | } |
| 413 | } catch {} |
| 414 | } |
| 415 | |
| 416 | if (response.body && response.headers.get("content-type")?.includes("text/event-stream")) { |
| 417 | const reader = response.body.getReader() |
| 418 | const encoder = new TextEncoder() |
| 419 | const decoder = new TextDecoder() |
| 420 | const stream = new ReadableStream({ |
| 421 | async pull(ctrl) { |
| 422 | const { done, value } = await reader.read() |
| 423 | if (done) { |
| 424 | ctrl.close() |
| 425 | return |
| 426 | } |
| 427 | const text = decoder.decode(value, { stream: true }) |
| 428 | ctrl.enqueue(encoder.encode(text.replace(/"role"\s*:\s*""/g, '"role":"assistant"'))) |
| 429 | }, |
| 430 | cancel() { |
| 431 | reader.cancel() |
| 432 | }, |
| 433 | }) |
| 434 | return new Response(stream, { headers: response.headers, status: response.status }) |
| 435 | } |
| 436 | |
| 437 | return response |
| 438 | } |
| 439 | |
| 440 | const expiresSoon = |
| 441 | !currentOauth.expires || |