mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Add Claude Fable 5 to the model catalog (#1443)
* Add Claude Fable 5 to the model catalog
Fable 5 (`claude-fable-5`) is the new top-tier Claude model above Opus,
but the Claude provider's model list is hardcoded in `CLAUDE_MODELS` and
was not fetched dynamically, so it never appeared in the selector.
- Add `claude-fable-5` to `CLAUDE_MODELS` (non-default; Opus 4.8 stays the
default). Uses the Opus extended-thinking effort levels (low/medium/high/
xhigh/max). No `[1m]` variant: Fable 5 is natively 1M context, unlike the
Opus/Sonnet entries whose `[1m]` opts a 200K-default model into 1M.
- Teach `normalizeClaudeRuntimeModelId` the Fable family. Its version is a
single segment (`fable-5`) rather than the `{major}-{minor}` scheme, so it
needs its own match to map dated runtime IDs back to the catalog ID.
- Update the model-list and normalization test expectations, plus the CLI
provider e2e catalog fixture.
Fast Mode is correctly unaffected — its allowlist is Opus 4.6/4.7/4.8 only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Simplify Fable runtime-ID normalization
Drop the unused `[1m]` capture from the Fable match branch. There is no
`claude-fable-5[1m]` catalog entry — Fable 5 is natively 1M context, so
there is no 200K-default model to opt into 1M — which made that path dead
code (and an untested one). Keep the `[-_ ]+` separator class for
consistency with the sibling opus/sonnet/haiku regex right below it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: lumingjun <lumingjun@bytedance.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,11 @@ interface ProviderListRow {
|
||||
}
|
||||
|
||||
const EXPECTED_CLAUDE_MODELS = [
|
||||
{
|
||||
id: "claude-fable-5",
|
||||
model: "Fable 5",
|
||||
descriptionFragment: "Most powerful",
|
||||
},
|
||||
{
|
||||
id: "claude-opus-4-8[1m]",
|
||||
model: "Opus 4.8 1M",
|
||||
|
||||
@@ -408,6 +408,7 @@ describe("ClaudeAgentClient.listModels", () => {
|
||||
const models = await client.listModels({ cwd: "/tmp/claude-models", force: false });
|
||||
|
||||
expect(models.map((m) => m.id)).toEqual([
|
||||
"claude-fable-5",
|
||||
"claude-opus-4-8[1m]",
|
||||
"claude-opus-4-8",
|
||||
"claude-opus-4-7[1m]",
|
||||
|
||||
@@ -35,6 +35,7 @@ describe("getClaudeModels", () => {
|
||||
it("returns all claude models", () => {
|
||||
const models = getClaudeModels();
|
||||
expect(models.map((m) => m.id)).toEqual([
|
||||
"claude-fable-5",
|
||||
"claude-opus-4-8[1m]",
|
||||
"claude-opus-4-8",
|
||||
"claude-opus-4-7[1m]",
|
||||
@@ -179,6 +180,7 @@ describe("ClaudeAgentClient.listModels", () => {
|
||||
|
||||
describe("normalizeClaudeRuntimeModelId", () => {
|
||||
it("returns exact match for known model IDs", () => {
|
||||
expect(normalizeClaudeRuntimeModelId("claude-fable-5")).toBe("claude-fable-5");
|
||||
expect(normalizeClaudeRuntimeModelId("claude-opus-4-6")).toBe("claude-opus-4-6");
|
||||
expect(normalizeClaudeRuntimeModelId("claude-opus-4-6[1m]")).toBe("claude-opus-4-6[1m]");
|
||||
expect(normalizeClaudeRuntimeModelId("claude-sonnet-4-6")).toBe("claude-sonnet-4-6");
|
||||
@@ -186,6 +188,7 @@ describe("normalizeClaudeRuntimeModelId", () => {
|
||||
});
|
||||
|
||||
it("normalizes dated model IDs to base model", () => {
|
||||
expect(normalizeClaudeRuntimeModelId("claude-fable-5-20260301")).toBe("claude-fable-5");
|
||||
expect(normalizeClaudeRuntimeModelId("claude-opus-4-6-20260101")).toBe("claude-opus-4-6");
|
||||
expect(normalizeClaudeRuntimeModelId("claude-sonnet-4-6-20260101")).toBe("claude-sonnet-4-6");
|
||||
expect(normalizeClaudeRuntimeModelId("claude-haiku-4-5-20251001")).toBe("claude-haiku-4-5");
|
||||
|
||||
@@ -21,6 +21,13 @@ const CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS = [
|
||||
] as const;
|
||||
|
||||
const CLAUDE_MODELS: AgentModelDefinition[] = [
|
||||
{
|
||||
provider: "claude",
|
||||
id: "claude-fable-5",
|
||||
label: "Fable 5",
|
||||
description: "Fable 5 · Most powerful model",
|
||||
thinkingOptions: [...CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS],
|
||||
},
|
||||
{
|
||||
provider: "claude",
|
||||
id: "claude-opus-4-8[1m]",
|
||||
@@ -206,6 +213,15 @@ export function normalizeClaudeRuntimeModelId(value: string | null | undefined):
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
// Fable uses a single-segment version (claude-fable-5), not the {major}-{minor}
|
||||
// scheme of opus/sonnet/haiku, so match it separately. This maps dated runtime
|
||||
// strings (e.g. claude-fable-5-20260301) back to the catalog ID. No [1m] variant:
|
||||
// Fable 5 is natively 1M, so there is no 200K-default model to opt into 1M.
|
||||
const fableMatch = trimmed.match(/(?:claude-)?fable[-_ ]+(\d+)/i);
|
||||
if (fableMatch) {
|
||||
return `claude-fable-${fableMatch[1]}`;
|
||||
}
|
||||
|
||||
// Match: claude-{family}-{major}-{minor}[1m]? possibly followed by a date suffix
|
||||
const runtimeMatch = trimmed.match(
|
||||
/(?:claude-)?(opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(\[1m\])?/i,
|
||||
|
||||
Reference in New Issue
Block a user