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
12 changes: 7 additions & 5 deletions site/src/content/docs/features/agent-configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Select a model from the dropdown in the chat header. Available models:
| **Sonnet 4.6** | `sonnet` | Fast and capable |
| **Sonnet 4.6 1M** | `claude-sonnet-4-6[1m]` | Sonnet 4.6 with a 1M context window (extra usage) |
| **Haiku 4.5** | `haiku` | Fastest, most affordable |
| **Fable 5** | `claude-fable-5` | Opus-class model with full effort support, incl. XHigh (200K context) |
| **Fable 5 1M** | `claude-fable-5[1m]` | Fable 5 with a 1M context window |

Earlier-generation models (Opus 4.7, Opus 4.7 1M, Opus 4.6, Opus 4.6 1M, Opus 4.5, Sonnet 4.5, Haiku 3.5) remain selectable in the picker as legacy entries.

Expand Down Expand Up @@ -46,11 +48,11 @@ Control how much reasoning the agent applies to each response:
| Level | Description | Available Models |
|-------|-------------|-----------------|
| **Auto** | Let Claude decide (default) | All models |
| **Low** | Fast, minimal reasoning | Opus, Sonnet |
| **Medium** | Balanced | Opus, Sonnet |
| **High** | Deep reasoning | Opus, Sonnet |
| **XHigh** | Extended reasoning budget | Opus 4.7+ only |
| **Max** | Maximum reasoning budget | Opus and Sonnet (effort-capable models) |
| **Low** | Fast, minimal reasoning | Opus, Sonnet, Fable 5 |
| **Medium** | Balanced | Opus, Sonnet, Fable 5 |
| **High** | Deep reasoning | Opus, Sonnet, Fable 5 |
| **XHigh** | Extended reasoning budget | Opus 4.7+, Fable 5 |
| **Max** | Maximum reasoning budget | Opus, Sonnet, Fable 5 (effort-capable models) |

Select the effort level from the dropdown in the chat header, next to the model selector.

Expand Down
4 changes: 2 additions & 2 deletions site/src/content/docs/features/cli-client.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ Boolean flags are tri-state — pass `--plan` to force on, `--no-plan` to force

| Flag | Values | Effect |
|---|---|---|
| `--model` | `opus`, `sonnet`, `haiku`, `claude-opus-4-8`, ... | Override model for this turn |
| `--model` | `opus`, `sonnet`, `haiku`, `claude-opus-4-8`, `claude-fable-5`, ... | Override model for this turn |
| `--plan` / `--no-plan` | — | Plan mode (read-only until approved) |
| `--thinking` / `--no-thinking` | — | Extended thinking |
| `--fast` / `--no-fast` | — | Fast mode (built-in support: Opus 4.6) |
| `--effort` | `low`, `medium`, `high`, `xhigh`, `max` | Reasoning effort (`xhigh` requires Opus 4.7+) |
| `--effort` | `low`, `medium`, `high`, `xhigh`, `max` | Reasoning effort (`xhigh` requires Opus 4.7+ or Fable 5) |
| `--chrome` / `--no-chrome` | — | Chrome browser tool |
| `--disable-1m-context` | — | Suppress Max-plan auto-upgrade to a 1M context window |
| `--permission` | `default`, `acceptEdits`, `bypassPermissions` | Permission level |
Expand Down
2 changes: 1 addition & 1 deletion site/src/content/docs/features/settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Default values applied to all new agent sessions. Per-workspace overrides are av

