mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
feat(ai): add Claude Fable 5 metadata
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added Claude Fable 5 to Anthropic and Amazon Bedrock model metadata, with adaptive thinking and `xhigh` effort support.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Amazon Bedrock inference profile ARN region resolution to prefer the ARN's embedded region over `AWS_REGION` ([#5527](https://github.com/earendil-works/pi/pull/5527) by [@AJM10565](https://github.com/AJM10565)).
|
||||
|
||||
@@ -232,7 +232,8 @@ function isAnthropicAdaptiveThinkingModel(modelId: string): boolean {
|
||||
modelId.includes("opus-4-8") ||
|
||||
modelId.includes("opus-4.8") ||
|
||||
modelId.includes("sonnet-4-6") ||
|
||||
modelId.includes("sonnet-4.6")
|
||||
modelId.includes("sonnet-4.6") ||
|
||||
modelId.includes("fable-5")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -294,6 +295,12 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
|
||||
) {
|
||||
mergeThinkingLevelMap(model, { xhigh: "xhigh" });
|
||||
}
|
||||
if (
|
||||
(model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") &&
|
||||
model.id.includes("fable-5")
|
||||
) {
|
||||
mergeThinkingLevelMap(model, { xhigh: "xhigh" });
|
||||
}
|
||||
if (model.api === "anthropic-messages" && isAnthropicAdaptiveThinkingModel(model.id)) {
|
||||
mergeAnthropicMessagesCompat(model, { forceAdaptiveThinking: true });
|
||||
}
|
||||
|
||||
@@ -528,13 +528,18 @@ function getModelMatchCandidates(modelId: string, modelName?: string): string[]
|
||||
function supportsAdaptiveThinking(modelId: string, modelName?: string): boolean {
|
||||
const candidates = getModelMatchCandidates(modelId, modelName);
|
||||
return candidates.some(
|
||||
(s) => s.includes("opus-4-6") || s.includes("opus-4-7") || s.includes("opus-4-8") || s.includes("sonnet-4-6"),
|
||||
(s) =>
|
||||
s.includes("opus-4-6") ||
|
||||
s.includes("opus-4-7") ||
|
||||
s.includes("opus-4-8") ||
|
||||
s.includes("sonnet-4-6") ||
|
||||
s.includes("fable-5"),
|
||||
);
|
||||
}
|
||||
|
||||
function supportsNativeXhighEffort(model: Model<"bedrock-converse-stream">): boolean {
|
||||
const candidates = getModelMatchCandidates(model.id, model.name);
|
||||
return candidates.some((s) => s.includes("opus-4-7") || s.includes("opus-4-8"));
|
||||
return candidates.some((s) => s.includes("opus-4-7") || s.includes("opus-4-8") || s.includes("fable-5"));
|
||||
}
|
||||
|
||||
function mapThinkingLevelToEffort(
|
||||
|
||||
@@ -200,7 +200,7 @@ export interface AnthropicOptions extends StreamOptions {
|
||||
* Effort level for adaptive thinking models.
|
||||
* Controls how much thinking Claude allocates:
|
||||
* - "max": Always thinks with no constraints (Opus 4.6 only)
|
||||
* - "xhigh": Highest reasoning level (Opus 4.7)
|
||||
* - "xhigh": Highest reasoning level (Opus 4.7+, Fable 5)
|
||||
* - "high": Always thinks, deep reasoning
|
||||
* - "medium": Moderate thinking, may skip for simple queries
|
||||
* - "low": Minimal thinking, skips for simple tasks
|
||||
@@ -711,7 +711,7 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
|
||||
|
||||
/**
|
||||
* Map ThinkingLevel to Anthropic effort levels for adaptive thinking.
|
||||
* Note: effort "max" is only valid on Opus 4.6, while Opus 4.7 supports "xhigh".
|
||||
* Note: effort "max" is only valid on Opus 4.6, while Opus 4.7+ and Fable 5 support "xhigh".
|
||||
*/
|
||||
function mapThinkingLevelToEffort(
|
||||
model: Model<"anthropic-messages">,
|
||||
|
||||
@@ -83,6 +83,13 @@ describe("Anthropic forceAdaptiveThinking compat override", () => {
|
||||
expect(payload.output_config).toEqual({ effort: "medium" });
|
||||
});
|
||||
|
||||
it("uses adaptive thinking with native xhigh effort for Claude Fable 5", async () => {
|
||||
const payload = await capturePayload(getModel("anthropic", "claude-fable-5"), { reasoning: "xhigh" });
|
||||
|
||||
expect(payload.thinking).toEqual({ type: "adaptive", display: "summarized" });
|
||||
expect(payload.output_config).toEqual({ effort: "xhigh" });
|
||||
});
|
||||
|
||||
it("allows built-in adaptive models to opt out with compat.forceAdaptiveThinking false", async () => {
|
||||
const model: Model<"anthropic-messages"> = {
|
||||
...getModel("anthropic", "claude-opus-4-8"),
|
||||
|
||||
@@ -83,6 +83,25 @@ describe("Bedrock thinking payload", () => {
|
||||
expect(payload.additionalModelRequestFields?.anthropic_beta).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses adaptive thinking for Claude Fable 5 when reasoning is enabled", async () => {
|
||||
const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5");
|
||||
|
||||
const payload = await capturePayload(model);
|
||||
|
||||
expect(payload.additionalModelRequestFields?.thinking).toEqual({ type: "adaptive", display: "summarized" });
|
||||
expect(payload.additionalModelRequestFields?.output_config).toEqual({ effort: "high" });
|
||||
expect(payload.additionalModelRequestFields?.anthropic_beta).toBeUndefined();
|
||||
});
|
||||
|
||||
it("maps xhigh reasoning to effort=xhigh for Claude Fable 5", async () => {
|
||||
const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5");
|
||||
|
||||
const payload = await capturePayload(model, { reasoning: "xhigh" });
|
||||
|
||||
expect(payload.additionalModelRequestFields?.thinking).toEqual({ type: "adaptive", display: "summarized" });
|
||||
expect(payload.additionalModelRequestFields?.output_config).toEqual({ effort: "xhigh" });
|
||||
});
|
||||
|
||||
it("omits display for GovCloud model ids on non-adaptive Claude thinking", async () => {
|
||||
const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-sonnet-4-5-20250929-v1:0");
|
||||
const model: Model<"bedrock-converse-stream"> = {
|
||||
|
||||
@@ -20,7 +20,13 @@ describe("getSupportedThinkingLevels", () => {
|
||||
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
|
||||
});
|
||||
|
||||
it("does not include xhigh for non-Opus Anthropic models", () => {
|
||||
it("includes xhigh for Anthropic Claude Fable 5 on anthropic-messages API", () => {
|
||||
const model = getModel("anthropic", "claude-fable-5");
|
||||
expect(model).toBeDefined();
|
||||
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
|
||||
});
|
||||
|
||||
it("does not include xhigh for Claude Sonnet 4.5", () => {
|
||||
const model = getModel("anthropic", "claude-sonnet-4-5");
|
||||
expect(model).toBeDefined();
|
||||
expect(getSupportedThinkingLevels(model!)).not.toContain("xhigh");
|
||||
@@ -79,4 +85,10 @@ describe("getSupportedThinkingLevels", () => {
|
||||
expect(model).toBeDefined();
|
||||
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
|
||||
});
|
||||
|
||||
it("includes xhigh for Bedrock Claude Fable 5", () => {
|
||||
const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5");
|
||||
expect(model).toBeDefined();
|
||||
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user