mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (#4665) (#5010)
* fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (#4665) MODEL_MAP was missing the advertised catalog ids gpt-5.5, gpt-5.5-pro, gpt-5.4-pro and gpt-5.2-pro, so MODEL_MAP[model] ?? model sent the dot-form id verbatim to the ChatGPT backend-api, which silently rejected it and served the default Plus model. Map each to its dash-form slug. gpt-4-5 is already dash-form and falls through correctly, so it is intentionally left unmapped. Extends the executor MODEL_MAP test with the four ids and adds a drift guard asserting every advertised dot-form catalog id reaches the backend in dash-form (never verbatim), guarding future catalog<->map drift. file-size: tests/unit/chatgpt-web.test.ts frozen baseline 2809->2855 (+46) for the added test cases and drift-guard test; executor source unchanged in baseline. * docs(changelog): restore #3981/#5003 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com>
This commit is contained in:
committed by
GitHub
parent
515bc3465f
commit
09d0d11ed5
@@ -16,6 +16,7 @@ _In development — bullets added per PR; finalized at release._
|
||||
- **fix(dashboard):** on OAuth providers (e.g. GLM Coding), "Test all models" with auto-hide-failed now switches the model list to the "visible" filter after the run, so just-hidden failed models actually disappear on-screen — parity with the passthrough-provider path (#3610). Previously they were hidden in the DB but stayed visible under the "All" filter, so it looked like nothing was hidden. (#4887)
|
||||
- **fix(pollinations):** stop forcing `jsonMode` on every request. Pollinations treats `jsonMode=true` as "the model MUST return JSON" and rejects (HTTP 400 "messages must contain the word 'json'") any normal chat request whose messages don't mention "json", so all non-JSON chat was broken. `jsonMode` is now only enabled when the caller actually requests JSON output (`response_format.type` of `json_object` or `json_schema`). (#3981)
|
||||
- **fix(antigravity):** default `safetySettings` to all-OFF for parity with the native Gemini paths. The Antigravity (Google Cloud Code) request builder set `safetySettings: undefined`, which `JSON.stringify` drops — so no safety settings reached Google and its server-side defaults false-flagged benign technical prompts as `prohibited_content` (HTTP 200 + blocked body, which combo failover treats as terminal). Now honors a caller-supplied value and otherwise defaults to `DEFAULT_SAFETY_SETTINGS`, matching the claude-to-gemini / openai-to-gemini paths (#5003)
|
||||
- **fix(chatgpt-web):** map the advertised `gpt-5.5`, `gpt-5.5-pro`, `gpt-5.4-pro` and `gpt-5.2-pro` catalog ids to their dash-form ChatGPT backend slugs. They were missing from `MODEL_MAP`, so the executor sent the dot-form id verbatim, which the ChatGPT backend silently ignored and served the default Plus model instead of the requested one. Adds a drift guard asserting no advertised dot-form id reaches the backend verbatim. (#4665)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@
|
||||
"tests/unit/cc-compatible-provider.test.ts": 1179,
|
||||
"tests/unit/chatcore-sanitization.test.ts": 829,
|
||||
"tests/unit/chatcore-translation-paths.test.ts": 2810,
|
||||
"tests/unit/chatgpt-web.test.ts": 2809,
|
||||
"tests/unit/chatgpt-web.test.ts": 2855,
|
||||
"tests/unit/combo-routing-engine.test.ts": 3213,
|
||||
"tests/unit/combo-strategy-fallbacks.test.ts": 880,
|
||||
"tests/unit/db-core-init.test.ts": 867,
|
||||
|
||||
@@ -82,9 +82,13 @@ const MODEL_MAP: Record<string, string> = {
|
||||
"gpt-5.3-instant": "gpt-5-3-instant",
|
||||
"gpt-5.3": "gpt-5-3",
|
||||
"gpt-5.3-mini": "gpt-5-3-mini",
|
||||
"gpt-5.5-pro": "gpt-5-5-pro",
|
||||
"gpt-5.5-thinking": "gpt-5-5-thinking",
|
||||
"gpt-5.5": "gpt-5-5",
|
||||
"gpt-5.4-pro": "gpt-5-4-pro",
|
||||
"gpt-5.4-thinking": "gpt-5-4-thinking",
|
||||
"gpt-5.4-thinking-mini": "gpt-5-4-t-mini",
|
||||
"gpt-5.2-pro": "gpt-5-2-pro",
|
||||
"gpt-5.2-instant": "gpt-5-2-instant",
|
||||
"gpt-5.2": "gpt-5-2",
|
||||
"gpt-5.2-thinking": "gpt-5-2-thinking",
|
||||
|
||||
@@ -1119,6 +1119,13 @@ test("Executor MODEL_MAP: dot-form OmniRoute IDs translate to dash-form ChatGPT
|
||||
["gpt-5.4-thinking-mini", "gpt-5-4-t-mini"],
|
||||
["gpt-5.2-thinking", "gpt-5-2-thinking"],
|
||||
["o3", "o3"],
|
||||
// Regression #4665: these advertised catalog ids were missing from
|
||||
// MODEL_MAP and fell through as their dot-form slug verbatim, which the
|
||||
// ChatGPT backend-api silently rejects → served the default Plus model.
|
||||
["gpt-5.5", "gpt-5-5"],
|
||||
["gpt-5.5-pro", "gpt-5-5-pro"],
|
||||
["gpt-5.4-pro", "gpt-5-4-pro"],
|
||||
["gpt-5.2-pro", "gpt-5-2-pro"],
|
||||
];
|
||||
for (const [omniId, expectedSlug] of cases) {
|
||||
m.calls.urls.length = 0;
|
||||
@@ -1141,6 +1148,45 @@ test("Executor MODEL_MAP: dot-form OmniRoute IDs translate to dash-form ChatGPT
|
||||
}
|
||||
});
|
||||
|
||||
test("MODEL_MAP drift guard: every advertised dot-form catalog id resolves to a dash-form backend slug (no verbatim fall-through) (#4665)", async () => {
|
||||
reset();
|
||||
const { getRegistryEntry } = await import("../../open-sse/config/providerRegistry.ts");
|
||||
const ids = (getRegistryEntry("chatgpt-web")?.models || []).map((m) => m.id);
|
||||
// Dot-form ids must never reach the ChatGPT backend verbatim — the backend
|
||||
// only accepts dash-form slugs. (Ids that are already dash-form, e.g.
|
||||
// "gpt-4-5", legitimately pass through unchanged and are exempt.)
|
||||
const dotFormIds = ids.filter((id) => id.includes("."));
|
||||
const m = installMockFetch();
|
||||
try {
|
||||
for (const omniId of dotFormIds) {
|
||||
m.calls.urls.length = 0;
|
||||
m.calls.bodies.length = 0;
|
||||
const executor = new ChatGptWebExecutor();
|
||||
await executor.execute({
|
||||
model: omniId,
|
||||
body: { messages: [{ role: "user", content: "hi" }] },
|
||||
stream: false,
|
||||
credentials: { apiKey: "test" },
|
||||
signal: AbortSignal.timeout(10_000),
|
||||
log: null,
|
||||
});
|
||||
const convIdx = m.calls.urls.findIndex((u) => u.endsWith("/backend-api/f/conversation"));
|
||||
const body = JSON.parse(m.calls.bodies[convIdx]);
|
||||
assert.ok(
|
||||
!body.model.includes("."),
|
||||
`${omniId} reached the backend as "${body.model}" (still dot-form) — missing MODEL_MAP entry causes silent model substitution`,
|
||||
);
|
||||
assert.notEqual(
|
||||
body.model,
|
||||
omniId,
|
||||
`${omniId} fell through MODEL_MAP verbatim — add a dash-form mapping`,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
m.restore();
|
||||
}
|
||||
});
|
||||
|
||||
// ─── thinking_effort PATCH user_last_used_model_config ─────────────────────
|
||||
|
||||
test("thinking_effort: high → PATCH user_last_used_model_config with extended", async () => {
|
||||
|
||||
Reference in New Issue
Block a user