Skip to content

Commit 9ac4499

Browse files
authored
fix: ensure assistant message content is never undefined for Gemini compatibility (#10559)
1 parent caa3779 commit 9ac4499

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

src/api/transform/__tests__/openai-format.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,36 @@ describe("convertToOpenAiMessages", () => {
225225
expect(assistantMessage.tool_calls![0].id).toBe("custom_toolu_123")
226226
})
227227

228+
it("should use empty string for content when assistant message has only tool calls (Gemini compatibility)", () => {
229+
// This test ensures that assistant messages with only tool_use blocks (no text)
230+
// have content set to "" instead of undefined. Gemini (via OpenRouter) requires
231+
// every message to have at least one "parts" field, which fails if content is undefined.
232+
// See: ROO-425
233+
const anthropicMessages: Anthropic.Messages.MessageParam[] = [
234+
{
235+
role: "assistant",
236+
content: [
237+
{
238+
type: "tool_use",
239+
id: "tool-123",
240+
name: "read_file",
241+
input: { path: "test.ts" },
242+
},
243+
],
244+
},
245+
]
246+
247+
const openAiMessages = convertToOpenAiMessages(anthropicMessages)
248+
expect(openAiMessages).toHaveLength(1)
249+
250+
const assistantMessage = openAiMessages[0] as OpenAI.Chat.ChatCompletionAssistantMessageParam
251+
expect(assistantMessage.role).toBe("assistant")
252+
// Content should be an empty string, NOT undefined
253+
expect(assistantMessage.content).toBe("")
254+
expect(assistantMessage.tool_calls).toHaveLength(1)
255+
expect(assistantMessage.tool_calls![0].id).toBe("tool-123")
256+
})
257+
228258
describe("mergeToolResultText option", () => {
229259
it("should merge text content into last tool message when mergeToolResultText is true", () => {
230260
const anthropicMessages: Anthropic.Messages.MessageParam[] = [

src/api/transform/openai-format.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ export function convertToOpenAiMessages(
223223
reasoning_details?: any[]
224224
} = {
225225
role: "assistant",
226-
content,
226+
// Use empty string instead of undefined for providers like Gemini (via OpenRouter)
227+
// that require every message to have content in the "parts" field
228+
content: content ?? "",
227229
}
228230

229231
// Pass through reasoning_details to preserve the original shape from the API.

0 commit comments

Comments
 (0)