fix(anthropic-effort): skip effort injection for internal agents (fixes #2940)
Internal agents (title, summary, compaction) no longer receive the anthropic-beta effort header, preventing 400 errors on Google Vertex Anthropic provider. Verified: 12 tests pass, typecheck clean
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { log, normalizeModelID } from "../../shared"
|
import { log, normalizeModelID } from "../../shared"
|
||||||
|
|
||||||
const OPUS_PATTERN = /claude-.*opus/i
|
const OPUS_PATTERN = /claude-.*opus/i
|
||||||
|
const INTERNAL_SKIP_AGENTS = new Set(["title", "summary", "compaction"])
|
||||||
|
|
||||||
function isClaudeProvider(providerID: string, modelID: string): boolean {
|
function isClaudeProvider(providerID: string, modelID: string): boolean {
|
||||||
if (["anthropic", "google-vertex-anthropic", "opencode"].includes(providerID)) return true
|
if (["anthropic", "google-vertex-anthropic", "opencode"].includes(providerID)) return true
|
||||||
@@ -13,6 +14,11 @@ function isOpusModel(modelID: string): boolean {
|
|||||||
return OPUS_PATTERN.test(normalized)
|
return OPUS_PATTERN.test(normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldSkipForInternalAgent(agentName: string | undefined): boolean {
|
||||||
|
if (!agentName) return false
|
||||||
|
return INTERNAL_SKIP_AGENTS.has(agentName.trim().toLowerCase())
|
||||||
|
}
|
||||||
|
|
||||||
interface ChatParamsInput {
|
interface ChatParamsInput {
|
||||||
sessionID: string
|
sessionID: string
|
||||||
agent: { name?: string }
|
agent: { name?: string }
|
||||||
@@ -48,10 +54,11 @@ export function createAnthropicEffortHook() {
|
|||||||
input: ChatParamsInput,
|
input: ChatParamsInput,
|
||||||
output: ChatParamsOutput
|
output: ChatParamsOutput
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const { model, message } = input
|
const { agent, model, message } = input
|
||||||
if (!model?.modelID || !model?.providerID) return
|
if (!model?.modelID || !model?.providerID) return
|
||||||
if (message.variant !== "max") 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 (output.options.effort !== undefined) return
|
if (output.options.effort !== undefined) return
|
||||||
|
|
||||||
const opus = isOpusModel(model.modelID)
|
const opus = isOpusModel(model.modelID)
|
||||||
|
|||||||
@@ -108,6 +108,25 @@ describe("createAnthropicEffortHook", () => {
|
|||||||
expect(output.options.effort).toBeUndefined()
|
expect(output.options.effort).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("#given internal hidden agents", () => {
|
||||||
|
const internalAgents = ["title", "summary", "compaction"] as const
|
||||||
|
|
||||||
|
for (const agentName of internalAgents) {
|
||||||
|
it(`skips effort injection for ${agentName} agent`, async () => {
|
||||||
|
// given
|
||||||
|
const hook = createAnthropicEffortHook()
|
||||||
|
const { input, output } = createMockParams({ agentName })
|
||||||
|
|
||||||
|
// when
|
||||||
|
await hook["chat.params"](input, output)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(output.options.effort).toBeUndefined()
|
||||||
|
expect(input.message.variant).toBe("max")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it("should clamp effort to high for non-opus claude model with variant max", async () => {
|
it("should clamp effort to high for non-opus claude model with variant max", async () => {
|
||||||
//#given claude-sonnet-4-6 (not opus) with variant max
|
//#given claude-sonnet-4-6 (not opus) with variant max
|
||||||
const hook = createAnthropicEffortHook()
|
const hook = createAnthropicEffortHook()
|
||||||
|
|||||||
Reference in New Issue
Block a user