| Setting | Description | Default |
|---------|-------------|---------|
| Default model | Model for new chats (Opus 4.8 1M, Opus 4.8, Sonnet 4.6, Sonnet 4.6 1M, Haiku 4.5; older models such as Opus 4.7 / 4.6 / 4.5 remain selectable behind the picker's "More" disclosure) | — |
| Default model | Model for new chats (Opus 4.8 1M, Opus 4.8, Sonnet 4.6, Sonnet 4.6 1M, Haiku 4.5, Fable 5, Fable 5 1M; older models such as Opus 4.7 / 4.6 / 4.5 remain selectable behind the picker's "More" disclosure) | — |
| Default effort / Codex intelligence | Claude models use effort levels (`auto`, `low`, `medium`, `high`, `xhigh`, `max` where supported). Codex uses intelligence levels (`low`, `medium`, `high`, `xhigh`). | Auto / High |
| Default thinking | Enable extended thinking for Claude models. Codex does not expose a reasoning on/off toggle; use Codex intelligence instead. | Off |
| Show thinking / reasoning blocks | Display Claude thinking blocks or Codex reasoning summaries in the chat UI. | Off |
Expand Down
2 changes: 1 addition & 1 deletion src-cli/src/commands/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ pub enum Action {
#[arg(long = "no-fast", overrides_with = "fast", hide = true)]
no_fast: bool,
/// Effort level: `low`, `medium`, `high`, `xhigh`, `max`
/// (`xhigh` requires Opus 4.7+).
/// (`xhigh` requires Opus 4.7+ or Fable 5).
#[arg(long)]
effort: Option<String>,
/// Enable Chrome browser mode for this session. Pair: `--no-chrome`
Expand Down
20 changes: 20 additions & 0 deletions src/ui/src/components/chat/modelCapabilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ describe("isFastSupported", () => {
expect(isFastSupported("claude-opus-4-7")).toBe(false);
});

it("returns false for claude-fable-5 (Opus-class but fast is Opus-4.6-only)", () => {
expect(isFastSupported("claude-fable-5")).toBe(false);
});

it("returns false for sonnet", () => {
expect(isFastSupported("sonnet")).toBe(false);
});
Expand All @@ -36,6 +40,14 @@ describe("isEffortSupported", () => {
expect(isEffortSupported("claude-opus-4-8")).toBe(true);
});

it("returns true for claude-fable-5", () => {
expect(isEffortSupported("claude-fable-5")).toBe(true);
});

it("returns true for claude-fable-5[1m]", () => {
expect(isEffortSupported("claude-fable-5[1m]")).toBe(true);
});

it("returns true for claude-opus-4-7", () => {
expect(isEffortSupported("claude-opus-4-7")).toBe(true);
});
Expand Down Expand Up @@ -74,6 +86,10 @@ describe("isXhighEffortAllowed", () => {
expect(isXhighEffortAllowed("claude-opus-4-8")).toBe(true);
});

it("returns true for claude-fable-5", () => {
expect(isXhighEffortAllowed("claude-fable-5")).toBe(true);
});

it("returns true for claude-opus-4-7", () => {
expect(isXhighEffortAllowed("claude-opus-4-7")).toBe(true);
});
Expand Down Expand Up @@ -104,6 +120,10 @@ describe("isMaxEffortAllowed", () => {
expect(isMaxEffortAllowed("claude-opus-4-8")).toBe(true);
});

it("returns true for claude-fable-5", () => {
expect(isMaxEffortAllowed("claude-fable-5")).toBe(true);
});

it("returns true for claude-opus-4-7", () => {
expect(isMaxEffortAllowed("claude-opus-4-7")).toBe(true);
});
Expand Down
8 changes: 4 additions & 4 deletions src/ui/src/components/chat/modelCapabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
const FAST_SUPPORTED_MODELS = new Set(["claude-opus-4-6", "claude-opus-4-6[1m]"]);

/** Models that support effort levels. */
const EFFORT_SUPPORTED_MODELS = new Set(["opus", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-7[1m]", "claude-opus-4-6", "claude-opus-4-6[1m]", "sonnet", "claude-sonnet-4-6[1m]"]);
const EFFORT_SUPPORTED_MODELS = new Set(["opus", "claude-opus-4-8", "claude-fable-5", "claude-fable-5[1m]", "claude-opus-4-7", "claude-opus-4-7[1m]", "claude-opus-4-6", "claude-opus-4-6[1m]", "sonnet", "claude-sonnet-4-6[1m]"]);

/** Models that support the "xhigh" effort level (Opus 4.7+ only). */
const XHIGH_EFFORT_MODELS = new Set(["opus", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-7[1m]"]);
/** Models that support the "xhigh" effort level (Opus 4.7+ and Fable 5). */
const XHIGH_EFFORT_MODELS = new Set(["opus", "claude-opus-4-8", "claude-fable-5", "claude-fable-5[1m]", "claude-opus-4-7", "claude-opus-4-7[1m]"]);

/** Models that support the "max" effort level. */
const MAX_EFFORT_MODELS = new Set(["opus", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-7[1m]", "claude-opus-4-6", "claude-opus-4-6[1m]", "sonnet", "claude-sonnet-4-6[1m]"]);
const MAX_EFFORT_MODELS = new Set(["opus", "claude-opus-4-8", "claude-fable-5", "claude-fable-5[1m]", "claude-opus-4-7", "claude-opus-4-7[1m]", "claude-opus-4-6", "claude-opus-4-6[1m]", "sonnet", "claude-sonnet-4-6[1m]"]);

export function isFastSupported(model: string): boolean {
return FAST_SUPPORTED_MODELS.has(model);
Expand Down
1 change: 1 addition & 0 deletions src/ui/src/components/chat/modelRegistry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe("modelRegistry", () => {
describe("get1mFallback", () => {
it("maps 1M models to their 200K equivalents", () => {
expect(get1mFallback("opus")).toBe("claude-opus-4-8");
expect(get1mFallback("claude-fable-5[1m]")).toBe("claude-fable-5");
expect(get1mFallback("claude-opus-4-7[1m]")).toBe("claude-opus-4-7");
expect(get1mFallback("claude-sonnet-4-6[1m]")).toBe("sonnet");
expect(get1mFallback("claude-opus-4-6[1m]")).toBe("claude-opus-4-6");
Expand Down
7 changes: 7 additions & 0 deletions src/ui/src/components/chat/modelRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export function is1mContextModel(modelId: string): boolean {

const NON_1M_FALLBACKS: Record<string, string> = {
"opus": "claude-opus-4-8",
"claude-fable-5[1m]": "claude-fable-5",
"claude-opus-4-7[1m]": "claude-opus-4-7",
"claude-sonnet-4-6[1m]": "sonnet",
"claude-opus-4-6[1m]": "claude-opus-4-6",
Expand All @@ -80,6 +81,12 @@ export const MODELS: readonly Model[] = [
{ id: "sonnet", label: "Sonnet 4.6", group: "Claude Code", extraUsage: false, contextWindowTokens: 200_000 },
{ id: "claude-sonnet-4-6[1m]", label: "Sonnet 4.6 1M", group: "Claude Code", extraUsage: true, contextWindowTokens: 1_000_000 },
{ id: "haiku", label: "Haiku 4.5", group: "Claude Code", extraUsage: false, contextWindowTokens: 200_000 },
// Fable 5 is an Opus-class Anthropic model (effort incl. xhigh/max, 1M variant).
// It has no bare alias — the concrete id carries through to the Claude CLI `--model`
// arg and passes the `claude-` prefix gate in `gateway_translate.rs`. The 1M variant
// uses the `[1m]` suffix convention so `is1mContextModel` detects it without a special case.
{ id: "claude-fable-5", label: "Fable 5", group: "Claude Code", extraUsage: false, contextWindowTokens: 200_000 },
{ id: "claude-fable-5[1m]", label: "Fable 5 1M", group: "Claude Code", extraUsage: false, contextWindowTokens: 1_000_000 },
{ id: "claude-opus-4-7", label: "Opus 4.7", group: "Claude Code", extraUsage: false, legacy: true, contextWindowTokens: 200_000 },
{ id: "claude-opus-4-7[1m]", label: "Opus 4.7 1M", group: "Claude Code", extraUsage: false, legacy: true, contextWindowTokens: 1_000_000 },
{ id: "claude-opus-4-6", label: "Opus 4.6", group: "Claude Code", extraUsage: false, legacy: true, contextWindowTokens: 200_000 },
Expand Down
2 changes: 1 addition & 1 deletion src/ui/src/components/command-palette/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ export function buildEffortCommands(
{ id: "low", label: "Low", description: "Fast, minimal reasoning" },
{ id: "medium", label: "Medium", description: "Balanced" },
{ id: "high", label: "High", description: "Deep reasoning" },
{ id: "xhigh", label: "Extra High", description: "Extended reasoning (Opus 4.7+)" },
{ id: "xhigh", label: "Extra High", description: "Extended reasoning (Opus 4.7+, Fable 5)" },
{ id: "max", label: "Max", description: "Full budget" },
];
const levels = !isEffortSupported(selectedModel)
Expand Down
19 changes: 19 additions & 0 deletions src/usage/pricing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ const PRICING_TABLE: &[(&str, ModelPricing)] = &[
},
),
// -- Anthropic (only used when local-aggregating, e.g. via Pi) -----
// Fable 5 is priced at 2x Opus. The `[1m]` variant matches this same
// prefix via `starts_with`, so a single entry covers both ids.
(
"claude-fable-5",
ModelPricing {
prompt_per_mtok_usd: 30.00,
completion_per_mtok_usd: 150.00,
},
),
(
"claude-opus-4-8",
ModelPricing {
Expand Down Expand Up @@ -147,6 +156,16 @@ mod tests {
assert!((p.prompt_per_mtok_usd - 1.25).abs() < f64::EPSILON);
}

#[test]
fn lookup_fable_5_priced_at_2x_opus() {
let p = lookup("claude-fable-5").expect("claude-fable-5 has pricing");
assert!((p.prompt_per_mtok_usd - 30.00).abs() < f64::EPSILON);
assert!((p.completion_per_mtok_usd - 150.00).abs() < f64::EPSILON);
// The 1M variant shares the bare prefix via `starts_with`.
let one_m = lookup("claude-fable-5[1m]").expect("1M variant resolves to same pricing");
assert!((one_m.prompt_per_mtok_usd - 30.00).abs() < f64::EPSILON);
}

#[test]
fn lookup_handles_provider_prefix() {
// Pi qualifies model ids as `<provider>/<id>`; the table is
Expand Down
Loading