fix: filter out reasoning type messages in AnthropicVertexHandler

The AnthropicVertexHandler was not filtering out reasoning type messages before sending them to the Vertex AI API, causing an error when the context filled up. This fix adds filtering similar to what GeminiHandler does, removing messages with type: "reasoning" which are not recognized by the Vertex AI API.

Fixes #9583
This commit is contained in:
Roo Code 2025-11-25 17:12:01 +00:00
parent 86cdbff0a5
commit 30304e25be
2 changed files with 107 additions and 1 deletions

View file

@ -809,4 +809,96 @@ describe("VertexHandler", () => {
)
})
})
describe("reasoning message filtering", () => {
it("should filter out reasoning type messages before sending to API", async () => {
handler = new AnthropicVertexHandler({
apiModelId: "claude-3-5-sonnet-v2@20241022",
vertexProjectId: "test-project",
vertexRegion: "us-central1",
})
// Include a reasoning type message that should be filtered out
const messagesWithReasoning = [
{
role: "user",
content: "Hello",
} as Anthropic.Messages.MessageParam,
{
type: "reasoning",
encrypted_content: "encrypted_payload",
summary: [],
} as any, // This should be filtered out
{
role: "assistant",
content: "Hi there!",
} as Anthropic.Messages.MessageParam,
]
const mockStream = [
{
type: "message_start",
message: {
usage: {
input_tokens: 10,
output_tokens: 0,
},
},
},
{
type: "content_block_start",
index: 0,
content_block: {
type: "text",
text: "Response",
},
},
]
const asyncIterator = {
async *[Symbol.asyncIterator]() {
for (const chunk of mockStream) {
yield chunk
}
},
}
const mockCreate = vitest.fn().mockResolvedValue(asyncIterator)
;(handler["client"].messages as any).create = mockCreate
const stream = handler.createMessage("System prompt", messagesWithReasoning)
const chunks: ApiStreamChunk[] = []
for await (const chunk of stream) {
chunks.push(chunk)
}
// Verify that the reasoning message was filtered out
expect(mockCreate).toHaveBeenCalledWith(
expect.objectContaining({
messages: [
{
role: "user",
content: [
{
type: "text",
text: "Hello",
cache_control: { type: "ephemeral" },
},
],
},
{
role: "assistant",
content: "Hi there!",
},
],
}),
)
// Verify the reasoning message was not included
const calledMessages = mockCreate.mock.calls[0][0].messages
expect(calledMessages).toHaveLength(2)
expect(calledMessages.every((msg: any) => msg.type !== "reasoning")).toBe(true)
})
})
})

View file

@ -70,6 +70,20 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
reasoning: thinking,
} = this.getModel()
// Filter out reasoning type messages that are not valid for Vertex AI API
// The message list can include provider-specific meta entries such as
// `{ type: "reasoning", ... }` that are intended only for providers like
// openai-native. Vertex AI doesn't recognize these and will return an error.
type ReasoningMetaLike = { type?: string }
const filteredMessages = messages.filter((message): message is Anthropic.Messages.MessageParam => {
const meta = message as ReasoningMetaLike
if (meta.type === "reasoning") {
return false
}
return true
})
/**
* Vertex API has specific limitations for prompt caching:
* 1. Maximum of 4 blocks can have cache_control
@ -92,7 +106,7 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
system: supportsPromptCache
? [{ text: systemPrompt, type: "text" as const, cache_control: { type: "ephemeral" } }]
: systemPrompt,
messages: supportsPromptCache ? addCacheBreakpoints(messages) : messages,
messages: supportsPromptCache ? addCacheBreakpoints(filteredMessages) : filteredMessages,
stream: true,
}