fix(core): preserve custom Codex endpoints

This commit is contained in:
Aiden Cline 2026-07-28 04:35:55 +00:00 committed by opencode-agent[bot]
commit 2de8ab95d1
4 changed files with 20 additions and 10 deletions

View file

@ -256,7 +256,6 @@ const codexModel = (
const account = OpenAICodex.accountID(credential)
return withDefaults(model, OpenAIResponses.route)
.with({
endpoint: { baseURL: OpenAICodex.baseURL },
auth: (key === undefined ? Auth.none : Auth.bearer(key)).andThen(
account === undefined ? Auth.none : Auth.headers({ "chatgpt-account-id": account }),
),

View file

@ -193,6 +193,7 @@ export const OpenAIPlugin = define({
if (!chatgpt) return
const item = evt.provider.get(Provider.ID.openai)
if (!item) return
item.provider.settings = Provider.mergeOverlay(item.provider.settings, { baseURL: OpenAICodex.baseURL })
for (const model of item.models.values()) {
// ChatGPT-plan tokens only authorize codex-eligible models, and the
// subscription covers usage, so hide the rest and zero the cost.

View file

@ -307,7 +307,7 @@ describe("ModelResolver", () => {
}),
)
it.effect("routes ChatGPT OAuth credentials to the codex backend", () =>
it.effect("keeps an explicit endpoint for ChatGPT OAuth credentials", () =>
Effect.gen(function* () {
const resolved = yield* ModelResolver.fromCatalogModel(
model(Provider.aisdk("@ai-sdk/openai"), {
@ -328,21 +328,21 @@ describe("ModelResolver", () => {
const headers = yield* resolved.route.auth.apply({
request,
method: "POST",
url: "https://chatgpt.com/backend-api/codex/responses",
url: "https://openai.example/v1/responses",
body: "{}",
headers: Headers.empty,
})
expect(resolved.route).toMatchObject({
id: "openai-responses",
endpoint: { baseURL: "https://chatgpt.com/backend-api/codex" },
endpoint: { baseURL: "https://openai.example/v1" },
})
expect(headers.authorization).toBe("Bearer chatgpt-token")
expect(headers["chatgpt-account-id"]).toBe("acct_123")
}),
)
it.effect("routes native OpenAI provider packages with ChatGPT credentials to the codex backend", () =>
it.effect("keeps an explicit endpoint for native OpenAI packages with ChatGPT credentials", () =>
Effect.gen(function* () {
const resolved = yield* ModelResolver.fromCatalogModel(
model("@opencode-ai/ai/providers/openai", {
@ -360,12 +360,12 @@ describe("ModelResolver", () => {
const headers = yield* resolved.route.auth.apply({
request: LLM.request({ model: resolved, prompt: "Hello" }),
method: "POST",
url: "https://chatgpt.com/backend-api/codex/responses",
url: "https://openai.example/v1/responses",
body: "{}",
headers: Headers.empty,
})
expect(resolved.route.endpoint.baseURL).toBe("https://chatgpt.com/backend-api/codex")
expect(resolved.route.endpoint.baseURL).toBe("https://openai.example/v1")
expect(headers.authorization).toBe("Bearer chatgpt-token")
expect(headers["chatgpt-account-id"]).toBe("acct_123")
}),
@ -407,7 +407,7 @@ describe("ModelResolver", () => {
}),
)
it.effect("routes ChatGPT OAuth credentials without an account id to the codex backend", () =>
it.effect("keeps an explicit endpoint for ChatGPT OAuth credentials without an account id", () =>
Effect.gen(function* () {
const resolved = yield* ModelResolver.fromCatalogModel(
model(Provider.aisdk("@ai-sdk/openai"), {
@ -427,12 +427,12 @@ describe("ModelResolver", () => {
const headers = yield* resolved.route.auth.apply({
request,
method: "POST",
url: "https://chatgpt.com/backend-api/codex/responses",
url: "https://openai.example/v1/responses",
body: "{}",
headers: Headers.empty,
})
expect(resolved.route.endpoint.baseURL).toBe("https://chatgpt.com/backend-api/codex")
expect(resolved.route.endpoint.baseURL).toBe("https://openai.example/v1")
expect(headers.authorization).toBe("Bearer chatgpt-token")
expect(headers["chatgpt-account-id"]).toBeUndefined()
}),

View file

@ -208,6 +208,7 @@ describe("OpenAIPlugin", () => {
const eligible = required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.5")))
expect(eligible.cost).toEqual([])
expect(eligible.enabled).toBe(true)
expect(eligible.settings?.baseURL).toBe("https://chatgpt.com/backend-api/codex")
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.5-pro"))).enabled).toBe(
false,
)
@ -219,6 +220,15 @@ describe("OpenAIPlugin", () => {
true,
)
expect(required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-4.1"))).enabled).toBe(false)
yield* catalog.transform((catalog) => {
catalog.provider.update(Provider.ID.openai, (provider) => {
provider.settings = Provider.mergeOverlay(provider.settings, { baseURL: "https://proxy.example/v1" })
})
})
expect(
required(yield* catalog.model.get(Provider.ID.openai, Model.ID.make("gpt-5.5"))).settings?.baseURL,
).toBe("https://proxy.example/v1")
}),
)