test(openai): cover route timeout wiring

This commit is contained in:
Aiden Cline 2026-06-03 22:49:05 -05:00
commit e4a9538289
3 changed files with 34 additions and 9 deletions

View file

@ -36,6 +36,12 @@ const OPENAI_HEADER_TIMEOUT_DEFAULT = 10_000
// Custom fetch adapters can opt out when they apply route-specific header timing internally.
const HEADER_TIMEOUT = Symbol.for("opencode.provider.header-timeout")
export function headerTimeoutForFetch(fetch: unknown, timeout: number | false | undefined) {
if (timeout === false) return undefined
if (typeof fetch === "function" && fetch[HEADER_TIMEOUT] === false) return undefined
return timeout
}
function wrapSSE(res: Response, ms: number, ctl: AbortController) {
if (typeof ms !== "number" || ms <= 0) return res
if (!res.body) return res
@ -1605,8 +1611,7 @@ export const layer = Layer.effect(
const fetchFn = customFetch ?? fetch
const opts = init ?? {}
const chunkAbortCtl = typeof chunkTimeout === "number" && chunkTimeout > 0 ? new AbortController() : undefined
const headerTimeoutMs =
headerTimeout === false || customFetch?.[HEADER_TIMEOUT] === false ? undefined : headerTimeout
const headerTimeoutMs = headerTimeoutForFetch(customFetch, headerTimeout)
const headerTimeoutCtl = typeof headerTimeoutMs === "number" ? timeoutController(headerTimeoutMs) : undefined
const signals: AbortSignal[] = []

View file

@ -176,14 +176,24 @@ describe("plugin.codex", () => {
})
test("can disable websocket HTTP fallback header timeout", async () => {
const response = await fetchWithHeaderTimeout(
async () => new Response("http"),
"https://example.com/v1/responses",
undefined,
false,
)
using server = Bun.serve({
port: 0,
async fetch() {
await Bun.sleep(30)
return new Response("http")
},
})
const hooks = await CodexAuthPlugin({} as never, { experimentalWebSockets: true })
await hooks.config!({ provider: { openai: { options: { headerTimeout: false } } } } as never)
const loaded = await hooks.auth!.loader!(async () => ({ type: "api", key: "sk-test" }) as never, {} as never)
const response = await loaded.fetch!(new URL("/v1/responses", server.url), {
method: "POST",
body: JSON.stringify({ stream: true }),
})
expect(await response.text()).toBe("http")
await hooks.dispose?.()
})
test("deduplicates concurrent Codex token refreshes", async () => {

View file

@ -1,4 +1,4 @@
import { afterEach, expect } from "bun:test"
import { afterEach, expect, test } from "bun:test"
import { createServer, type Server } from "node:http"
import { streamText } from "ai"
import { Effect, Layer } from "effect"
@ -20,6 +20,16 @@ const it = testEffect(
Layer.mergeAll(Provider.defaultLayer, Env.defaultLayer, Plugin.defaultLayer, CrossSpawnSpawner.defaultLayer),
)
test("marked custom fetch adapters opt out of outer header timeout", () => {
const fetch = Object.assign(() => Promise.resolve(new Response()), {
[Symbol.for("opencode.provider.header-timeout")]: false,
})
expect(Provider.headerTimeoutForFetch(fetch, 10_000)).toBeUndefined()
expect(Provider.headerTimeoutForFetch(() => Promise.resolve(new Response()), 10_000)).toBe(10_000)
expect(Provider.headerTimeoutForFetch(fetch, false)).toBeUndefined()
})
it.live("headerTimeout does not abort delayed SSE body after headers arrive", () =>
Effect.gen(function* () {
const server = yield* Effect.acquireRelease(