Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 11 additions & 21 deletions packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,31 +606,21 @@ function openaiCompatibleReasoningEfforts(id: string) {
return gpt5CodexReasoningEfforts(apiId) ?? versionedGpt5ReasoningEfforts(apiId) ?? OPENAI_EFFORTS
}

function anthropicOpus47OrLater(apiId: string) {
// Matches "opus-4.7" (Anthropic/Bedrock/Vertex) and "claude-4.7-opus" (SAP AI Core inverted).
// Greedy \d+ correctly extends to multi-digit majors (e.g. "claude-10.0-opus") for forward compatibility.
const version = /opus-(\d+)[.-](\d+)(?:[.@-]|$)|claude-(\d+)[.-](\d+)-opus(?:[.@-]|$)/i.exec(apiId)
if (!version) return false
const major = Number(version[1] ?? version[3])
const minor = Number(version[2] ?? version[4])
function anthropicUsesModernAdaptiveThinking(apiId: string) {
if (!apiId.toLowerCase().includes("claude-")) return false
// Covers family-first IDs such as claude-opus-4.7 and version-first IDs such as claude-4.7-opus.
// Limit minors to two digits so release dates in IDs such as claude-opus-4-20250514 are not versions.
const version = /claude-(?:[a-z]+-)?(\d+)(?:[.-](\d{1,2}))?(?:[.@-]|$)/i.exec(apiId)
if (!version) return true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Unversioned claude- IDs silently default to "modern adaptive"

When the regex doesn't match at all (!version), the function now returns true instead of the old false. In practice every current test case that reaches this function has a digit somewhere in the id (e.g. claude-fable-5 matches via major=5), so this fallback branch is currently untested. A future unversioned alias for a non-adaptive/legacy Claude model (no digits at all after claude-) would be misclassified as using modern adaptive thinking, which changes request shape (thinking/reasoning params) sent to the provider. Consider either keeping the previous safer default (false) for truly unversioned ids, or add a test that exercises this exact fallback path so a future regression is caught.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

const major = Number(version[1])
const minor = Number(version[2] ?? 0)
return major > 4 || (major === 4 && minor >= 7)
}

// kilocode_change start - Claude 5+ models are adaptive thinking models like opus-4.7/4.8
function anthropicClaude5(apiId: string) {
const id = apiId.toLowerCase()
if (id.includes("fable")) return true
const version = /(?:opus|sonnet)[.-](\d+)(?:[.@-]|$)|claude-(\d+)(?:[.-]\d+)?-(?:opus|sonnet)(?:[.@-]|$)/.exec(id)
return Number(version?.[1] ?? version?.[2]) >= 5
}
// kilocode_change end

function anthropicAdaptiveEfforts(apiId: string): string[] | null {
// kilocode_change start - include Claude 5+ models
if (anthropicOpus47OrLater(apiId) || anthropicClaude5(apiId)) {
if (anthropicUsesModernAdaptiveThinking(apiId)) {
return ["low", "medium", "high", "xhigh", "max"]
}
// kilocode_change end
if (
["opus-4-6", "opus-4.6", "4-6-opus", "4.6-opus", "sonnet-4-6", "sonnet-4.6", "4-6-sonnet", "4.6-sonnet"].some((v) =>
apiId.includes(v),
Expand All @@ -642,7 +632,7 @@ function anthropicAdaptiveEfforts(apiId: string): string[] | null {
}

function anthropicOmitsThinking(apiId: string) {
return anthropicOpus47OrLater(apiId) || anthropicClaude5(apiId) // kilocode_change - include Kilo's Claude 5 aliases
return anthropicUsesModernAdaptiveThinking(apiId)
}

function googleThinkingLevelEfforts(apiId: string) {
Expand Down Expand Up @@ -982,7 +972,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
if (
model.api.id.includes("opus-4.7") ||
model.api.id.includes("opus-4.8") ||
anthropicClaude5(model.api.id)
anthropicUsesModernAdaptiveThinking(model.api.id)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Redundant substring checks now dead code

anthropicUsesModernAdaptiveThinking already returns true for ids containing opus-4.7 / opus-4.8 (major=4, minor>=7), so the explicit model.api.id.includes("opus-4.7") || model.api.id.includes("opus-4.8") checks on the two lines above are now always short-circuited by this call and can be removed for clarity.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

) {
efforts = ["medium"]
}
Expand Down
21 changes: 19 additions & 2 deletions packages/opencode/test/kilocode/transform-opus-4.7.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,14 @@ describe("ProviderTransform.variants - Claude Opus 4.7 / 4.8", () => {
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
})

test("opus-5 on bedrock returns adaptive reasoningConfig with xhigh", () => {
test.each([
"anthropic.claude-opus-5",
"us.anthropic.claude-opus-5-v1:0",
"global.anthropic.claude-opus-5",
])("opus-5 on bedrock returns adaptive reasoningConfig with xhigh for %s", (id) => {
const model = mockModel({
api: {
id: "anthropic.claude-opus-5",
id,
url: "https://bedrock.amazonaws.com",
npm: "@ai-sdk/amazon-bedrock",
},
Expand Down Expand Up @@ -302,4 +306,17 @@ describe("ProviderTransform.variants - Claude Opus 4.7 / 4.8", () => {
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "max"])
})

test("opus-4 release date is not treated as a modern adaptive version", () => {
const model = mockModel({
api: {
id: "claude-opus-4-20250514",
url: "https://api.anthropic.com",
npm: "@ai-sdk/anthropic",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["high", "max"])
expect(result.high).toEqual({ thinking: { type: "enabled", budgetTokens: 16000 } })
})
})
Loading