From 3e59adb4dcea119e2ce281852fd0f6d4afbb8684 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 1 Sep 2026 21:51:51 +0200 Subject: [PATCH] Add Claude Fable 5.1 to the model catalog (#4179) * feat(claude): add Fable 5.1 model Expose the new 1M-context model through the curated Claude catalog and normalize its dated and context-suffixed runtime IDs back to one canonical entry. * fix(claude): group Fable models in catalog * chore(release): cut 0.7.1 * fix(nix): refresh 0.7.1 dependency hash * test(cli): follow package version in plugin scaffold * test(cli): keep Claude catalog checks extensible --- .../android/en-US/changelogs/70011.txt | 4 ++ .../android/en-US/changelogs/70012.txt | 4 ++ .../android/en-US/changelogs/70013.txt | 4 ++ .../android/en-US/changelogs/70014.txt | 4 ++ nix/npm-deps.hash | 2 +- package-lock.json | 54 +++++++++---------- package.json | 2 +- packages/app/package.json | 2 +- packages/cli/package.json | 8 +-- .../cli/src/commands/plugin/scaffold.test.ts | 5 +- packages/cli/tests/15-provider.test.ts | 44 ++++++++------- packages/client/package.json | 6 +-- packages/desktop/package.json | 2 +- packages/expo-two-way-audio/package.json | 2 +- packages/highlight/package.json | 2 +- packages/plugin/package.json | 10 ++-- packages/protocol/package.json | 2 +- packages/relay/package.json | 2 +- packages/server/package.json | 12 ++--- .../agent/providers/claude/agent.test.ts | 2 + .../agent/providers/claude/model-manifest.ts | 25 +++++++-- .../agent/providers/claude/models.test.ts | 27 +++++++++- packages/website/package.json | 2 +- 23 files changed, 143 insertions(+), 84 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/70011.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/70012.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/70013.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/70014.txt diff --git a/fastlane/metadata/android/en-US/changelogs/70011.txt b/fastlane/metadata/android/en-US/changelogs/70011.txt new file mode 100644 index 0000000000..cd7180bd82 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/70011.txt @@ -0,0 +1,4 @@ +Added +- Added Claude Fable 5.1 with a 1M context window + +Full notes: https://paseo.sh/changelog diff --git a/fastlane/metadata/android/en-US/changelogs/70012.txt b/fastlane/metadata/android/en-US/changelogs/70012.txt new file mode 100644 index 0000000000..cd7180bd82 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/70012.txt @@ -0,0 +1,4 @@ +Added +- Added Claude Fable 5.1 with a 1M context window + +Full notes: https://paseo.sh/changelog diff --git a/fastlane/metadata/android/en-US/changelogs/70013.txt b/fastlane/metadata/android/en-US/changelogs/70013.txt new file mode 100644 index 0000000000..cd7180bd82 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/70013.txt @@ -0,0 +1,4 @@ +Added +- Added Claude Fable 5.1 with a 1M context window + +Full notes: https://paseo.sh/changelog diff --git a/fastlane/metadata/android/en-US/changelogs/70014.txt b/fastlane/metadata/android/en-US/changelogs/70014.txt new file mode 100644 index 0000000000..cd7180bd82 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/70014.txt @@ -0,0 +1,4 @@ +Added +- Added Claude Fable 5.1 with a 1M context window + +Full notes: https://paseo.sh/changelog diff --git a/nix/npm-deps.hash b/nix/npm-deps.hash index 9ee12f2b4a..eb791db66e 100644 --- a/nix/npm-deps.hash +++ b/nix/npm-deps.hash @@ -1 +1 @@ -sha256-HFYBrCP62r6ZofazBIGSOnMhk8IIEmv+TFJMpqTIJQ8= +sha256-j3lk7o4W10hcXeNIN3kGlqSHn8aCr+GCDkKYZNXNSrw= diff --git a/package-lock.json b/package-lock.json index 8298bd116d..845c1617d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "paseo", - "version": "0.7.0", + "version": "0.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "paseo", - "version": "0.7.0", + "version": "0.7.1", "hasInstallScript": true, "license": "Apache-2.0", "workspaces": [ @@ -36298,7 +36298,7 @@ }, "packages/app": { "name": "@getpaseo/app", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "@codemirror/commands": "6.10.4", "@codemirror/language": "6.12.4", @@ -37363,12 +37363,12 @@ }, "packages/cli": { "name": "@getpaseo/cli", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "@clack/prompts": "^1.0.0", - "@getpaseo/client": "0.7.0", - "@getpaseo/protocol": "0.7.0", - "@getpaseo/server": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/protocol": "0.7.1", + "@getpaseo/server": "0.7.1", "chalk": "^5.3.0", "commander": "^12.0.0", "mime-types": "^2.1.35", @@ -37615,10 +37615,10 @@ }, "packages/client": { "name": "@getpaseo/client", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { - "@getpaseo/protocol": "0.7.0", - "@getpaseo/relay": "0.7.0", + "@getpaseo/protocol": "0.7.1", + "@getpaseo/relay": "0.7.1", "zod": "^4.4.3" }, "devDependencies": { @@ -37629,7 +37629,7 @@ }, "packages/desktop": { "name": "@getpaseo/desktop", - "version": "0.7.0", + "version": "0.7.1", "license": "Apache-2.0", "dependencies": { "@getpaseo/cli": "*", @@ -37872,7 +37872,7 @@ }, "packages/expo-two-way-audio": { "name": "@getpaseo/expo-two-way-audio", - "version": "0.7.0", + "version": "0.7.1", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.14", @@ -38768,7 +38768,7 @@ }, "packages/highlight": { "name": "@getpaseo/highlight", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "@codemirror/language": "6.12.4", "@codemirror/legacy-modes": "^6.5.3", @@ -38797,13 +38797,13 @@ }, "packages/plugin": { "name": "@getpaseo/plugin", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "use-sync-external-store": "^1.6.0" }, "devDependencies": { - "@getpaseo/client": "0.7.0", - "@getpaseo/protocol": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/protocol": "0.7.1", "@types/node": "^20.9.0", "@types/react": "~19.2.0", "react": "19.1.0", @@ -38812,15 +38812,15 @@ "zod": "^4.4.3" }, "peerDependencies": { - "@getpaseo/client": "0.7.0", - "@getpaseo/protocol": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/protocol": "0.7.1", "react": "19.1.0", "zod": "^4.4.3" } }, "packages/protocol": { "name": "@getpaseo/protocol", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "zod": "^4.4.3" }, @@ -38833,7 +38833,7 @@ }, "packages/relay": { "name": "@getpaseo/relay", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "base64-js": "^1.5.1", "tweetnacl": "^1.0.3", @@ -39051,17 +39051,17 @@ }, "packages/server": { "name": "@getpaseo/server", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "@agentclientprotocol/sdk": "^0.17.1", "@anthropic-ai/claude-agent-sdk": "0.3.246", "@anthropic-ai/sdk": "^0.104.2", "@babel/parser": "^7.29.8", - "@getpaseo/client": "0.7.0", - "@getpaseo/highlight": "0.7.0", - "@getpaseo/plugin": "0.7.0", - "@getpaseo/protocol": "0.7.0", - "@getpaseo/relay": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/highlight": "0.7.1", + "@getpaseo/plugin": "0.7.1", + "@getpaseo/protocol": "0.7.1", + "@getpaseo/relay": "0.7.1", "@isaacs/ttlcache": "^2.1.4", "@modelcontextprotocol/sdk": "1.29.0", "@opencode-ai/sdk": "1.14.46", @@ -39985,7 +39985,7 @@ }, "packages/website": { "name": "@getpaseo/website", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "@cloudflare/vite-plugin": "^1.29.1", "@cloudflare/workers-types": "^4.20260317.1", diff --git a/package.json b/package.json index ff33f4dfb4..f99820234e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "paseo", - "version": "0.7.0", + "version": "0.7.1", "private": true, "description": "Paseo: voice-controlled development environment for local AI coding agents", "keywords": [ diff --git a/packages/app/package.json b/packages/app/package.json index 77cbe9484b..1c25d55947 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/app", - "version": "0.7.0", + "version": "0.7.1", "private": true, "main": "index.ts", "scripts": { diff --git a/packages/cli/package.json b/packages/cli/package.json index b6ce33e99d..4c0f2bbb69 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/cli", - "version": "0.7.0", + "version": "0.7.1", "description": "Paseo CLI - control your AI coding agents from the command line", "bin": { "paseo": "bin/paseo" @@ -28,9 +28,9 @@ }, "dependencies": { "@clack/prompts": "^1.0.0", - "@getpaseo/client": "0.7.0", - "@getpaseo/protocol": "0.7.0", - "@getpaseo/server": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/protocol": "0.7.1", + "@getpaseo/server": "0.7.1", "chalk": "^5.3.0", "commander": "^12.0.0", "mime-types": "^2.1.35", diff --git a/packages/cli/src/commands/plugin/scaffold.test.ts b/packages/cli/src/commands/plugin/scaffold.test.ts index 3a97d5dc25..a565ea7d82 100644 --- a/packages/cli/src/commands/plugin/scaffold.test.ts +++ b/packages/cli/src/commands/plugin/scaffold.test.ts @@ -34,13 +34,16 @@ describe("plugin scaffold", () => { expect(JSON.parse(await readFile(path.join(directory, "paseo-plugin.json"), "utf8"))).toEqual({ id: "hello-plugin", }); + const cliPackageJson = JSON.parse( + await readFile(new URL("../../../package.json", import.meta.url), "utf8"), + ) as { version: string }; expect(JSON.parse(await readFile(path.join(directory, "package.json"), "utf8"))).toEqual({ name: "hello-plugin", private: true, version: "0.0.0", scripts: { typecheck: "tsc --noEmit" }, devDependencies: { - "@getpaseo/plugin": "0.7.0", + "@getpaseo/plugin": cliPackageJson.version, "@tanstack/react-query": "^5.90.11", "@types/react": "~19.2.0", react: "19.1.0", diff --git a/packages/cli/tests/15-provider.test.ts b/packages/cli/tests/15-provider.test.ts index ee2eaaf298..a1d302e9c4 100644 --- a/packages/cli/tests/15-provider.test.ts +++ b/packages/cli/tests/15-provider.test.ts @@ -57,10 +57,15 @@ const EXPECTED_CLAUDE_MODELS = [ model: "Opus 5", descriptionFragment: "Latest release", }, + { + id: "claude-fable-5-1", + model: "Fable 5.1", + descriptionFragment: "Most powerful", + }, { id: "claude-fable-5", model: "Fable 5", - descriptionFragment: "Most powerful", + descriptionFragment: "Previous release", }, { id: "claude-opus-4-8[1m]", @@ -161,18 +166,9 @@ async function runProviderModelsJson(provider: string): Promise } function assertClaudeModels(data: ProviderModel[]): void { - assert.strictEqual( - data.length, - EXPECTED_CLAUDE_CATALOG_MODELS.length, - "claude output should match the current catalog size", - ); - const byId = new Map(data.map((model) => [model.id, model])); - const ids = [...byId.keys()].sort(); - const expectedIds = EXPECTED_CLAUDE_CATALOG_MODELS.map((model) => model.id).sort(); assert.strictEqual(byId.size, data.length, "claude model IDs should be unique"); - assert.deepStrictEqual(ids, expectedIds, "claude IDs should match the current catalog"); for (const expectedModel of EXPECTED_CLAUDE_CATALOG_MODELS) { const actualModel = byId.get(expectedModel.id); @@ -187,6 +183,18 @@ function assertClaudeModels(data: ProviderModel[]): void { `${expectedModel.id} description should mention ${expectedModel.descriptionFragment}`, ); } + + const fable51Index = data.findIndex((model) => model.id === "claude-fable-5-1"); + const fable5Index = data.findIndex((model) => model.id === "claude-fable-5"); + assert.strictEqual( + fable5Index, + fable51Index + 1, + "Fable models should stay adjacent and newest-first", + ); + assert( + !byId.has("claude-fable-5[1m]"), + "compatibility-only Fable aliases should not appear in CLI output", + ); } try { @@ -411,20 +419,10 @@ try { const result = await ctx.paseo(["provider", "models", "claude", "--quiet"]); assert.strictEqual(result.exitCode, 0, "should exit 0"); const lines = result.stdout.trim().split("\n").filter(Boolean); - assert.strictEqual( - lines.length, - EXPECTED_CLAUDE_CATALOG_MODELS.length, - "should have one line per Claude catalog model", - ); assert.deepStrictEqual( - [...lines].sort(), - [...claudeModelIdsFromJson].sort(), - "--quiet should print the same model IDs returned by --json", - ); - assert.deepStrictEqual( - [...lines].sort(), - EXPECTED_CLAUDE_CATALOG_MODELS.map((model) => model.id).sort(), - "--quiet should print the current Claude catalog IDs", + lines, + claudeModelIdsFromJson, + "--quiet should print the same ordered model IDs returned by --json", ); assert( claudeModelsFromJson.some((m) => m.id === "claude-sonnet-5"), diff --git a/packages/client/package.json b/packages/client/package.json index 61972c4a0c..6719583328 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/client", - "version": "0.7.0", + "version": "0.7.1", "description": "Paseo client SDK package", "files": [ "dist", @@ -39,8 +39,8 @@ "test": "vitest run" }, "dependencies": { - "@getpaseo/protocol": "0.7.0", - "@getpaseo/relay": "0.7.0", + "@getpaseo/protocol": "0.7.1", + "@getpaseo/relay": "0.7.1", "zod": "^4.4.3" }, "devDependencies": { diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 77bda4856e..00974d503b 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/desktop", - "version": "0.7.0", + "version": "0.7.1", "private": true, "description": "Paseo desktop app (Electron wrapper)", "homepage": "https://paseo.sh", diff --git a/packages/expo-two-way-audio/package.json b/packages/expo-two-way-audio/package.json index bbc29c31d4..197f9f7139 100644 --- a/packages/expo-two-way-audio/package.json +++ b/packages/expo-two-way-audio/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/expo-two-way-audio", - "version": "0.7.0", + "version": "0.7.1", "description": "Native module for two way audio streaming", "keywords": [ "ExpoTwoWayAudio", diff --git a/packages/highlight/package.json b/packages/highlight/package.json index dcef051db2..f593ada89e 100644 --- a/packages/highlight/package.json +++ b/packages/highlight/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/highlight", - "version": "0.7.0", + "version": "0.7.1", "files": [ "dist", "!dist/**/*.map", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 69b42173a3..5b751f6503 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/plugin", - "version": "0.7.0", + "version": "0.7.1", "description": "Paseo plugin SDK package", "files": [ "dist", @@ -44,8 +44,8 @@ "use-sync-external-store": "^1.6.0" }, "devDependencies": { - "@getpaseo/client": "0.7.0", - "@getpaseo/protocol": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/protocol": "0.7.1", "@types/node": "^20.9.0", "@types/react": "~19.2.0", "react": "19.1.0", @@ -54,8 +54,8 @@ "zod": "^4.4.3" }, "peerDependencies": { - "@getpaseo/client": "0.7.0", - "@getpaseo/protocol": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/protocol": "0.7.1", "react": "19.1.0", "zod": "^4.4.3" } diff --git a/packages/protocol/package.json b/packages/protocol/package.json index 4d64e6cde1..1ed93f7249 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/protocol", - "version": "0.7.0", + "version": "0.7.1", "description": "Paseo shared protocol schemas and wire types", "files": [ "dist", diff --git a/packages/relay/package.json b/packages/relay/package.json index 3b67b762f9..d6fad797c9 100644 --- a/packages/relay/package.json +++ b/packages/relay/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/relay", - "version": "0.7.0", + "version": "0.7.1", "description": "Paseo relay for bridging daemon and client connections", "files": [ "dist", diff --git a/packages/server/package.json b/packages/server/package.json index cddd8357b0..e3ea2f2cd5 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/server", - "version": "0.7.0", + "version": "0.7.1", "description": "Paseo backend server", "files": [ "dist/server", @@ -72,11 +72,11 @@ "@anthropic-ai/claude-agent-sdk": "0.3.246", "@anthropic-ai/sdk": "^0.104.2", "@babel/parser": "^7.29.8", - "@getpaseo/client": "0.7.0", - "@getpaseo/highlight": "0.7.0", - "@getpaseo/plugin": "0.7.0", - "@getpaseo/protocol": "0.7.0", - "@getpaseo/relay": "0.7.0", + "@getpaseo/client": "0.7.1", + "@getpaseo/highlight": "0.7.1", + "@getpaseo/plugin": "0.7.1", + "@getpaseo/protocol": "0.7.1", + "@getpaseo/relay": "0.7.1", "@isaacs/ttlcache": "^2.1.4", "@modelcontextprotocol/sdk": "1.29.0", "@opencode-ai/sdk": "1.14.46", diff --git a/packages/server/src/server/agent/providers/claude/agent.test.ts b/packages/server/src/server/agent/providers/claude/agent.test.ts index 5e860732bc..443518eb60 100644 --- a/packages/server/src/server/agent/providers/claude/agent.test.ts +++ b/packages/server/src/server/agent/providers/claude/agent.test.ts @@ -425,6 +425,7 @@ describe("ClaudeAgentClient.fetchCatalog", () => { expect(models.map((m) => m.id)).toEqual([ "claude-opus-5", + "claude-fable-5-1", "claude-fable-5", "claude-fable-5[1m]", "claude-opus-4-8[1m]", @@ -495,6 +496,7 @@ describe("ClaudeAgentClient.fetchCatalog", () => { }; expect(getThinkingIds("claude-opus-5")).toContain("ultracode"); + expect(getThinkingIds("claude-fable-5-1")).toContain("ultracode"); expect(getThinkingIds("claude-fable-5")).toContain("ultracode"); expect(getThinkingIds("claude-opus-4-8[1m]")).toContain("ultracode"); expect(getThinkingIds("claude-opus-4-8")).toContain("ultracode"); diff --git a/packages/server/src/server/agent/providers/claude/model-manifest.ts b/packages/server/src/server/agent/providers/claude/model-manifest.ts index c51fb70a6d..e7e660a229 100644 --- a/packages/server/src/server/agent/providers/claude/model-manifest.ts +++ b/packages/server/src/server/agent/providers/claude/model-manifest.ts @@ -45,12 +45,19 @@ export const CLAUDE_MODEL_MANIFEST = [ supportsThinkingDisabled: true, supportsFastMode: true, }, + { + id: "claude-fable-5-1", + label: "Fable 5.1", + description: "Fable 5.1 · Most powerful model", + contextWindowMaxTokens: 1_000_000, + effortLevels: CLAUDE_EFFORT_LEVELS.xhigh, + }, { id: "claude-fable-5", // COMPAT(claudeFable5OneMillionId): added in v0.3.0, remove after 2027-02-06 once pre-v0.3.0 app preferences are outside support. aliases: ["claude-fable-5[1m]"], label: "Fable 5", - description: "Fable 5 · Most powerful model", + description: "Fable 5 · Previous release", minimumClaudeCodeVersion: "2.1.169", contextWindowMaxTokens: 1_000_000, effortLevels: CLAUDE_EFFORT_LEVELS.xhigh, @@ -326,7 +333,7 @@ export function normalizeClaudeManifestModelId(value: string | null | undefined) } const runtimeMatch = trimmed.match( - /^(?:claude[-_ ])?(opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(?:\[1m\])?(?:[-_ ]+\d{8})?(?:\[1m\])?$/i, + /^(?:claude[-_ ])?(fable|opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(?:\[1m\])?(?:[-_ ]+\d{8})?(?:\[1m\])?$/i, ); if (!runtimeMatch) { return null; @@ -371,7 +378,7 @@ export function normalizeClaudeRuntimeModelId(value: string | null | undefined): } const runtimeMatch = trimmed.match( - /claude[-_ ](opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(\[1m\])?/i, + /claude[-_ ](fable|opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(\[1m\])?/i, ); if (!runtimeMatch) { return null; @@ -417,6 +424,14 @@ function normalizeMajorMinorClaudeModelId( ): string | null { const family = familyValue.toLowerCase(); const suffix = hasOneMillionContext ? "[1m]" : ""; - const candidate = `claude-${family}-${major}-${minor}${suffix}`; - return isClaudeManifestModelId(candidate) ? candidate : null; + const candidates = [ + `claude-${family}-${major}-${minor}${suffix}`, + `claude-${family}-${major}-${minor}`, + ]; + for (const candidate of candidates) { + if (isClaudeManifestModelId(candidate)) { + return candidate; + } + } + return null; } diff --git a/packages/server/src/server/agent/providers/claude/models.test.ts b/packages/server/src/server/agent/providers/claude/models.test.ts index c379ab998f..9e3cc088bd 100644 --- a/packages/server/src/server/agent/providers/claude/models.test.ts +++ b/packages/server/src/server/agent/providers/claude/models.test.ts @@ -51,6 +51,7 @@ describe("getClaudeModels", () => { const models = getClaudeModels(); expect(models.map((m) => m.id)).toEqual([ "claude-opus-5", + "claude-fable-5-1", "claude-fable-5", "claude-fable-5[1m]", "claude-opus-4-8[1m]", @@ -82,6 +83,7 @@ describe("getClaudeModels", () => { expect(contextWindows).toEqual( new Map([ ["claude-opus-5", 1_000_000], + ["claude-fable-5-1", 1_000_000], ["claude-fable-5", 1_000_000], ["claude-fable-5[1m]", 1_000_000], ["claude-opus-4-8[1m]", 1_000_000], @@ -160,6 +162,9 @@ describe("getClaudeModels", () => { expect(models.get("claude-fable-5")?.thinkingOptions?.map((option) => option.id)).not.toContain( CLAUDE_DISABLED_THINKING_OPTION_ID, ); + expect( + models.get("claude-fable-5-1")?.thinkingOptions?.map((option) => option.id), + ).not.toContain(CLAUDE_DISABLED_THINKING_OPTION_ID); expect(models.get("claude-haiku-4-5")?.thinkingOptions).toBeUndefined(); }); @@ -170,6 +175,7 @@ describe("getClaudeModels", () => { ["claude-sonnet-5[1m]", true, "high"], ["claude-sonnet-5-20260101", true, "high"], ["claude-fable-5", false, "high"], + ["claude-fable-5-1", false, "high"], ["claude-haiku-4-5", false, undefined], ["openrouter/anthropic/claude-opus-4-8", false, undefined], [null, false, undefined], @@ -458,7 +464,7 @@ describe("Claude Opus 5 catalog", () => { describe("Claude Fable 5 catalog", () => { it("offers one selectable Fable 5 entry and a compatibility entry for old apps", () => { const fable5Models = getClaudeModels() - .filter((model) => model.id.startsWith("claude-fable-5")) + .filter((model) => model.id === "claude-fable-5" || model.id === "claude-fable-5[1m]") .map(({ id, aliases, isSelectable, label, contextWindowMaxTokens }) => ({ id, aliases, @@ -491,6 +497,24 @@ describe("Claude Fable 5 catalog", () => { }); }); +describe("Claude Fable 5.1 catalog", () => { + it("offers one Fable 5.1 entry with a 1M context window", () => { + const fable51Models = getClaudeModels() + .filter((model) => model.id.startsWith("claude-fable-5-1")) + .map(({ id, label, contextWindowMaxTokens }) => ({ id, label, contextWindowMaxTokens })); + + expect(fable51Models).toEqual([ + { id: "claude-fable-5-1", label: "Fable 5.1", contextWindowMaxTokens: 1_000_000 }, + ]); + }); + + it("resolves suffixed and dated Fable 5.1 IDs to the catalog entry", () => { + expect(findClaudeModel("claude-fable-5-1[1m]")?.id).toBe("claude-fable-5-1"); + expect(findClaudeModel("claude-fable-5-1-20260901")?.id).toBe("claude-fable-5-1"); + expect(findClaudeModel("claude-fable-5-1-20260901[1m]")?.id).toBe("claude-fable-5-1"); + }); +}); + describe("claudeManifestModelSupportsFastMode", () => { it("keeps fast mode strict to first-party manifest model IDs", () => { expect(normalizeClaudeManifestModelId("openrouter/anthropic/claude-opus-4-8")).toBeNull(); @@ -502,5 +526,6 @@ describe("claudeManifestModelSupportsFastMode", () => { expect(claudeManifestModelSupportsFastMode("claude-opus-5")).toBe(true); expect(claudeManifestModelSupportsFastMode("claude-sonnet-5")).toBe(false); expect(claudeManifestModelSupportsFastMode("claude-fable-5")).toBe(false); + expect(claudeManifestModelSupportsFastMode("claude-fable-5-1")).toBe(false); }); }); diff --git a/packages/website/package.json b/packages/website/package.json index e48455978d..37aec393e9 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "@getpaseo/website", - "version": "0.7.0", + "version": "0.7.1", "private": true, "type": "module", "scripts": {