Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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 .github/workflows/auto-cleanup-fixup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,6 @@ jobs:
FAILED_RUN_ID: ${{ github.event.workflow_run.id }}
run: |
bunx mux@next run \
--model anthropic:claude-opus-5 \
--model anthropic:claude-opus-5-1 \
--thinking xhigh \
< .github/prompts/auto-cleanup-fixup.md
2 changes: 1 addition & 1 deletion .github/workflows/auto-cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ jobs:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
bunx @coder/xum@next run \
--model anthropic:claude-opus-5 \
--model anthropic:claude-opus-5-1 \
--thinking xhigh \
< .github/prompts/auto-cleanup.md
4 changes: 2 additions & 2 deletions .github/workflows/nightly-terminal-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
workflow_dispatch:
inputs:
models:
description: 'Models to test (comma-separated, or "all" for opus-5 + gpt-5.6-sol + google/gemini-3-pro-preview + google/gemini-3-flash-preview + google/gemini-3.7-flash)'
description: 'Models to test (comma-separated, or "all" for opus-5-1 + gpt-5.6-sol + google/gemini-3-pro-preview + google/gemini-3-flash-preview + google/gemini-3.7-flash)'
required: false
default: "all"
type: string
Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:
INPUT_MODELS: ${{ inputs.models }}
run: |
if [ "$INPUT_MODELS" = "all" ] || [ -z "$INPUT_MODELS" ]; then
echo 'models=["anthropic/claude-opus-5","openai/gpt-5.6-sol","google/gemini-3-pro-preview","google/gemini-3-flash-preview","google/gemini-3.7-flash"]' >> "$GITHUB_OUTPUT"
echo 'models=["anthropic/claude-opus-5-1","openai/gpt-5.6-sol","google/gemini-3-pro-preview","google/gemini-3-flash-preview","google/gemini-3.7-flash"]' >> "$GITHUB_OUTPUT"
Comment thread
ThomasK33 marked this conversation as resolved.
else
# Convert comma-separated to JSON array
models_json=$(echo "$INPUT_MODELS" | jq -R -s -c 'split(",") | map(gsub("^\\s+|\\s+$"; ""))')
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/terminal-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_call:
inputs:
model_name:
description: "Model to use (e.g., anthropic/claude-opus-5, openai/gpt-5.6-sol)"
description: "Model to use (e.g., anthropic/claude-opus-5-1, openai/gpt-5.6-sol)"
required: false
type: string
dataset:
Expand Down Expand Up @@ -98,7 +98,7 @@ on:
required: false
type: string
model_name:
description: "Model to use (e.g., anthropic/claude-opus-5, openai/gpt-5.6-sol)"
description: "Model to use (e.g., anthropic/claude-opus-5-1, openai/gpt-5.6-sol)"
required: false
type: string
mux_run_args:
Expand Down
2 changes: 1 addition & 1 deletion docs/config/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Xum ships with curated models kept up to date with the frontier. Use any custom
| ---------------------- | ----------------------------- | ------------------------------------------------------------ | ------- |
| Fable 5.1 | anthropic:claude-fable-5-1 | `fable` | |
| Mythos 5 | anthropic:claude-mythos-5 | `mythos` | |
| Opus 5 | anthropic:claude-opus-5 | `opus` | βœ“ |
| Opus 5.1 | anthropic:claude-opus-5-1 | `opus` | βœ“ |
| Sonnet 5 | anthropic:claude-sonnet-5 | `sonnet` | |
| Haiku 4.5 | anthropic:claude-haiku-4-5 | `haiku` | |
| GPT-5.6 Sol | openai:gpt-5.6-sol | `gpt`, `sol` | |
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/github-actions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ jobs:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
bunx @coder/xum@next run \
--model anthropic:claude-opus-5 \
--model anthropic:claude-opus-5-1 \
--thinking xhigh \
< .github/prompts/auto-cleanup.md
```
Expand Down
4 changes: 2 additions & 2 deletions src/browser/features/ChatInput/useCreationWorkspace.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,7 @@ describe("useCreationWorkspace", () => {
});
expect(onWorkspaceCreated.mock.calls[0][1]).toEqual({
autoNavigate: true,
pendingStreamModel: "anthropic:claude-opus-5",
pendingStreamModel: "anthropic:claude-opus-5-1",
markPendingInitialSend: false,
});
});
Expand Down Expand Up @@ -1838,7 +1838,7 @@ describe("useCreationWorkspace", () => {
expect(onWorkspaceCreated.mock.calls.length).toBe(1);
expect(onWorkspaceCreated.mock.calls[0][1]).toEqual({
autoNavigate: true,
pendingStreamModel: "anthropic:claude-opus-5",
pendingStreamModel: "anthropic:claude-opus-5-1",
markPendingInitialSend: true,
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/cli/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ describe("xum CLI", () => {
test("shows default model as opus", async () => {
const result = await runCli(["run", "--help"]);
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain("anthropic:claude-opus-5");
expect(result.stdout).toContain("anthropic:claude-opus-5-1");
});

test("--service-tier has no default auto", async () => {
Expand Down
7 changes: 7 additions & 0 deletions src/common/config/schemas/appConfigOnDisk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ export const AppConfigMigrationsSchema = z
* source key.
*/
defaultModelFallbacksSeededFable51: z.boolean().optional(),
/**
* One-time chain-target migration after the opus alias moved to Opus 5.1:
* chains still exactly equal to the superseded shipped default
* (Fable 5.1 β†’ Opus 5) move to the current default (Fable 5.1 β†’ Opus 5.1);
* any user-edited chain is left untouched.
*/
defaultModelFallbacksSeededOpus51: z.boolean().optional(),
/** One-time migration from the legacy auto-delete default to persistent sub-agents. */
persistentSubagentsDefaulted: z.boolean().optional(),
})
Expand Down
16 changes: 15 additions & 1 deletion src/common/constants/knownModels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
*/

import { describe, test, expect } from "@jest/globals";
import { KNOWN_MODELS, MODEL_ABBREVIATIONS } from "@/common/constants/knownModels";
import {
KNOWN_MODELS,
MODEL_ABBREVIATIONS,
TOKENIZER_MODEL_OVERRIDES,
} from "@/common/constants/knownModels";
import modelsJson from "@/common/utils/tokens/models.json";
import { findMissingKnownModels } from "@/common/utils/tokens/updateModelsData";

Expand All @@ -19,6 +23,16 @@ describe("Known Models Integration", () => {
}
});

test("opus alias tracks Opus 5.1 and retired ids keep tokenizer overrides", () => {
expect(MODEL_ABBREVIATIONS.opus).toBe("anthropic:claude-opus-5-1");
expect(KNOWN_MODELS.OPUS.id).toBe("anthropic:claude-opus-5-1");
// Exact-id lookup for retired-but-documented custom model strings must keep
// resolving to the Opus 4.5 approximation instead of falling back (with a
// warning) to the generic per-provider tokenizer.
expect(TOKENIZER_MODEL_OVERRIDES["anthropic:claude-opus-5"]).toBe("anthropic/claude-opus-4.5");
expect(TOKENIZER_MODEL_OVERRIDES[KNOWN_MODELS.OPUS.id]).toBe("anthropic/claude-opus-4.5");
});

test("gemini-flash resolves to the stable Gemini 3.7 Flash model", () => {
expect(MODEL_ABBREVIATIONS["gemini-flash"]).toBe("google:gemini-3.7-flash");
});
Expand Down
11 changes: 6 additions & 5 deletions src/common/constants/knownModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ const MODEL_DEFINITIONS = {
// approximate counting; real usage can run ~1.0-1.3x higher.
tokenizerOverride: "anthropic/claude-opus-4.5",
},
// Claude Opus 5 - released July 24, 2026. Successor to Opus 4.8 at the same pricing
// ($5/M input, $25/M output). API id `claude-opus-5`; Opus 4.8 stays usable as the
// custom model string `anthropic:claude-opus-4-8`.
// Claude Opus 5.1 - successor to Opus 5 (released July 24, 2026) at unchanged pricing
// ($5/M input, $25/M output). API id `claude-opus-5-1`; Opus 5 stays usable as the
// custom model string `anthropic:claude-opus-5`.
OPUS: {
provider: "anthropic",
providerModelId: "claude-opus-5",
providerModelId: "claude-opus-5-1",
aliases: ["opus"],
warm: true,
// Opus 5 uses the newer Opus 4.7+ tokenizer (~30% more tokens for the same text),
// Opus 5.1 uses the newer Opus 4.7+ tokenizer (~30% more tokens for the same text),
// which isn't published upstream; reuse Opus 4.5 for approximate counting. Real
// usage can run ~1.0-1.3x higher than this estimate (same situation as FABLE above).
tokenizerOverride: "anthropic/claude-opus-4.5",
Expand Down Expand Up @@ -280,6 +280,7 @@ export const MODEL_ABBREVIATIONS: Record<string, string> = Object.fromEntries(
// lookup does not fall back to the generic per-provider tokenizer.
const LEGACY_TOKENIZER_MODEL_OVERRIDES: Record<string, string> = {
"anthropic:claude-fable-5": "anthropic/claude-opus-4.5",
"anthropic:claude-opus-5": "anthropic/claude-opus-4.5",
"anthropic:claude-opus-4-8": "anthropic/claude-opus-4.5",
};

Expand Down
1 change: 1 addition & 0 deletions src/common/utils/ai/modelDisplay.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe("formatCompactModelDisplayName", () => {

test("falls back to the full display name when no shorter label is clearer", () => {
expect(formatCompactModelDisplayName("claude-opus-5")).toBe("Opus 5");
expect(formatCompactModelDisplayName("claude-opus-5-1")).toBe("Opus 5.1");
expect(formatCompactModelDisplayName("gpt-5.3-codex-spark")).toBe("Spark 5.3");
});
});
Expand Down
24 changes: 22 additions & 2 deletions src/common/utils/ai/modelFallbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export const MODEL_FALLBACK_CHAIN_LIMIT = 3;
*
* Seeded into the config exactly once, guarded by
* migrations.defaultModelFallbacksSeeded (plus the one-shot
* defaultModelFallbacksSeededFable51 re-seed for the key move to Fable 5.1)
* defaultModelFallbacksSeededFable51 re-seed for the key move to Fable 5.1,
* and the one-shot defaultModelFallbacksSeededOpus51 target migration for the
* Opus 5.1 promotion, see SUPERSEDED_DEFAULT_MODEL_FALLBACKS)
* β€” on versions that know the flag,
* user edits or deletions of these chains are never overridden by updates.
* (Versions predating the flag strip it on save, so a downgrade→save→
Expand All @@ -37,14 +39,32 @@ export const DEFAULT_MODEL_FALLBACKS: ModelFallbacks = {
* refusal fallback intact.
*/
export const LEGACY_DEFAULT_MODEL_FALLBACKS: ModelFallbacks = {
"anthropic:claude-fable-5": { models: [KNOWN_MODELS.OPUS.id] },
// Target pinned to the literal Opus 5 id (not KNOWN_MODELS.OPUS.id): this
// chain exists for downgraded pre-5.1 builds, whose own shipped default was
// Fable 5 β†’ Opus 5. Pinning keeps the seeded bytes identical no matter which
// build ran the original seed pass.
"anthropic:claude-fable-5": { models: ["anthropic:claude-opus-5"] },
};

/**
* Shipped defaults superseded by the Opus 5.1 promotion, keyed like
* DEFAULT_MODEL_FALLBACKS. Guarded by migrations.defaultModelFallbacksSeededOpus51,
* config load rewrites a chain to the current default exactly once IF the stored
* entry still deep-equals the superseded default (same single-model chain, no
* enabled/triggers customization). Any deviation is user intent and is never
* touched; the legacy `anthropic:claude-fable-5` chain is deliberately not
* migrated so downgraded builds keep their expected bytes on disk.
*/
export const SUPERSEDED_DEFAULT_MODEL_FALLBACKS: ModelFallbacks = {
[KNOWN_MODELS.FABLE.id]: { models: ["anthropic:claude-opus-5"] },
};
// Deep-freeze: entries are spread by reference into live configs (fresh-install
// defaults, seed merge). Accidental in-place mutation must crash fast instead
// of silently corrupting the process-wide default.
for (const entry of [
...Object.values(Object.freeze(DEFAULT_MODEL_FALLBACKS)),
...Object.values(Object.freeze(LEGACY_DEFAULT_MODEL_FALLBACKS)),
...Object.values(Object.freeze(SUPERSEDED_DEFAULT_MODEL_FALLBACKS)),
]) {
Object.freeze(entry);
Object.freeze(entry.models);
Expand Down
8 changes: 7 additions & 1 deletion src/common/utils/ai/models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,15 @@ describe("Anthropic 1M context classification", () => {
expect(hasNative1MContext("anthropic:claude-sonnet-4-5")).toBe(false);
});

it("treats Opus 4.6 to 4.8, Opus 5, and Sonnet 4.6 as native 1M models", () => {
it("treats Opus 4.6 to 4.8, Opus 5, Opus 5.1, and Sonnet 4.6 as native 1M models", () => {
expect(getAnthropic1MContextMode("anthropic:claude-opus-5")).toBe("native");
expect(getAnthropic1MContextMode("anthropic:claude-opus-5-20260724")).toBe("native");
// The claude-opus-5 pattern only tolerates date suffixes, so the 5.1 id
// needs (and has) its own pattern.
expect(getAnthropic1MContextMode("anthropic:claude-opus-5-1")).toBe("native");
expect(getAnthropic1MContextMode("mux-gateway:anthropic/claude-opus-5-1")).toBe("native");
expect(hasNative1MContext("anthropic:claude-opus-5-1")).toBe(true);
expect(supports1MContext("anthropic:claude-opus-5-1")).toBe(false);
expect(getAnthropic1MContextMode("anthropic:claude-opus-4-8")).toBe("native");
expect(getAnthropic1MContextMode("anthropic:claude-opus-4-8-20260528")).toBe("native");
expect(getAnthropic1MContextMode("anthropic:claude-opus-4-6")).toBe("native");
Expand Down
1 change: 1 addition & 0 deletions src/common/utils/ai/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ const ANTHROPIC_NATIVE_1M_PATTERNS = [
new RegExp(`^claude-fable-5-1${OPTIONAL_VERSION_SUFFIX}$`, "i"),
new RegExp(`^claude-mythos-5${OPTIONAL_VERSION_SUFFIX}$`, "i"),
new RegExp(`^claude-opus-5${OPTIONAL_VERSION_SUFFIX}$`, "i"),
new RegExp(`^claude-opus-5-1${OPTIONAL_VERSION_SUFFIX}$`, "i"),
new RegExp(`^claude-opus-4-8${OPTIONAL_VERSION_SUFFIX}$`, "i"),
new RegExp(`^claude-opus-4-7${OPTIONAL_VERSION_SUFFIX}$`, "i"),
new RegExp(`^claude-opus-4-6${OPTIONAL_VERSION_SUFFIX}$`, "i"),
Expand Down
7 changes: 6 additions & 1 deletion src/common/utils/ai/providerOptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,12 @@ describe("buildProviderOptions - Anthropic", () => {
// Native-xhigh models (Opus 4.7+ / Sonnet 5+): xhigh is a distinct native
// effort and adaptive thinking requires `display: "summarized"` to return
// thinking content.
for (const model of ["claude-opus-4-7", "claude-opus-5", "claude-sonnet-5"] as const) {
for (const model of [
"claude-opus-4-7",
"claude-opus-5",
"claude-opus-5-1",
"claude-sonnet-5",
] as const) {
describe(`${model} (native xhigh effort + summarized display)`, () => {
for (const { thinking, expectedThinking, effort } of [
{
Expand Down
10 changes: 10 additions & 0 deletions src/common/utils/thinking/policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,16 @@ describe("getThinkingPolicyForModel", () => {
"xhigh",
"max",
]);
// Opus 5.1 rides the same Opus 5+ wildcard: full 6-level ladder, and
// (unlike Mythos-class models) "off" stays available.
expect(getThinkingPolicyForModel("anthropic:claude-opus-5-1")).toEqual([
"off",
"low",
"medium",
"high",
"xhigh",
"max",
]);
expect(getThinkingPolicyForModel("anthropic:claude-opus-5-0")).toEqual([
"off",
"low",
Expand Down
19 changes: 19 additions & 0 deletions src/common/utils/tokens/models-extra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,25 @@ export const modelsExtra: Record<string, ModelData> = {
supports_response_schema: true,
},

// Claude Opus 5.1 - successor to Opus 5 at the same pricing/shape: $5/M input,
// $25/M output, cache write 1.25x input / cache read 0.1x input, native 1M
// context, 128K max output, full effort ladder with native xhigh and max.
"claude-opus-5-1": {
max_input_tokens: 1000000,
max_output_tokens: 128000,
input_cost_per_token: 0.000005, // $5 per million input tokens
output_cost_per_token: 0.000025, // $25 per million output tokens
cache_creation_input_token_cost: 0.00000625, // $6.25 per million tokens (1.25Γ— input)
cache_read_input_token_cost: 0.0000005, // $0.50 per million tokens (0.1Γ— input)
litellm_provider: "anthropic",
mode: "chat",
supports_function_calling: true,
supports_vision: true,
supports_pdf_input: true,
supports_reasoning: true,
supports_response_schema: true,
},

// Claude Opus 5 - Released July 24, 2026
// Same pricing/shape as Opus 4.8: $5/M input, $25/M output, native 1M context
// (both default and maximum), 128K max output, full effort ladder with native
Expand Down
1 change: 1 addition & 0 deletions src/common/utils/tools/tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ describe("supportsAnthropicNativeWebFetch", () => {
["claude-mythos-5", true],
// Two-segment IDs at/after the 4.6 cutoff.
["claude-fable-5-1", true],
["claude-opus-5-1", true],
["claude-sonnet-4-6", true],
["claude-opus-4-6", true],
["claude-opus-4-8", true],
Expand Down
Loading
Loading