Skip to content

Commit dee28a8

Browse files
committed
Add Claude Opus 4.7 model support
- Register Opus 4.7 across provider catalogs and aliases - Update shared capability checks and tests for fast mode, max effort, and adaptive reasoning
1 parent 150e57d commit dee28a8

4 files changed

Lines changed: 60 additions & 9 deletions

File tree

apps/server/src/provider/providerCatalog.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ export const BUILT_IN_PROVIDER_MODELS: Record<ProviderKind, ReadonlyArray<Provid
5353
{ slug: "gpt-5.2", name: "GPT-5.2", capabilities: noCapabilities },
5454
],
5555
claudeAgent: [
56+
{
57+
slug: "claude-opus-4-7",
58+
name: "Claude Opus 4.7",
59+
capabilities: {
60+
reasoningEffortLevels: [
61+
{ value: "low", label: "Low" },
62+
{ value: "medium", label: "Medium" },
63+
{ value: "high", label: "High", isDefault: true },
64+
{ value: "max", label: "Max" },
65+
{ value: "ultrathink", label: "Ultrathink" },
66+
],
67+
supportsFastMode: true,
68+
supportsThinkingToggle: false,
69+
contextWindowOptions: [],
70+
promptInjectedEffortLevels: ["ultrathink"],
71+
},
72+
},
5673
{
5774
slug: "claude-opus-4-6",
5875
name: "Claude Opus 4.6",
@@ -110,6 +127,7 @@ export const BUILT_IN_PROVIDER_MODELS: Record<ProviderKind, ReadonlyArray<Provid
110127
{ slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", capabilities: noCapabilities },
111128
{ slug: "claude-sonnet-4-5", name: "Claude Sonnet 4.5", capabilities: noCapabilities },
112129
{ slug: "claude-haiku-4-5", name: "Claude Haiku 4.5", capabilities: noCapabilities },
130+
{ slug: "claude-opus-4-7", name: "Claude Opus 4.7", capabilities: noCapabilities },
113131
{ slug: "claude-opus-4-6", name: "Claude Opus 4.6", capabilities: noCapabilities },
114132
{ slug: "claude-opus-4-5", name: "Claude Opus 4.5", capabilities: noCapabilities },
115133
{ slug: "gemini-3.1-pro", name: "Gemini 3.1 Pro", capabilities: noCapabilities },

packages/contracts/src/model.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export const MODEL_OPTIONS_BY_PROVIDER = {
6868
{ slug: "gpt-5.2", name: "GPT-5.2" },
6969
],
7070
claudeAgent: [
71+
{ slug: "claude-opus-4-7", name: "Claude Opus 4.7" },
7172
{ slug: "claude-opus-4-6", name: "Claude Opus 4.6" },
7273
{ slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
7374
{ slug: "claude-haiku-4-5", name: "Claude Haiku 4.5" },
@@ -84,6 +85,7 @@ export const MODEL_OPTIONS_BY_PROVIDER = {
8485
{ slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
8586
{ slug: "claude-sonnet-4-5", name: "Claude Sonnet 4.5" },
8687
{ slug: "claude-haiku-4-5", name: "Claude Haiku 4.5" },
88+
{ slug: "claude-opus-4-7", name: "Claude Opus 4.7" },
8789
{ slug: "claude-opus-4-6", name: "Claude Opus 4.6" },
8890
{ slug: "claude-opus-4-5", name: "Claude Opus 4.5" },
8991
{ slug: "gemini-3.1-pro", name: "Gemini 3.1 Pro" },
@@ -126,7 +128,9 @@ export const MODEL_SLUG_ALIASES_BY_PROVIDER: Record<ProviderKind, Record<string,
126128
"gpt-5.3-spark": "gpt-5.3-codex-spark",
127129
},
128130
claudeAgent: {
129-
opus: "claude-opus-4-6",
131+
opus: "claude-opus-4-7",
132+
"opus-4.7": "claude-opus-4-7",
133+
"claude-opus-4.7": "claude-opus-4-7",
130134
"opus-4.6": "claude-opus-4-6",
131135
"claude-opus-4.6": "claude-opus-4-6",
132136
"claude-opus-4-6-20251117": "claude-opus-4-6",
@@ -167,6 +171,9 @@ export const MODEL_SLUG_ALIASES_BY_PROVIDER: Record<ProviderKind, Record<string,
167171
"claude opus 4.5": "claude-opus-4-5",
168172
"claude-opus-4.5": "claude-opus-4-5",
169173
"claude-opus-4-5": "claude-opus-4-5",
174+
"claude opus 4.7": "claude-opus-4-7",
175+
"claude-opus-4.7": "claude-opus-4-7",
176+
"claude-opus-4-7": "claude-opus-4-7",
170177
"claude opus 4.6": "claude-opus-4-6",
171178
"claude-opus-4.6": "claude-opus-4-6",
172179
"claude-opus-4-6": "claude-opus-4-6",

packages/shared/src/model.test.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ describe("normalizeModelSlug", () => {
5656

5757
it("uses provider-specific aliases", () => {
5858
expect(normalizeModelSlug("sonnet", "claudeAgent")).toBe("claude-sonnet-4-6");
59+
expect(normalizeModelSlug("opus", "claudeAgent")).toBe("claude-opus-4-7");
60+
expect(normalizeModelSlug("opus-4.7", "claudeAgent")).toBe("claude-opus-4-7");
5961
expect(normalizeModelSlug("opus-4.6", "claudeAgent")).toBe("claude-opus-4-6");
6062
expect(normalizeModelSlug("claude-haiku-4-5-20251001", "claudeAgent")).toBe("claude-haiku-4-5");
6163
});
@@ -171,6 +173,16 @@ describe("getReasoningEffortOptions", () => {
171173
expect(getReasoningEffortOptions("codex")).toEqual(REASONING_EFFORT_OPTIONS_BY_PROVIDER.codex);
172174
});
173175

176+
it("returns claude effort options for Opus 4.7", () => {
177+
expect(getReasoningEffortOptions("claudeAgent", "claude-opus-4-7")).toEqual([
178+
"low",
179+
"medium",
180+
"high",
181+
"max",
182+
"ultrathink",
183+
]);
184+
});
185+
174186
it("returns claude effort options for Opus 4.6", () => {
175187
expect(getReasoningEffortOptions("claudeAgent", "claude-opus-4-6")).toEqual([
176188
"low",
@@ -198,6 +210,7 @@ describe("getReasoningEffortOptions", () => {
198210
describe("inferProviderForModel", () => {
199211
it("detects known provider model slugs", () => {
200212
expect(inferProviderForModel("gpt-5.3-codex")).toBe("codex");
213+
expect(inferProviderForModel("claude-opus-4-7")).toBe("claudeAgent");
201214
expect(inferProviderForModel("claude-sonnet-4-6")).toBe("claudeAgent");
202215
expect(inferProviderForModel("anthropic/claude-sonnet-4-6")).toBe("claudeAgent");
203216
expect(inferProviderForModel("sonnet")).toBe("claudeAgent");
@@ -299,7 +312,8 @@ describe("normalizeClaudeModelOptions", () => {
299312
});
300313

301314
describe("supportsClaudeAdaptiveReasoning", () => {
302-
it("only enables adaptive reasoning for Opus 4.6 and Sonnet 4.6", () => {
315+
it("only enables adaptive reasoning for Opus 4.7, Opus 4.6, and Sonnet 4.6", () => {
316+
expect(supportsClaudeAdaptiveReasoning("claude-opus-4-7")).toBe(true);
303317
expect(supportsClaudeAdaptiveReasoning("claude-opus-4-6")).toBe(true);
304318
expect(supportsClaudeAdaptiveReasoning("claude-sonnet-4-6")).toBe(true);
305319
expect(supportsClaudeAdaptiveReasoning("claude-haiku-4-5")).toBe(false);
@@ -308,7 +322,8 @@ describe("supportsClaudeAdaptiveReasoning", () => {
308322
});
309323

310324
describe("supportsClaudeMaxEffort", () => {
311-
it("only enables max effort for Opus 4.6", () => {
325+
it("only enables max effort for Opus 4.7 and Opus 4.6", () => {
326+
expect(supportsClaudeMaxEffort("claude-opus-4-7")).toBe(true);
312327
expect(supportsClaudeMaxEffort("claude-opus-4-6")).toBe(true);
313328
expect(supportsClaudeMaxEffort("claude-sonnet-4-6")).toBe(false);
314329
expect(supportsClaudeMaxEffort("claude-haiku-4-5")).toBe(false);
@@ -317,17 +332,20 @@ describe("supportsClaudeMaxEffort", () => {
317332
});
318333

319334
describe("supportsClaudeFastMode", () => {
320-
it("only enables Claude fast mode for Opus 4.6", () => {
321-
expect(supportsClaudeFastMode("claude-opus-4-6")).toBe(true);
335+
it("only enables Claude fast mode for Opus 4.7 and Opus 4.6", () => {
336+
expect(supportsClaudeFastMode("claude-opus-4-7")).toBe(true);
322337
expect(supportsClaudeFastMode("opus")).toBe(true);
338+
expect(supportsClaudeFastMode("claude-opus-4-6")).toBe(true);
339+
expect(supportsClaudeFastMode("opus-4.6")).toBe(true);
323340
expect(supportsClaudeFastMode("claude-sonnet-4-6")).toBe(false);
324341
expect(supportsClaudeFastMode("claude-haiku-4-5")).toBe(false);
325342
expect(supportsClaudeFastMode(undefined)).toBe(false);
326343
});
327344
});
328345

329346
describe("supportsClaudeUltrathinkKeyword", () => {
330-
it("only enables ultrathink keyword handling for Opus 4.6 and Sonnet 4.6", () => {
347+
it("only enables ultrathink keyword handling for Opus 4.7, Opus 4.6, and Sonnet 4.6", () => {
348+
expect(supportsClaudeUltrathinkKeyword("claude-opus-4-7")).toBe(true);
331349
expect(supportsClaudeUltrathinkKeyword("claude-opus-4-6")).toBe(true);
332350
expect(supportsClaudeUltrathinkKeyword("claude-sonnet-4-6")).toBe(true);
333351
expect(supportsClaudeUltrathinkKeyword("claude-haiku-4-5")).toBe(false);
@@ -336,6 +354,7 @@ describe("supportsClaudeUltrathinkKeyword", () => {
336354

337355
describe("supportsClaudeThinkingToggle", () => {
338356
it("only enables the Claude thinking toggle for Haiku 4.5", () => {
357+
expect(supportsClaudeThinkingToggle("claude-opus-4-7")).toBe(false);
339358
expect(supportsClaudeThinkingToggle("claude-opus-4-6")).toBe(false);
340359
expect(supportsClaudeThinkingToggle("claude-sonnet-4-6")).toBe(false);
341360
expect(supportsClaudeThinkingToggle("claude-haiku-4-5")).toBe(true);

packages/shared/src/model.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const MODEL_SLUG_SET_BY_PROVIDER: Record<ProviderKind, ReadonlySet<ModelSlug>> =
2828
gemini: new Set(MODEL_OPTIONS_BY_PROVIDER.gemini.map((option) => option.slug)),
2929
};
3030

31+
const CLAUDE_OPUS_4_7_MODEL = "claude-opus-4-7";
3132
const CLAUDE_OPUS_4_6_MODEL = "claude-opus-4-6";
3233
const CLAUDE_SONNET_4_6_MODEL = "claude-sonnet-4-6";
3334
const CLAUDE_HAIKU_4_5_MODEL = "claude-haiku-4-5";
@@ -46,16 +47,22 @@ export function getDefaultModel(provider: ProviderKind = "codex"): ModelSlug {
4647
}
4748

4849
export function supportsClaudeFastMode(model: string | null | undefined): boolean {
49-
return normalizeModelSlug(model, "claudeAgent") === CLAUDE_OPUS_4_6_MODEL;
50+
const normalized = normalizeModelSlug(model, "claudeAgent");
51+
return normalized === CLAUDE_OPUS_4_7_MODEL || normalized === CLAUDE_OPUS_4_6_MODEL;
5052
}
5153

5254
export function supportsClaudeAdaptiveReasoning(model: string | null | undefined): boolean {
5355
const normalized = normalizeModelSlug(model, "claudeAgent");
54-
return normalized === CLAUDE_OPUS_4_6_MODEL || normalized === CLAUDE_SONNET_4_6_MODEL;
56+
return (
57+
normalized === CLAUDE_OPUS_4_7_MODEL ||
58+
normalized === CLAUDE_OPUS_4_6_MODEL ||
59+
normalized === CLAUDE_SONNET_4_6_MODEL
60+
);
5561
}
5662

5763
export function supportsClaudeMaxEffort(model: string | null | undefined): boolean {
58-
return normalizeModelSlug(model, "claudeAgent") === CLAUDE_OPUS_4_6_MODEL;
64+
const normalized = normalizeModelSlug(model, "claudeAgent");
65+
return normalized === CLAUDE_OPUS_4_7_MODEL || normalized === CLAUDE_OPUS_4_6_MODEL;
5966
}
6067

6168
export function supportsClaudeUltrathinkKeyword(model: string | null | undefined): boolean {

0 commit comments

Comments
 (0)