diff --git a/README.md b/README.md index 3b707140..6a585caa 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ This snippet mirrors the current settings schema and built-in model defaults in - Mode overrides are stored as `askModelSelection`, `planModelSelection`, `codeModelSelection`, and `reviewModelSelection`. - Default provider models are `gpt-5.4` for Codex and `claude-sonnet-4-6` for Claude. - Git text generation and prompt enhancement currently default to `gpt-5.4-mini`. -- Other built-in models currently exposed include `gpt-5.3-codex`, `gpt-5.3-codex-spark`, `claude-opus-4-6`, and `claude-haiku-4-5`. +- Other built-in models currently exposed include `gpt-5.3-codex`, `gpt-5.3-codex-spark`, `claude-opus-4-7`, `claude-opus-4-6`, and `claude-haiku-4-5`.
diff --git a/apps/server/src/provider/Layers/ClaudeProvider.ts b/apps/server/src/provider/Layers/ClaudeProvider.ts index b62d21e3..de6f7225 100644 --- a/apps/server/src/provider/Layers/ClaudeProvider.ts +++ b/apps/server/src/provider/Layers/ClaudeProvider.ts @@ -37,27 +37,35 @@ const DEFAULT_CLAUDE_MODEL_CAPABILITIES: ModelCapabilities = { }; const PROVIDER = "claudeAgent" as const; +const CLAUDE_OPUS_CAPABILITIES = { + reasoningEffortLevels: [ + { value: "low", label: "Low" }, + { value: "medium", label: "Medium" }, + { value: "high", label: "High", isDefault: true }, + { value: "max", label: "Max" }, + { value: "ultrathink", label: "Ultrathink" }, + ], + supportsFastMode: true, + supportsThinkingToggle: false, + contextWindowOptions: [ + { value: "200k", label: "200k", isDefault: true }, + { value: "1m", label: "1M" }, + ], + promptInjectedEffortLevels: ["ultrathink"], +} satisfies ModelCapabilities; + const BUILT_IN_MODELS: ReadonlyArray = [ + { + slug: "claude-opus-4-7", + name: "Claude Opus 4.7", + isCustom: false, + capabilities: CLAUDE_OPUS_CAPABILITIES, + }, { slug: "claude-opus-4-6", name: "Claude Opus 4.6", isCustom: false, - capabilities: { - reasoningEffortLevels: [ - { value: "low", label: "Low" }, - { value: "medium", label: "Medium" }, - { value: "high", label: "High", isDefault: true }, - { value: "max", label: "Max" }, - { value: "ultrathink", label: "Ultrathink" }, - ], - supportsFastMode: true, - supportsThinkingToggle: false, - contextWindowOptions: [ - { value: "200k", label: "200k", isDefault: true }, - { value: "1m", label: "1M" }, - ], - promptInjectedEffortLevels: ["ultrathink"], - } satisfies ModelCapabilities, + capabilities: CLAUDE_OPUS_CAPABILITIES, }, { slug: "claude-sonnet-4-6", diff --git a/apps/server/src/serverSettings.test.ts b/apps/server/src/serverSettings.test.ts index c03c590a..4dc412de 100644 --- a/apps/server/src/serverSettings.test.ts +++ b/apps/server/src/serverSettings.test.ts @@ -534,11 +534,21 @@ it.layer(NodeServices.layer)("server settings", (it) => { undefined, ); assert.equal(next.modelSelectionPresets.claudeAgent["starter-claude-free"]?.name, "Free"); + assert.deepEqual( + next.modelSelectionPresets.claudeAgent["starter-claude-pro"]?.planModelSelection, + { + provider: "claudeAgent", + model: "claude-haiku-4-5", + options: { + thinking: true, + }, + }, + ); assert.deepEqual( next.modelSelectionPresets.claudeAgent["starter-claude-max-20x"]?.reviewModelSelection, { provider: "claudeAgent", - model: "claude-opus-4-6", + model: "claude-opus-4-7", options: { effort: "high", }, diff --git a/apps/server/src/serverSettings.ts b/apps/server/src/serverSettings.ts index e95bc0dc..b4114563 100644 --- a/apps/server/src/serverSettings.ts +++ b/apps/server/src/serverSettings.ts @@ -257,7 +257,7 @@ const BUILT_IN_MODEL_SELECTION_PRESETS: { }), makeClaudePreset("starter-claude-pro", "Pro", { ask: { model: "claude-haiku-4-5", thinking: false }, - plan: { model: "claude-sonnet-4-6", effort: "low" }, + plan: { model: "claude-haiku-4-5", thinking: true }, code: { model: "claude-sonnet-4-6", effort: "low" }, review: { model: "claude-sonnet-4-6", effort: "medium" }, }), @@ -271,7 +271,7 @@ const BUILT_IN_MODEL_SELECTION_PRESETS: { ask: { model: "claude-sonnet-4-6", effort: "low" }, plan: { model: "claude-sonnet-4-6", effort: "high" }, code: { model: "claude-sonnet-4-6", effort: "medium" }, - review: { model: "claude-opus-4-6", effort: "high" }, + review: { model: "claude-opus-4-7", effort: "high" }, }), ], }; diff --git a/apps/web/src/components/chat/ModelPickerContent.tsx b/apps/web/src/components/chat/ModelPickerContent.tsx index 0cf715d3..0f7ddb5d 100644 --- a/apps/web/src/components/chat/ModelPickerContent.tsx +++ b/apps/web/src/components/chat/ModelPickerContent.tsx @@ -418,9 +418,9 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: { isLocked ? "flex-col" : "flex-row", )} > - {isLocked && LockedProviderIcon && props.lockedProvider ? ( + {isLocked && props.lockedProvider ? (
- + {LockedProviderIcon ? : null} {PROVIDER_DISPLAY_NAMES[props.lockedProvider]} diff --git a/apps/web/src/components/chat/modelPickerModelHighlights.ts b/apps/web/src/components/chat/modelPickerModelHighlights.ts index 9afc33a5..35a81d7c 100644 --- a/apps/web/src/components/chat/modelPickerModelHighlights.ts +++ b/apps/web/src/components/chat/modelPickerModelHighlights.ts @@ -4,7 +4,7 @@ import type { ProviderKind } from "@t3tools/contracts"; * Keep release-callout logic centralized so future model launches do not need * ad hoc badge checks spread across the picker rows. */ -const NEW_MODEL_KEYS = new Set([]); +const NEW_MODEL_KEYS = new Set(["claudeAgent:claude-opus-4-7"]); export function isModelPickerNewModel(provider: ProviderKind, slug: string): boolean { return NEW_MODEL_KEYS.has(`${provider}:${slug}`); diff --git a/apps/web/src/components/chat/providerIconUtils.ts b/apps/web/src/components/chat/providerIconUtils.ts index ca530527..d78eacfa 100644 --- a/apps/web/src/components/chat/providerIconUtils.ts +++ b/apps/web/src/components/chat/providerIconUtils.ts @@ -10,7 +10,7 @@ export const PROVIDER_ICON_BY_PROVIDER: Record = export const PROVIDER_TINT_CLASS_BY_PROVIDER: Record = { codex: "text-neutral-900 dark:text-white", - claudeAgent: "text-orange-500 dark:text-orange-300", + claudeAgent: "text-[#CC7C5E]", cursor: "text-violet-500 dark:text-violet-400", }; diff --git a/apps/web/src/components/settings/SettingsModelsSection.tsx b/apps/web/src/components/settings/SettingsModelsSection.tsx index f0349b90..79f9a001 100644 --- a/apps/web/src/components/settings/SettingsModelsSection.tsx +++ b/apps/web/src/components/settings/SettingsModelsSection.tsx @@ -22,7 +22,6 @@ import { import { ensureNativeApi } from "../../nativeApi"; import { useServerProviders } from "../../rpc/serverState"; import type { SettingsUpdatePatch } from "../../hooks/useSettings"; -import { cn } from "../../lib/utils"; import { Button } from "../ui/button"; import { ClaudeAI, OpenAI } from "../Icons"; import { Select, SelectItem, SelectPopup, SelectTrigger } from "../ui/select"; @@ -237,8 +236,8 @@ const BUILT_IN_PRESET_MODE_SELECTIONS: Readonly< }, planModelSelection: { provider: "claudeAgent", - model: "claude-sonnet-4-6", - options: { effort: "low" }, + model: "claude-haiku-4-5", + options: { thinking: true }, }, codeModelSelection: { provider: "claudeAgent", @@ -291,7 +290,7 @@ const BUILT_IN_PRESET_MODE_SELECTIONS: Readonly< }, reviewModelSelection: { provider: "claudeAgent", - model: "claude-opus-4-6", + model: "claude-opus-4-7", options: { effort: "high" }, }, }, @@ -325,10 +324,8 @@ function ProviderPresetLabel({ provider }: { provider: ProviderKind }) { diff --git a/packages/contracts/src/model.ts b/packages/contracts/src/model.ts index 43a9377e..404014e7 100644 --- a/packages/contracts/src/model.ts +++ b/packages/contracts/src/model.ts @@ -74,7 +74,9 @@ export const MODEL_SLUG_ALIASES_BY_PROVIDER: Record { expect(normalizeModelSlug("5.5")).toBe("gpt-5.5"); expect(normalizeModelSlug("5.3")).toBe("gpt-5.3-codex"); expect(normalizeModelSlug("sonnet", "claudeAgent")).toBe("claude-sonnet-4-6"); + expect(normalizeModelSlug("opus", "claudeAgent")).toBe("claude-opus-4-7"); + expect(normalizeModelSlug("opus-4.6", "claudeAgent")).toBe("claude-opus-4-6"); }); it("normalizes auto model selection case-insensitively", () => { @@ -320,29 +322,29 @@ describe("resolveApiModelId", () => { expect( resolveApiModelId({ provider: "claudeAgent", - model: "claude-opus-4-6", + model: "claude-opus-4-7", options: { contextWindow: "1m" }, }), - ).toBe("claude-opus-4-6[1m]"); + ).toBe("claude-opus-4-7[1m]"); }); it("returns the model as-is for 200k context window", () => { expect( resolveApiModelId({ provider: "claudeAgent", - model: "claude-opus-4-6", + model: "claude-opus-4-7", options: { contextWindow: "200k" }, }), - ).toBe("claude-opus-4-6"); + ).toBe("claude-opus-4-7"); }); it("returns the model as-is when no context window is set", () => { - expect(resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6" })).toBe( - "claude-opus-4-6", + expect(resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-7" })).toBe( + "claude-opus-4-7", ); expect( - resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6", options: {} }), - ).toBe("claude-opus-4-6"); + resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-7", options: {} }), + ).toBe("claude-opus-4-7"); }); it("returns the model as-is for Codex selections", () => {