Просмотр исходного кода

fix(core): preserve custom Codex endpoints

Aiden Cline 2 недель назад
Родитель
Сommit
2de8ab95d1

+ 0 - 1
packages/core/src/model-resolver.ts

@@ -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 }),
       ),

+ 1 - 0
packages/core/src/plugin/provider/openai.ts

@@ -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.

+ 9 - 9
packages/core/test/model-resolver.test.ts

@@ -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()
     }),

+ 10 - 0
packages/core/test/plugin/provider-openai.test.ts

@@ -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")
     }),
   )