FN-7390: add latest Claude CLI models

Expose the latest Claude CLI-callable Anthropic models with corrected supplemental metadata.

- Add Sonnet 5, Fable 5, and Opus 4.8 to the pi-claude-cli supplemental model catalog.
- Update context/output limits for recent Claude 4.x CLI rows.
- Preserve catalog deduplication and assert Fable 5 uses the current 0/0 per MTok pricing.
- Add a patch changeset for the published Fusion CLI package.

Files changed:
 .changeset/fn-7390-claude-cli-latest-models.md     |  7 ++++
 packages/pi-claude-cli/index.ts                    | 40 ++++++++++++++++--
 .../pi-claude-cli/src/__tests__/provider.test.ts   | 47 +++++++++++++++-------
 3 files changed, 76 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-7390

Fusion-Task-Lineage: 54df5de7-c29e-44af-bcb6-9d768103576e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-01 11:59:51 -07:00
parent d7ee6ce87f
commit 3219ced7c1
3 changed files with 76 additions and 18 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Restore Claude Sonnet 5 and latest Anthropic models in the Claude CLI model picker.
category: fix
dev: pi-claude-cli supplemental extraModels now advertises claude-sonnet-5 for the subscription-authenticated CLI surface; direct-Anthropic supplemental registration and static pricing remain withheld per FN-7374's 404 not_found_error handling. Local evidence used claude 2.1.197 with --model accepting aliases/full names; checksum remains upstream-pending-verification.

View File

@@ -193,7 +193,39 @@ export default function (pi: ExtensionAPI) {
/*
* FNXC:ModelCatalog 2026-07-01-18:18:
* Keep Claude CLI supplemental metadata limited to models that Fusion can advertise without triggering the direct-Anthropic Sonnet 5 404 loop. `claude-sonnet-5` must come from the upstream/live registry before this provider shows it, because static metadata cannot prove the current account and CLI surface can call that model.
*
* FNXC:ModelCatalog 2026-07-01-20:37:
* Supersede the prior Claude CLI withholding only for `pi-claude-cli`: the local `claude` subprocess routes through the user's Claude subscription/login and its 2.1.197 `--model` help accepts latest aliases/full names, so the CLI picker should advertise Sonnet 5 and newer CLI-callable rows. Keep direct Anthropic supplemental metadata and static pricing withheld because FN-7374's per-account `404 not_found_error` applies to that API surface, not this subscription-authenticated CLI surface.
*/
{
id: "claude-sonnet-5",
name: "Claude Sonnet 5",
reasoning: true,
input: ["text", "image"],
cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
contextWindow: 1_000_000,
maxTokens: 128_000,
},
{
id: "claude-fable-5",
name: "Claude Fable 5",
reasoning: true,
input: ["text", "image"],
// FNXC:ModelCatalog 2026-07-01-21:04: Fable 5 must use Anthropic's current $10/$50 per MTok row so Fusion's CLI picker does not understate supplemental model cost estimates.
cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 },
contextWindow: 1_000_000,
maxTokens: 128_000,
},
{
id: "claude-opus-4-8",
name: "Claude Opus 4.8",
reasoning: true,
input: ["text", "image"],
// FNXC:ModelCatalog 2026-07-01-20:37: The overview confirms Opus 4.8 context/output limits; mirror the closest current Opus CLI supplemental pricing until a precise per-model price row is pinned for this subscription surface.
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
contextWindow: 1_000_000,
maxTokens: 128_000,
},
{
id: "claude-opus-4-7",
name: "Claude Opus 4.7",
@@ -209,8 +241,8 @@ export default function (pi: ExtensionAPI) {
reasoning: true,
input: ["text", "image"],
cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
contextWindow: 200_000,
maxTokens: 16_384,
contextWindow: 1_000_000,
maxTokens: 64_000,
},
{
id: "claude-sonnet-4-5",
@@ -219,7 +251,7 @@ export default function (pi: ExtensionAPI) {
input: ["text", "image"],
cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
contextWindow: 200_000,
maxTokens: 8_192,
maxTokens: 64_000,
},
{
id: "claude-haiku-4-5",
@@ -228,7 +260,7 @@ export default function (pi: ExtensionAPI) {
input: ["text", "image"],
cost: { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
contextWindow: 200_000,
maxTokens: 8_192,
maxTokens: 64_000,
},
];

View File

@@ -116,7 +116,7 @@ describe("provider registration (default export)", () => {
expect(firstModel.cost).toBeDefined();
});
it("includes supported extra Claude model entries without force-adding Sonnet 5", async () => {
it("includes latest Claude models including Sonnet 5 for the CLI surface", async () => {
const registerProvider = vi.fn();
const mockPi = { registerProvider, on: vi.fn() } as any;
@@ -127,6 +127,9 @@ describe("provider registration (default export)", () => {
const modelIds = new Set(config.models.map((m: { id: string }) => m.id));
for (const id of [
"claude-sonnet-5",
"claude-fable-5",
"claude-opus-4-8",
"claude-opus-4-7",
"claude-sonnet-4-6",
"claude-sonnet-4-5",
@@ -135,30 +138,35 @@ describe("provider registration (default export)", () => {
expect(modelIds.has(id)).toBe(true);
}
expect(modelIds.has("claude-sonnet-5")).toBe(false);
expect(
config.models.find((m: { id: string }) => m.id === "claude-fable-5"),
).toMatchObject({
cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 },
});
});
it("deduplicates extra models when catalog already includes them", async () => {
const registerProvider = vi.fn();
const mockPi = { registerProvider, on: vi.fn() } as any;
const getModelsMock = vi.mocked(getModels);
const upstreamSonnet5 = {
id: "claude-sonnet-5",
name: "Claude Sonnet 5 Upstream",
api: "anthropic",
provider: "anthropic",
reasoning: false,
input: ["text"],
cost: { input: 99, output: 199, cacheRead: 9.9, cacheWrite: 24.75 },
contextWindow: 123_456,
maxTokens: 7_654,
} as any;
getModelsMock.mockReturnValueOnce([
...mockModels,
{
id: "claude-sonnet-5",
name: "Claude Sonnet 5 Upstream",
api: "anthropic",
provider: "anthropic",
reasoning: true,
input: ["text", "image"],
cost: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
contextWindow: 1_000_000,
maxTokens: 128_000,
} as any,
upstreamSonnet5,
{
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6",
name: "Claude Sonnet 4.6 Upstream",
api: "anthropic",
provider: "anthropic",
reasoning: true,
@@ -179,6 +187,17 @@ describe("provider registration (default export)", () => {
);
expect(matches).toHaveLength(1);
}
expect(
config.models.find((m: { id: string }) => m.id === "claude-sonnet-5"),
).toMatchObject({
name: upstreamSonnet5.name,
reasoning: upstreamSonnet5.reasoning,
input: upstreamSonnet5.input,
cost: upstreamSonnet5.cost,
contextWindow: upstreamSonnet5.contextWindow,
maxTokens: upstreamSonnet5.maxTokens,
});
});
});