Add Fable and Sonnet 5 as adaptive reasoning models

This commit is contained in:
Christiaan Arnoldus
2026-07-03 11:50:48 +02:00
parent 4c07a1db51
commit b0f90c00ed
3 changed files with 117 additions and 7 deletions
@@ -126,8 +126,11 @@ function build(key: string, remote: Item, url: string, prev?: Model): Model {
variants[effort] = {
thinking: {
type: "adaptive",
// kilocode_change start - treat opus-4.8 like opus-4.7
...(model.api.id.includes("opus-4.7") || model.api.id.includes("opus-4.8")
// kilocode_change start - treat opus-4.8, fable, and sonnet-5 like opus-4.7
...(model.api.id.includes("opus-4.7") ||
model.api.id.includes("opus-4.8") ||
model.api.id.toLowerCase().includes("fable") ||
/sonnet[.-]5/.test(model.api.id.toLowerCase())
? { display: "summarized" }
: {}),
// kilocode_change end
+12 -5
View File
@@ -614,9 +614,16 @@ function anthropicOpus47OrLater(apiId: string) {
return major > 4 || (major === 4 && minor >= 7)
}
// kilocode_change start - fable and sonnet-5 models are adaptive thinking models like opus-4.7/4.8
function anthropicClaude5(apiId: string) {
const id = apiId.toLowerCase()
return id.includes("fable") || /sonnet[.-]5/.test(id)
}
// kilocode_change end
function anthropicAdaptiveEfforts(apiId: string): string[] | null {
// kilocode_change start - treat opus-4.8 like opus-4.7
if (anthropicOpus47OrLater(apiId)) {
// kilocode_change start - treat opus-4.8 and fable like opus-4.7
if (anthropicOpus47OrLater(apiId) || anthropicClaude5(apiId)) {
return ["low", "medium", "high", "xhigh", "max"]
}
// kilocode_change end
@@ -667,7 +674,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
thinking: { thinking: { type: "adaptive" } },
}
}
const adaptiveOpus = anthropicOpus47OrLater(model.api.id)
const adaptiveOpus = anthropicOpus47OrLater(model.api.id) || anthropicClaude5(model.api.id) // kilocode_change - fable/sonnet-5
const adaptiveEfforts = anthropicAdaptiveEfforts(model.api.id)
if (glm52 && model.api.npm === "@openrouter/ai-sdk-provider") {
// OpenRouter maps xhigh to GLM-5.2's native max effort.
@@ -915,8 +922,8 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
if (adaptiveEfforts) {
let efforts = [...adaptiveEfforts]
if (model.providerID === "github-copilot") {
// kilocode_change start - treat opus-4.8 like opus-4.7
if (model.api.id.includes("opus-4.7") || model.api.id.includes("opus-4.8")) {
// kilocode_change start - treat opus-4.8 and fable like opus-4.7
if (model.api.id.includes("opus-4.7") || model.api.id.includes("opus-4.8") || anthropicClaude5(model.api.id)) {
efforts = ["medium"]
}
// kilocode_change end
@@ -119,6 +119,106 @@ describe("ProviderTransform.variants - Claude Opus 4.7 / 4.8", () => {
})
})
test("fable returns adaptive thinking variants including xhigh (native anthropic)", () => {
const model = mockModel({
api: {
id: "claude-fable-5",
url: "https://api.anthropic.com",
npm: "@ai-sdk/anthropic",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(result.xhigh).toEqual({
thinking: { type: "adaptive", display: "summarized" },
effort: "xhigh",
})
})
test("fable returns adaptive thinking variants via @ai-sdk/gateway", () => {
const model = mockModel({
id: "anthropic/claude-fable-5",
api: {
id: "anthropic/claude-fable-5",
url: "https://gateway.ai",
npm: "@ai-sdk/gateway",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
})
test("fable on bedrock returns adaptive reasoningConfig with xhigh", () => {
const model = mockModel({
api: {
id: "anthropic.claude-fable-5",
url: "https://bedrock.amazonaws.com",
npm: "@ai-sdk/amazon-bedrock",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(result.xhigh).toEqual({
reasoningConfig: { type: "adaptive", maxReasoningEffort: "xhigh", display: "summarized" },
})
})
test("sonnet-5 returns adaptive thinking variants including xhigh (native anthropic)", () => {
const model = mockModel({
api: {
id: "claude-sonnet-5",
url: "https://api.anthropic.com",
npm: "@ai-sdk/anthropic",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(result.xhigh).toEqual({
thinking: { type: "adaptive", display: "summarized" },
effort: "xhigh",
})
})
test("sonnet-5 returns adaptive thinking variants via @ai-sdk/gateway", () => {
const model = mockModel({
id: "anthropic/claude-sonnet-5",
api: {
id: "anthropic/claude-sonnet-5",
url: "https://gateway.ai",
npm: "@ai-sdk/gateway",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
})
test("sonnet-5 on bedrock returns adaptive reasoningConfig with xhigh", () => {
const model = mockModel({
api: {
id: "anthropic.claude-sonnet-5",
url: "https://bedrock.amazonaws.com",
npm: "@ai-sdk/amazon-bedrock",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(result.xhigh).toEqual({
reasoningConfig: { type: "adaptive", maxReasoningEffort: "xhigh", display: "summarized" },
})
})
test("sonnet-4.6 keeps original adaptive efforts without xhigh", () => {
const model = mockModel({
api: {
id: "claude-sonnet-4.6",
url: "https://api.anthropic.com",
npm: "@ai-sdk/anthropic",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "max"])
})
test("opus-4-6 keeps original adaptive efforts without xhigh", () => {
const model = mockModel({
api: {