mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-25 16:51:12 +00:00
fix(anthropic): add Fable 5 to Claude CLI catalog (#101453)
* fix(anthropic): add claude-fable-5 to CLI allowlist, aliases, labels, and context window CLI path was missing claude-fable-5 across all four metadata layers while the direct Anthropic provider path in register.runtime.ts already had full support via isAnthropicFable5Model() / resolveAnthropicFixedContextWindow(). - CLAUDE_CLI_DEFAULT_ALLOWLIST_REFS: add claude-cli/claude-fable-5 - CLAUDE_CLI_MODEL_ALIASES: add fable/fable-5/claude-fable-5 mappings - CLAUDE_CLI_CONTEXT_WINDOWS: add claude-fable-5 -> 1_000_000 (was falling back to 200K) - CLAUDE_CLI_MODEL_LABELS: add Claude Fable 5 (Claude CLI) - resolveClaudeCliImageMediaInput: add fable-5 to 2576 max-side tier Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(anthropic): route fable alias through context/model-ref canonicalization paths * fix(agent): include claude-cli in fable-5/mythos-5 fixed context window resolution * fix(anthropic): add claude-fable-5 to static CLI manifest catalog * test(anthropic): cover fable-5 alias canonicalization in bare and provider-qualified forms * style(anthropic): fix indentation in plugin manifest * fix(anthropic): publish Fable CLI output limit --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import { CLAUDE_CLI_BACKEND_ID, CLAUDE_CLI_MODEL_ALIASES } from "./cli-constants
|
||||
const DEFAULT_CLAUDE_MODEL_BY_FAMILY: Record<string, string> = {
|
||||
opus: "claude-opus-4-8",
|
||||
sonnet: "claude-sonnet-5",
|
||||
fable: "claude-fable-5",
|
||||
haiku: "claude-haiku-4-5",
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { CLAUDE_CLI_BACKEND_ID, CLAUDE_CLI_DEFAULT_ALLOWLIST_REFS } from "./cli-
|
||||
const CLAUDE_CLI_DEFAULT_CONTEXT_WINDOW = 200_000;
|
||||
const CLAUDE_CLI_CONTEXT_WINDOWS: Record<string, number> = {
|
||||
"claude-sonnet-5": 1_000_000,
|
||||
"claude-fable-5": 1_000_000,
|
||||
};
|
||||
const CLAUDE_CLI_DEFAULT_MAX_OUTPUT_TOKENS = 64_000;
|
||||
const CLAUDE_CLI_MAX_OUTPUT_TOKENS: Record<string, number> = {
|
||||
@@ -16,6 +17,7 @@ const CLAUDE_CLI_MAX_OUTPUT_TOKENS: Record<string, number> = {
|
||||
"claude-opus-4-7": 128_000,
|
||||
"claude-opus-4-6": 128_000,
|
||||
"claude-sonnet-5": 128_000,
|
||||
"claude-fable-5": 128_000,
|
||||
"claude-sonnet-4-6": 128_000,
|
||||
};
|
||||
|
||||
@@ -24,12 +26,18 @@ const CLAUDE_CLI_MODEL_LABELS: Record<string, string> = {
|
||||
"claude-opus-4-7": "Claude Opus 4.7 (Claude CLI)",
|
||||
"claude-opus-4-6": "Claude Opus 4.6 (Claude CLI)",
|
||||
"claude-sonnet-5": "Claude Sonnet 5 (Claude CLI)",
|
||||
"claude-fable-5": "Claude Fable 5 (Claude CLI)",
|
||||
"claude-sonnet-4-6": "Claude Sonnet 4.6 (Claude CLI)",
|
||||
};
|
||||
|
||||
function resolveClaudeCliImageMediaInput(id: string): ModelCatalogEntry["mediaInput"] {
|
||||
const maxSidePx =
|
||||
id === "claude-opus-4-8" || id === "claude-opus-4-7" || id === "claude-sonnet-5" ? 2576 : 1568;
|
||||
id === "claude-opus-4-8" ||
|
||||
id === "claude-opus-4-7" ||
|
||||
id === "claude-sonnet-5" ||
|
||||
id === "claude-fable-5"
|
||||
? 2576
|
||||
: 1568;
|
||||
return {
|
||||
image: {
|
||||
maxSidePx,
|
||||
|
||||
@@ -20,6 +20,7 @@ export const CLAUDE_CLI_CANONICAL_DEFAULT_MODEL_REF = `anthropic/${CLAUDE_CLI_CA
|
||||
export const CLAUDE_CLI_DEFAULT_ALLOWLIST_REFS = [
|
||||
CLAUDE_CLI_DEFAULT_MODEL_REF,
|
||||
`${CLAUDE_CLI_BACKEND_ID}/claude-sonnet-5`,
|
||||
`${CLAUDE_CLI_BACKEND_ID}/claude-fable-5`,
|
||||
`${CLAUDE_CLI_BACKEND_ID}/claude-opus-4-7`,
|
||||
`${CLAUDE_CLI_BACKEND_ID}/claude-sonnet-4-6`,
|
||||
`${CLAUDE_CLI_BACKEND_ID}/claude-opus-4-6`,
|
||||
@@ -39,6 +40,9 @@ export const CLAUDE_CLI_MODEL_ALIASES: Record<string, string> = {
|
||||
"claude-sonnet-5": "claude-sonnet-5",
|
||||
"sonnet-4.6": "claude-sonnet-4-6",
|
||||
"claude-sonnet-4-6": "claude-sonnet-4-6",
|
||||
fable: "fable",
|
||||
"fable-5": "claude-fable-5",
|
||||
"claude-fable-5": "claude-fable-5",
|
||||
haiku: "haiku",
|
||||
};
|
||||
|
||||
|
||||
@@ -61,6 +61,20 @@ describe("anthropic Claude model refs", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("canonicalizes fable family aliases in bare and provider-qualified forms", () => {
|
||||
// "fable-5" must map to the full model id, not the family name: the
|
||||
// canonicalizer only accepts alias values that already start with
|
||||
// "claude-", so a family-name value would leave the shorthand unresolved.
|
||||
expect(resolveKnownAnthropicModelRef("fable")).toBe("anthropic/claude-fable-5");
|
||||
expect(resolveKnownAnthropicModelRef("fable-5")).toBe("anthropic/claude-fable-5");
|
||||
expect(resolveKnownAnthropicModelRef("claude-fable-5")).toBe("anthropic/claude-fable-5");
|
||||
expect(resolveKnownAnthropicModelRef("claude-cli/fable")).toBe("anthropic/claude-fable-5");
|
||||
expect(resolveKnownAnthropicModelRef("claude-cli/fable-5")).toBe("anthropic/claude-fable-5");
|
||||
expect(resolveKnownAnthropicModelRef("claude-cli/claude-fable-5")).toBe(
|
||||
"anthropic/claude-fable-5",
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves the current claude-haiku-4-5 model and its bare alias", () => {
|
||||
// claude-haiku-4-5 is a current production model (not retired), so neither
|
||||
// its full ref, its dotted variant, nor the bare "haiku" family alias must
|
||||
@@ -166,14 +180,15 @@ describe("anthropic cli migration", () => {
|
||||
alias: "Opus",
|
||||
agentRuntime: { id: "claude-cli" },
|
||||
},
|
||||
"anthropic/claude-opus-4-8": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-5": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-4-6": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-opus-4-6": {
|
||||
alias: "Opus",
|
||||
agentRuntime: { id: "claude-cli" },
|
||||
},
|
||||
"openai/gpt-5.2": {},
|
||||
"anthropic/claude-opus-4-8": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-5": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-fable-5": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-4-6": { agentRuntime: { id: "claude-cli" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -259,9 +274,10 @@ describe("anthropic cli migration", () => {
|
||||
defaults: {
|
||||
models: {
|
||||
"openai/gpt-5.2": {},
|
||||
"anthropic/claude-opus-4-7": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-opus-4-8": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-5": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-opus-4-7": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-fable-5": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-4-6": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-opus-4-6": { agentRuntime: { id: "claude-cli" } },
|
||||
},
|
||||
@@ -304,9 +320,10 @@ describe("anthropic cli migration", () => {
|
||||
defaults: {
|
||||
model: { primary: "anthropic/claude-opus-4-7" },
|
||||
models: {
|
||||
"anthropic/claude-opus-4-7": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-opus-4-8": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-5": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-opus-4-7": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-fable-5": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-sonnet-4-6": { agentRuntime: { id: "claude-cli" } },
|
||||
"anthropic/claude-opus-4-6": { agentRuntime: { id: "claude-cli" } },
|
||||
},
|
||||
|
||||
@@ -134,6 +134,20 @@ describe("anthropic provider replay hooks", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("publishes Claude Fable 5 CLI metadata without downgrading its API contract", () => {
|
||||
expect(
|
||||
buildClaudeCliCatalogEntries().find((model) => model.id === "claude-fable-5"),
|
||||
).toMatchObject({
|
||||
id: "claude-fable-5",
|
||||
name: "Claude Fable 5 (Claude CLI)",
|
||||
contextWindow: 1_000_000,
|
||||
maxTokens: 128_000,
|
||||
mediaInput: {
|
||||
image: { maxSidePx: 2576, preferredSidePx: 2576, tokenMode: "provider" },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps bare Claude CLI context plan-safe while publishing output limits", () => {
|
||||
const models = buildClaudeCliCatalogEntries();
|
||||
for (const id of [
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"providerCatalogEntry": "./provider-discovery.ts",
|
||||
"modelCatalog": {
|
||||
"runtimeAugment": true,
|
||||
"providers": {
|
||||
"providers": {
|
||||
"claude-cli": {
|
||||
"models": [
|
||||
{
|
||||
@@ -28,6 +28,17 @@
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 128000
|
||||
},
|
||||
{
|
||||
"id": "claude-fable-5",
|
||||
"name": "Claude Fable 5 (Claude CLI)",
|
||||
"reasoning": true,
|
||||
"input": ["text", "image"],
|
||||
"mediaInput": {
|
||||
"image": { "maxSidePx": 2576, "preferredSidePx": 2576, "tokenMode": "provider" }
|
||||
},
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 128000
|
||||
},
|
||||
{
|
||||
"id": "claude-opus-4-8",
|
||||
"name": "Claude Opus 4.8 (Claude CLI)",
|
||||
|
||||
@@ -10,6 +10,8 @@ export const CLAUDE_CLI_CONTEXT_MODEL_ALIASES: Record<string, string> = {
|
||||
"sonnet-5": "claude-sonnet-5",
|
||||
"sonnet-4.6": "claude-sonnet-4-6",
|
||||
"sonnet-4-6": "claude-sonnet-4-6",
|
||||
fable: "claude-fable-5",
|
||||
"fable-5": "claude-fable-5",
|
||||
};
|
||||
|
||||
export function resolveNodeClaudePlacement(params: {
|
||||
|
||||
@@ -197,13 +197,13 @@ export function resolveAnthropicFixedContextWindow(
|
||||
return undefined;
|
||||
}
|
||||
if (
|
||||
(provider === "anthropic" || provider === "anthropic-vertex") &&
|
||||
(provider === "anthropic" || provider === "anthropic-vertex" || provider === "claude-cli") &&
|
||||
/^claude-fable-5(?=$|[^a-z0-9])/.test(modelId)
|
||||
) {
|
||||
return ANTHROPIC_FABLE_CONTEXT_TOKENS;
|
||||
}
|
||||
if (
|
||||
(provider === "anthropic" || provider === "anthropic-vertex") &&
|
||||
(provider === "anthropic" || provider === "anthropic-vertex" || provider === "claude-cli") &&
|
||||
/^claude-mythos-5(?=$|[^a-z0-9])/.test(modelId)
|
||||
) {
|
||||
return ANTHROPIC_MYTHOS_5_CONTEXT_TOKENS;
|
||||
|
||||
@@ -558,8 +558,10 @@ describe("resolveContextTokensForModel", () => {
|
||||
it.each([
|
||||
["anthropic", "claude-fable-5", ANTHROPIC_FABLE_CONTEXT_TOKENS],
|
||||
["anthropic-vertex", "claude-fable-5", ANTHROPIC_FABLE_CONTEXT_TOKENS],
|
||||
["claude-cli", "claude-fable-5", ANTHROPIC_FABLE_CONTEXT_TOKENS],
|
||||
["anthropic", "claude-mythos-5", ANTHROPIC_MYTHOS_5_CONTEXT_TOKENS],
|
||||
["anthropic-vertex", "claude-mythos-5", ANTHROPIC_MYTHOS_5_CONTEXT_TOKENS],
|
||||
["claude-cli", "claude-mythos-5", ANTHROPIC_MYTHOS_5_CONTEXT_TOKENS],
|
||||
["anthropic", "claude-sonnet-5", ANTHROPIC_SONNET_5_CONTEXT_TOKENS],
|
||||
["anthropic-vertex", "claude-sonnet-5", ANTHROPIC_SONNET_5_CONTEXT_TOKENS],
|
||||
["claude-cli", "claude-sonnet-5", ANTHROPIC_SONNET_5_CONTEXT_TOKENS],
|
||||
@@ -697,8 +699,10 @@ describe("resolveContextTokensForModel", () => {
|
||||
it.each([
|
||||
["anthropic", "claude-fable-5", ANTHROPIC_FABLE_CONTEXT_TOKENS],
|
||||
["anthropic-vertex", "claude-fable-5", ANTHROPIC_FABLE_CONTEXT_TOKENS],
|
||||
["claude-cli", "claude-fable-5", ANTHROPIC_FABLE_CONTEXT_TOKENS],
|
||||
["anthropic", "claude-mythos-5", ANTHROPIC_MYTHOS_5_CONTEXT_TOKENS],
|
||||
["anthropic-vertex", "claude-mythos-5", ANTHROPIC_MYTHOS_5_CONTEXT_TOKENS],
|
||||
["claude-cli", "claude-mythos-5", ANTHROPIC_MYTHOS_5_CONTEXT_TOKENS],
|
||||
["anthropic", "claude-sonnet-5", ANTHROPIC_SONNET_5_CONTEXT_TOKENS],
|
||||
["anthropic-vertex", "claude-sonnet-5", ANTHROPIC_SONNET_5_CONTEXT_TOKENS],
|
||||
["claude-cli", "claude-sonnet-5", ANTHROPIC_SONNET_5_CONTEXT_TOKENS],
|
||||
|
||||
Reference in New Issue
Block a user