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:
@@ -76,23 +76,35 @@ export function createAnthropicEffortHook() {
|
|||||||
const { agent, model, message } = input
|
const { agent, model, message } = input
|
||||||
if (!model?.modelID || !model?.providerID) return
|
if (!model?.modelID || !model?.providerID) return
|
||||||
if (isEffortUnsupportedModel(model.modelID)) return
|
if (isEffortUnsupportedModel(model.modelID)) return
|
||||||
if (message.variant !== "max") return
|
|
||||||
if (!isClaudeProvider(model.providerID, model.modelID)) return
|
if (!isClaudeProvider(model.providerID, model.modelID)) return
|
||||||
if (shouldSkipForInternalAgent(agent?.name)) return
|
if (shouldSkipForInternalAgent(agent?.name)) return
|
||||||
if (output.options.effort !== undefined) return
|
|
||||||
|
|
||||||
const opus = isOpusModel(model.modelID)
|
const opus = isOpusModel(model.modelID)
|
||||||
const constrained = isConstrainedProvider(model.providerID)
|
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)
|
const clamped = clampVariant(message.variant, opus, constrained)
|
||||||
output.options.effort = clamped
|
output.options.effort = clamped
|
||||||
|
|
||||||
const shouldOverrideMessageVariant = !opus || constrained
|
const shouldOverrideMessageVariant = !opus || constrained
|
||||||
|
|
||||||
if (shouldOverrideMessageVariant) {
|
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
|
;(message as { variant?: string }).variant = clamped
|
||||||
log("anthropic-effort: clamped variant max→high", {
|
log("anthropic-effort: clamped variant max→high", {
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
|
|||||||
@@ -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", () => {
|
describe("#given anthropic OAuth auth (Claude Pro/Max) — regression for #3429", () => {
|
||||||
let tempDataDir: string
|
let tempDataDir: string
|
||||||
const originalXdgDataHome = process.env.XDG_DATA_HOME
|
const originalXdgDataHome = process.env.XDG_DATA_HOME
|
||||||
|
|||||||
Reference in New Issue
Block a user