Skip to content
Closed
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
64 changes: 52 additions & 12 deletions src/api/providers/anthropic-vertex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,43 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
* This ensures we stay under the 4-block limit while maintaining effective caching
* for the most relevant context.
*/
const params: Anthropic.Messages.MessageCreateParamsStreaming = {
// Build params with optional prompt caching
const buildParams = (enableCache: boolean): Anthropic.Messages.MessageCreateParamsStreaming => ({
model: id,
max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS,
temperature,
thinking,
// Cache the system prompt if caching is enabled.
system: supportsPromptCache
system: enableCache
? [{ text: systemPrompt, type: "text" as const, cache_control: { type: "ephemeral" } }]
: systemPrompt,
messages: supportsPromptCache ? addCacheBreakpoints(messages) : messages,
messages: enableCache ? addCacheBreakpoints(messages) : messages,
stream: true,
}
})

// Some environments (notably certain Vertex setups) have started throwing
// TypeError("'path' argument must be of type string. Received an instance of Array")
// when the SDK receives array-form system/content blocks. As a safe fallback,
// retry without prompt caching if we detect this error.
const isPathArrayError = (err: unknown) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider extracting the isPathArrayError function into a shared helper to avoid duplicating this logic in both createMessage and completePrompt.

This comment was generated because it violated a code review rule: irule_tTqpIuNs8DV0QFGj.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The isPathArrayError helper function is duplicated here and in completePrompt() (line 227). As mentioned in the PR description, could we refactor this into a shared private method of the class? Something like:

Suggested change
const isPathArrayError = (err: unknown) =>
private isPathArrayError(err: unknown): boolean {
return typeof (err as any)?.message === "string" &&
(err as any).message.includes("'path'") &&
(err as any).message.includes("type string") &&
(err as any).message.includes("Array")
}

typeof (err as any)?.message === "string" &&
(err as any).message.includes("'path'") &&
(err as any).message.includes("type string") &&
(err as any).message.includes("Array")

const stream = await this.client.messages.create(params)
let stream: AsyncIterable<any>
try {
stream = await this.client.messages.create(buildParams(!!supportsPromptCache))
} catch (err) {
if (supportsPromptCache && isPathArrayError(err)) {
console.warn(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consider including the model ID in the warning message for better debugging context:

Suggested change
console.warn(
console.warn(
`Roo Code <Vertex/Anthropic>: Retry without prompt caching for model ${id} due to path/Array error:`,
(err as any).message,
)

"Roo Code <Vertex/Anthropic>: Retry without prompt caching due to path/Array error:",
(err as any).message,
)
stream = await this.client.messages.create(buildParams(false))
} else {
throw err
}
}

for await (const chunk of stream) {
switch (chunk.type) {
Expand Down Expand Up @@ -185,35 +208,52 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
reasoning: thinking,
} = this.getModel()

const params: Anthropic.Messages.MessageCreateParamsNonStreaming = {
const buildParams = (enableCache: boolean): Anthropic.Messages.MessageCreateParamsNonStreaming => ({
model: id,
max_tokens: maxTokens,
temperature,
thinking,
messages: [
{
role: "user",
content: supportsPromptCache
content: enableCache
? [{ type: "text" as const, text: prompt, cache_control: { type: "ephemeral" } }]
: prompt,
},
],
stream: false,
})

const isPathArrayError = (err: unknown) =>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same duplication of isPathArrayError as mentioned above. This should use the shared class method once refactored.

typeof (err as any)?.message === "string" &&
(err as any).message.includes("'path'") &&
(err as any).message.includes("type string") &&
(err as any).message.includes("Array")

let response: Anthropic.Messages.Message
try {
response = await this.client.messages.create(buildParams(!!supportsPromptCache))
} catch (err) {
if (supportsPromptCache && isPathArrayError(err)) {
console.warn(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar to the streaming case, consider including the model ID in this warning:

Suggested change
console.warn(
console.warn(
`Roo Code <Vertex/Anthropic>: Non-streaming retry without prompt caching for model ${id} due to path/Array error:`,
(err as any).message,
)

"Roo Code <Vertex/Anthropic>: Non-streaming retry without prompt caching due to path/Array error:",
(err as any).message,
)
response = await this.client.messages.create(buildParams(false))
} else {
throw err
}
}

const response = await this.client.messages.create(params)
const content = response.content[0]

if (content.type === "text") {
return content.text
}

return ""
} catch (error) {
if (error instanceof Error) {
throw new Error(`Vertex completion error: ${error.message}`)
}

throw error
}
}
Expand Down
Loading