fix(opencode): preserve websocket api errors (#30321)

This commit is contained in:
Aiden Cline
2026-06-01 23:23:51 -05:00
committed by GitHub
parent 497ff36e91
commit 1b85d55a0e
3 changed files with 127 additions and 6 deletions

View File

@@ -3,6 +3,7 @@ import { EventEmitter } from "node:events"
import { createServer, type IncomingMessage, type Server as HttpServer } from "node:http"
import net, { type AddressInfo, type Socket } from "node:net"
import WebSocket, { WebSocketServer } from "ws"
import { APICallError } from "ai"
import { ProviderError } from "../../src/provider/error"
import { OpenAIWebSocket } from "../../src/plugin/openai/ws"
import { OpenAIWebSocketPool, TITLE_HEADER } from "../../src/plugin/openai/ws-pool"
@@ -253,6 +254,72 @@ describe("plugin.openai.ws-pool", () => {
fetch.close()
})
test("returns initial websocket error frames as HTTP-style API errors", async () => {
const error = {
type: "invalid_request_error",
message: "The model is not supported when using Codex with a ChatGPT account.",
}
const event = {
type: "error",
status: 400,
error,
headers: {
"x-codex-primary-window-minutes": 15,
ignored: { nested: true },
},
}
await using server = await createWebSocketServer((socket) => {
socket.once("message", () => {
socket.send(JSON.stringify(event))
})
})
const fetch = OpenAIWebSocketPool.createWebSocketFetch({
url: server.url,
})
const response = await fetch(server.url, streamRequest())
expect(response.status).toBe(400)
expect(response.headers.get("content-type")).toContain("application/json")
expect(response.headers.get("x-codex-primary-window-minutes")).toBe("15")
expect(response.headers.get("ignored")).toBeNull()
expect(await response.json()).toEqual(event)
fetch.close()
})
test("fails mid-stream wrapped websocket errors as HTTP-style API errors", async () => {
const event = {
type: "error",
status_code: 429,
error: {
type: "usage_limit_reached",
message: "The usage limit has been reached",
},
headers: {
"x-codex-primary-used-percent": "100.0",
},
}
await using server = await createWebSocketServer((socket) => {
socket.once("message", () => {
socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
socket.send(JSON.stringify(event))
})
})
const fetch = OpenAIWebSocketPool.createWebSocketFetch({
url: server.url,
})
const response = await fetch(server.url, streamRequest())
const error = await readTextError(response.text())
expect(APICallError.isInstance(error)).toBe(true)
if (!APICallError.isInstance(error)) throw new Error("Expected APICallError")
expect(error.statusCode).toBe(429)
expect(error.responseHeaders).toEqual({ "x-codex-primary-used-percent": "100.0" })
expect(error.responseBody).toBe(JSON.stringify(event))
fetch.close()
})
test("retries websocket connection limit errors on the next stream attempt", async () => {
let connections = 0
let messages = 0