fix(models): skip canonical OpenAI row runtime loading

This commit is contained in:
Vincent Koc
2026-08-01 17:01:04 +02:00
parent d6763919c0
commit 80982ea92e
2 changed files with 77 additions and 0 deletions

View File

@@ -2,6 +2,7 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
normalizeModelCatalogId,
projectConfiguredModelRow,
resolveModelRoutes,
resolveThinkingProfile,
} from "./provider-policy-api.js";
@@ -15,6 +16,58 @@ describe("OpenAI provider policy artifact", () => {
vi.unstubAllEnvs();
});
it("skips runtime normalization for canonical Responses rows", () => {
expect(
projectConfiguredModelRow({
provider: "openai",
modelId: "gpt-5.5",
model: {
provider: "openai",
id: "gpt-5.5",
api: "openai-responses",
baseUrl: "http://127.0.0.1:8080/v1",
input: ["text"],
name: "GPT-5.5",
reasoning: true,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 96_000,
maxTokens: 128_000,
},
}),
).toBeNull();
});
it.each([
["openai-completions", "https://api.openai.com/v1", "gpt-5.5"],
["openai-chatgpt-responses", "https://chatgpt.com/backend-api/codex", "gpt-5.5"],
["openai-responses", "https://chatgpt.com/backend-api/codex", "gpt-5.5"],
[undefined, "https://api.openai.com/v1", "gpt-5.5"],
["anthropic-messages", "https://api.openai.com/v1", "gpt-5.5"],
["openai-responses", "https://api.openai.com/v1", "gpt-5.4-codex"],
] as const)(
"keeps runtime normalization for api=%s baseUrl=%s model=%s",
(api, baseUrl, modelId) => {
expect(
projectConfiguredModelRow({
provider: "openai",
modelId,
model: {
provider: "openai",
id: modelId,
api,
baseUrl,
input: ["text"],
name: "OpenAI model",
reasoning: true,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 96_000,
maxTokens: 128_000,
},
}),
).toBeUndefined();
},
);
it("normalizes the legacy Codex model alias at the provider boundary", () => {
expect(normalizeModelCatalogId({ provider: " OpenAI ", modelId: "openai/GPT-5.4-CODEX" })).toBe(
"gpt-5.4",

View File

@@ -1,5 +1,6 @@
// Openai API module exposes the plugin public contract.
import type { ProviderDefaultThinkingPolicyContext } from "openclaw/plugin-sdk/core";
import type { ProviderNormalizeResolvedModelContext } from "openclaw/plugin-sdk/plugin-entry";
import type {
ModelApi,
ModelProviderConfig,
@@ -11,6 +12,7 @@ import type {
} from "openclaw/plugin-sdk/provider-model-types";
import {
classifyOpenAIBaseUrl,
isOpenAICodexBaseUrl,
OPENAI_API_BASE_URL,
OPENAI_CODEX_RESPONSES_BASE_URL,
} from "./base-url.js";
@@ -52,6 +54,28 @@ export function normalizeModelCatalogId(params: ProviderNormalizeModelCatalogIdC
: null;
}
/**
* Skips full runtime loading only when OpenAI normalization is provably a no-op.
* Transport-sensitive routes and legacy model aliases still use the runtime hook.
*/
export function projectConfiguredModelRow(ctx: ProviderNormalizeResolvedModelContext) {
if (ctx.provider.trim().toLowerCase() !== "openai") {
return undefined;
}
const modelId = ctx.model.id;
const canonicalModelId = normalizeOpenAIModelRouteId(modelId);
const canonicalRouteId = normalizeOpenAIModelRouteId(ctx.modelId);
if (
ctx.model.api !== OPENAI_RESPONSES_API ||
isOpenAICodexBaseUrl(ctx.model.baseUrl) ||
canonicalModelId !== modelId ||
canonicalRouteId !== ctx.modelId
) {
return undefined;
}
return null;
}
function firstRouteBaseUrl(...values: unknown[]): unknown {
for (const value of values) {
if (typeof value === "string") {