Merge pull request #4131 from code-yeongyu/fix/3563-effort-max-pre-set-clamp

fix(anthropic-effort): clamp pre-set effort=max for constrained providers regardless of variant (fixes #3563)
This commit is contained in:
YeonGyu-Kim
2026-05-18 12:50:26 +09:00
committed by GitHub
2 changed files with 92 additions and 6 deletions
+18 -6
View File
@@ -76,23 +76,35 @@ export function createAnthropicEffortHook() {
const { agent, model, message } = input
if (!model?.modelID || !model?.providerID) return
if (isEffortUnsupportedModel(model.modelID)) return
if (message.variant !== "max") return
if (!isClaudeProvider(model.providerID, model.modelID)) return
if (shouldSkipForInternalAgent(agent?.name)) return
if (output.options.effort !== undefined) return
const opus = isOpusModel(model.modelID)
const constrained = isConstrainedProvider(model.providerID)
if (output.options.effort !== undefined) {
if (output.options.effort === "max" && constrained) {
const clamped = clampVariant("max", opus, constrained)
output.options.effort = clamped
;(message as { variant?: string }).variant = clamped
log("anthropic-effort: clamped pre-set effort max→high", {
sessionID: input.sessionID,
provider: model.providerID,
model: model.modelID,
reason: "constrained-provider",
})
}
return
}
if (message.variant !== "max") return
const clamped = clampVariant(message.variant, opus, constrained)
output.options.effort = clamped
const shouldOverrideMessageVariant = !opus || constrained
if (shouldOverrideMessageVariant) {
// Override the variant so OpenCode doesn't pass "max" to the API.
// Non-Opus models cap at high; Anthropic OAuth (Claude Pro/Max) also
// caps at high even on Opus because the OAuth API only accepts
// low | medium | high.
;(message as { variant?: string }).variant = clamped
log("anthropic-effort: clamped variant max→high", {
sessionID: input.sessionID,
+74
View File
@@ -221,6 +221,80 @@ describe("createAnthropicEffortHook", () => {
})
})
describe("#given pre-set effort via session params — regression for #3563", () => {
it("#given pre-set effort=max + variant=max + github-copilot Opus #when hook runs #then effort and variant are both clamped to high", async () => {
// given
const hook = createAnthropicEffortHook()
const { input, output } = createMockParams({
providerID: "github-copilot",
modelID: "claude-opus-4-7",
variant: "max",
existingOptions: { effort: "max" },
})
// when
await hook["chat.params"](input, output)
// then
expect(output.options.effort).toBe("high")
expect(input.message.variant).toBe("high")
})
it("#given pre-set effort=max + variant=high + github-copilot Opus #when hook runs #then effort and variant are both clamped to high", async () => {
// given — this is the cubic violation case from PR #3608:
// message.variant is NOT "max", but pre-set effort IS "max"
const hook = createAnthropicEffortHook()
const { input, output } = createMockParams({
providerID: "github-copilot",
modelID: "claude-opus-4-7",
variant: "high",
existingOptions: { effort: "max" },
})
// when
await hook["chat.params"](input, output)
// then — constrained provider must clamp pre-set effort=max regardless of variant
expect(output.options.effort).toBe("high")
expect(input.message.variant).toBe("high")
})
it("#given pre-set effort=max + non-constrained Opus #when hook runs #then effort stays max", async () => {
// given — anthropic (non-OAuth, non-constrained) Opus with pre-set effort=max
const hook = createAnthropicEffortHook()
const { input, output } = createMockParams({
providerID: "anthropic",
modelID: "claude-opus-4-7",
variant: "max",
existingOptions: { effort: "max" },
})
// when
await hook["chat.params"](input, output)
// then — non-constrained Opus keeps max
expect(output.options.effort).toBe("max")
expect(input.message.variant).toBe("max")
})
it("#given pre-set effort=high + github-copilot Opus #when hook runs #then effort stays high", async () => {
// given — legitimate pre-set effort=high should not be overwritten
const hook = createAnthropicEffortHook()
const { input, output } = createMockParams({
providerID: "github-copilot",
modelID: "claude-opus-4-7",
variant: "max",
existingOptions: { effort: "high" },
})
// when
await hook["chat.params"](input, output)
// then — high is already valid for constrained providers, don't touch it
expect(output.options.effort).toBe("high")
})
})
describe("#given anthropic OAuth auth (Claude Pro/Max) — regression for #3429", () => {
let tempDataDir: string
const originalXdgDataHome = process.env.XDG_DATA_HOME