From ccd68ac7852c776bf42924fea1e6ff84d0bea73e Mon Sep 17 00:00:00 2001 From: Roo Code Date: Fri, 5 Sep 2025 06:30:06 +0000 Subject: [PATCH] fix(vertex-anthropic): retry without prompt caching when Vertex SDK throws "path must be of type string. Received an instance of Array" --- src/api/providers/anthropic-vertex.ts | 64 ++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/src/api/providers/anthropic-vertex.ts b/src/api/providers/anthropic-vertex.ts index c70a15926d..b2fc2f7789 100644 --- a/src/api/providers/anthropic-vertex.ts +++ b/src/api/providers/anthropic-vertex.ts @@ -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) => + 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 + try { + stream = await this.client.messages.create(buildParams(!!supportsPromptCache)) + } catch (err) { + if (supportsPromptCache && isPathArrayError(err)) { + console.warn( + "Roo Code : 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) { @@ -185,7 +208,7 @@ 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, @@ -193,27 +216,44 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple messages: [ { role: "user", - content: supportsPromptCache + content: enableCache ? [{ type: "text" as const, text: prompt, cache_control: { type: "ephemeral" } }] : prompt, }, ], stream: false, + }) + + const isPathArrayError = (err: unknown) => + 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( + "Roo Code : 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 } }