From 64b65a28490eea4cb2da44461c49a0b22ff442e8 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Wed, 25 Mar 2026 23:05:36 -0700 Subject: [PATCH] fix: filter empty/whitespace text content blocks at provider boundaries Skip empty and whitespace-only text content blocks at each provider's message conversion layer, preventing 400 errors from Anthropic, Bedrock, Venice, and other OpenAI-compatible APIs. - Anthropic: check .trim() instead of truthiness in convertMessageContentToBlocks - Bedrock (core): skip empty text in _convertMessageContentToBlocks - Bedrock (adapter): skip empty text parts in user message conversion - OpenAI adapter: filter empty text parts from assistant array content Fixes #9232, #9765, #9767, #10148, #10293, #10504, #10804, #11045, #11264, #11446, #11497, #11728 --- core/llm/llms/Anthropic.ts | 4 ++-- core/llm/llms/Bedrock.ts | 8 ++++++-- packages/openai-adapters/src/apis/Bedrock.ts | 7 ++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/core/llm/llms/Anthropic.ts b/core/llm/llms/Anthropic.ts index e33f92f203f..f9fd996d1c9 100644 --- a/core/llm/llms/Anthropic.ts +++ b/core/llm/llms/Anthropic.ts @@ -90,7 +90,7 @@ class Anthropic extends BaseLLM { ): ContentBlockParam[] { const parts: ContentBlockParam[] = []; if (typeof content === "string") { - if (content) { + if (content.trim()) { parts.push({ type: "text", text: content, @@ -99,7 +99,7 @@ class Anthropic extends BaseLLM { } else { for (const part of content) { if (part.type === "text") { - if (part.text) { + if (part.text?.trim()) { parts.push({ type: "text", text: part.text, diff --git a/core/llm/llms/Bedrock.ts b/core/llm/llms/Bedrock.ts index 98ad4e6f3f7..c6c2cd6d588 100644 --- a/core/llm/llms/Bedrock.ts +++ b/core/llm/llms/Bedrock.ts @@ -538,11 +538,15 @@ class Bedrock extends BaseLLM { ): ContentBlock[] { const blocks: ContentBlock[] = []; if (typeof content === "string") { - blocks.push({ text: content }); + if (content.trim()) { + blocks.push({ text: content }); + } } else { for (const part of content) { if (part.type === "text") { - blocks.push({ text: part.text }); + if (part.text?.trim()) { + blocks.push({ text: part.text }); + } } else if (part.type === "imageUrl" && part.imageUrl) { const parsed = parseDataUrl(part.imageUrl.url); if (parsed) { diff --git a/packages/openai-adapters/src/apis/Bedrock.ts b/packages/openai-adapters/src/apis/Bedrock.ts index d98ad25d2f5..7477e81e056 100644 --- a/packages/openai-adapters/src/apis/Bedrock.ts +++ b/packages/openai-adapters/src/apis/Bedrock.ts @@ -203,9 +203,14 @@ export class BedrockApi implements BaseLlmApi { const content = message.content; if (content) { if (typeof content === "string") { - currentBlocks.push({ text: content }); + if (content.trim()) { + currentBlocks.push({ text: content }); + } } else { content.forEach((part) => { + if (part.type === "text" && !part.text?.trim()) { + return; + } currentBlocks.push(this._oaiPartToBedrockPart(part)); }); }