diff --git a/packages/core/src/session/runner/to-llm-message.ts b/packages/core/src/session/runner/to-llm-message.ts index 8b5d767f7f62..5f1165c64180 100644 --- a/packages/core/src/session/runner/to-llm-message.ts +++ b/packages/core/src/session/runner/to-llm-message.ts @@ -197,10 +197,17 @@ const assistant = (message: SessionMessage.Assistant, model: Model.Ref, provider ) return result ? [call, result] : [call] }) + const hasOutput = content.some((part) => { + if (part.type === "text" || part.type === "reasoning") return part.text !== "" + return true + }) const meaningful = content.filter((part) => { if (part.type === "text") return part.text !== "" if (part.type !== "reasoning") return true - return part.text !== "" || (part.providerMetadata !== undefined && Object.keys(part.providerMetadata).length > 0) + return ( + part.text !== "" || + (hasOutput && part.providerMetadata !== undefined && Object.keys(part.providerMetadata).length > 0) + ) }) const results = message.content .filter((item): item is SessionMessage.AssistantTool => item.type === "tool" && item.executed !== true) diff --git a/packages/core/test/session-runner-message.test.ts b/packages/core/test/session-runner-message.test.ts index 5f37a4d19aab..977fe9679cc9 100644 --- a/packages/core/test/session-runner-message.test.ts +++ b/packages/core/test/session-runner-message.test.ts @@ -68,18 +68,52 @@ describe("toLLMMessages", () => { assistant("empty-text", [SessionMessage.AssistantText.make({ type: "text", text: "" })]), assistant("empty-reasoning", [SessionMessage.AssistantReasoning.make({ type: "reasoning", text: "" })]), assistant("text", [SessionMessage.AssistantText.make({ type: "text", text: "Partial" })]), - assistant("reasoning", [ + assistant("signed-reasoning", [ SessionMessage.AssistantReasoning.make({ type: "reasoning", text: "", state: { signature: "sig_1" }, }), ]), + assistant("signed-reasoning-with-text", [ + SessionMessage.AssistantReasoning.make({ + type: "reasoning", + text: "", + state: { signature: "sig_2" }, + }), + SessionMessage.AssistantText.make({ type: "text", text: "Visible" }), + ]), + assistant("signed-reasoning-with-tool", [ + SessionMessage.AssistantReasoning.make({ + type: "reasoning", + text: "", + state: { signature: "sig_3" }, + }), + SessionMessage.AssistantTool.make({ + type: "tool", + id: "read", + name: "read", + state: SessionMessage.ToolStateStreaming.make({ status: "streaming", input: '{"path":"README.md"}' }), + time: { created }, + }), + ]), ], model, ) - expect(messages.map((message) => message.id)).toEqual([id("text"), id("reasoning")]) + expect(messages.map((message) => message.id)).toEqual([ + id("text"), + id("signed-reasoning-with-text"), + id("signed-reasoning-with-tool"), + ]) + expect(messages[1]?.content).toEqual([ + { type: "reasoning", text: "", providerMetadata: { provider: { signature: "sig_2" } } }, + { type: "text", text: "Visible", providerMetadata: undefined }, + ]) + expect(messages[2]?.content).toEqual([ + { type: "reasoning", text: "", providerMetadata: { provider: { signature: "sig_3" } } }, + { type: "tool-call", id: "read", name: "read", input: { path: "README.md" } }, + ]) }) test("maps every top-level Session message type", () => {