mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:10:44 +00:00
test(openai): cover GPT-5.5 defaults
This commit is contained in:
@@ -224,7 +224,7 @@ describe("openai codex provider", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
defaultModel: "openai-codex/gpt-5.4",
|
||||
defaultModel: "openai-codex/gpt-5.5",
|
||||
});
|
||||
expect(result?.profiles[0]?.credential).not.toHaveProperty("idToken");
|
||||
expect(result?.profiles[0]?.credential).not.toHaveProperty("accountId");
|
||||
@@ -329,6 +329,40 @@ describe("openai codex provider", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves gpt-5.5 and gpt-5.5-pro with launch pricing and codex-sized runtime cap", () => {
|
||||
const provider = buildOpenAICodexProviderPlugin();
|
||||
|
||||
const model = provider.resolveDynamicModel?.({
|
||||
provider: "openai-codex",
|
||||
modelId: "gpt-5.5",
|
||||
modelRegistry: createSingleModelRegistry(createCodexTemplate({ id: "gpt-5.4" })) as never,
|
||||
});
|
||||
const pro = provider.resolveDynamicModel?.({
|
||||
provider: "openai-codex",
|
||||
modelId: "gpt-5.5-pro",
|
||||
modelRegistry: createSingleModelRegistry(createCodexTemplate({ id: "gpt-5.4-pro" })) as never,
|
||||
});
|
||||
|
||||
expect(model).toMatchObject({
|
||||
id: "gpt-5.5",
|
||||
api: "openai-codex-responses",
|
||||
baseUrl: "https://chatgpt.com/backend-api",
|
||||
contextWindow: 1_000_000,
|
||||
contextTokens: 272_000,
|
||||
maxTokens: 128_000,
|
||||
cost: { input: 5, output: 30, cacheRead: 0, cacheWrite: 0 },
|
||||
});
|
||||
expect(pro).toMatchObject({
|
||||
id: "gpt-5.5-pro",
|
||||
api: "openai-codex-responses",
|
||||
baseUrl: "https://chatgpt.com/backend-api",
|
||||
contextWindow: 1_000_000,
|
||||
contextTokens: 272_000,
|
||||
maxTokens: 128_000,
|
||||
cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves gpt-5.4-pro from a gpt-5.4 runtime template when legacy codex rows are absent", () => {
|
||||
const provider = buildOpenAICodexProviderPlugin();
|
||||
|
||||
@@ -398,7 +432,7 @@ describe("openai codex provider", () => {
|
||||
expect(model).not.toHaveProperty("contextTokens");
|
||||
});
|
||||
|
||||
it("augments catalog with gpt-5.4 native contextWindow and runtime cap", () => {
|
||||
it("augments catalog with gpt-5.5 and gpt-5.4 native metadata", () => {
|
||||
const provider = buildOpenAICodexProviderPlugin();
|
||||
|
||||
const entries = provider.augmentModelCatalog?.({
|
||||
@@ -415,6 +449,22 @@ describe("openai codex provider", () => {
|
||||
],
|
||||
} as never);
|
||||
|
||||
expect(entries).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id: "gpt-5.5",
|
||||
contextWindow: 1_000_000,
|
||||
contextTokens: 272_000,
|
||||
cost: { input: 5, output: 30, cacheRead: 0, cacheWrite: 0 },
|
||||
}),
|
||||
);
|
||||
expect(entries).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id: "gpt-5.5-pro",
|
||||
contextWindow: 1_000_000,
|
||||
contextTokens: 272_000,
|
||||
cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 },
|
||||
}),
|
||||
);
|
||||
expect(entries).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id: "gpt-5.4",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { buildOpenAIProvider } from "./openai-provider.js";
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "";
|
||||
const DEFAULT_LIVE_MODEL_IDS = ["gpt-5.4-mini", "gpt-5.4-nano"] as const;
|
||||
const DEFAULT_LIVE_MODEL_IDS = ["gpt-5.5", "gpt-5.4-mini", "gpt-5.4-nano"] as const;
|
||||
const liveEnabled = OPENAI_API_KEY.trim().length > 0 && process.env.OPENCLAW_LIVE_TEST === "1";
|
||||
const describeLive = liveEnabled ? describe : describe.skip;
|
||||
|
||||
@@ -18,6 +18,24 @@ type LiveModelCase = {
|
||||
|
||||
function resolveLiveModelCase(modelId: string): LiveModelCase {
|
||||
switch (modelId) {
|
||||
case "gpt-5.5":
|
||||
return {
|
||||
modelId,
|
||||
templateId: "gpt-5.4",
|
||||
templateName: "GPT-5.4",
|
||||
cost: { input: 5, output: 30, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1_000_000,
|
||||
maxTokens: 128_000,
|
||||
};
|
||||
case "gpt-5.5-pro":
|
||||
return {
|
||||
modelId,
|
||||
templateId: "gpt-5.4-pro",
|
||||
templateName: "GPT-5.4 Pro",
|
||||
cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1_000_000,
|
||||
maxTokens: 128_000,
|
||||
};
|
||||
case "gpt-5.4":
|
||||
return {
|
||||
modelId,
|
||||
|
||||
@@ -229,6 +229,101 @@ describe("buildOpenAIProvider", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves gpt-5.5 and gpt-5.5-pro with launch metadata", () => {
|
||||
const provider = buildOpenAIProvider();
|
||||
|
||||
const model = provider.resolveDynamicModel?.({
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.5",
|
||||
modelRegistry: {
|
||||
find: (_provider: string, id: string) =>
|
||||
id === "gpt-5.4"
|
||||
? {
|
||||
id,
|
||||
name: "GPT-5.4",
|
||||
provider: "openai",
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 },
|
||||
contextWindow: 1_050_000,
|
||||
maxTokens: 128_000,
|
||||
}
|
||||
: null,
|
||||
} as never,
|
||||
});
|
||||
const pro = provider.resolveDynamicModel?.({
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.5-pro",
|
||||
modelRegistry: {
|
||||
find: (_provider: string, id: string) =>
|
||||
id === "gpt-5.4-pro"
|
||||
? {
|
||||
id,
|
||||
name: "GPT-5.4 Pro",
|
||||
provider: "openai",
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1_050_000,
|
||||
maxTokens: 128_000,
|
||||
}
|
||||
: null,
|
||||
} as never,
|
||||
});
|
||||
|
||||
expect(model).toMatchObject({
|
||||
provider: "openai",
|
||||
id: "gpt-5.5",
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
contextWindow: 1_000_000,
|
||||
maxTokens: 128_000,
|
||||
cost: { input: 5, output: 30, cacheRead: 0, cacheWrite: 0 },
|
||||
});
|
||||
expect(pro).toMatchObject({
|
||||
provider: "openai",
|
||||
id: "gpt-5.5-pro",
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
contextWindow: 1_000_000,
|
||||
maxTokens: 128_000,
|
||||
cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("surfaces gpt-5.5 in xhigh and augmented catalog metadata", () => {
|
||||
const provider = buildOpenAIProvider();
|
||||
|
||||
expect(
|
||||
provider
|
||||
.resolveThinkingProfile?.({
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.5",
|
||||
} as never)
|
||||
?.levels.some((level) => level.id === "xhigh"),
|
||||
).toBe(true);
|
||||
|
||||
const entries = provider.augmentModelCatalog?.({
|
||||
env: process.env,
|
||||
entries: [{ provider: "openai", id: "gpt-5.4", name: "GPT-5.4" }],
|
||||
} as never);
|
||||
|
||||
expect(entries).toContainEqual(
|
||||
expect.objectContaining({
|
||||
provider: "openai",
|
||||
id: "gpt-5.5",
|
||||
name: "gpt-5.5",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 1_000_000,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps modern live selection on OpenAI 5.2+ and Codex 5.2+", () => {
|
||||
const provider = buildOpenAIProvider();
|
||||
const codexProvider = buildOpenAICodexProviderPlugin();
|
||||
@@ -251,6 +346,12 @@ describe("buildOpenAIProvider", () => {
|
||||
modelId: "gpt-5.4",
|
||||
} as never),
|
||||
).toBe(true);
|
||||
expect(
|
||||
provider.isModernModelRef?.({
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.5",
|
||||
} as never),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
codexProvider.isModernModelRef?.({
|
||||
@@ -276,6 +377,12 @@ describe("buildOpenAIProvider", () => {
|
||||
modelId: "gpt-5.4",
|
||||
} as never),
|
||||
).toBe(true);
|
||||
expect(
|
||||
codexProvider.isModernModelRef?.({
|
||||
provider: "openai-codex",
|
||||
modelId: "gpt-5.5",
|
||||
} as never),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("owns replay policy for OpenAI and Codex transports", () => {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { runRealtimeSttLiveTest } from "../../test/helpers/stt-live-audio.js";
|
||||
import plugin from "./index.js";
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "";
|
||||
const LIVE_MODEL_ID = process.env.OPENCLAW_LIVE_OPENAI_PLUGIN_MODEL?.trim() || "gpt-5.4-nano";
|
||||
const LIVE_MODEL_ID = process.env.OPENCLAW_LIVE_OPENAI_PLUGIN_MODEL?.trim() || "gpt-5.5";
|
||||
const LIVE_IMAGE_MODEL = process.env.OPENCLAW_LIVE_OPENAI_IMAGE_MODEL?.trim() || "gpt-image-2";
|
||||
const LIVE_VISION_MODEL = process.env.OPENCLAW_LIVE_OPENAI_VISION_MODEL?.trim() || "gpt-4.1-mini";
|
||||
const liveEnabled = OPENAI_API_KEY.trim().length > 0 && process.env.OPENCLAW_LIVE_TEST === "1";
|
||||
@@ -29,6 +29,8 @@ const ModelRegistryCtor = ModelRegistry as unknown as {
|
||||
|
||||
function resolveTemplateModelId(modelId: string) {
|
||||
switch (modelId) {
|
||||
case "gpt-5.5":
|
||||
return "gpt-5.4";
|
||||
case "gpt-5.4":
|
||||
return "gpt-5.2";
|
||||
case "gpt-5.4-mini":
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { beforeEach, describe, it, vi } from "vitest";
|
||||
import {
|
||||
expectAugmentedCodexCatalog,
|
||||
expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55,
|
||||
expectCodexBuiltInSuppression,
|
||||
expectCodexMissingAuthHint,
|
||||
importProviderRuntimeCatalogModule,
|
||||
@@ -116,7 +117,10 @@ export function describeOpenAIProviderCatalogContract() {
|
||||
|
||||
it("keeps bundled model augmentation wired through the provider runtime", async () => {
|
||||
const { augmentModelCatalogWithProviderPlugins } = await contractDepsPromise;
|
||||
await expectAugmentedCodexCatalog(augmentModelCatalogWithProviderPlugins);
|
||||
await expectAugmentedCodexCatalog(
|
||||
augmentModelCatalogWithProviderPlugins,
|
||||
expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -223,7 +223,7 @@ describe("runQaCharacterEval", () => {
|
||||
|
||||
expect(runSuite).toHaveBeenCalledTimes(8);
|
||||
expect(runSuite.mock.calls.map(([params]) => params.primaryModel)).toEqual([
|
||||
"openai/gpt-5.4",
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.2",
|
||||
"openai/gpt-5",
|
||||
"anthropic/claude-opus-4-6",
|
||||
@@ -254,7 +254,7 @@ describe("runQaCharacterEval", () => {
|
||||
]);
|
||||
expect(runJudge).toHaveBeenCalledTimes(2);
|
||||
expect(runJudge.mock.calls.map(([params]) => params.judgeModel)).toEqual([
|
||||
"openai/gpt-5.4",
|
||||
"openai/gpt-5.5",
|
||||
"anthropic/claude-opus-4-6",
|
||||
]);
|
||||
expect(runJudge.mock.calls.map(([params]) => params.judgeThinkingDefault)).toEqual([
|
||||
|
||||
@@ -1135,8 +1135,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
transportId: "qa-channel",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.4",
|
||||
alternateModel: "openai/gpt-5.4",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
fastMode: undefined,
|
||||
message: "read qa kickoff and reply short",
|
||||
timeoutMs: undefined,
|
||||
@@ -1166,7 +1166,7 @@ describe("qa cli runtime", () => {
|
||||
it("defaults manual frontier runs onto Codex OAuth when the runtime resolver prefers it", async () => {
|
||||
defaultQaRuntimeModelForMode.mockImplementation((mode, options) =>
|
||||
mode === "live-frontier"
|
||||
? "openai-codex/gpt-5.4"
|
||||
? "openai-codex/gpt-5.5"
|
||||
: defaultQaProviderModelForMode(mode as QaProviderModeInput, options),
|
||||
);
|
||||
|
||||
@@ -1179,8 +1179,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
transportId: "qa-channel",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai-codex/gpt-5.4",
|
||||
alternateModel: "openai-codex/gpt-5.4",
|
||||
primaryModel: "openai-codex/gpt-5.5",
|
||||
alternateModel: "openai-codex/gpt-5.5",
|
||||
fastMode: undefined,
|
||||
message: "read qa kickoff and reply short",
|
||||
timeoutMs: undefined,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { selectQaRunnerModelOptions } from "./model-catalog.runtime.js";
|
||||
|
||||
describe("qa runner model catalog", () => {
|
||||
it("filters to available rows and prefers gpt-5.4 first", () => {
|
||||
it("filters to available rows and prefers gpt-5.5 first", () => {
|
||||
expect(
|
||||
selectQaRunnerModelOptions([
|
||||
{
|
||||
@@ -13,8 +13,8 @@ describe("qa runner model catalog", () => {
|
||||
missing: false,
|
||||
},
|
||||
{
|
||||
key: "openai/gpt-5.4",
|
||||
name: "gpt-5.4",
|
||||
key: "openai/gpt-5.5",
|
||||
name: "gpt-5.5",
|
||||
input: "text,image",
|
||||
available: true,
|
||||
missing: false,
|
||||
@@ -27,6 +27,6 @@ describe("qa runner model catalog", () => {
|
||||
missing: false,
|
||||
},
|
||||
]).map((entry) => entry.key),
|
||||
).toEqual(["openai/gpt-5.4", "anthropic/claude-sonnet-4-5"]);
|
||||
).toEqual(["openai/gpt-5.5", "anthropic/claude-sonnet-4-5"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ describe("qa model selection runtime", () => {
|
||||
resolveEnvApiKey.mockReturnValue({ apiKey: "sk-test" });
|
||||
|
||||
expect(resolveQaPreferredLiveModel()).toBeUndefined();
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai/gpt-5.4");
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai/gpt-5.5");
|
||||
expect(loadAuthProfileStoreForRuntime).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -43,8 +43,8 @@ describe("qa model selection runtime", () => {
|
||||
provider === "openai-codex" ? ["openai-codex:user@example.com"] : [],
|
||||
);
|
||||
|
||||
expect(resolveQaPreferredLiveModel()).toBe("openai-codex/gpt-5.4");
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai-codex/gpt-5.4");
|
||||
expect(resolveQaPreferredLiveModel()).toBe("openai-codex/gpt-5.5");
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai-codex/gpt-5.5");
|
||||
});
|
||||
|
||||
it("keeps the OpenAI live default when stored OpenAI profiles are available", () => {
|
||||
@@ -53,7 +53,7 @@ describe("qa model selection runtime", () => {
|
||||
);
|
||||
|
||||
expect(resolveQaPreferredLiveModel()).toBeUndefined();
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai/gpt-5.4");
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai/gpt-5.5");
|
||||
});
|
||||
|
||||
it("leaves mock defaults unchanged", () => {
|
||||
|
||||
@@ -19,7 +19,7 @@ describe("extractQaFailureReplyText", () => {
|
||||
it("classifies explicit provider auth guidance as a failure", () => {
|
||||
expect(
|
||||
extractQaFailureReplyText(
|
||||
'⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.4 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.4.',
|
||||
'⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.5 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.5.',
|
||||
),
|
||||
).toContain('No API key found for provider "openai".');
|
||||
});
|
||||
@@ -27,7 +27,7 @@ describe("extractQaFailureReplyText", () => {
|
||||
it("classifies curated missing-key guidance as a failure", () => {
|
||||
expect(
|
||||
extractQaFailureReplyText(
|
||||
"⚠️ Missing API key for OpenAI on the gateway. Use `openai-codex/gpt-5.4` for OAuth, or set `OPENAI_API_KEY`, then try again.",
|
||||
"⚠️ Missing API key for OpenAI on the gateway. Use `openai-codex/gpt-5.5` for OAuth, or set `OPENAI_API_KEY`, then try again.",
|
||||
),
|
||||
).toContain("Missing API key for OpenAI on the gateway.");
|
||||
});
|
||||
|
||||
@@ -45,8 +45,8 @@ describe("qa run config", () => {
|
||||
it("creates a live-by-default selection that arms every scenario", () => {
|
||||
expect(createDefaultQaRunSelection(scenarios)).toEqual({
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.4",
|
||||
alternateModel: "openai/gpt-5.4",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
fastMode: true,
|
||||
scenarioIds: ["dm-chat-baseline", "thread-lifecycle"],
|
||||
});
|
||||
@@ -57,7 +57,7 @@ describe("qa run config", () => {
|
||||
normalizeQaRunSelection(
|
||||
{
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.4",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "",
|
||||
fastMode: false,
|
||||
scenarioIds: ["thread-lifecycle", "missing", "thread-lifecycle"],
|
||||
@@ -66,8 +66,8 @@ describe("qa run config", () => {
|
||||
),
|
||||
).toEqual({
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.4",
|
||||
alternateModel: "openai/gpt-5.4",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
fastMode: true,
|
||||
scenarioIds: ["thread-lifecycle"],
|
||||
});
|
||||
@@ -99,13 +99,13 @@ describe("qa run config", () => {
|
||||
});
|
||||
|
||||
it("keeps idle snapshots on static defaults so startup does not inspect auth profiles", () => {
|
||||
defaultQaRuntimeModelForMode.mockReturnValue("openai-codex/gpt-5.4");
|
||||
defaultQaRuntimeModelForMode.mockReturnValue("openai-codex/gpt-5.5");
|
||||
defaultQaRuntimeModelForMode.mockClear();
|
||||
|
||||
expect(createIdleQaRunnerSnapshot(scenarios).selection).toMatchObject({
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.4",
|
||||
alternateModel: "openai/gpt-5.4",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
});
|
||||
expect(defaultQaRuntimeModelForMode).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -138,14 +138,14 @@ describe("qa run config", () => {
|
||||
it("prefers the Codex OAuth default when the runtime resolver says it is available", () => {
|
||||
defaultQaRuntimeModelForMode.mockImplementation((mode, options) =>
|
||||
mode === "live-frontier"
|
||||
? "openai-codex/gpt-5.4"
|
||||
? "openai-codex/gpt-5.5"
|
||||
: defaultQaProviderModelForMode(mode as QaProviderModeInput, options),
|
||||
);
|
||||
|
||||
expect(createDefaultQaRunSelection(scenarios)).toEqual({
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai-codex/gpt-5.4",
|
||||
alternateModel: "openai-codex/gpt-5.4",
|
||||
primaryModel: "openai-codex/gpt-5.5",
|
||||
alternateModel: "openai-codex/gpt-5.5",
|
||||
fastMode: true,
|
||||
scenarioIds: ["dm-chat-baseline", "thread-lifecycle"],
|
||||
});
|
||||
|
||||
@@ -137,7 +137,7 @@ describe("qa scenario catalog", () => {
|
||||
|
||||
expect(scenario.sourcePath).toBe("qa/scenarios/models/gpt54-thinking-visibility-switch.md");
|
||||
expect(config?.requiredLiveProvider).toBe("openai");
|
||||
expect(config?.requiredLiveModel).toBe("gpt-5.4");
|
||||
expect(config?.requiredLiveModel).toBe("gpt-5.5");
|
||||
expect(config?.offDirective).toBe("/think off");
|
||||
expect(config?.maxDirective).toBe("/think max");
|
||||
expect(config?.reasoningDirective).toBe("/reasoning on");
|
||||
@@ -169,10 +169,10 @@ describe("qa scenario catalog", () => {
|
||||
},
|
||||
});
|
||||
expect(config?.requiredProvider).toBe("openai");
|
||||
expect(config?.requiredModel).toBe("gpt-5.4");
|
||||
expect(config?.requiredModel).toBe("gpt-5.5");
|
||||
expect(config?.expectedMarker).toBe("WEB-SEARCH-OK");
|
||||
expect(scenario.execution.flow?.steps.map((step) => step.name)).toEqual([
|
||||
"confirms live OpenAI GPT-5.4 web search auto mode",
|
||||
"confirms live OpenAI GPT-5.5 web search auto mode",
|
||||
"searches official OpenAI News through the live model",
|
||||
]);
|
||||
});
|
||||
@@ -191,7 +191,7 @@ describe("qa scenario catalog", () => {
|
||||
expect(scenario.sourcePath).toBe("qa/scenarios/models/thinking-slash-model-remap.md");
|
||||
expect(config?.requiredProviderMode).toBe("live-frontier");
|
||||
expect(config?.anthropicModelRef).toBe("anthropic/claude-sonnet-4-6");
|
||||
expect(config?.openAiXhighModelRef).toBe("openai/gpt-5.4");
|
||||
expect(config?.openAiXhighModelRef).toBe("openai/gpt-5.5");
|
||||
expect(config?.noXhighModelRef).toBe("anthropic/claude-sonnet-4-6");
|
||||
expect(scenario.execution.flow?.steps.map((step) => step.name)).toEqual([
|
||||
"selects Anthropic and verifies adaptive options",
|
||||
|
||||
@@ -35,7 +35,7 @@ describe("qa suite transport helpers", () => {
|
||||
|
||||
state.addOutboundMessage({
|
||||
to: "dm:qa-operator",
|
||||
text: '⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.4 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.4.',
|
||||
text: '⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.5 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.5.',
|
||||
senderId: "openclaw",
|
||||
senderName: "OpenClaw QA",
|
||||
});
|
||||
@@ -117,7 +117,7 @@ describe("qa suite transport helpers", () => {
|
||||
|
||||
state.addOutboundMessage({
|
||||
to: "dm:qa-operator",
|
||||
text: '⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.4 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.4.',
|
||||
text: '⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.5 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.5.',
|
||||
senderId: "openclaw",
|
||||
senderName: "OpenClaw QA",
|
||||
});
|
||||
@@ -164,7 +164,7 @@ describe("qa suite transport helpers", () => {
|
||||
|
||||
state.addOutboundMessage({
|
||||
to: "dm:qa-operator",
|
||||
text: '⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.4 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.4.',
|
||||
text: '⚠️ No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.5 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.5.',
|
||||
senderId: "openclaw",
|
||||
senderName: "OpenClaw QA",
|
||||
});
|
||||
|
||||
@@ -37,8 +37,8 @@ GPT baseline:
|
||||
```bash
|
||||
pnpm openclaw qa suite \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.4 \
|
||||
--alt-model openai/gpt-5.4 \
|
||||
--model openai/gpt-5.5 \
|
||||
--alt-model openai/gpt-5.5 \
|
||||
--fast \
|
||||
--scenario approval-turn-tool-followthrough \
|
||||
--scenario model-switch-tool-continuity \
|
||||
@@ -104,8 +104,8 @@ GPT manual lane:
|
||||
```bash
|
||||
pnpm openclaw qa manual \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.4 \
|
||||
--alt-model openai/gpt-5.4 \
|
||||
--model openai/gpt-5.5 \
|
||||
--alt-model openai/gpt-5.5 \
|
||||
--fast \
|
||||
--message "read QA_KICKOFF_TASK.md, tell me what feels half-baked about this qa mission, and keep it to two short sentences"
|
||||
```
|
||||
|
||||
@@ -24,10 +24,10 @@ codeRefs:
|
||||
- extensions/qa-lab/src/suite.ts
|
||||
execution:
|
||||
kind: flow
|
||||
summary: Run with `pnpm openclaw qa suite --provider-mode live-frontier --model codex/gpt-5.4 --alt-model codex/gpt-5.4 --scenario codex-harness-no-meta-leak`.
|
||||
summary: Run with `pnpm openclaw qa suite --provider-mode live-frontier --model codex/gpt-5.5 --alt-model codex/gpt-5.5 --scenario codex-harness-no-meta-leak`.
|
||||
config:
|
||||
requiredProvider: codex
|
||||
requiredModel: gpt-5.4
|
||||
requiredModel: gpt-5.5
|
||||
harnessRuntime: codex
|
||||
harnessFallback: none
|
||||
expectedReply: QA_LEAK_OK
|
||||
@@ -47,7 +47,7 @@ execution:
|
||||
|
||||
```yaml qa-flow
|
||||
steps:
|
||||
- name: confirms GPT-5.4 Codex harness target
|
||||
- name: confirms GPT-5.5 Codex harness target
|
||||
actions:
|
||||
- set: selected
|
||||
value:
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# GPT-5.4 thinking visibility switch
|
||||
# GPT-5.5 thinking visibility switch
|
||||
|
||||
```yaml qa-scenario
|
||||
id: gpt54-thinking-visibility-switch
|
||||
title: GPT-5.4 thinking visibility switch
|
||||
title: GPT-5.5 thinking visibility switch
|
||||
surface: models
|
||||
coverage:
|
||||
primary:
|
||||
- models.thinking
|
||||
secondary:
|
||||
- runtime.reasoning-visibility
|
||||
objective: Verify GPT-5.4 can switch from disabled thinking to max thinking while reasoning display stays enabled.
|
||||
objective: Verify GPT-5.5 can switch from disabled thinking to max thinking while reasoning display stays enabled.
|
||||
successCriteria:
|
||||
- Live runs target openai/gpt-5.4, not a mini or pro variant.
|
||||
- Live runs target openai/gpt-5.5, not a mini or pro variant.
|
||||
- The session enables reasoning display before the comparison turns.
|
||||
- The disabled-thinking turn returns its visible marker without a Reasoning-prefixed message.
|
||||
- The max-thinking turn returns its visible marker and a separate Reasoning-prefixed message.
|
||||
@@ -27,10 +27,10 @@ codeRefs:
|
||||
- extensions/qa-lab/src/providers/mock-openai/server.ts
|
||||
execution:
|
||||
kind: flow
|
||||
summary: Toggle reasoning display and GPT-5.4 thinking between off/none and max/high, then verify visible reasoning only on the max turn.
|
||||
summary: Toggle reasoning display and GPT-5.5 thinking between off/none and max/high, then verify visible reasoning only on the max turn.
|
||||
config:
|
||||
requiredLiveProvider: openai
|
||||
requiredLiveModel: gpt-5.4
|
||||
requiredLiveModel: gpt-5.5
|
||||
offDirective: /think off
|
||||
maxDirective: /think max
|
||||
reasoningDirective: /reasoning on
|
||||
@@ -60,7 +60,7 @@ steps:
|
||||
- assert:
|
||||
expr: "env.providerMode !== 'live-frontier' || (selected?.provider === config.requiredLiveProvider && selected?.model === config.requiredLiveModel)"
|
||||
message:
|
||||
expr: "`expected live GPT-5.4, got ${env.primaryModel}`"
|
||||
expr: "`expected live GPT-5.5, got ${env.primaryModel}`"
|
||||
- call: state.addInboundMessage
|
||||
args:
|
||||
- conversation:
|
||||
@@ -133,9 +133,9 @@ steps:
|
||||
value:
|
||||
expr: "requests.find((request) => String(request.allInputText ?? '').includes(config.offPrompt))"
|
||||
- assert:
|
||||
expr: "String(offRequest?.model ?? '').includes('gpt-5.4')"
|
||||
expr: "String(offRequest?.model ?? '').includes('gpt-5.5')"
|
||||
message:
|
||||
expr: "`expected GPT-5.4 off mock request, got ${String(offRequest?.model ?? '')}`"
|
||||
expr: "`expected GPT-5.5 off mock request, got ${String(offRequest?.model ?? '')}`"
|
||||
detailsExpr: "`off ack=${offAck.text}; off answer=${offAnswer.text}`"
|
||||
- name: switches to max thinking
|
||||
actions:
|
||||
@@ -204,8 +204,8 @@ steps:
|
||||
value:
|
||||
expr: "requests.find((request) => String(request.allInputText ?? '').includes(config.maxPrompt))"
|
||||
- assert:
|
||||
expr: "String(maxRequest?.model ?? '').includes('gpt-5.4')"
|
||||
expr: "String(maxRequest?.model ?? '').includes('gpt-5.5')"
|
||||
message:
|
||||
expr: "`expected GPT-5.4 mock request, got ${String(maxRequest?.model ?? '')}`"
|
||||
expr: "`expected GPT-5.5 mock request, got ${String(maxRequest?.model ?? '')}`"
|
||||
detailsExpr: "`answer=${maxAnswer.text}`"
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@ coverage:
|
||||
objective: Verify a live OpenAI GPT model can use OpenAI native web_search when OpenClaw web search is enabled in auto mode.
|
||||
successCriteria:
|
||||
- A live-frontier run fails fast unless the selected primary provider is openai.
|
||||
- The selected primary model is GPT-5.4, not a mini or pro variant.
|
||||
- The selected primary model is GPT-5.5, not a mini or pro variant.
|
||||
- Web search is enabled without pinning a managed web_search provider.
|
||||
- The live reply includes the required marker plus an official OpenAI News URL and headline found through web search.
|
||||
gatewayConfigPatch:
|
||||
@@ -32,10 +32,10 @@ codeRefs:
|
||||
- extensions/qa-lab/src/suite.ts
|
||||
execution:
|
||||
kind: flow
|
||||
summary: Run with `OPENCLAW_LIVE_OPENAI_KEY="${OPENAI_API_KEY}" pnpm openclaw qa suite --provider-mode live-frontier --model openai/gpt-5.4 --alt-model openai/gpt-5.4 --scenario openai-native-web-search-live`.
|
||||
summary: Run with `OPENCLAW_LIVE_OPENAI_KEY="${OPENAI_API_KEY}" pnpm openclaw qa suite --provider-mode live-frontier --model openai/gpt-5.5 --alt-model openai/gpt-5.5 --scenario openai-native-web-search-live`.
|
||||
config:
|
||||
requiredProvider: openai
|
||||
requiredModel: gpt-5.4
|
||||
requiredModel: gpt-5.5
|
||||
expectedMarker: WEB-SEARCH-OK
|
||||
failureMarker: WEB-SEARCH-FAILED
|
||||
searchPrompt: |-
|
||||
@@ -49,7 +49,7 @@ execution:
|
||||
|
||||
```yaml qa-flow
|
||||
steps:
|
||||
- name: confirms live OpenAI GPT-5.4 web search auto mode
|
||||
- name: confirms live OpenAI GPT-5.5 web search auto mode
|
||||
actions:
|
||||
- call: waitForGatewayHealthy
|
||||
args:
|
||||
|
||||
@@ -13,8 +13,8 @@ coverage:
|
||||
objective: Verify /think lists provider-owned levels and remaps stored thinking levels when /model changes provider capabilities.
|
||||
successCriteria:
|
||||
- Anthropic Claude Sonnet 4.6 advertises adaptive but not OpenAI-only xhigh or Opus max.
|
||||
- A stored adaptive level remaps to medium when switching to OpenAI GPT-5.4.
|
||||
- OpenAI GPT-5.4 advertises xhigh but not adaptive or max.
|
||||
- A stored adaptive level remaps to medium when switching to OpenAI GPT-5.5.
|
||||
- OpenAI GPT-5.5 advertises xhigh but not adaptive or max.
|
||||
- A stored xhigh level remaps to high when switching to an Anthropic model without xhigh support.
|
||||
docsRefs:
|
||||
- docs/tools/thinking.md
|
||||
@@ -33,7 +33,7 @@ execution:
|
||||
config:
|
||||
requiredProviderMode: live-frontier
|
||||
anthropicModelRef: anthropic/claude-sonnet-4-6
|
||||
openAiXhighModelRef: openai/gpt-5.4
|
||||
openAiXhighModelRef: openai/gpt-5.5
|
||||
noXhighModelRef: anthropic/claude-sonnet-4-6
|
||||
conversationId: qa-thinking-slash-remap
|
||||
```
|
||||
@@ -165,7 +165,7 @@ steps:
|
||||
- assert:
|
||||
expr: "/Options: .*\\bxhigh\\b/i.test(openAiThinkStatus.text) && !/Options: .*\\badaptive\\b/i.test(openAiThinkStatus.text) && !/Options: .*\\bmax\\b/i.test(openAiThinkStatus.text)"
|
||||
message:
|
||||
expr: "`expected OpenAI GPT-5.4 /think options to include xhigh only, got ${openAiThinkStatus.text}`"
|
||||
expr: "`expected OpenAI GPT-5.5 /think options to include xhigh only, got ${openAiThinkStatus.text}`"
|
||||
detailsExpr: "`adaptive=${adaptiveAck.text}; switch=${openAiModelAck.text}; think=${openAiThinkStatus.text}`"
|
||||
- name: maps xhigh to high on a model without xhigh
|
||||
actions:
|
||||
|
||||
@@ -11,7 +11,7 @@ coverage:
|
||||
- models.codex-cli
|
||||
objective: Verify the Codex app-server harness can plan and build a medium-complex self-contained browser game.
|
||||
successCriteria:
|
||||
- A live-frontier run fails fast unless the selected primary model is codex/gpt-5.4.
|
||||
- A live-frontier run fails fast unless the selected primary model is codex/gpt-5.5.
|
||||
- The scenario forces the Codex embedded harness and disables PI fallback.
|
||||
- The prompt explicitly asks the agent to enter plan mode before editing.
|
||||
- The agent writes a self-contained HTML game with a canvas loop, controls, scoring, waves, pause, and restart.
|
||||
@@ -25,10 +25,10 @@ codeRefs:
|
||||
- extensions/qa-lab/src/suite.ts
|
||||
execution:
|
||||
kind: flow
|
||||
summary: Run with `pnpm openclaw qa suite --provider-mode live-frontier --model codex/gpt-5.4 --alt-model codex/gpt-5.4 --scenario medium-game-plan-codex-harness`.
|
||||
summary: Run with `pnpm openclaw qa suite --provider-mode live-frontier --model codex/gpt-5.5 --alt-model codex/gpt-5.5 --scenario medium-game-plan-codex-harness`.
|
||||
config:
|
||||
requiredProvider: codex
|
||||
requiredModel: gpt-5.4
|
||||
requiredModel: gpt-5.5
|
||||
harnessRuntime: codex
|
||||
harnessFallback: none
|
||||
artifactFile: star-garden-defenders-codex.html
|
||||
@@ -52,7 +52,7 @@ execution:
|
||||
|
||||
```yaml qa-flow
|
||||
steps:
|
||||
- name: confirms GPT-5.4 Codex harness target
|
||||
- name: confirms GPT-5.5 Codex harness target
|
||||
actions:
|
||||
- set: selected
|
||||
value:
|
||||
|
||||
@@ -9,9 +9,9 @@ coverage:
|
||||
- workspace.planning
|
||||
secondary:
|
||||
- agents.pi-harness
|
||||
objective: Verify GPT-5.4 can use the PI harness to plan and build a medium-complex self-contained browser game.
|
||||
objective: Verify GPT-5.5 can use the PI harness to plan and build a medium-complex self-contained browser game.
|
||||
successCriteria:
|
||||
- A live-frontier run fails fast unless the selected primary model is openai/gpt-5.4.
|
||||
- A live-frontier run fails fast unless the selected primary model is openai/gpt-5.5.
|
||||
- The scenario forces the embedded PI harness before the build turn.
|
||||
- The prompt explicitly asks the agent to enter plan mode before editing.
|
||||
- The agent writes a self-contained HTML game with a canvas loop, controls, scoring, waves, pause, and restart.
|
||||
@@ -25,10 +25,10 @@ codeRefs:
|
||||
- extensions/qa-lab/src/suite.ts
|
||||
execution:
|
||||
kind: flow
|
||||
summary: Run with `pnpm openclaw qa suite --provider-mode live-frontier --model openai/gpt-5.4 --alt-model openai/gpt-5.4 --scenario medium-game-plan-pi-harness`.
|
||||
summary: Run with `pnpm openclaw qa suite --provider-mode live-frontier --model openai/gpt-5.5 --alt-model openai/gpt-5.5 --scenario medium-game-plan-pi-harness`.
|
||||
config:
|
||||
requiredProvider: openai
|
||||
requiredModel: gpt-5.4
|
||||
requiredModel: gpt-5.5
|
||||
harnessRuntime: pi
|
||||
harnessFallback: pi
|
||||
artifactFile: star-garden-defenders-pi.html
|
||||
@@ -52,7 +52,7 @@ execution:
|
||||
|
||||
```yaml qa-flow
|
||||
steps:
|
||||
- name: confirms GPT-5.4 PI harness target
|
||||
- name: confirms GPT-5.5 PI harness target
|
||||
actions:
|
||||
- set: selected
|
||||
value:
|
||||
|
||||
@@ -46,7 +46,7 @@ function createBackendEntry(params: {
|
||||
params.id === "claude-cli"
|
||||
? "claude-cli/claude-sonnet-4-6"
|
||||
: params.id === "codex-cli"
|
||||
? "codex-cli/gpt-5.4"
|
||||
? "codex-cli/gpt-5.5"
|
||||
: params.id === "google-gemini-cli"
|
||||
? "google-gemini-cli/gemini-3-flash-preview"
|
||||
: undefined,
|
||||
@@ -385,7 +385,7 @@ describe("resolveCliBackendLiveTest", () => {
|
||||
|
||||
it("returns plugin-owned live smoke metadata for codex", () => {
|
||||
expect(resolveCliBackendLiveTest("codex-cli")).toEqual({
|
||||
defaultModelRef: "codex-cli/gpt-5.4",
|
||||
defaultModelRef: "codex-cli/gpt-5.5",
|
||||
defaultImageProbe: true,
|
||||
defaultMcpProbe: true,
|
||||
dockerNpmPackage: "@openai/codex",
|
||||
|
||||
@@ -117,7 +117,7 @@ vi.mock("../plugins/provider-runtime.js", () => ({
|
||||
context: { listProfileIds: (providerId: string) => string[] };
|
||||
}) => {
|
||||
if (params.provider === "openai" && params.context.listProfileIds("openai-codex").length > 0) {
|
||||
return 'No API key found for provider "openai". Use openai-codex/gpt-5.4.';
|
||||
return 'No API key found for provider "openai". Use openai-codex/gpt-5.5.';
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
@@ -365,7 +365,7 @@ describe("getApiKeyForModel", () => {
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
expect(String(error)).toContain("openai-codex/gpt-5.4");
|
||||
expect(String(error)).toContain("openai-codex/gpt-5.5");
|
||||
},
|
||||
);
|
||||
} finally {
|
||||
|
||||
@@ -386,10 +386,14 @@ describe("isModernModelRef", () => {
|
||||
it("includes plugin-advertised modern models", () => {
|
||||
providerRuntimeMocks.resolveProviderModernModelRef.mockImplementation(({ provider, context }) =>
|
||||
provider === "openai" &&
|
||||
["gpt-5.4", "gpt-5.4-pro", "gpt-5.4-mini", "gpt-5.4-nano"].includes(context.modelId)
|
||||
["gpt-5.5", "gpt-5.5-pro", "gpt-5.4", "gpt-5.4-pro", "gpt-5.4-mini", "gpt-5.4-nano"].includes(
|
||||
context.modelId,
|
||||
)
|
||||
? true
|
||||
: provider === "openai-codex" &&
|
||||
["gpt-5.4", "gpt-5.4-pro", "gpt-5.4-mini"].includes(context.modelId)
|
||||
["gpt-5.5", "gpt-5.5-pro", "gpt-5.4", "gpt-5.4-pro", "gpt-5.4-mini"].includes(
|
||||
context.modelId,
|
||||
)
|
||||
? true
|
||||
: provider === "opencode" && ["claude-opus-4-6", "gemini-3-pro"].includes(context.modelId)
|
||||
? true
|
||||
@@ -398,10 +402,14 @@ describe("isModernModelRef", () => {
|
||||
: undefined,
|
||||
);
|
||||
|
||||
expect(isModernModelRef({ provider: "openai", id: "gpt-5.5" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai", id: "gpt-5.5-pro" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai", id: "gpt-5.4" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai", id: "gpt-5.4-pro" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai", id: "gpt-5.4-mini" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai", id: "gpt-5.4-nano" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai-codex", id: "gpt-5.5" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai-codex", id: "gpt-5.5-pro" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai-codex", id: "gpt-5.4" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai-codex", id: "gpt-5.4-pro" })).toBe(true);
|
||||
expect(isModernModelRef({ provider: "openai-codex", id: "gpt-5.4-mini" })).toBe(true);
|
||||
|
||||
@@ -680,7 +680,7 @@ describeLive("live models (profile keys)", () => {
|
||||
if (
|
||||
model.provider === "openai" &&
|
||||
model.api === "openai-responses" &&
|
||||
model.id === "gpt-5.4"
|
||||
(model.id === "gpt-5.5" || model.id === "gpt-5.4")
|
||||
) {
|
||||
logProgress(`${progressLabel}: tool-only regression`);
|
||||
const noopTool = {
|
||||
|
||||
@@ -805,7 +805,7 @@ describeCacheLive("pi embedded runner prompt caching (live)", () => {
|
||||
provider: "openai",
|
||||
api: "openai-responses",
|
||||
envVar: "OPENCLAW_LIVE_OPENAI_CACHE_MODEL",
|
||||
preferredModelIds: ["gpt-5.4-mini", "gpt-5.4", "gpt-5.4"],
|
||||
preferredModelIds: ["gpt-5.5", "gpt-5.4-mini", "gpt-5.4"],
|
||||
});
|
||||
logLiveCache(`openai model=${fixture.model.provider}/${fixture.model.id}`);
|
||||
}, 120_000);
|
||||
|
||||
@@ -162,7 +162,7 @@ describeCacheLive("MCP-style prompt caching (live)", () => {
|
||||
provider: "openai",
|
||||
api: "openai-responses",
|
||||
envVar: "OPENCLAW_LIVE_OPENAI_CACHE_MODEL",
|
||||
preferredModelIds: ["gpt-5.4-mini", "gpt-5.4", "gpt-5.4"],
|
||||
preferredModelIds: ["gpt-5.5", "gpt-5.4-mini", "gpt-5.4"],
|
||||
});
|
||||
logLiveCache(`openai mcp-style model=${fixture.model.provider}/${fixture.model.id}`);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ describeLive("provider response headers (live)", () => {
|
||||
provider: "openai",
|
||||
api: "openai-responses",
|
||||
envVar: "OPENCLAW_LIVE_OPENAI_CACHE_MODEL",
|
||||
preferredModelIds: ["gpt-5.4-mini", "gpt-5.4", "gpt-5.4"],
|
||||
preferredModelIds: ["gpt-5.5", "gpt-5.4-mini", "gpt-5.4"],
|
||||
});
|
||||
}, 120_000);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ describe("resolveSimpleCompletionSelectionForAgent", () => {
|
||||
expect(selection).toEqual(
|
||||
expect.objectContaining({
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.4",
|
||||
modelId: "gpt-5.5",
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -118,7 +118,7 @@ describe("resolveSimpleCompletionSelectionForAgent", () => {
|
||||
expect(selection).toEqual(
|
||||
expect.objectContaining({
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.4",
|
||||
modelId: "gpt-5.5",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1517,7 +1517,7 @@ describe("runAgentTurnWithFallback", () => {
|
||||
it("surfaces direct provider auth guidance for missing API keys", async () => {
|
||||
state.runEmbeddedPiAgentMock.mockRejectedValueOnce(
|
||||
new Error(
|
||||
'No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.4 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.4. | No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.4 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.4.',
|
||||
'No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.5 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.5. | No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.5 (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.5.',
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1549,7 +1549,7 @@ describe("runAgentTurnWithFallback", () => {
|
||||
expect(result.kind).toBe("final");
|
||||
if (result.kind === "final") {
|
||||
expect(result.payload.text).toBe(
|
||||
"⚠️ Missing API key for OpenAI on the gateway. Use `openai-codex/gpt-5.4` for OAuth, or set `OPENAI_API_KEY`, then try again.",
|
||||
"⚠️ Missing API key for OpenAI on the gateway. Use `openai-codex/gpt-5.5` for OAuth, or set `OPENAI_API_KEY`, then try again.",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -181,7 +181,7 @@ describe("runMemoryFlushIfNeeded", () => {
|
||||
cfg: { agents: { defaults: { cliBackends: { "codex-cli": { command: "codex" } } } } },
|
||||
followupRun: createTestFollowupRun({ provider: "codex-cli" }),
|
||||
sessionCtx: { Provider: "whatsapp" } as unknown as TemplateContext,
|
||||
defaultModel: "codex-cli/gpt-5.4",
|
||||
defaultModel: "codex-cli/gpt-5.5",
|
||||
agentCfgContextTokens: 100_000,
|
||||
resolvedVerboseLevel: "off",
|
||||
sessionEntry,
|
||||
|
||||
@@ -83,8 +83,8 @@ vi.mock("../agents/model-selection.js", () => {
|
||||
return primary?.primary;
|
||||
};
|
||||
const resolveDefaultRef = (cfg?: ConfigWithModels): ModelRef => {
|
||||
const parsed = parseModelRefImpl(resolvePrimary(cfg) ?? "openai/gpt-5.4", "openai");
|
||||
return parsed ?? { provider: "openai", model: "gpt-5.4" };
|
||||
const parsed = parseModelRefImpl(resolvePrimary(cfg) ?? "openai/gpt-5.5", "openai");
|
||||
return parsed ?? { provider: "openai", model: "gpt-5.5" };
|
||||
};
|
||||
const resolveModelConfig = (cfg: ConfigWithModels | undefined, ref: ModelRef) => {
|
||||
const models = cfg?.agents?.defaults?.models ?? {};
|
||||
|
||||
@@ -130,8 +130,8 @@ function createAcpEnabledConfig(home: string, storePath: string): OpenClawConfig
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "openai/gpt-5.4" },
|
||||
models: { "openai/gpt-5.4": {} },
|
||||
model: { primary: "openai/gpt-5.5" },
|
||||
models: { "openai/gpt-5.5": {} },
|
||||
workspace: path.join(home, "openclaw"),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -492,7 +492,7 @@ async function createDefaultProviderPlugins(): Promise<ProviderPlugin[]> {
|
||||
flagName: "--openai-api-key",
|
||||
envVar: "OPENAI_API_KEY",
|
||||
promptMessage: "Enter OpenAI API key",
|
||||
defaultModel: "openai/gpt-5.4",
|
||||
defaultModel: "openai/gpt-5.5",
|
||||
}),
|
||||
await createApiKeyProvider({
|
||||
providerId: "opencode",
|
||||
|
||||
@@ -168,7 +168,7 @@ describe("promptAuthConfig", () => {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"openai/gpt-5.4": { alias: "GPT" },
|
||||
"openai/gpt-5.5": { alias: "GPT" },
|
||||
"anthropic/claude-opus-4-6": { alias: "Opus" },
|
||||
},
|
||||
},
|
||||
@@ -193,7 +193,7 @@ describe("promptAuthConfig", () => {
|
||||
const result = await promptAuthConfig({}, makeRuntime(), noopPrompter);
|
||||
|
||||
expect(result.agents?.defaults?.models).toEqual({
|
||||
"openai/gpt-5.4": { alias: "GPT" },
|
||||
"openai/gpt-5.5": { alias: "GPT" },
|
||||
"anthropic/claude-sonnet-4-6": {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ describe("normalizeStoredCronJobs", () => {
|
||||
jobId: "legacy-job",
|
||||
schedule: { kind: "cron", cron: "*/5 * * * *", tz: "UTC" },
|
||||
message: "say hi",
|
||||
model: "openai/gpt-5.4",
|
||||
model: "openai/gpt-5.5",
|
||||
deliver: true,
|
||||
provider: " TeLeGrAm ",
|
||||
to: "12345",
|
||||
@@ -73,7 +73,7 @@ describe("normalizeStoredCronJobs", () => {
|
||||
expect(job?.payload).toMatchObject({
|
||||
kind: "agentTurn",
|
||||
message: "say hi",
|
||||
model: "openai/gpt-5.4",
|
||||
model: "openai/gpt-5.5",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -116,13 +116,13 @@ describe("promptDefaultModel", () => {
|
||||
loadModelCatalog.mockResolvedValue([
|
||||
{
|
||||
provider: "openai",
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
},
|
||||
{
|
||||
provider: "openai-codex",
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -141,11 +141,11 @@ describe("promptDefaultModel", () => {
|
||||
expect(options).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
value: "openai/gpt-5.4",
|
||||
value: "openai/gpt-5.5",
|
||||
hint: expect.stringContaining("API key route"),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
value: "openai-codex/gpt-5.4",
|
||||
value: "openai-codex/gpt-5.5",
|
||||
hint: expect.stringContaining("ChatGPT OAuth route"),
|
||||
}),
|
||||
]),
|
||||
@@ -156,8 +156,8 @@ describe("promptDefaultModel", () => {
|
||||
loadModelCatalog.mockResolvedValue([
|
||||
{
|
||||
provider: "openai",
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
},
|
||||
{
|
||||
provider: "byteplus-plan",
|
||||
@@ -171,7 +171,7 @@ describe("promptDefaultModel", () => {
|
||||
const config = {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.4",
|
||||
model: "openai/gpt-5.5",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
@@ -276,8 +276,8 @@ describe("promptDefaultModel", () => {
|
||||
loadModelCatalog.mockResolvedValue([
|
||||
{
|
||||
provider: "openai",
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
},
|
||||
]);
|
||||
providerModelPickerContributionRuntime.enabled = true;
|
||||
@@ -343,8 +343,8 @@ describe("promptModelAllowlist", () => {
|
||||
},
|
||||
{
|
||||
provider: "openai",
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.2",
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -374,8 +374,8 @@ describe("promptModelAllowlist", () => {
|
||||
},
|
||||
{
|
||||
provider: "openai",
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
},
|
||||
{
|
||||
provider: "openai",
|
||||
@@ -396,7 +396,7 @@ describe("promptModelAllowlist", () => {
|
||||
|
||||
const options = multiselect.mock.calls[0]?.[0]?.options ?? [];
|
||||
expect(options.map((opt: { value: string }) => opt.value)).toEqual([
|
||||
"openai/gpt-5.4",
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.4-mini",
|
||||
]);
|
||||
});
|
||||
@@ -440,16 +440,16 @@ describe("applyModelAllowlist", () => {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"openai/gpt-5.4": { alias: "gpt" },
|
||||
"openai/gpt-5.5": { alias: "gpt" },
|
||||
"anthropic/claude-opus-4-6": { alias: "opus" },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const next = applyModelAllowlist(config, ["openai/gpt-5.4"]);
|
||||
const next = applyModelAllowlist(config, ["openai/gpt-5.5"]);
|
||||
expect(next.agents?.defaults?.models).toEqual({
|
||||
"openai/gpt-5.4": { alias: "gpt" },
|
||||
"openai/gpt-5.5": { alias: "gpt" },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -458,7 +458,7 @@ describe("applyModelAllowlist", () => {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"openai/gpt-5.4": { alias: "gpt" },
|
||||
"openai/gpt-5.5": { alias: "gpt" },
|
||||
"anthropic/claude-opus-4-6": { alias: "opus" },
|
||||
"anthropic/claude-sonnet-4-6": { alias: "sonnet" },
|
||||
},
|
||||
@@ -470,7 +470,7 @@ describe("applyModelAllowlist", () => {
|
||||
scopeKeys: ["anthropic/claude-opus-4-6", "anthropic/claude-sonnet-4-6"],
|
||||
});
|
||||
expect(next.agents?.defaults?.models).toEqual({
|
||||
"openai/gpt-5.4": { alias: "gpt" },
|
||||
"openai/gpt-5.5": { alias: "gpt" },
|
||||
"anthropic/claude-sonnet-4-6": { alias: "sonnet" },
|
||||
});
|
||||
});
|
||||
@@ -480,7 +480,7 @@ describe("applyModelAllowlist", () => {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"openai/gpt-5.4": { alias: "gpt" },
|
||||
"openai/gpt-5.5": { alias: "gpt" },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -515,15 +515,15 @@ describe("applyModelFallbacksFromSelection", () => {
|
||||
const config = {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "anthropic/claude-opus-4-6", fallbacks: ["openai/gpt-5.4"] },
|
||||
model: { primary: "anthropic/claude-opus-4-6", fallbacks: ["openai/gpt-5.5"] },
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const next = applyModelFallbacksFromSelection(config, ["openai/gpt-5.4"]);
|
||||
const next = applyModelFallbacksFromSelection(config, ["openai/gpt-5.5"]);
|
||||
expect(next.agents?.defaults?.model).toEqual({
|
||||
primary: "anthropic/claude-opus-4-6",
|
||||
fallbacks: ["openai/gpt-5.4"],
|
||||
fallbacks: ["openai/gpt-5.5"],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -298,7 +298,7 @@ describe("modelsAuthLoginCommand", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
defaultModel: "openai-codex/gpt-5.4",
|
||||
defaultModel: "openai-codex/gpt-5.5",
|
||||
});
|
||||
mocks.resolvePluginProviders.mockReturnValue([
|
||||
createProvider({
|
||||
@@ -365,7 +365,7 @@ describe("modelsAuthLoginCommand", () => {
|
||||
"Auth profile: openai-codex:user@example.com (openai-codex/oauth)",
|
||||
);
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
"Default model available: openai-codex/gpt-5.4 (use --set-default to apply)",
|
||||
"Default model available: openai-codex/gpt-5.5 (use --set-default to apply)",
|
||||
);
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
"Tip: Codex-capable models can use native Codex web search. Enable it with openclaw configure --section web (recommended mode: cached). Docs: https://docs.openclaw.ai/tools/web",
|
||||
@@ -585,7 +585,7 @@ describe("modelsAuthLoginCommand", () => {
|
||||
"anthropic/claude-sonnet-4-6": { alias: "sonnet" },
|
||||
"anthropic/claude-opus-4-6": { alias: "opus" },
|
||||
"moonshot/kimi-k2.5": { alias: "kimi" },
|
||||
"openai-codex/gpt-5.4": { alias: "gpt54" },
|
||||
"openai-codex/gpt-5.5": { alias: "gpt55" },
|
||||
};
|
||||
currentConfig = { agents: { defaults: { models: existingModels } } };
|
||||
runProviderAuth.mockResolvedValue({
|
||||
@@ -602,8 +602,8 @@ describe("modelsAuthLoginCommand", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
configPatch: { agents: { defaults: { models: { "openai-codex/gpt-5.4": {} } } } },
|
||||
defaultModel: "openai-codex/gpt-5.4",
|
||||
configPatch: { agents: { defaults: { models: { "openai-codex/gpt-5.5": {} } } } },
|
||||
defaultModel: "openai-codex/gpt-5.5",
|
||||
});
|
||||
|
||||
await modelsAuthLoginCommand({ provider: "openai-codex" }, runtime);
|
||||
|
||||
@@ -13,9 +13,9 @@ describe("resolveConfiguredEntries", () => {
|
||||
const { entries } = resolveConfiguredEntries({
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "codex/gpt-5.4", fallbacks: ["codex/gpt-5.4-mini"] },
|
||||
model: { primary: "codex/gpt-5.5", fallbacks: ["codex/gpt-5.4-mini"] },
|
||||
models: {
|
||||
"codex/gpt-5.4": { alias: "Codex" },
|
||||
"codex/gpt-5.5": { alias: "Codex" },
|
||||
"codex/gpt-5.4-mini": {},
|
||||
},
|
||||
},
|
||||
@@ -23,7 +23,7 @@ describe("resolveConfiguredEntries", () => {
|
||||
models: { providers: {} },
|
||||
});
|
||||
|
||||
expect(entries.map((entry) => entry.key)).toEqual(["codex/gpt-5.4", "codex/gpt-5.4-mini"]);
|
||||
expect(entries.map((entry) => entry.key)).toEqual(["codex/gpt-5.5", "codex/gpt-5.4-mini"]);
|
||||
expect(entries[0]?.tags).toEqual(new Set(["default", "configured"]));
|
||||
expect(entries[0]?.aliases).toEqual(["Codex"]);
|
||||
expect(entries[1]?.tags).toEqual(new Set(["fallback#1", "configured"]));
|
||||
|
||||
@@ -8,8 +8,8 @@ const mocks = vi.hoisted(() => ({
|
||||
}),
|
||||
loadProviderCatalogModelsForList: vi.fn().mockResolvedValue([
|
||||
{
|
||||
id: "gpt-5.4",
|
||||
name: "gpt-5.4",
|
||||
id: "gpt-5.5",
|
||||
name: "gpt-5.5",
|
||||
provider: "codex",
|
||||
api: "openai-codex-responses",
|
||||
baseUrl: "https://chatgpt.com/backend-api",
|
||||
@@ -57,7 +57,7 @@ describe("appendProviderCatalogRows", () => {
|
||||
seenKeys: new Set(),
|
||||
context: {
|
||||
cfg: {
|
||||
agents: { defaults: { model: { primary: "codex/gpt-5.4" } } },
|
||||
agents: { defaults: { model: { primary: "codex/gpt-5.5" } } },
|
||||
models: { providers: {} },
|
||||
},
|
||||
agentDir: "/tmp/openclaw-agent",
|
||||
@@ -72,7 +72,7 @@ describe("appendProviderCatalogRows", () => {
|
||||
expect(mocks.shouldSuppressBuiltInModel).not.toHaveBeenCalled();
|
||||
expect(rows).toMatchObject([
|
||||
{
|
||||
key: "codex/gpt-5.4",
|
||||
key: "codex/gpt-5.5",
|
||||
available: true,
|
||||
missing: false,
|
||||
},
|
||||
|
||||
@@ -429,8 +429,8 @@ describe("modelsStatusCommand auth overview", () => {
|
||||
mocks.loadConfig.mockReturnValue({
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "codex/gpt-5.4", fallbacks: [] },
|
||||
models: { "codex/gpt-5.4": {} },
|
||||
model: { primary: "codex/gpt-5.5", fallbacks: [] },
|
||||
models: { "codex/gpt-5.5": {} },
|
||||
},
|
||||
},
|
||||
models: { providers: {} },
|
||||
|
||||
@@ -64,7 +64,7 @@ describe("onboard auth provider config merges", () => {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"openai/gpt-5.4": { alias: "GPT" },
|
||||
"openai/gpt-5.5": { alias: "GPT" },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -89,7 +89,7 @@ describe("onboard auth provider config merges", () => {
|
||||
});
|
||||
|
||||
expect(next.agents?.defaults?.models).toEqual({
|
||||
"openai/gpt-5.4": { alias: "GPT" },
|
||||
"openai/gpt-5.5": { alias: "GPT" },
|
||||
...agentModels,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,7 +73,7 @@ describe("applyDefaultModelChoice", () => {
|
||||
});
|
||||
|
||||
it("uses applyDefaultConfig path when setDefaultModel is true", async () => {
|
||||
const defaultModel = "openai/gpt-5.4";
|
||||
const defaultModel = "openai/gpt-5.5";
|
||||
const applied = await applyDefaultModelChoice({
|
||||
config: {},
|
||||
setDefaultModel: true,
|
||||
|
||||
@@ -19,7 +19,7 @@ describe("status-overview-rows", () => {
|
||||
"1 files · 2 chunks · plugin memory · ok(vector ready) · warn(fts ready) · muted(cache warm)",
|
||||
},
|
||||
{ Item: "Plugin compatibility", Value: "warn(1 notice · 1 plugin)" },
|
||||
{ Item: "Sessions", Value: "2 active · default gpt-5.4 (12k ctx) · store.json" },
|
||||
{ Item: "Sessions", Value: "2 active · default gpt-5.5 (12k ctx) · store.json" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -54,10 +54,10 @@ describe("status-overview-values", () => {
|
||||
sessions: {
|
||||
count: 2,
|
||||
paths: ["store.json", "other.json"],
|
||||
defaults: { model: "gpt-5.4", contextTokens: 12_000 },
|
||||
defaults: { model: "gpt-5.5", contextTokens: 12_000 },
|
||||
},
|
||||
formatKTokens: (value) => `${Math.round(value / 1000)}k`,
|
||||
}),
|
||||
).toBe("2 active · default gpt-5.4 (12k ctx) · 2 stores");
|
||||
).toBe("2 active · default gpt-5.5 (12k ctx) · 2 stores");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,17 +79,17 @@ describe("statusSummaryRuntime.resolveSessionModelRef", () => {
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "openai/gpt-5.4" },
|
||||
model: { primary: "openai/gpt-5.5" },
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
{
|
||||
model: "gpt-5.4",
|
||||
model: "gpt-5.5",
|
||||
},
|
||||
),
|
||||
).toEqual({
|
||||
provider: "openai",
|
||||
model: "gpt-5.4",
|
||||
model: "gpt-5.5",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ vi.mock("./status.summary.runtime.js", () => ({
|
||||
classifySessionKey: vi.fn(() => "direct"),
|
||||
resolveConfiguredStatusModelRef: vi.fn(() => ({
|
||||
provider: "openai",
|
||||
model: "gpt-5.4",
|
||||
model: "gpt-5.5",
|
||||
})),
|
||||
resolveSessionModelRef: vi.fn(() => ({
|
||||
provider: "openai",
|
||||
model: "gpt-5.4",
|
||||
model: "gpt-5.5",
|
||||
})),
|
||||
resolveContextTokensForModel: vi.fn(() => 200_000),
|
||||
},
|
||||
@@ -26,7 +26,7 @@ vi.mock("./status.summary.runtime.js", () => ({
|
||||
|
||||
vi.mock("../agents/defaults.js", () => ({
|
||||
DEFAULT_CONTEXT_TOKENS: 200_000,
|
||||
DEFAULT_MODEL: "gpt-5.4",
|
||||
DEFAULT_MODEL: "gpt-5.5",
|
||||
DEFAULT_PROVIDER: "openai",
|
||||
}));
|
||||
|
||||
|
||||
@@ -92,14 +92,14 @@ export const baseStatusSummary = {
|
||||
sessions: {
|
||||
count: 2,
|
||||
paths: ["store.json"],
|
||||
defaults: { model: "gpt-5.4", contextTokens: 12_000 },
|
||||
defaults: { model: "gpt-5.5", contextTokens: 12_000 },
|
||||
recent: [
|
||||
{
|
||||
key: "session-key",
|
||||
kind: "direct",
|
||||
updatedAt: 1,
|
||||
age: 5_000,
|
||||
model: "gpt-5.4",
|
||||
model: "gpt-5.5",
|
||||
totalTokens: 12_000,
|
||||
totalTokensFresh: true,
|
||||
remainingTokens: 4_000,
|
||||
|
||||
@@ -36,7 +36,7 @@ const describeLive = LIVE && ACP_BIND_LIVE ? describe : describe.skip;
|
||||
|
||||
const CONNECT_TIMEOUT_MS = 90_000;
|
||||
const LIVE_TIMEOUT_MS = 240_000;
|
||||
const DEFAULT_LIVE_CODEX_MODEL = "gpt-5.4";
|
||||
const DEFAULT_LIVE_CODEX_MODEL = "gpt-5.5";
|
||||
type LiveAcpAgent = "claude" | "codex" | "gemini";
|
||||
|
||||
function createSlackCurrentConversationBindingRegistry() {
|
||||
|
||||
@@ -112,7 +112,7 @@ describe("gateway cli backend live helpers", () => {
|
||||
);
|
||||
expect(shouldRunCliModelSwitchProbe("claude-cli", "claude-cli/claude-sonnet-4-6")).toBe(true);
|
||||
expect(shouldRunCliModelSwitchProbe("claude-cli", "claude-cli/claude-opus-4-6")).toBe(false);
|
||||
expect(shouldRunCliModelSwitchProbe("codex-cli", "codex-cli/gpt-5.4")).toBe(false);
|
||||
expect(shouldRunCliModelSwitchProbe("codex-cli", "codex-cli/gpt-5.5")).toBe(false);
|
||||
});
|
||||
|
||||
it("lets env disable the model switch probe", async () => {
|
||||
|
||||
@@ -515,7 +515,7 @@ describe("resolveGatewayLiveMaxModels", () => {
|
||||
});
|
||||
|
||||
it("keeps explicit gateway model lists uncapped unless a cap is provided", () => {
|
||||
process.env.OPENCLAW_LIVE_GATEWAY_MODELS = "openai/gpt-5.4,anthropic/claude-opus-4-6";
|
||||
process.env.OPENCLAW_LIVE_GATEWAY_MODELS = "openai/gpt-5.5,anthropic/claude-opus-4-6";
|
||||
delete process.env.OPENCLAW_LIVE_GATEWAY_MAX_MODELS;
|
||||
delete process.env.OPENCLAW_LIVE_MAX_MODELS;
|
||||
|
||||
|
||||
@@ -344,8 +344,8 @@ function createChatContext(): Pick<
|
||||
mockState.modelCatalog ?? [
|
||||
{
|
||||
provider: "openai",
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
input: ["text", "image"],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -122,7 +122,7 @@ describe("gateway startup primary model warmup", () => {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "codex-cli/gpt-5.4",
|
||||
primary: "codex-cli/gpt-5.5",
|
||||
},
|
||||
cliBackends: {
|
||||
"codex-cli": {
|
||||
|
||||
@@ -17,7 +17,7 @@ describe("resolveDefaultMediaModel", () => {
|
||||
"MiniMax-VL-01",
|
||||
);
|
||||
expect(resolveDefaultMediaModel({ providerId: "openai-codex", capability: "image" })).toBe(
|
||||
"gpt-5.4",
|
||||
"gpt-5.5",
|
||||
);
|
||||
expect(resolveDefaultMediaModel({ providerId: "moonshot", capability: "image" })).toBe(
|
||||
"kimi-k2.6",
|
||||
|
||||
@@ -94,12 +94,12 @@ describe("normalizePluginsConfig", () => {
|
||||
name: "normalizes plugin subagent override policy settings",
|
||||
subagent: {
|
||||
allowModelOverride: true,
|
||||
allowedModels: [" anthropic/claude-sonnet-4-6 ", "", "openai/gpt-5.4"],
|
||||
allowedModels: [" anthropic/claude-sonnet-4-6 ", "", "openai/gpt-5.5"],
|
||||
},
|
||||
expected: {
|
||||
allowModelOverride: true,
|
||||
hasAllowedModelsConfig: true,
|
||||
allowedModels: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4"],
|
||||
allowedModels: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.5"],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -17,11 +17,11 @@ describe("applyProviderAuthConfigPatch", () => {
|
||||
};
|
||||
|
||||
it("merges default model maps by default so other providers survive login", () => {
|
||||
const patch = { agents: { defaults: { models: { "openai-codex/gpt-5.4": {} } } } };
|
||||
const patch = { agents: { defaults: { models: { "openai-codex/gpt-5.5": {} } } } };
|
||||
const next = applyProviderAuthConfigPatch(base, patch);
|
||||
expect(next.agents?.defaults?.models).toEqual({
|
||||
...base.agents.defaults.models,
|
||||
"openai-codex/gpt-5.4": {},
|
||||
"openai-codex/gpt-5.5": {},
|
||||
});
|
||||
expect(next.agents?.defaults?.model).toEqual(base.agents.defaults.model);
|
||||
});
|
||||
|
||||
@@ -23,6 +23,15 @@ export const expectedAugmentedOpenaiCodexCatalogEntries = [
|
||||
},
|
||||
];
|
||||
|
||||
export const expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55 = [
|
||||
{ provider: "openai", id: "gpt-5.5", name: "gpt-5.5" },
|
||||
{ provider: "openai", id: "gpt-5.5-pro", name: "gpt-5.5-pro" },
|
||||
...expectedAugmentedOpenaiCodexCatalogEntries.slice(0, 4),
|
||||
{ provider: "openai-codex", id: "gpt-5.5", name: "gpt-5.5" },
|
||||
{ provider: "openai-codex", id: "gpt-5.5-pro", name: "gpt-5.5-pro" },
|
||||
...expectedAugmentedOpenaiCodexCatalogEntries.slice(4),
|
||||
];
|
||||
|
||||
export function expectCodexMissingAuthHint(
|
||||
buildProviderMissingAuthMessageWithPlugin: (params: {
|
||||
provider: string;
|
||||
@@ -44,7 +53,7 @@ export function expectCodexMissingAuthHint(
|
||||
listProfileIds: (providerId) => (providerId === "openai-codex" ? ["p1"] : []),
|
||||
},
|
||||
}),
|
||||
).toContain("openai-codex/gpt-5.4");
|
||||
).toContain("openai-codex/gpt-5.5");
|
||||
}
|
||||
|
||||
export function expectCodexBuiltInSuppression(
|
||||
@@ -80,6 +89,7 @@ export async function expectAugmentedCodexCatalog(
|
||||
entries: typeof openaiCodexCatalogEntries;
|
||||
};
|
||||
}) => Promise<unknown>,
|
||||
expectedEntries = expectedAugmentedOpenaiCodexCatalogEntries,
|
||||
) {
|
||||
const result = (await augmentModelCatalogWithProviderPlugins({
|
||||
env: process.env,
|
||||
@@ -88,8 +98,8 @@ export async function expectAugmentedCodexCatalog(
|
||||
entries: openaiCodexCatalogEntries,
|
||||
},
|
||||
})) as Array<Record<string, unknown>>;
|
||||
expect(result).toHaveLength(expectedAugmentedOpenaiCodexCatalogEntries.length);
|
||||
for (const entry of expectedAugmentedOpenaiCodexCatalogEntries) {
|
||||
expect(result).toHaveLength(expectedEntries.length);
|
||||
for (const entry of expectedEntries) {
|
||||
expect(result).toContainEqual(expect.objectContaining(entry));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,7 +943,7 @@ describe("provider-runtime", () => {
|
||||
{
|
||||
...createOpenAiCatalogProviderPlugin({
|
||||
buildMissingAuthMessage: () =>
|
||||
'No API key found for provider "openai". Use openai-codex/gpt-5.4.',
|
||||
'No API key found for provider "openai". Use openai-codex/gpt-5.5.',
|
||||
buildUnknownModelHint,
|
||||
}),
|
||||
} as ProviderPlugin,
|
||||
|
||||
@@ -437,7 +437,7 @@ describe("plugin status reports", () => {
|
||||
enabled: true,
|
||||
subagent: {
|
||||
allowModelOverride: true,
|
||||
allowedModels: ["openai/gpt-5.4"],
|
||||
allowedModels: ["openai/gpt-5.5"],
|
||||
hasAllowedModelsConfig: true,
|
||||
},
|
||||
},
|
||||
@@ -467,7 +467,7 @@ describe("plugin status reports", () => {
|
||||
expectInspectPolicy(inspect!, {
|
||||
allowPromptInjection: undefined,
|
||||
allowModelOverride: true,
|
||||
allowedModels: ["openai/gpt-5.4"],
|
||||
allowedModels: ["openai/gpt-5.5"],
|
||||
hasAllowedModelsConfig: true,
|
||||
});
|
||||
expectPluginLoaderCall({ loadModules: true });
|
||||
@@ -586,7 +586,7 @@ describe("plugin status reports", () => {
|
||||
hooks: { allowPromptInjection: false },
|
||||
subagent: {
|
||||
allowModelOverride: true,
|
||||
allowedModels: ["openai/gpt-5.4"],
|
||||
allowedModels: ["openai/gpt-5.5"],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -624,7 +624,7 @@ describe("plugin status reports", () => {
|
||||
expectInspectPolicy(inspect!, {
|
||||
allowPromptInjection: false,
|
||||
allowModelOverride: true,
|
||||
allowedModels: ["openai/gpt-5.4"],
|
||||
allowedModels: ["openai/gpt-5.5"],
|
||||
hasAllowedModelsConfig: true,
|
||||
});
|
||||
expect(inspect?.diagnostics).toEqual([
|
||||
|
||||
@@ -99,8 +99,8 @@ const modelCatalogMocks = getSharedMocks("openclaw.trigger-handling.model-catalo
|
||||
contextWindow: 200000,
|
||||
},
|
||||
{ provider: "openai", id: "gpt-4.1-mini", name: "GPT-4.1 mini" },
|
||||
{ provider: "openai", id: "gpt-5.4", name: "GPT-5.2" },
|
||||
{ provider: "openai-codex", id: "gpt-5.4", name: "GPT-5.2 (Codex)" },
|
||||
{ provider: "openai", id: "gpt-5.5", name: "GPT-5.5" },
|
||||
{ provider: "openai-codex", id: "gpt-5.5", name: "GPT-5.5 (Codex)" },
|
||||
{ provider: "minimax", id: "MiniMax-M2.7", name: "MiniMax M2.7" },
|
||||
]),
|
||||
resetModelCatalogCacheForTest: vi.fn(),
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import type { PluginRuntime } from "../../../src/plugins/runtime/types.js";
|
||||
|
||||
const DEFAULT_PROVIDER = "openai";
|
||||
const DEFAULT_MODEL = "gpt-5.4";
|
||||
const DEFAULT_MODEL = "gpt-5.5";
|
||||
|
||||
type DeepPartial<T> = {
|
||||
[K in keyof T]?: T[K] extends (...args: never[]) => unknown
|
||||
|
||||
@@ -119,12 +119,12 @@ function buildOpenAICodexOAuthResult(params: {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"openai-codex/gpt-5.4": {},
|
||||
"openai-codex/gpt-5.5": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultModel: "openai-codex/gpt-5.4",
|
||||
defaultModel: "openai-codex/gpt-5.5",
|
||||
notes: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export {
|
||||
expectAugmentedCodexCatalog,
|
||||
expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55,
|
||||
expectCodexBuiltInSuppression,
|
||||
expectCodexMissingAuthHint,
|
||||
} from "../../../src/plugins/provider-runtime.test-support.js";
|
||||
|
||||
@@ -445,6 +445,34 @@ export function describeOpenAIProviderRuntimeContract(load: ProviderRuntimeContr
|
||||
});
|
||||
});
|
||||
|
||||
it("owns openai gpt-5.5 forward-compat resolution", () => {
|
||||
const provider = requireProviderContractProvider("openai");
|
||||
const model = provider.resolveDynamicModel?.({
|
||||
provider: "openai",
|
||||
modelId: "gpt-5.5",
|
||||
modelRegistry: {
|
||||
find: (_provider: string, id: string) =>
|
||||
id === "gpt-5.4"
|
||||
? createModel({
|
||||
id,
|
||||
provider: "openai",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
input: ["text", "image"],
|
||||
})
|
||||
: null,
|
||||
} as never,
|
||||
});
|
||||
|
||||
expect(model).toMatchObject({
|
||||
id: "gpt-5.5",
|
||||
provider: "openai",
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
contextWindow: 1_000_000,
|
||||
maxTokens: 128_000,
|
||||
});
|
||||
});
|
||||
|
||||
it("owns openai gpt-5.4 mini forward-compat resolution", () => {
|
||||
const provider = requireProviderContractProvider("openai");
|
||||
const model = provider.resolveDynamicModel?.({
|
||||
@@ -542,6 +570,34 @@ export function describeOpenAIProviderRuntimeContract(load: ProviderRuntimeContr
|
||||
});
|
||||
});
|
||||
|
||||
it("owns forward-compat codex gpt-5.5 models", () => {
|
||||
const provider = requireProviderContractProvider("openai-codex");
|
||||
const model = provider.resolveDynamicModel?.({
|
||||
provider: "openai-codex",
|
||||
modelId: "gpt-5.5",
|
||||
modelRegistry: {
|
||||
find: (_provider: string, id: string) =>
|
||||
id === "gpt-5.4"
|
||||
? createModel({
|
||||
id,
|
||||
api: "openai-codex-responses",
|
||||
provider: "openai-codex",
|
||||
baseUrl: "https://chatgpt.com/backend-api",
|
||||
})
|
||||
: null,
|
||||
} as never,
|
||||
});
|
||||
|
||||
expect(model).toMatchObject({
|
||||
id: "gpt-5.5",
|
||||
provider: "openai-codex",
|
||||
api: "openai-codex-responses",
|
||||
contextWindow: 1_000_000,
|
||||
contextTokens: 272_000,
|
||||
maxTokens: 128_000,
|
||||
});
|
||||
});
|
||||
|
||||
it("owns forward-compat codex mini models", () => {
|
||||
const provider = requireProviderContractProvider("openai-codex");
|
||||
const model = provider.resolveDynamicModel?.({
|
||||
|
||||
@@ -183,7 +183,7 @@ describe("buildAgentContext", () => {
|
||||
id: "main",
|
||||
workspace: "/tmp/agent-workspace",
|
||||
model: {
|
||||
primary: "openai/gpt-5.4",
|
||||
primary: "openai/gpt-5.5",
|
||||
fallbacks: ["openai-codex/gpt-5.2-codex"],
|
||||
},
|
||||
},
|
||||
@@ -194,7 +194,7 @@ describe("buildAgentContext", () => {
|
||||
);
|
||||
|
||||
expect(context.workspace).toBe("/tmp/agent-workspace");
|
||||
expect(context.model).toBe("openai/gpt-5.4 (+1 fallback)");
|
||||
expect(context.model).toBe("openai/gpt-5.5 (+1 fallback)");
|
||||
expect(context.isDefault).toBe(true);
|
||||
});
|
||||
|
||||
@@ -206,7 +206,7 @@ describe("buildAgentContext", () => {
|
||||
defaults: {
|
||||
workspace: "/tmp/default-workspace",
|
||||
model: {
|
||||
primary: "openai/gpt-5.4",
|
||||
primary: "openai/gpt-5.5",
|
||||
fallbacks: ["openai-codex/gpt-5.2-codex"],
|
||||
},
|
||||
},
|
||||
@@ -219,6 +219,6 @@ describe("buildAgentContext", () => {
|
||||
);
|
||||
|
||||
expect(context.workspace).toBe("/tmp/default-workspace");
|
||||
expect(context.model).toBe("openai/gpt-5.4 (+1 fallback)");
|
||||
expect(context.model).toBe("openai/gpt-5.5 (+1 fallback)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { renderQuickSettings, type QuickSettingsProps } from "./config-quick.ts"
|
||||
|
||||
function createProps(overrides: Partial<QuickSettingsProps> = {}): QuickSettingsProps {
|
||||
return {
|
||||
currentModel: "gpt-5.4",
|
||||
currentModel: "gpt-5.5",
|
||||
thinkingLevel: "off",
|
||||
fastMode: false,
|
||||
onModelChange: vi.fn(),
|
||||
|
||||
Reference in New Issue
Block a user