From 1da591b84d96fa0bddfd84c9e9ca05048397cf11 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 09:14:41 -0500 Subject: [PATCH] fix(core): return content-only Code Mode results (#41954) Co-authored-by: Aiden Cline --- packages/core/src/codemode/tool.ts | 6 ++-- packages/core/test/mcp.test.ts | 38 +++++++++++++++++++++ packages/core/test/plugin/promise.test.ts | 41 +++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/packages/core/src/codemode/tool.ts b/packages/core/src/codemode/tool.ts index aa7f4af73b..23aa7a4708 100644 --- a/packages/core/src/codemode/tool.ts +++ b/packages/core/src/codemode/tool.ts @@ -75,7 +75,9 @@ export const create = ( const outputFileParts = outputFiles(content) if (outputFileParts.length > 0) yield* Ref.update(files, (items) => [...items, { index, files: outputFileParts }]) - return executed.output + if (executed.output !== undefined) return executed.output + const text = content.flatMap((part) => (part.type === "text" ? [part.text] : [])).join("\n") + return text === "" ? null : text }), { onToolCallStart: ({ index, name, input }) => { @@ -155,7 +157,7 @@ function runtime( tools[path] = Tool.make({ description: child.description, input: child.inputSchema, - output: child.outputSchema, + output: child.outputSchema ?? Schema.NullOr(Schema.String), execute: (input) => executeTool(name, registration, input), }) } diff --git a/packages/core/test/mcp.test.ts b/packages/core/test/mcp.test.ts index ed295f75e2..1f2cf2d2d2 100644 --- a/packages/core/test/mcp.test.ts +++ b/packages/core/test/mcp.test.ts @@ -248,6 +248,12 @@ const mcp = Layer.mock(MCP.Service, { required: ["ok"], }, }), + new MCP.Tool({ + server: MCP.ServerName.make("demo"), + name: "status", + description: "Status", + inputSchema: { type: "object", properties: {} }, + }), new MCP.Tool({ server: MCP.ServerName.make("direct"), name: "lookup", @@ -290,6 +296,13 @@ const mcp = Layer.mock(MCP.Service, { { type: "media", data: "aGVsbG8=", mimeType: "image/png" }, ], }) + if (input.name === "status") + return new MCP.ToolResult({ + server: MCP.ServerName.make(input.server), + tool: input.name, + isError: false, + content: [{ type: "text", text: "hello" }], + }) return new MCP.ToolResult({ server: MCP.ServerName.make(input.server), tool: input.name, @@ -984,6 +997,31 @@ it.effect("advertises MCP output schemas to Code Mode", () => }), ) +it.effect("returns content-only MCP results through Code Mode", () => + Effect.gen(function* () { + assertion = yield* Deferred.make() + decision = Effect.void + const registry = yield* Tool.Service + const toolSet = yield* waitForCodeModeTool(registry, "demo.status") + + const execution = yield* toolSet.execute({ + sessionID: Session.ID.make("ses_mcp_content_only"), + ...toolIdentity, + call: { + type: "tool-call", + id: "call_mcp_content_only", + name: "execute", + input: { code: "return await tools.demo.status({})" }, + }, + }) + + expect(execution).toMatchObject({ + output: { output: "hello", toolCalls: [{ tool: "demo.status", status: "completed" }] }, + content: [{ type: "text", text: "hello" }], + }) + }), +) + it.effect("advertises MCP tools directly when Code Mode is disabled for the server", () => Effect.gen(function* () { const registry = yield* Tool.Service diff --git a/packages/core/test/plugin/promise.test.ts b/packages/core/test/plugin/promise.test.ts index e5551e4340..efc25e07cb 100644 --- a/packages/core/test/plugin/promise.test.ts +++ b/packages/core/test/plugin/promise.test.ts @@ -393,4 +393,45 @@ describe("fromPromise", () => { expect(progress).toEqual([{ phase: "greeting" }]) }), ) + + it.effect("returns content-only plugin results through Code Mode", () => + Effect.gen(function* () { + const plugins = yield* Plugin.Service + const registry = yield* Tool.Service + const host = yield* PluginHost.make(plugins) + const promisePlugin = define({ + id: "content-only-tool", + setup: async (ctx) => { + await ctx.tool.transform((tools) => { + tools.add({ + name: "demo_status", + description: "Returns a status string", + input: Schema.Struct({}), + execute: async () => ({ content: [{ type: "text", text: "hello" }] }), + options: { codemode: true }, + }) + }) + }, + }) + + yield* PluginPromise.fromPromise(promisePlugin).effect(host) + + const toolSet = yield* registry.snapshot() + const throughCodeMode = yield* toolSet.execute({ + sessionID: Session.ID.make("ses_content_only_tool"), + agent: Agent.ID.make("build"), + messageID: SessionMessage.ID.make("msg_content_only_tool"), + call: { + type: "tool-call", + id: "call_content_only_tool", + name: "execute", + input: { code: "return await tools.demo_status({})" }, + }, + }) + expect(throughCodeMode).toMatchObject({ + output: { output: "hello", toolCalls: [{ tool: "demo_status", status: "completed" }] }, + content: [{ type: "text", text: "hello" }], + }) + }), + ) })