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:
@@ -28,7 +28,7 @@ const SYSTEM_DEFAULT_MODEL = "anthropic/claude-sonnet-4-6"
|
||||
|
||||
const TEST_CONNECTED_PROVIDERS = ["anthropic", "google", "openai"]
|
||||
const TEST_AVAILABLE_MODELS = new Set([
|
||||
"anthropic/claude-opus-4-6",
|
||||
"anthropic/claude-opus-4-7",
|
||||
"anthropic/claude-sonnet-4-6",
|
||||
"anthropic/claude-haiku-4-5",
|
||||
"google/gemini-3.1-pro",
|
||||
@@ -66,7 +66,7 @@ describe("sisyphus-task", () => {
|
||||
cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic", "google", "openai"])
|
||||
providerModelsSpy = spyOn(connectedProvidersCache, "readProviderModelsCache").mockReturnValue({
|
||||
models: {
|
||||
anthropic: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"],
|
||||
anthropic: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"],
|
||||
google: ["gemini-3.1-pro", "gemini-3-flash"],
|
||||
openai: ["gpt-5.4", "gpt-5.3-codex"],
|
||||
},
|
||||
@@ -112,13 +112,13 @@ describe("sisyphus-task", () => {
|
||||
expect(category.variant).toBe("medium")
|
||||
})
|
||||
|
||||
test("unspecified-high category uses claude-opus-4-6 max as primary", () => {
|
||||
test("unspecified-high category uses claude-opus-4-7 max as primary", () => {
|
||||
// given
|
||||
const category = DEFAULT_CATEGORIES["unspecified-high"]
|
||||
|
||||
// when / #then
|
||||
expect(category).toBeDefined()
|
||||
expect(category.model).toBe("anthropic/claude-opus-4-6")
|
||||
expect(category.model).toBe("anthropic/claude-opus-4-7")
|
||||
expect(category.variant).toBe("max")
|
||||
})
|
||||
})
|
||||
@@ -757,7 +757,7 @@ describe("sisyphus-task", () => {
|
||||
test("blocks requiresModel when availability is known and missing the required model", () => {
|
||||
// given - artistry has requiresModel: gemini-3.1-pro
|
||||
const categoryName = "artistry"
|
||||
const availableModels = new Set<string>(["anthropic/claude-opus-4-6"])
|
||||
const availableModels = new Set<string>(["anthropic/claude-opus-4-7"])
|
||||
|
||||
// when
|
||||
const result = resolveCategoryConfig(categoryName, {
|
||||
@@ -787,9 +787,9 @@ describe("sisyphus-task", () => {
|
||||
test("bypasses requiresModel when explicit user config provided", () => {
|
||||
// #given
|
||||
const categoryName = "deep"
|
||||
const availableModels = new Set<string>(["anthropic/claude-opus-4-6"])
|
||||
const availableModels = new Set<string>(["anthropic/claude-opus-4-7"])
|
||||
const userCategories = {
|
||||
deep: { model: "anthropic/claude-opus-4-6" },
|
||||
deep: { model: "anthropic/claude-opus-4-7" },
|
||||
}
|
||||
|
||||
// #when
|
||||
@@ -801,7 +801,7 @@ describe("sisyphus-task", () => {
|
||||
|
||||
// #then
|
||||
expect(result).not.toBeNull()
|
||||
expect(result!.config.model).toBe("anthropic/claude-opus-4-6")
|
||||
expect(result!.config.model).toBe("anthropic/claude-opus-4-7")
|
||||
})
|
||||
|
||||
test("bypasses requiresModel when explicit user config provided even with empty availability", () => {
|
||||
@@ -809,7 +809,7 @@ describe("sisyphus-task", () => {
|
||||
const categoryName = "deep"
|
||||
const availableModels = new Set<string>()
|
||||
const userCategories = {
|
||||
deep: { model: "anthropic/claude-opus-4-6" },
|
||||
deep: { model: "anthropic/claude-opus-4-7" },
|
||||
}
|
||||
|
||||
// #when
|
||||
@@ -821,7 +821,7 @@ describe("sisyphus-task", () => {
|
||||
|
||||
// #then
|
||||
expect(result).not.toBeNull()
|
||||
expect(result!.config.model).toBe("anthropic/claude-opus-4-6")
|
||||
expect(result!.config.model).toBe("anthropic/claude-opus-4-7")
|
||||
})
|
||||
|
||||
test("returns default model from DEFAULT_CATEGORIES for builtin category", () => {
|
||||
@@ -841,7 +841,7 @@ describe("sisyphus-task", () => {
|
||||
// given
|
||||
const categoryName = "visual-engineering"
|
||||
const userCategories = {
|
||||
"visual-engineering": { model: "anthropic/claude-opus-4-6" },
|
||||
"visual-engineering": { model: "anthropic/claude-opus-4-7" },
|
||||
}
|
||||
|
||||
// when
|
||||
@@ -849,7 +849,7 @@ describe("sisyphus-task", () => {
|
||||
|
||||
// then
|
||||
expect(result).not.toBeNull()
|
||||
expect(result!.config.model).toBe("anthropic/claude-opus-4-6")
|
||||
expect(result!.config.model).toBe("anthropic/claude-opus-4-7")
|
||||
})
|
||||
|
||||
test("user prompt_append is appended to default", () => {
|
||||
@@ -913,7 +913,7 @@ describe("sisyphus-task", () => {
|
||||
test("category built-in model takes precedence over inheritedModel", () => {
|
||||
// given - builtin category with its own model, parent model also provided
|
||||
const categoryName = "visual-engineering"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-6"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-7"
|
||||
|
||||
// when
|
||||
const result = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -927,7 +927,7 @@ describe("sisyphus-task", () => {
|
||||
// given - custom category with no model defined
|
||||
const categoryName = "my-custom-no-model"
|
||||
const userCategories = { "my-custom-no-model": { temperature: 0.5 } } as unknown as Record<string, CategoryConfig>
|
||||
const inheritedModel = "cliproxy/claude-opus-4-6"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-7"
|
||||
|
||||
// when
|
||||
const result = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -943,7 +943,7 @@ describe("sisyphus-task", () => {
|
||||
const userCategories = {
|
||||
"visual-engineering": { model: "my-provider/my-model" },
|
||||
}
|
||||
const inheritedModel = "cliproxy/claude-opus-4-6"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-7"
|
||||
|
||||
// when
|
||||
const result = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -1054,7 +1054,7 @@ describe("sisyphus-task", () => {
|
||||
const mockClient = {
|
||||
app: { agents: async () => ({ data: [] }) },
|
||||
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
|
||||
model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-6" }] },
|
||||
model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-7" }] },
|
||||
session: {
|
||||
create: async () => ({ data: { id: "test-session" } }),
|
||||
prompt: async () => ({ data: {} }),
|
||||
@@ -1078,7 +1078,7 @@ describe("sisyphus-task", () => {
|
||||
abort: new AbortController().signal,
|
||||
}
|
||||
|
||||
// when - unspecified-high uses claude-opus-4-6 max in DEFAULT_CATEGORIES
|
||||
// when - unspecified-high uses claude-opus-4-7 max in DEFAULT_CATEGORIES
|
||||
await tool.execute(
|
||||
{
|
||||
description: "Test unspecified-high default variant",
|
||||
@@ -1090,10 +1090,10 @@ describe("sisyphus-task", () => {
|
||||
toolContext
|
||||
)
|
||||
|
||||
// then - claude-opus-4-6 should be passed with max variant
|
||||
// then - claude-opus-4-7 should be passed with max variant
|
||||
expect(launchInput.model).toEqual({
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-opus-4-6",
|
||||
modelID: "claude-opus-4-7",
|
||||
variant: "max",
|
||||
})
|
||||
}, { timeout: 20000 })
|
||||
@@ -1113,7 +1113,7 @@ describe("sisyphus-task", () => {
|
||||
const mockClient = {
|
||||
app: { agents: async () => ({ data: [] }) },
|
||||
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
|
||||
model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-6" }] },
|
||||
model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-7" }] },
|
||||
session: {
|
||||
get: async () => ({ data: { directory: "/project" } }),
|
||||
create: async () => ({ data: { id: "ses_sync_default_variant" } }),
|
||||
@@ -1139,7 +1139,7 @@ describe("sisyphus-task", () => {
|
||||
abort: new AbortController().signal,
|
||||
}
|
||||
|
||||
// when - unspecified-high uses claude-opus-4-6 max in DEFAULT_CATEGORIES
|
||||
// when - unspecified-high uses claude-opus-4-7 max in DEFAULT_CATEGORIES
|
||||
await tool.execute(
|
||||
{
|
||||
description: "Test unspecified-high sync variant",
|
||||
@@ -1151,10 +1151,10 @@ describe("sisyphus-task", () => {
|
||||
toolContext
|
||||
)
|
||||
|
||||
// then - claude-opus-4-6 should be passed with max variant
|
||||
// then - claude-opus-4-7 should be passed with max variant
|
||||
expect(promptBody.model).toEqual({
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-opus-4-6",
|
||||
modelID: "claude-opus-4-7",
|
||||
})
|
||||
expect(promptBody.variant).toBe("max")
|
||||
}, { timeout: 20000 })
|
||||
@@ -1550,7 +1550,7 @@ describe("sisyphus-task", () => {
|
||||
let promptCalled = false
|
||||
const mockManager = { launch: async () => ({}) }
|
||||
const mockClient = {
|
||||
app: { agents: async () => ({ data: [{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-6" } }] }) },
|
||||
app: { agents: async () => ({ data: [{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-7" } }] }) },
|
||||
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
|
||||
session: {
|
||||
get: async () => ({ data: { directory: "/project" } }),
|
||||
@@ -1835,7 +1835,7 @@ describe("sisyphus-task", () => {
|
||||
id: "msg_001",
|
||||
role: "user",
|
||||
agent: "sisyphus-junior",
|
||||
model: { providerID: "anthropic", modelID: "claude-opus-4-6" },
|
||||
model: { providerID: "anthropic", modelID: "claude-opus-4-7" },
|
||||
variant: "max",
|
||||
time: { created: baseTime },
|
||||
},
|
||||
@@ -1917,7 +1917,7 @@ describe("sisyphus-task", () => {
|
||||
const callArgs = promptMock.mock.calls[0][0]
|
||||
expect(callArgs.body.variant).toBe("max")
|
||||
expect(callArgs.body.agent).toBe("sisyphus-junior")
|
||||
expect(callArgs.body.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" })
|
||||
expect(callArgs.body.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" })
|
||||
}, { timeout: 10000 })
|
||||
|
||||
test("task_id with background=true should return immediately without waiting", async () => {
|
||||
@@ -2551,7 +2551,7 @@ describe("sisyphus-task", () => {
|
||||
// Override provider cache to include kimi-for-coding provider
|
||||
providerModelsSpy.mockReturnValue({
|
||||
models: {
|
||||
anthropic: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"],
|
||||
anthropic: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"],
|
||||
google: ["gemini-3.1-pro", "gemini-3-flash"],
|
||||
openai: ["gpt-5.4", "gpt-5.3-codex"],
|
||||
"kimi-for-coding": ["k2p5"],
|
||||
@@ -2798,7 +2798,7 @@ describe("sisyphus-task", () => {
|
||||
manager: mockManager,
|
||||
client: mockClient,
|
||||
userCategories: {
|
||||
"fallback-test": { model: "anthropic/claude-opus-4-6" },
|
||||
"fallback-test": { model: "anthropic/claude-opus-4-7" },
|
||||
},
|
||||
connectedProvidersOverride: TEST_CONNECTED_PROVIDERS,
|
||||
availableModelsOverride: createTestAvailableModels(),
|
||||
@@ -3465,7 +3465,7 @@ describe("sisyphus-task", () => {
|
||||
test("category built-in model takes precedence over inheritedModel for builtin category", () => {
|
||||
// given - builtin ultrabrain category with its own model, inherited model also provided
|
||||
const categoryName = "ultrabrain"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-6"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-7"
|
||||
|
||||
// when
|
||||
const resolved = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -3480,7 +3480,7 @@ describe("sisyphus-task", () => {
|
||||
// given
|
||||
const categoryName = "ultrabrain"
|
||||
const userCategories = { "ultrabrain": { model: "my-provider/custom-model" } }
|
||||
const inheritedModel = "cliproxy/claude-opus-4-6"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-7"
|
||||
|
||||
// when
|
||||
const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -3497,7 +3497,7 @@ describe("sisyphus-task", () => {
|
||||
// given - This test verifies the fix for PR #770 bug
|
||||
// The bug was: checking `if (inheritedModel)` instead of `if (actualModel === inheritedModel)`
|
||||
const categoryName = "ultrabrain"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-6"
|
||||
const inheritedModel = "cliproxy/claude-opus-4-7"
|
||||
const userCategories = { "ultrabrain": { model: "user/model" } }
|
||||
|
||||
// when - user model wins
|
||||
@@ -3525,7 +3525,7 @@ describe("sisyphus-task", () => {
|
||||
// given a builtin category with its own model, and an inherited model from parent
|
||||
// The CORRECT chain: userConfig?.model ?? categoryBuiltIn ?? systemDefaultModel
|
||||
const categoryName = "ultrabrain"
|
||||
const inheritedModel = "anthropic/claude-opus-4-6"
|
||||
const inheritedModel = "anthropic/claude-opus-4-7"
|
||||
|
||||
// when category has a built-in model (gpt-5.4 for ultrabrain)
|
||||
const resolved = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -3556,7 +3556,7 @@ describe("sisyphus-task", () => {
|
||||
// given userConfig.model is explicitly set
|
||||
const categoryName = "ultrabrain"
|
||||
const userCategories = { "ultrabrain": { model: "custom/user-model" } }
|
||||
const inheritedModel = "anthropic/claude-opus-4-6"
|
||||
const inheritedModel = "anthropic/claude-opus-4-7"
|
||||
const systemDefaultModel = "anthropic/claude-sonnet-4-6"
|
||||
|
||||
// when resolveCategoryConfig is called with all sources
|
||||
@@ -3575,7 +3575,7 @@ describe("sisyphus-task", () => {
|
||||
// given userConfig.model is empty string "" for a custom category (no built-in model)
|
||||
const categoryName = "custom-empty-model"
|
||||
const userCategories = { "custom-empty-model": { model: "", temperature: 0.3 } }
|
||||
const inheritedModel = "anthropic/claude-opus-4-6"
|
||||
const inheritedModel = "anthropic/claude-opus-4-7"
|
||||
|
||||
// when resolveCategoryConfig is called
|
||||
const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -3590,7 +3590,7 @@ describe("sisyphus-task", () => {
|
||||
const categoryName = "visual-engineering"
|
||||
// Using type assertion since we're testing fallback behavior for categories without model
|
||||
const userCategories = { "visual-engineering": { temperature: 0.2 } } as unknown as Record<string, CategoryConfig>
|
||||
const inheritedModel = "anthropic/claude-opus-4-6"
|
||||
const inheritedModel = "anthropic/claude-opus-4-7"
|
||||
|
||||
// when resolveCategoryConfig is called
|
||||
const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL })
|
||||
@@ -3810,7 +3810,7 @@ describe("sisyphus-task", () => {
|
||||
app: {
|
||||
agents: async () => ({
|
||||
data: [
|
||||
{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-6" } },
|
||||
{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-7" } },
|
||||
],
|
||||
}),
|
||||
},
|
||||
@@ -3854,7 +3854,7 @@ describe("sisyphus-task", () => {
|
||||
// then - matched agent's model should be passed to session.prompt
|
||||
expect(promptBody.model).toEqual({
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-opus-4-6",
|
||||
modelID: "claude-opus-4-7",
|
||||
})
|
||||
}, { timeout: 20000 })
|
||||
|
||||
@@ -3956,7 +3956,7 @@ describe("sisyphus-task", () => {
|
||||
manager: mockManager,
|
||||
client: mockClient,
|
||||
agentOverrides: {
|
||||
oracle: { model: "anthropic/claude-opus-4-6" },
|
||||
oracle: { model: "anthropic/claude-opus-4-7" },
|
||||
},
|
||||
})
|
||||
|
||||
@@ -3982,7 +3982,7 @@ describe("sisyphus-task", () => {
|
||||
// then - user-configured model should take priority over matchedAgent.model
|
||||
expect(promptBody.model).toEqual({
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-opus-4-6",
|
||||
modelID: "claude-opus-4-7",
|
||||
})
|
||||
}, { timeout: 20000 })
|
||||
|
||||
@@ -4023,7 +4023,7 @@ describe("sisyphus-task", () => {
|
||||
manager: mockManager,
|
||||
client: mockClient,
|
||||
agentOverrides: {
|
||||
oracle: { model: "anthropic/claude-opus-4-6", variant: "max" },
|
||||
oracle: { model: "anthropic/claude-opus-4-7", variant: "max" },
|
||||
},
|
||||
})
|
||||
|
||||
@@ -4111,7 +4111,7 @@ describe("sisyphus-task", () => {
|
||||
)
|
||||
|
||||
// then - should resolve via AGENT_MODEL_REQUIREMENTS fallback chain for oracle
|
||||
// oracle fallback chain: gpt-5.4 (openai) > gemini-3.1-pro (google) > claude-opus-4-6 (anthropic)
|
||||
// oracle fallback chain: gpt-5.4 (openai) > gemini-3.1-pro (google) > claude-opus-4-7 (anthropic)
|
||||
// Since openai is in connectedProviders, should resolve to openai/gpt-5.4
|
||||
expect(promptBody.model).toBeDefined()
|
||||
expect(promptBody.model.providerID).toBe("openai")
|
||||
|
||||
Reference in New Issue
Block a user