Skip to content

Commit 037785f

Browse files
authored
🤖 feat: upgrade Claude Opus to 4-5 (#734)
_Generated with `mux`_
1 parent 0d923bf commit 037785f

File tree

7 files changed

+44
-25
lines changed

7 files changed

+44
-25
lines changed

mobile/app/workspace-settings.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,11 @@ import { ThemedText } from "../src/components/ThemedText";
1010
import { useWorkspaceDefaults } from "../src/hooks/useWorkspaceDefaults";
1111
import type { ThinkingLevel, WorkspaceMode } from "../src/types/settings";
1212
import { supports1MContext } from "@/common/utils/ai/models";
13+
import { KNOWN_MODEL_OPTIONS } from "@/common/constants/knownModels";
1314

1415
const MODE_TABS: WorkspaceMode[] = ["plan", "exec"];
1516
const THINKING_LEVELS: ThinkingLevel[] = ["off", "low", "medium", "high"];
1617

17-
// Common models from MODEL_ABBREVIATIONS
18-
const AVAILABLE_MODELS = [
19-
{ label: "Claude Sonnet 4.5", value: "anthropic:claude-sonnet-4-5" },
20-
{ label: "Claude Haiku 4.5", value: "anthropic:claude-haiku-4-5" },
21-
{ label: "Claude Opus 4.1", value: "anthropic:claude-opus-4-1" },
22-
{ label: "GPT-5", value: "openai:gpt-5" },
23-
{ label: "GPT-5 Pro", value: "openai:gpt-5-pro" },
24-
{ label: "GPT-5 Codex", value: "openai:gpt-5-codex" },
25-
];
26-
2718
function thinkingLevelToValue(level: ThinkingLevel): number {
2819
const index = THINKING_LEVELS.indexOf(level);
2920
return index >= 0 ? index : 0;
@@ -110,7 +101,7 @@ export default function WorkspaceSettings(): JSX.Element {
110101
}}
111102
dropdownIconColor={theme.colors.foregroundPrimary}
112103
>
113-
{AVAILABLE_MODELS.map((model) => (
104+
{KNOWN_MODEL_OPTIONS.map((model) => (
114105
<Picker.Item
115106
key={model.value}
116107
label={model.label}

src/browser/utils/slashCommands/compact.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ describe("compact command parser", () => {
133133
});
134134

135135
it("parses -m flag with full model string", () => {
136-
const result = parseCommand("/compact -m anthropic:claude-opus-4-1");
136+
const result = parseCommand(`/compact -m ${KNOWN_MODELS.OPUS.id}`);
137137
expect(result).toEqual({
138138
type: "compact",
139139
maxOutputTokens: undefined,

src/common/constants/knownModels.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
* Centralized model metadata. Update model versions here and everywhere else will follow.
33
*/
44

5+
import { formatModelDisplayName } from "../utils/ai/modelDisplay";
6+
57
type ModelProvider = "anthropic" | "openai" | "google" | "xai";
68

79
interface KnownModelDefinition {
@@ -43,7 +45,7 @@ const MODEL_DEFINITIONS = {
4345
},
4446
OPUS: {
4547
provider: "anthropic",
46-
providerModelId: "claude-opus-4-1",
48+
providerModelId: "claude-opus-4-5",
4749
aliases: ["opus"],
4850
},
4951
GPT: {
@@ -151,3 +153,9 @@ export const MODEL_NAMES: Record<ModelProvider, Record<string, string>> = Object
151153
},
152154
{} as Record<ModelProvider, Record<string, string>>
153155
);
156+
157+
/** Picker-friendly list: { label, value } for each known model */
158+
export const KNOWN_MODEL_OPTIONS = Object.values(KNOWN_MODELS).map((model) => ({
159+
label: formatModelDisplayName(model.providerModelId),
160+
value: model.id,
161+
}));

src/common/utils/tokens/models-extra.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,23 @@ interface ModelData {
2222
}
2323

2424
export const modelsExtra: Record<string, ModelData> = {
25+
// Claude Opus 4.5 - Released November 2025
26+
// $15/M input, $75/M output (same pricing as Opus 4.1)
27+
"claude-opus-4-5": {
28+
max_input_tokens: 200000,
29+
max_output_tokens: 32000,
30+
input_cost_per_token: 0.000015, // $15 per million input tokens
31+
output_cost_per_token: 0.000075, // $75 per million output tokens
32+
cache_creation_input_token_cost: 0.00001875, // $18.75 per million tokens
33+
cache_read_input_token_cost: 0.0000015, // $1.50 per million tokens
34+
litellm_provider: "anthropic",
35+
mode: "chat",
36+
supports_function_calling: true,
37+
supports_vision: true,
38+
supports_reasoning: true,
39+
supports_response_schema: true,
40+
},
41+
2542
// GPT-5 Pro - Released October 6, 2025 at DevDay
2643
// $15/M input, $120/M output
2744
// Only available via OpenAI's Responses API

src/node/services/mock/scenarios/slashCommands.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,26 @@ const modelStatusTurn: ScenarioTurn = {
6565
kind: "stream-start",
6666
delay: 0,
6767
messageId: "msg-slash-model-status",
68-
model: "anthropic:claude-opus-4-1",
68+
model: "anthropic:claude-opus-4-5",
6969
},
7070
{
7171
kind: "stream-delta",
7272
delay: STREAM_BASE_DELAY,
73-
text: "Claude Opus 4.1 is now responding with enhanced reasoning capacity.",
73+
text: "Claude Opus 4.5 is now responding with enhanced reasoning capacity.",
7474
},
7575
{
7676
kind: "stream-end",
7777
delay: STREAM_BASE_DELAY * 2,
7878
metadata: {
79-
model: "anthropic:claude-opus-4-1",
79+
model: "anthropic:claude-opus-4-5",
8080
inputTokens: 70,
8181
outputTokens: 54,
8282
systemMessageTokens: 12,
8383
},
8484
parts: [
8585
{
8686
type: "text",
87-
text: "I'm responding as Claude Opus 4.1, which you selected via /model opus. Let me know how to proceed.",
87+
text: "I'm responding as Claude Opus 4.5, which you selected via /model opus. Let me know how to proceed.",
8888
},
8989
],
9090
},

tests/e2e/scenarios/slashCommands.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,17 @@ test.describe("slash command flows", () => {
109109
).toBeVisible();
110110

111111
await ui.chat.sendMessage("/model opus");
112-
await ui.chat.expectStatusMessageContains("Model changed to anthropic:claude-opus-4-1");
113-
await expect(modeToggles.getByText("anthropic:claude-opus-4-1", { exact: true })).toBeVisible();
112+
await ui.chat.expectStatusMessageContains("Model changed to anthropic:claude-opus-4-5");
113+
await expect(modeToggles.getByText("anthropic:claude-opus-4-5", { exact: true })).toBeVisible();
114114

115115
const timeline = await ui.chat.captureStreamTimeline(async () => {
116116
await ui.chat.sendMessage(SLASH_COMMAND_PROMPTS.MODEL_STATUS);
117117
});
118118

119119
const streamStart = timeline.events.find((event) => event.type === "stream-start");
120-
expect(streamStart?.model).toBe("anthropic:claude-opus-4-1");
120+
expect(streamStart?.model).toBe("anthropic:claude-opus-4-5");
121121
await ui.chat.expectTranscriptContains(
122-
"Claude Opus 4.1 is now responding with enhanced reasoning capacity."
122+
"Claude Opus 4.5 is now responding with enhanced reasoning capacity."
123123
);
124124
});
125125

tests/models/knownModels.test.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import { describe, test, expect } from "@jest/globals";
99
import { KNOWN_MODELS } from "@/common/constants/knownModels";
1010
import modelsJson from "@/common/utils/tokens/models.json";
11+
import { modelsExtra } from "@/common/utils/tokens/models-extra";
1112

1213
describe("Known Models Integration", () => {
1314
test("all known models exist in models.json", () => {
@@ -16,10 +17,10 @@ describe("Known Models Integration", () => {
1617
for (const [key, model] of Object.entries(KNOWN_MODELS)) {
1718
const modelId = model.providerModelId;
1819

19-
// Check if model exists in models.json
20+
// Check if model exists in models.json or models-extra
2021
// xAI models are prefixed with "xai/" in models.json
2122
const lookupKey = model.provider === "xai" ? `xai/${modelId}` : modelId;
22-
if (!(lookupKey in modelsJson)) {
23+
if (!(lookupKey in modelsJson) && !(modelId in modelsExtra)) {
2324
missingModels.push(`${key}: ${model.provider}:${modelId}`);
2425
}
2526
}
@@ -34,11 +35,13 @@ describe("Known Models Integration", () => {
3435
});
3536

3637
test("all known models have required metadata", () => {
37-
for (const [key, model] of Object.entries(KNOWN_MODELS)) {
38+
for (const [, model] of Object.entries(KNOWN_MODELS)) {
3839
const modelId = model.providerModelId;
3940
// xAI models are prefixed with "xai/" in models.json
4041
const lookupKey = model.provider === "xai" ? `xai/${modelId}` : modelId;
41-
const modelData = modelsJson[lookupKey as keyof typeof modelsJson] as Record<string, unknown>;
42+
const modelData =
43+
(modelsJson[lookupKey as keyof typeof modelsJson] as Record<string, unknown>) ??
44+
(modelsExtra[modelId as keyof typeof modelsExtra] as unknown as Record<string, unknown>);
4245

4346
expect(modelData).toBeDefined();
4447
// Check that basic metadata fields exist (not all models have all fields)

0 commit comments

Comments
 (0)