fix(claude): show a single 1M-context Opus 5 model (#2497)

This commit is contained in:
Mohamed Boudra
2026-07-28 18:18:21 +08:00
committed by GitHub
parent cbbf6c1684
commit f91a984348
4 changed files with 33 additions and 34 deletions
-10
View File
@@ -108,16 +108,6 @@ const EXPECTED_CLAUDE_MODELS = [
] as const; ] as const;
const EXPECTED_CLAUDE_CONTEXT_MODELS = [ const EXPECTED_CLAUDE_CONTEXT_MODELS = [
{
id: "claude-opus-5[1m]",
model: "Opus 5 1M",
descriptionFragment: "1M context window",
},
{
id: "claude-opus-5",
model: "Opus 5",
descriptionFragment: "200K context window",
},
{ {
id: "claude-fable-5[1m]", id: "claude-fable-5[1m]",
model: "Fable 5 1M", model: "Fable 5 1M",
@@ -416,7 +416,6 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
}); });
expect(models.map((m) => m.id)).toEqual([ expect(models.map((m) => m.id)).toEqual([
"claude-opus-5[1m]",
"claude-opus-5", "claude-opus-5",
"claude-fable-5[1m]", "claude-fable-5[1m]",
"claude-fable-5", "claude-fable-5",
@@ -439,7 +438,7 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
} }
const defaultModel = models.find((m) => m.isDefault); const defaultModel = models.find((m) => m.isDefault);
expect(defaultModel?.id).toBe("claude-opus-5[1m]"); expect(defaultModel?.id).toBe("claude-opus-5");
} finally { } finally {
await fs.rm(emptyConfigDir, { recursive: true, force: true }); await fs.rm(emptyConfigDir, { recursive: true, force: true });
} }
@@ -461,7 +460,7 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
force: false, force: false,
}); });
expect(models.find((model) => model.isDefault)?.id).toBe("claude-opus-5[1m]"); expect(models.find((model) => model.isDefault)?.id).toBe("claude-opus-5");
expect(models.map((model) => model.id)).toContain("claude-fable-5[1m]"); expect(models.map((model) => model.id)).toContain("claude-fable-5[1m]");
} finally { } finally {
await fs.rm(emptyConfigDir, { recursive: true, force: true }); await fs.rm(emptyConfigDir, { recursive: true, force: true });
@@ -32,24 +32,15 @@ export const CLAUDE_ULTRACODE_THINKING_OPTION_ID = "ultracode";
export const CLAUDE_MODEL_MANIFEST = [ export const CLAUDE_MODEL_MANIFEST = [
{ {
id: "claude-opus-5[1m]", id: "claude-opus-5",
label: "Opus 5 1M", label: "Opus 5",
description: "Opus 5 with 1M context window", description: "Opus 5 · Latest release",
defaultPriority: 2, defaultPriority: 2,
minimumClaudeCodeVersion: "2.1.219", minimumClaudeCodeVersion: "2.1.219",
contextWindowMaxTokens: 1_000_000, contextWindowMaxTokens: 1_000_000,
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh, effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
supportsThinkingDisabled: true, supportsThinkingDisabled: true,
}, },
{
id: "claude-opus-5",
label: "Opus 5",
description: "Opus 5 · 200K context window",
minimumClaudeCodeVersion: "2.1.219",
contextWindowMaxTokens: 200_000,
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
supportsThinkingDisabled: true,
},
{ {
id: "claude-fable-5[1m]", id: "claude-fable-5[1m]",
label: "Fable 5 1M", label: "Fable 5 1M",
@@ -50,7 +50,6 @@ describe("getClaudeModels", () => {
it("returns all claude models", () => { it("returns all claude models", () => {
const models = getClaudeModels(); const models = getClaudeModels();
expect(models.map((m) => m.id)).toEqual([ expect(models.map((m) => m.id)).toEqual([
"claude-opus-5[1m]",
"claude-opus-5", "claude-opus-5",
"claude-fable-5[1m]", "claude-fable-5[1m]",
"claude-fable-5", "claude-fable-5",
@@ -72,7 +71,7 @@ describe("getClaudeModels", () => {
const models = getClaudeModels(); const models = getClaudeModels();
const defaults = models.filter((m) => m.isDefault); const defaults = models.filter((m) => m.isDefault);
expect(defaults).toHaveLength(1); expect(defaults).toHaveLength(1);
expect(defaults[0].id).toBe("claude-opus-5[1m]"); expect(defaults[0].id).toBe("claude-opus-5");
}); });
it("defines context window sizes in the catalog", () => { it("defines context window sizes in the catalog", () => {
@@ -82,8 +81,7 @@ describe("getClaudeModels", () => {
expect(contextWindows).toEqual( expect(contextWindows).toEqual(
new Map([ new Map([
["claude-opus-5[1m]", 1_000_000], ["claude-opus-5", 1_000_000],
["claude-opus-5", 200_000],
["claude-fable-5[1m]", 1_000_000], ["claude-fable-5[1m]", 1_000_000],
["claude-fable-5", 200_000], ["claude-fable-5", 200_000],
["claude-opus-4-8[1m]", 1_000_000], ["claude-opus-4-8[1m]", 1_000_000],
@@ -103,10 +101,8 @@ describe("getClaudeModels", () => {
it("filters models by their minimum Claude Code version", () => { it("filters models by their minimum Claude Code version", () => {
const oldVersionModels = getClaudeModels("2.1.218"); const oldVersionModels = getClaudeModels("2.1.218");
expect(oldVersionModels.map((model) => model.id)).not.toContain("claude-opus-5[1m]");
expect(oldVersionModels.map((model) => model.id)).not.toContain("claude-opus-5"); expect(oldVersionModels.map((model) => model.id)).not.toContain("claude-opus-5");
expect(oldVersionModels.find((model) => model.isDefault)?.id).toBe("claude-opus-4-8"); expect(oldVersionModels.find((model) => model.isDefault)?.id).toBe("claude-opus-4-8");
expect(getClaudeModels("2.1.219").map((model) => model.id)).toContain("claude-opus-5[1m]");
expect(getClaudeModels("2.1.219").map((model) => model.id)).toContain("claude-opus-5"); expect(getClaudeModels("2.1.219").map((model) => model.id)).toContain("claude-opus-5");
expect(getClaudeModels("2.1.168").map((model) => model.id)).not.toContain("claude-fable-5[1m]"); expect(getClaudeModels("2.1.168").map((model) => model.id)).not.toContain("claude-fable-5[1m]");
@@ -347,7 +343,6 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
describe("normalizeClaudeRuntimeModelId", () => { describe("normalizeClaudeRuntimeModelId", () => {
it("returns exact match for known model IDs", () => { it("returns exact match for known model IDs", () => {
expect(normalizeClaudeRuntimeModelId("claude-opus-5[1m]")).toBe("claude-opus-5[1m]");
expect(normalizeClaudeRuntimeModelId("claude-opus-5")).toBe("claude-opus-5"); expect(normalizeClaudeRuntimeModelId("claude-opus-5")).toBe("claude-opus-5");
expect(normalizeClaudeRuntimeModelId("claude-fable-5")).toBe("claude-fable-5"); expect(normalizeClaudeRuntimeModelId("claude-fable-5")).toBe("claude-fable-5");
expect(normalizeClaudeRuntimeModelId("claude-fable-5[1m]")).toBe("claude-fable-5[1m]"); expect(normalizeClaudeRuntimeModelId("claude-fable-5[1m]")).toBe("claude-fable-5[1m]");
@@ -366,7 +361,6 @@ describe("normalizeClaudeRuntimeModelId", () => {
expect(normalizeClaudeRuntimeModelId("claude-opus-4-6-20260101")).toBe("claude-opus-4-6"); expect(normalizeClaudeRuntimeModelId("claude-opus-4-6-20260101")).toBe("claude-opus-4-6");
expect(normalizeClaudeRuntimeModelId("claude-sonnet-4-6-20260101")).toBe("claude-sonnet-4-6"); expect(normalizeClaudeRuntimeModelId("claude-sonnet-4-6-20260101")).toBe("claude-sonnet-4-6");
expect(normalizeClaudeRuntimeModelId("claude-haiku-4-5-20251001")).toBe("claude-haiku-4-5"); expect(normalizeClaudeRuntimeModelId("claude-haiku-4-5-20251001")).toBe("claude-haiku-4-5");
expect(normalizeClaudeRuntimeModelId("claude-opus-5-20260724[1m]")).toBe("claude-opus-5[1m]");
expect(normalizeClaudeRuntimeModelId("claude-fable-5-20260301[1m]")).toBe("claude-fable-5[1m]"); expect(normalizeClaudeRuntimeModelId("claude-fable-5-20260301[1m]")).toBe("claude-fable-5[1m]");
expect(normalizeClaudeRuntimeModelId("claude-sonnet-5-20260101[1m]")).toBe( expect(normalizeClaudeRuntimeModelId("claude-sonnet-5-20260101[1m]")).toBe(
"claude-sonnet-5[1m]", "claude-sonnet-5[1m]",
@@ -374,7 +368,6 @@ describe("normalizeClaudeRuntimeModelId", () => {
}); });
it("preserves [1m] suffix from runtime model strings", () => { it("preserves [1m] suffix from runtime model strings", () => {
expect(normalizeClaudeRuntimeModelId("claude-opus-5[1m]")).toBe("claude-opus-5[1m]");
expect(normalizeClaudeRuntimeModelId("claude-fable-5[1m]")).toBe("claude-fable-5[1m]"); expect(normalizeClaudeRuntimeModelId("claude-fable-5[1m]")).toBe("claude-fable-5[1m]");
expect(normalizeClaudeRuntimeModelId("claude-sonnet-5[1m]")).toBe("claude-sonnet-5[1m]"); expect(normalizeClaudeRuntimeModelId("claude-sonnet-5[1m]")).toBe("claude-sonnet-5[1m]");
expect(normalizeClaudeRuntimeModelId("claude-opus-4-6[1m]")).toBe("claude-opus-4-6[1m]"); expect(normalizeClaudeRuntimeModelId("claude-opus-4-6[1m]")).toBe("claude-opus-4-6[1m]");
@@ -421,6 +414,32 @@ describe("findClaudeModel", () => {
}); });
}); });
describe("Claude Opus 5 catalog", () => {
it("offers a single Opus 5 entry with a 1M context window", () => {
const opus5Models = getClaudeModels()
.filter((model) => model.id.startsWith("claude-opus-5"))
.map(({ id, label, contextWindowMaxTokens }) => ({ id, label, contextWindowMaxTokens }));
expect(opus5Models).toEqual([
{ id: "claude-opus-5", label: "Opus 5", contextWindowMaxTokens: 1_000_000 },
]);
});
it("resolves retired and dated Opus 5 IDs to the single catalog entry", () => {
expect(findClaudeModel("claude-opus-5[1m]")?.id).toBe("claude-opus-5");
expect(findClaudeModel("claude-opus-5-20260724")?.id).toBe("claude-opus-5");
expect(findClaudeModel("claude-opus-5-20260724[1m]")?.id).toBe("claude-opus-5");
expect(findClaudeModel("claude-opus-5[1m]")?.contextWindowMaxTokens).toBe(1_000_000);
});
it("keeps disabled thinking available for agents persisted on the retired 1M ID", () => {
expect(resolveClaudeDisabledThinkingForModel("claude-opus-5[1m]")).toEqual({
supported: true,
fallbackThinkingOptionId: "low",
});
});
});
describe("claudeManifestModelSupportsFastMode", () => { describe("claudeManifestModelSupportsFastMode", () => {
it("keeps fast mode strict to first-party manifest model IDs", () => { it("keeps fast mode strict to first-party manifest model IDs", () => {
expect(normalizeClaudeManifestModelId("openrouter/anthropic/claude-opus-4-8")).toBeNull(); expect(normalizeClaudeManifestModelId("openrouter/anthropic/claude-opus-4-8")).toBeNull();