refactor(models): bump claude-opus-4-6 to claude-opus-4-7 across fallback chains, categories, and hooks

Updates the canonical Anthropic Opus model in every fallback chain
(sisyphus, oracle, prometheus, metis, momus, visual-engineering,
ultrabrain, deep, artistry, unspecified-high), the unspecified-high
category default, the think-mode HIGH_VARIANT_MAP, the Claude Code
alias map, the claude-thinking legacy alias, the context-limit GA
regex, and event.ts fallback strings.

Widens supportsCachedAnthropicLimit to accept both claude-*-4-6 and
claude-*-4-7 so the 1M context cache still applies across the bump.

Regenerates the bundled model-capabilities snapshot from models.dev
and the model-fallback snapshot to match the new source output.
This commit is contained in:
YeonGyu-Kim
2026-04-17 14:51:52 +09:00
parent b1764a880c
commit def44338ff
85 changed files with 39904 additions and 38116 deletions
+64 -64
View File
@@ -12,7 +12,7 @@ describe("resolveModel", () => {
test("returns userModel when all three are set", () => {
// given
const input: ModelResolutionInput = {
userModel: "anthropic/claude-opus-4-6",
userModel: "anthropic/claude-opus-4-7",
inheritedModel: "openai/gpt-5.4",
systemDefault: "google/gemini-3.1-pro",
}
@@ -21,7 +21,7 @@ describe("resolveModel", () => {
const result = resolveModel(input)
// then
expect(result).toBe("anthropic/claude-opus-4-6")
expect(result).toBe("anthropic/claude-opus-4-7")
})
test("returns inheritedModel when userModel is undefined", () => {
@@ -91,7 +91,7 @@ describe("resolveModel", () => {
test("same input returns same output (referential transparency)", () => {
// given
const input: ModelResolutionInput = {
userModel: "anthropic/claude-opus-4-6",
userModel: "anthropic/claude-opus-4-7",
inheritedModel: "openai/gpt-5.4",
systemDefault: "google/gemini-3.1-pro",
}
@@ -122,11 +122,11 @@ describe("resolveModelWithFallback", () => {
// given
const input: ExtendedModelResolutionInput = {
uiSelectedModel: "opencode/big-pickle",
userModel: "anthropic/claude-opus-4-6",
userModel: "anthropic/claude-opus-4-7",
fallbackChain: [
{ providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6" },
{ providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7" },
],
availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]),
availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -143,8 +143,8 @@ describe("resolveModelWithFallback", () => {
// given
const input: ExtendedModelResolutionInput = {
uiSelectedModel: "opencode/big-pickle",
userModel: "anthropic/claude-opus-4-6",
availableModels: new Set(["anthropic/claude-opus-4-6"]),
userModel: "anthropic/claude-opus-4-7",
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -160,8 +160,8 @@ describe("resolveModelWithFallback", () => {
// given
const input: ExtendedModelResolutionInput = {
uiSelectedModel: " ",
userModel: "anthropic/claude-opus-4-6",
availableModels: new Set(["anthropic/claude-opus-4-6"]),
userModel: "anthropic/claude-opus-4-7",
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -169,16 +169,16 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-6" })
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-7" })
})
test("empty string uiSelectedModel falls through to config override", () => {
// given
const input: ExtendedModelResolutionInput = {
uiSelectedModel: "",
userModel: "anthropic/claude-opus-4-6",
availableModels: new Set(["anthropic/claude-opus-4-6"]),
userModel: "anthropic/claude-opus-4-7",
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -186,7 +186,7 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
})
})
@@ -194,11 +194,11 @@ describe("resolveModelWithFallback", () => {
test("returns userModel with override source when userModel is provided", () => {
// given
const input: ExtendedModelResolutionInput = {
userModel: "anthropic/claude-opus-4-6",
userModel: "anthropic/claude-opus-4-7",
fallbackChain: [
{ providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6" },
{ providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7" },
],
availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]),
availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -206,9 +206,9 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("override")
expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-6" })
expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-7" })
})
test("override takes priority even if model not in availableModels", () => {
@@ -216,9 +216,9 @@ describe("resolveModelWithFallback", () => {
const input: ExtendedModelResolutionInput = {
userModel: "custom/my-model",
fallbackChain: [
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -235,9 +235,9 @@ describe("resolveModelWithFallback", () => {
const input: ExtendedModelResolutionInput = {
userModel: " ",
fallbackChain: [
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -253,9 +253,9 @@ describe("resolveModelWithFallback", () => {
const input: ExtendedModelResolutionInput = {
userModel: "",
fallbackChain: [
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -272,9 +272,9 @@ describe("resolveModelWithFallback", () => {
// given
const input: ExtendedModelResolutionInput = {
fallbackChain: [
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6" },
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-7" },
],
availableModels: new Set(["github-copilot/claude-opus-4-6-preview", "opencode/claude-opus-4-7"]),
availableModels: new Set(["github-copilot/claude-opus-4-7-preview", "opencode/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -282,12 +282,12 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then
expect(result!.model).toBe("github-copilot/claude-opus-4-6-preview")
expect(result!.model).toBe("github-copilot/claude-opus-4-7-preview")
expect(result!.source).toBe("provider-fallback")
expect(logSpy).toHaveBeenCalledWith("Model resolved via fallback chain (availability confirmed)", {
provider: "github-copilot",
model: "claude-opus-4-6",
match: "github-copilot/claude-opus-4-6-preview",
model: "claude-opus-4-7",
match: "github-copilot/claude-opus-4-7-preview",
variant: undefined,
})
})
@@ -298,7 +298,7 @@ describe("resolveModelWithFallback", () => {
fallbackChain: [
{ providers: ["openai", "anthropic", "google"], model: "gpt-5.4" },
],
availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6", "google/gemini-3.1-pro"]),
availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7", "google/gemini-3.1-pro"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -334,7 +334,7 @@ describe("resolveModelWithFallback", () => {
fallbackChain: [
{ providers: ["anthropic", "github-copilot"], model: "claude-opus" },
],
availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]),
availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -342,14 +342,14 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("provider-fallback")
})
test("skips fallback chain when not provided", () => {
// given
const input: ExtendedModelResolutionInput = {
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -364,7 +364,7 @@ describe("resolveModelWithFallback", () => {
// given
const input: ExtendedModelResolutionInput = {
fallbackChain: [],
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -381,7 +381,7 @@ describe("resolveModelWithFallback", () => {
fallbackChain: [
{ providers: ["anthropic"], model: "CLAUDE-OPUS" },
],
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -389,7 +389,7 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("provider-fallback")
})
@@ -480,7 +480,7 @@ describe("resolveModelWithFallback", () => {
fallbackChain: [
{ providers: ["anthropic"], model: "nonexistent-model" },
],
availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6"]),
availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7"]),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -498,7 +498,7 @@ describe("resolveModelWithFallback", () => {
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
const input: ExtendedModelResolutionInput = {
fallbackChain: [
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels: new Set(),
systemDefaultModel: undefined, // no system default configured
@@ -517,7 +517,7 @@ describe("resolveModelWithFallback", () => {
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai", "google"])
const input: ExtendedModelResolutionInput = {
fallbackChain: [
{ providers: ["anthropic", "openai"], model: "claude-opus-4-6" },
{ providers: ["anthropic", "openai"], model: "claude-opus-4-7" },
],
availableModels: new Set(),
systemDefaultModel: "google/gemini-3.1-pro",
@@ -527,7 +527,7 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then - should use connected provider (openai) from fallback chain
expect(result!.model).toBe("openai/claude-opus-4-6")
expect(result!.model).toBe("openai/claude-opus-4-7")
expect(result!.source).toBe("provider-fallback")
cacheSpy.mockRestore()
})
@@ -561,14 +561,14 @@ describe("resolveModelWithFallback", () => {
{ providers: ["openai", "opencode"], model: "claude-haiku-4-5" },
],
availableModels: new Set(),
systemDefaultModel: "anthropic/claude-opus-4-6-20251101",
systemDefaultModel: "anthropic/claude-opus-4-7-20251101",
}
// when
const result = resolveModelWithFallback(input)
// then - no provider in fallback is connected, fall through to system default
expect(result!.model).toBe("anthropic/claude-opus-4-6-20251101")
expect(result!.model).toBe("anthropic/claude-opus-4-7-20251101")
expect(result!.source).toBe("system-default")
cacheSpy.mockRestore()
})
@@ -578,7 +578,7 @@ describe("resolveModelWithFallback", () => {
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
const input: ExtendedModelResolutionInput = {
fallbackChain: [
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels: new Set(),
systemDefaultModel: "google/gemini-3.1-pro",
@@ -612,20 +612,20 @@ describe("resolveModelWithFallback", () => {
describe("Multi-entry fallbackChain", () => {
test("resolves to claude-opus when OpenAI unavailable but Anthropic available (oracle scenario)", () => {
// given
const availableModels = new Set(["anthropic/claude-opus-4-6"])
const availableModels = new Set(["anthropic/claude-opus-4-7"])
// when
const result = resolveModelWithFallback({
fallbackChain: [
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "high" },
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-7", variant: "max" },
],
availableModels,
systemDefaultModel: "system/default",
})
// then
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("provider-fallback")
})
@@ -652,14 +652,14 @@ describe("resolveModelWithFallback", () => {
// given
const availableModels = new Set([
"openai/gpt-5.4",
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-7",
])
// when
const result = resolveModelWithFallback({
fallbackChain: [
{ providers: ["openai"], model: "gpt-5.4" },
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels,
systemDefaultModel: "system/default",
@@ -678,7 +678,7 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback({
fallbackChain: [
{ providers: ["openai"], model: "gpt-5.4" },
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
{ providers: ["google"], model: "gemini-3.1-pro" },
],
availableModels,
@@ -695,7 +695,7 @@ describe("resolveModelWithFallback", () => {
test("result has correct ModelResolutionResult shape", () => {
// given
const input: ExtendedModelResolutionInput = {
userModel: "anthropic/claude-opus-4-6",
userModel: "anthropic/claude-opus-4-7",
availableModels: new Set(),
systemDefaultModel: "google/gemini-3.1-pro",
}
@@ -718,7 +718,7 @@ describe("resolveModelWithFallback", () => {
fallbackChain: [
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro" },
],
availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-6"]),
availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-7"]),
systemDefaultModel: "anthropic/claude-sonnet-4-6",
}
@@ -754,9 +754,9 @@ describe("resolveModelWithFallback", () => {
const input: ExtendedModelResolutionInput = {
categoryDefaultModel: "google/gemini-3.1-pro",
fallbackChain: [
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "system/default",
}
@@ -764,19 +764,19 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then - should fall through to fallbackChain
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("provider-fallback")
})
test("userModel takes priority over categoryDefaultModel", () => {
// given - both userModel and categoryDefaultModel provided
const input: ExtendedModelResolutionInput = {
userModel: "anthropic/claude-opus-4-6",
userModel: "anthropic/claude-opus-4-7",
categoryDefaultModel: "google/gemini-3.1-pro",
fallbackChain: [
{ providers: ["google"], model: "gemini-3.1-pro" },
],
availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-6"]),
availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-7"]),
systemDefaultModel: "system/default",
}
@@ -784,7 +784,7 @@ describe("resolveModelWithFallback", () => {
const result = resolveModelWithFallback(input)
// then - userModel wins
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("override")
})
@@ -916,7 +916,7 @@ describe("resolveModelWithFallback", () => {
test("still returns override when userModel provided even if systemDefaultModel undefined", () => {
// given
const input: ExtendedModelResolutionInput = {
userModel: "anthropic/claude-opus-4-6",
userModel: "anthropic/claude-opus-4-7",
availableModels: new Set(),
systemDefaultModel: undefined,
}
@@ -926,7 +926,7 @@ describe("resolveModelWithFallback", () => {
// then
expect(result).toBeDefined()
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("override")
})
@@ -934,9 +934,9 @@ describe("resolveModelWithFallback", () => {
// given
const input: ExtendedModelResolutionInput = {
fallbackChain: [
{ providers: ["anthropic"], model: "claude-opus-4-6" },
{ providers: ["anthropic"], model: "claude-opus-4-7" },
],
availableModels: new Set(["anthropic/claude-opus-4-6"]),
availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: undefined,
}
@@ -945,7 +945,7 @@ describe("resolveModelWithFallback", () => {
// then
expect(result).toBeDefined()
expect(result!.model).toBe("anthropic/claude-opus-4-6")
expect(result!.model).toBe("anthropic/claude-opus-4-7")
expect(result!.source).toBe("provider-fallback")
})
})