From 939e143096a82993351da860f0f1fbafa771a916 Mon Sep 17 00:00:00 2001 From: Brendan DeBeasi Date: Fri, 20 Mar 2026 10:11:08 -0700 Subject: [PATCH] fix(session): prevent assistant-last message array from reaching provider APIs Some providers and the AI SDK reject conversations ending with an assistant message (no prefill support). This can happen after compaction, error recovery, or filtered-out user messages leave an assistant message at the tail of the model message array. Add a guard in toModelMessages that appends a synthetic user message when the filtered array ends with an assistant role. --- packages/opencode/src/session/message-v2.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index f1335f6f21a3..36e4f89f8e84 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -782,13 +782,19 @@ export namespace MessageV2 { const tools = Object.fromEntries(Array.from(toolNames).map((toolName) => [toolName, { toModelOutput }])) - return convertToModelMessages( - result.filter((msg) => msg.parts.some((part) => part.type !== "step-start")), - { - //@ts-expect-error (convertToModelMessages expects a ToolSet but only actually needs tools[name]?.toModelOutput) - tools, - }, - ) + const filtered = result.filter((msg) => msg.parts.some((part) => part.type !== "step-start")) + if (filtered.length > 0 && filtered[filtered.length - 1].role === "assistant") { + filtered.push({ + id: MessageID.ascending(), + role: "user", + parts: [{ type: "text", text: "Continue." }], + }) + } + + return convertToModelMessages(filtered, { + //@ts-expect-error (convertToModelMessages expects a ToolSet but only actually needs tools[name]?.toModelOutput) + tools, + }) } export const page = fn(