diff --git a/nix/hashes.json b/nix/hashes.json index 29a102ae66..e60c498ffd 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { "x86_64-linux": "sha256-07XxcHLuToM4QfWVyaPLACxjPZ93ZM7gtpX2o08Lp18=", - "aarch64-linux": "sha256-E6lyYFApS1cw3jE7ISx5QZxDDJ9V3HU0ICYFdY+aIBw=", + "aarch64-linux": "sha256-0Im52dLeZ0ZtaPJr/U4m7+IRtOfziHNJI/Bu/V6cPho=", "aarch64-darwin": "sha256-U2UvE70nM0OI0VhIku8qnX+ptPbA+Q/y1BGXbFMcyt4=", - "x86_64-darwin": "sha256-LxBsYdq5AzInQJzF89taXvS2vigew5C5hjaIEH8rTb8=" + "x86_64-darwin": "sha256-grPR/YBqYPEUBks4nQKYe6/9f+9N0Fk9l2L9J6ylWkc=" } } diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 9f2e0ba061..f6f8fe0a1b 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -526,7 +526,11 @@ export namespace MessageV2 { state: "output-available", toolCallId: part.callID, input: part.state.input, - output: part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output, + // For compacted results, use plain string so SDK serializes as text type + // For normal results, pass object so toModelOutput can convert attachments to media parts + output: part.state.time.compacted + ? "[Old tool result content cleared]" + : { output: part.state.output, attachments: part.state.attachments }, callProviderMetadata: part.metadata, }) } diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 8327698fd5..50d8180a04 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -716,7 +716,10 @@ export namespace SessionPrompt { ) return result }, - toModelOutput(result) { + toModelOutput(result: string | { output: string; attachments?: MessageV2.FilePart[] }) { + // Handle compacted results (plain string) + if (typeof result === "string") return { type: "text", value: result } + if (!result.attachments?.length) return { type: "text", value: result.output } return { type: "text", value: result.output, @@ -806,7 +809,10 @@ export namespace SessionPrompt { content: result.content, // directly return content to preserve ordering when outputting to model } } - item.toModelOutput = (result) => { + item.toModelOutput = (result: string | { output: string; attachments?: MessageV2.FilePart[] }) => { + // Handle compacted results (plain string) + if (typeof result === "string") return { type: "text", value: result } + if (!result.attachments?.length) return { type: "text", value: result.output } return { type: "text", value: result.output, diff --git a/packages/opencode/test/session/message-v2.test.ts b/packages/opencode/test/session/message-v2.test.ts index f069f6ba68..9caa0d8520 100644 --- a/packages/opencode/test/session/message-v2.test.ts +++ b/packages/opencode/test/session/message-v2.test.ts @@ -297,7 +297,23 @@ describe("session.message-v2.toModelMessage", () => { type: "tool-result", toolCallId: "call-1", toolName: "bash", - output: { type: "text", value: "ok" }, + output: { + type: "json", + value: { + attachments: [ + { + id: "file-1", + sessionID: "session", + messageID: "m-assistant", + type: "file", + mime: "image/png", + filename: "attachment.png", + url: "https://example.com/attachment.png", + }, + ], + output: "ok", + }, + }, providerOptions: { openai: { tool: "meta" } }, }, ],