feat: add Claude Opus 4.6 to built-in model catalog (#9853)

* feat: add Claude Opus 4.6 to built-in model catalog

- Update default model from claude-opus-4-5 to claude-opus-4-6
- Add opus-4.6 model ID normalization
- Add claude-opus-4-6 to live model filter prefixes
- Update image tool to prefer claude-opus-4-6 for vision
- Add CLI backend alias for opus-4.6
- Update onboard auth default selections to include opus-4.6
- Update model picker placeholder

Closes #9811

* test: update tests for claude-opus-4-6 default

- Fix model-alias-defaults test to use claude-opus-4-6
- Fix image-tool test to expect claude-opus-4-6 in fallbacks

* feat: support claude-opus-4-6

* docs: update changelog for opus 4.6 (#9853) (thanks @TinyTb)

* chore: bump pi to 0.52.0

---------

Co-authored-by: Slurpy <slurpy@openclaw.ai>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Michael Lee
2026-02-05 12:09:23 -08:00
committed by GitHub
parent ea237115a9
commit eb80b9acb3
16 changed files with 73 additions and 48 deletions

View File

@@ -9,8 +9,10 @@ export type ResolvedCliBackend = {
const CLAUDE_MODEL_ALIASES: Record<string, string> = {
opus: "opus",
"opus-4.6": "opus",
"opus-4.5": "opus",
"opus-4": "opus",
"claude-opus-4-6": "opus",
"claude-opus-4-5": "opus",
"claude-opus-4": "opus",
sonnet: "sonnet",

View File

@@ -1,6 +1,6 @@
// Defaults for agent metadata when upstream does not supply them.
// Model id uses pi-ai's built-in Anthropic catalog.
export const DEFAULT_PROVIDER = "anthropic";
export const DEFAULT_MODEL = "claude-opus-4-5";
// Context window: Opus 4.5 supports ~200k tokens (per pi-ai models.generated.ts).
export const DEFAULT_MODEL = "claude-opus-4-6";
// Context window: Opus supports ~200k tokens (per pi-ai models.generated.ts for Opus 4.5).
export const DEFAULT_CONTEXT_TOKENS = 200_000;

View File

@@ -3,11 +3,17 @@ export type ModelRef = {
id?: string | null;
};
const ANTHROPIC_PREFIXES = ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5"];
const ANTHROPIC_PREFIXES = [
"claude-opus-4-6",
"claude-opus-4-5",
"claude-sonnet-4-5",
"claude-haiku-4-5",
];
const OPENAI_MODELS = ["gpt-5.2", "gpt-5.0"];
const CODEX_MODELS = [
"gpt-5.2",
"gpt-5.2-codex",
"gpt-5.3-codex",
"gpt-5.1-codex",
"gpt-5.1-codex-mini",
"gpt-5.1-codex-max",

View File

@@ -59,9 +59,15 @@ function normalizeAnthropicModelId(model: string): string {
return trimmed;
}
const lower = trimmed.toLowerCase();
if (lower === "opus-4.6") {
return "claude-opus-4-6";
}
if (lower === "opus-4.5") {
return "claude-opus-4-5";
}
if (lower === "opus-4.6") {
return "claude-opus-4-6";
}
if (lower === "sonnet-4.5") {
return "claude-sonnet-4-5";
}

View File

@@ -53,7 +53,7 @@ describe("image tool implicit imageModel config", () => {
};
expect(resolveImageModelConfigForTool({ cfg, agentDir })).toEqual({
primary: "minimax/MiniMax-VL-01",
fallbacks: ["openai/gpt-5-mini", "anthropic/claude-opus-4-5"],
fallbacks: ["openai/gpt-5-mini", "anthropic/claude-opus-4-6"],
});
expect(createImageTool({ config: cfg, agentDir })).not.toBeNull();
});

View File

@@ -117,7 +117,7 @@ export function resolveImageModelConfigForTool(params: {
} else if (primary.provider === "openai" && openaiOk) {
preferred = "openai/gpt-5-mini";
} else if (primary.provider === "anthropic" && anthropicOk) {
preferred = "anthropic/claude-opus-4-5";
preferred = "anthropic/claude-opus-4-6";
}
if (preferred?.trim()) {
@@ -125,7 +125,7 @@ export function resolveImageModelConfigForTool(params: {
addFallback("openai/gpt-5-mini");
}
if (anthropicOk) {
addFallback("anthropic/claude-opus-4-5");
addFallback("anthropic/claude-opus-4-6");
}
// Don't duplicate primary in fallbacks.
const pruned = fallbacks.filter((ref) => ref !== preferred);
@@ -138,7 +138,7 @@ export function resolveImageModelConfigForTool(params: {
// Cross-provider fallback when we can't pair with the primary provider.
if (openaiOk) {
if (anthropicOk) {
addFallback("anthropic/claude-opus-4-5");
addFallback("anthropic/claude-opus-4-6");
}
return {
primary: "openai/gpt-5-mini",
@@ -146,7 +146,7 @@ export function resolveImageModelConfigForTool(params: {
};
}
if (anthropicOk) {
return { primary: "anthropic/claude-opus-4-5" };
return { primary: "anthropic/claude-opus-4-6" };
}
return null;

View File

@@ -15,6 +15,7 @@ import {
type GatewayAuthChoice = "token" | "password";
const ANTHROPIC_OAUTH_MODEL_KEYS = [
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-5",
"anthropic/claude-sonnet-4-5",
"anthropic/claude-haiku-4-5",
@@ -81,7 +82,7 @@ export async function promptAuthConfig(
config: next,
prompter,
allowedKeys: anthropicOAuth ? ANTHROPIC_OAUTH_MODEL_KEYS : undefined,
initialSelections: anthropicOAuth ? ["anthropic/claude-opus-4-5"] : undefined,
initialSelections: anthropicOAuth ? ["anthropic/claude-opus-4-6"] : undefined,
message: anthropicOAuth ? "Anthropic OAuth models" : undefined,
});
if (allowlistSelection.models) {

View File

@@ -331,7 +331,7 @@ export async function promptModelAllowlist(params: {
params.message ??
"Allowlist models (comma-separated provider/model; blank to keep current)",
initialValue: existingKeys.join(", "),
placeholder: "openai-codex/gpt-5.2, anthropic/claude-opus-4-5",
placeholder: "openai-codex/gpt-5.2, anthropic/claude-opus-4-6",
});
const parsed = String(raw ?? "")
.split(",")

View File

@@ -14,9 +14,9 @@ import {
export function applyMinimaxProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
const models = { ...cfg.agents?.defaults?.models };
models["anthropic/claude-opus-4-5"] = {
...models["anthropic/claude-opus-4-5"],
alias: models["anthropic/claude-opus-4-5"]?.alias ?? "Opus",
models["anthropic/claude-opus-4-6"] = {
...models["anthropic/claude-opus-4-6"],
alias: models["anthropic/claude-opus-4-6"]?.alias ?? "Opus",
};
models["lmstudio/minimax-m2.1-gs32"] = {
...models["lmstudio/minimax-m2.1-gs32"],

View File

@@ -13,7 +13,7 @@ type AnthropicAuthDefaultsMode = "api_key" | "oauth";
const DEFAULT_MODEL_ALIASES: Readonly<Record<string, string>> = {
// Anthropic (pi-ai catalog uses "latest" ids without date suffix)
opus: "anthropic/claude-opus-4-5",
opus: "anthropic/claude-opus-4-6",
sonnet: "anthropic/claude-sonnet-4-5",
// OpenAI

View File

@@ -9,7 +9,7 @@ describe("applyModelDefaults", () => {
agents: {
defaults: {
models: {
"anthropic/claude-opus-4-5": {},
"anthropic/claude-opus-4-6": {},
"openai/gpt-5.2": {},
},
},
@@ -17,7 +17,7 @@ describe("applyModelDefaults", () => {
} satisfies OpenClawConfig;
const next = applyModelDefaults(cfg);
expect(next.agents?.defaults?.models?.["anthropic/claude-opus-4-5"]?.alias).toBe("opus");
expect(next.agents?.defaults?.models?.["anthropic/claude-opus-4-6"]?.alias).toBe("opus");
expect(next.agents?.defaults?.models?.["openai/gpt-5.2"]?.alias).toBe("gpt");
});
@@ -26,7 +26,7 @@ describe("applyModelDefaults", () => {
agents: {
defaults: {
models: {
"anthropic/claude-opus-4-5": { alias: "Opus" },
"anthropic/claude-opus-4-6": { alias: "Opus" },
},
},
},
@@ -34,7 +34,7 @@ describe("applyModelDefaults", () => {
const next = applyModelDefaults(cfg);
expect(next.agents?.defaults?.models?.["anthropic/claude-opus-4-5"]?.alias).toBe("Opus");
expect(next.agents?.defaults?.models?.["anthropic/claude-opus-4-6"]?.alias).toBe("Opus");
});
it("respects explicit empty alias disables", () => {

View File

@@ -53,7 +53,7 @@ const AUTO_IMAGE_KEY_PROVIDERS = ["openai", "anthropic", "google", "minimax"] as
const AUTO_VIDEO_KEY_PROVIDERS = ["google"] as const;
const DEFAULT_IMAGE_MODELS: Record<string, string> = {
openai: "gpt-5-mini",
anthropic: "claude-opus-4-5",
anthropic: "claude-opus-4-6",
google: "gemini-3-flash-preview",
minimax: "MiniMax-VL-01",
};

View File

@@ -194,7 +194,7 @@ export async function describeStickerImage(params: DescribeStickerParams): Promi
provider === "openai"
? "gpt-5-mini"
: provider === "anthropic"
? "claude-opus-4-5"
? "claude-opus-4-6"
: provider === "google"
? "gemini-3-flash-preview"
: "MiniMax-VL-01";