mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-16 12:00:43 +00:00
OpenAI removed the /backend-api/responses alias on chatgpt.com server-side.
The OpenAI SDK appends /responses to the configured baseUrl, so OpenClaw's
current baseUrl ("https://chatgpt.com/backend-api") now resolves to
/backend-api/responses and hits a Cloudflare HTML 403 block page. The
provider's 403+HTML error classifier then surfaces this as an auth-scope
failure, triggering fruitless OAuth re-login loops for every GPT-5.4
sub-agent call.
- Point OPENAI_CODEX_BASE_URL at https://chatgpt.com/backend-api/codex
(both the catalog constant and the sibling local constant in the provider).
- Extend isOpenAICodexBaseUrl to accept the new /codex segment while keeping
the legacy path recognized so pre-existing user configs and persisted
model metadata still round-trip through the normalizer correctly.
- Add positive-case test coverage for the new base URL; update existing
normalization tests whose expected canonical output now includes /codex.
Verified with live curl using the exact OAuth access token stored by
OpenClaw: the /codex/responses path returns HTTP 200 with streaming SSE,
while the old /responses alias returns HTTP 403 HTML regardless of auth
headers. Scoped tests (base-url, openai-codex-provider, transport-policy,
openai-provider, index) pass; pnpm tsgo and pnpm build are clean.
40 lines
2.1 KiB
TypeScript
40 lines
2.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { isOpenAIApiBaseUrl, isOpenAICodexBaseUrl } from "./base-url.js";
|
|
|
|
describe("openai base URL helpers", () => {
|
|
it("recognizes direct OpenAI API routes", () => {
|
|
expect(isOpenAIApiBaseUrl("https://api.openai.com")).toBe(true);
|
|
expect(isOpenAIApiBaseUrl("https://api.openai.com/v1")).toBe(true);
|
|
expect(isOpenAIApiBaseUrl("https://api.openai.com/v1/")).toBe(true);
|
|
});
|
|
|
|
it("rejects proxy or unrelated API routes", () => {
|
|
expect(isOpenAIApiBaseUrl("https://proxy.example.com/v1")).toBe(false);
|
|
expect(isOpenAIApiBaseUrl("https://chatgpt.com/backend-api")).toBe(false);
|
|
expect(isOpenAIApiBaseUrl(undefined)).toBe(false);
|
|
});
|
|
|
|
it("recognizes Codex ChatGPT backend routes", () => {
|
|
// New canonical form (includes /codex segment; OpenAI removed the
|
|
// /backend-api/responses alias server-side on 2026-04).
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/codex")).toBe(true);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/codex/")).toBe(true);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/codex/v1")).toBe(true);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/codex/v1/")).toBe(true);
|
|
// Legacy form still recognized as a Codex baseURL for backward
|
|
// compatibility with existing user configs.
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api")).toBe(true);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/")).toBe(true);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/v1")).toBe(true);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/v1/")).toBe(true);
|
|
});
|
|
|
|
it("rejects non-Codex backend routes", () => {
|
|
expect(isOpenAICodexBaseUrl("https://api.openai.com/v1")).toBe(false);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com")).toBe(false);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/v2")).toBe(false);
|
|
expect(isOpenAICodexBaseUrl("https://chatgpt.com/backend-api/codex/v2")).toBe(false);
|
|
expect(isOpenAICodexBaseUrl(undefined)).toBe(false);
|
|
});
|
|
});
|