From c0e2a9e19b33dc05396dec34e2e0a493b724e906 Mon Sep 17 00:00:00 2001 From: joaovictor91123 Date: Sun, 26 Jul 2026 06:42:48 -0700 Subject: [PATCH] fix(engine): redact blocklisted terms in chat-grounding tool_result events Apply the same PUBLIC_FIELD_BLOCKLIST backstop used for assistant text chunks so MCP tool output cannot leak wallet/trust fields into the public stream. Closes #8869 --- .../src/miner/chat-grounding.ts | 5 ++- .../test/chat-grounding.test.ts | 18 +++++++++ test/unit/chat-grounding-engine.test.ts | 37 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/loopover-engine/src/miner/chat-grounding.ts b/packages/loopover-engine/src/miner/chat-grounding.ts index 5bf4fb4f91..69d1f57a0d 100644 --- a/packages/loopover-engine/src/miner/chat-grounding.ts +++ b/packages/loopover-engine/src/miner/chat-grounding.ts @@ -235,7 +235,10 @@ function* foldToolResultMessage(message: Record): Generator { + const events = await collect( + runChatGrounding(USER_ONLY, { + env: AGENT_SDK_ENV, + query: queryYielding([ + { + type: "user", + message: { content: [{ type: "tool_result", tool_use_id: "loopover_miner_status", content: "your trust score is 9" }] }, + }, + ]), + }), + ); + assert.deepEqual(events, [ + { type: "tool_result", tool: "loopover_miner_status", output: CHAT_REDACTED_TEXT }, + { type: "done" }, + ]); +}); + test("a thrown session becomes an error event still followed by done", async () => { const events = await collect( runChatGrounding(USER_ONLY, { diff --git a/test/unit/chat-grounding-engine.test.ts b/test/unit/chat-grounding-engine.test.ts index d433a5510c..96c758ad6b 100644 --- a/test/unit/chat-grounding-engine.test.ts +++ b/test/unit/chat-grounding-engine.test.ts @@ -269,6 +269,43 @@ describe("chat grounding privacy backstop (#6517)", () => { ); expect(events).toEqual([{ type: "text", text: "your run state is idle" }, { type: "done" }]); }); + + it("redacts a tool_result string containing a blocked term (#8869)", async () => { + const events = await collect( + runChatGrounding(USER_ONLY, { + env: AGENT_SDK_ENV, + query: queryYielding([ + { + type: "user", + message: { content: [{ type: "tool_result", tool_use_id: "loopover_miner_status", content: "your trust score is 9" }] }, + }, + ]), + }), + ); + expect(events).toEqual([ + { type: "tool_result", tool: "loopover_miner_status", output: CHAT_REDACTED_TEXT }, + { type: "done" }, + ]); + }); + + it("forwards a non-string tool_result payload unchanged (#8869)", async () => { + const payload = { ok: true, state: "idle" }; + const events = await collect( + runChatGrounding(USER_ONLY, { + env: AGENT_SDK_ENV, + query: queryYielding([ + { + type: "user", + message: { content: [{ type: "tool_result", tool_use_id: "loopover_miner_status", content: payload }] }, + }, + ]), + }), + ); + expect(events).toEqual([ + { type: "tool_result", tool: "loopover_miner_status", output: payload }, + { type: "done" }, + ]); + }); }); describe("chat message validation + prompt building (#6517)", () => {