From b1dd507e7c688b0e57dccd9b40427e239bb0caa4 Mon Sep 17 00:00:00 2001 From: darrenwadley-ui <226991466+darrenwadley-ui@users.noreply.github.com> Date: Sat, 21 Feb 2026 20:59:38 +0000 Subject: [PATCH] fix: handle content array format in messagesToPrompt OpenAI chat completions API allows message content to be either a string or an array of content parts [{type: "text", text: "..."}]. Clients like OpenClaw always send content as an array, causing the proxy to pass [object Object] to Claude CLI instead of the actual text. Add extractContent() helper that normalizes both formats to a string. Co-Authored-By: Claude Opus 4.6 --- src/adapter/openai-to-cli.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/adapter/openai-to-cli.ts b/src/adapter/openai-to-cli.ts index c8ecaa1..a285c24 100644 --- a/src/adapter/openai-to-cli.ts +++ b/src/adapter/openai-to-cli.ts @@ -46,6 +46,28 @@ export function extractModel(model: string): ClaudeModel { return "opus"; } +/** + * Normalize message content to a plain string. + * + * The OpenAI chat completions API allows `content` to be either a string or + * an array of content parts (e.g. [{type: "text", text: "Hello"}]). Clients + * such as OpenClaw always send the array form, so we need to handle both. + */ +function extractContent(content: string | Array<{type: string; text?: string}> | unknown): string { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + return content + .map(part => { + if (typeof part === "string") return part; + if (part && part.type === "text" && typeof part.text === "string") return part.text; + return ""; + }) + .filter(Boolean) + .join("\n"); + } + return String(content ?? ""); +} + /** * Convert OpenAI messages array to a single prompt string for Claude CLI * @@ -59,17 +81,17 @@ export function messagesToPrompt(messages: OpenAIChatRequest["messages"]): strin switch (msg.role) { case "system": // System messages become context instructions - parts.push(`\n${msg.content}\n\n`); + parts.push(`\n${extractContent(msg.content)}\n\n`); break; case "user": // User messages are the main prompt - parts.push(msg.content); + parts.push(extractContent(msg.content)); break; case "assistant": // Previous assistant responses for context - parts.push(`\n${msg.content}\n\n`); + parts.push(`\n${extractContent(msg.content)}\n\n`); break; } }