fix(providers): strip provider prefix in getModelTargetFormat to route GPT-5.6 models to /v1/responses (#9545)

Closes #9545
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-08-06 22:55:21 -03:00
committed by GitHub
parent 616175a93e
commit 28dc5af7ba
3 changed files with 48 additions and 12 deletions

View File

@@ -0,0 +1 @@
- fix(providers): strip provider prefix in getModelTargetFormat to route GPT-5.6 models to /v1/responses (#9545)

View File

@@ -12,27 +12,27 @@ export const PROVIDER_MODELS: Record<string, RegistryModel[]> = new Proxy(
{} as Record<string, RegistryModel[]>,
{
get(_, prop) {
if (typeof prop === 'symbol') return undefined;
if (typeof prop === "symbol") return undefined;
return Reflect.get(initModels(), prop, _models);
},
has(_, prop) {
if (typeof prop === 'symbol') return false;
if (typeof prop === "symbol") return false;
return Reflect.has(initModels(), prop);
},
ownKeys() {
return Reflect.ownKeys(initModels());
},
getOwnPropertyDescriptor(_, prop) {
if (typeof prop === 'symbol') return undefined;
if (typeof prop === "symbol") return undefined;
return Object.getOwnPropertyDescriptor(initModels(), prop);
},
set(_, prop, value) {
if (typeof prop === 'symbol') return false;
if (typeof prop === "symbol") return false;
(initModels() as Record<string, RegistryModel[]>)[prop] = value;
return true;
},
deleteProperty(_, prop) {
if (typeof prop === 'symbol') return false;
if (typeof prop === "symbol") return false;
return Reflect.deleteProperty(initModels(), prop);
},
}
@@ -41,27 +41,27 @@ export const PROVIDER_ID_TO_ALIAS: Record<string, string> = new Proxy(
{} as Record<string, string>,
{
get(_, prop) {
if (typeof prop === 'symbol') return undefined;
if (typeof prop === "symbol") return undefined;
return Reflect.get(initAliases(), prop, _aliases);
},
has(_, prop) {
if (typeof prop === 'symbol') return false;
if (typeof prop === "symbol") return false;
return Reflect.has(initAliases(), prop);
},
ownKeys() {
return Reflect.ownKeys(initAliases());
},
getOwnPropertyDescriptor(_, prop) {
if (typeof prop === 'symbol') return undefined;
if (typeof prop === "symbol") return undefined;
return Object.getOwnPropertyDescriptor(initAliases(), prop);
},
set(_, prop, value) {
if (typeof prop === 'symbol') return false;
if (typeof prop === "symbol") return false;
(initAliases() as Record<string, string>)[prop] = value;
return true;
},
deleteProperty(_, prop) {
if (typeof prop === 'symbol') return false;
if (typeof prop === "symbol") return false;
return Reflect.deleteProperty(initAliases(), prop);
},
}
@@ -116,7 +116,13 @@ export function findModelName(aliasOrId: string, modelId: string): string {
export function getModelTargetFormat(aliasOrId: string, modelId: string): string | null {
const models = PROVIDER_MODELS[aliasOrId];
const found = models?.find((m) => m.id === modelId);
// Strip provider prefix if present: "openai/gpt-5.6-luna" → "gpt-5.6-luna"
const prefix = aliasOrId + "/";
const bareModelId =
typeof modelId === "string" && modelId.startsWith(prefix)
? modelId.slice(prefix.length)
: modelId;
const found = models?.find((m) => m.id === bareModelId);
if (found?.targetFormat) return found.targetFormat;
// #5842: OpenAI "*-pro" reasoning models (o1-pro, gpt-5.x-pro) are only served by
// the native /v1/responses endpoint — /v1/chat/completions 404s ("only supported
@@ -124,7 +130,7 @@ export function getModelTargetFormat(aliasOrId: string, modelId: string): string
// covers dynamically-synced ids that post-date the catalog (same spirit as the gh
// executor's /codex/i routing, 9router#102). Scoped to the openai alias so other
// providers shipping *-pro ids keep their own endpoint semantics.
if (aliasOrId === "openai" && /-pro$/i.test(modelId)) return "openai-responses";
if (aliasOrId === "openai" && /-pro$/i.test(bareModelId)) return "openai-responses";
return null;
}

View File

@@ -0,0 +1,29 @@
import { describe, it } from "node:test";
import assert from "node:assert";
describe("Issue #9545 — GPT-5.6 URL routing + reasoning_effort with tools", () => {
it("getModelTargetFormat should resolve gpt-5.6-luna with and without provider prefix", async () => {
const { getModelTargetFormat } = await import("../../open-sse/config/providerModels.ts");
assert.strictEqual(getModelTargetFormat("openai", "gpt-5.6-luna"), "openai-responses");
assert.strictEqual(getModelTargetFormat("openai", "openai/gpt-5.6-luna"), "openai-responses");
});
it("getModelTargetFormat should resolve non-prefixed models unchanged", async () => {
const { getModelTargetFormat } = await import("../../open-sse/config/providerModels.ts");
assert.strictEqual(getModelTargetFormat("openai", "gpt-4o"), null);
assert.strictEqual(getModelTargetFormat("openai", "gpt-5.5-pro"), "openai-responses");
assert.strictEqual(getModelTargetFormat("openai", "openai/gpt-5.5-pro"), "openai-responses");
});
it("stripGpt5ReasoningWhenTools should not strip when targetFormat=openai-responses", async () => {
const { stripGpt5ReasoningWhenTools } =
await import("../../open-sse/services/gpt5SamplingGuard.ts");
const body = {
model: "gpt-5.6-luna",
tools: [{ type: "function", function: { name: "test" } }],
reasoning_effort: "high",
};
const r = stripGpt5ReasoningWhenTools(body, "openai", "gpt-5.6-luna", "openai-responses", null);
assert.strictEqual(r.reasoning_effort, "high");
});
});