Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

<br>

Expand Down
40 changes: 24 additions & 16 deletions apps/server/src/provider/Layers/ClaudeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ServerProviderModel> = [
{
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",
Expand Down
12 changes: 11 additions & 1 deletion apps/server/src/serverSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/serverSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
}),
Expand All @@ -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" },
}),
],
};
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/components/chat/ModelPickerContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,9 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
isLocked ? "flex-col" : "flex-row",
)}
>
{isLocked && LockedProviderIcon && props.lockedProvider ? (
{isLocked && props.lockedProvider ? (
<div className="flex items-center gap-2 border-b px-4 py-3">
<LockedProviderIcon className="size-5 shrink-0" />
{LockedProviderIcon ? <LockedProviderIcon className="size-5 shrink-0" /> : null}
<span className="text-sm font-medium">
{PROVIDER_DISPLAY_NAMES[props.lockedProvider]}
</span>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/chat/modelPickerModelHighlights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>([]);
const NEW_MODEL_KEYS = new Set<string>(["claudeAgent:claude-opus-4-7"]);

export function isModelPickerNewModel(provider: ProviderKind, slug: string): boolean {
return NEW_MODEL_KEYS.has(`${provider}:${slug}`);
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/chat/providerIconUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const PROVIDER_ICON_BY_PROVIDER: Record<ProviderKind | "cursor", Icon> =

export const PROVIDER_TINT_CLASS_BY_PROVIDER: Record<ProviderKind | "cursor", string> = {
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",
};

Expand Down
13 changes: 5 additions & 8 deletions apps/web/src/components/settings/SettingsModelsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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" },
},
},
Expand Down Expand Up @@ -325,10 +324,8 @@ function ProviderPresetLabel({ provider }: { provider: ProviderKind }) {
<span className="flex items-center gap-2">
<ProviderIcon
aria-hidden="true"
className={cn(
"size-4 shrink-0",
provider === "claudeAgent" ? "text-[#d97757]" : "text-muted-foreground/85",
)}
className="size-4 shrink-0 text-muted-foreground/85 data-[claude=true]:text-[#CC7C5E]"
data-claude={provider === "claudeAgent"}
/>
<span>{PROVIDER_DISPLAY_NAMES[provider]}</span>
</span>
Expand Down
4 changes: 3 additions & 1 deletion packages/contracts/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ export const MODEL_SLUG_ALIASES_BY_PROVIDER: Record<ProviderKind, Record<string,
"gpt-5.3-spark": "gpt-5.3-codex-spark",
},
claudeAgent: {
opus: "claude-opus-4-6",
opus: "claude-opus-4-7",
"opus-4.7": "claude-opus-4-7",
"claude-opus-4.7": "claude-opus-4-7",
"opus-4.6": "claude-opus-4-6",
"claude-opus-4.6": "claude-opus-4-6",
"claude-opus-4-6-20251117": "claude-opus-4-6",
Expand Down
18 changes: 10 additions & 8 deletions packages/shared/src/model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ describe("normalizeModelSlug", () => {
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", () => {
Expand Down Expand Up @@ -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", () => {
Expand Down