From 0da3f84a2ed304d6fa7e0dbbbaacc2ae0c8badec Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 5 Dec 2025 19:16:03 +0000 Subject: [PATCH] fix: ignore rpc toolcall deltas to avoid duplicate replies --- src/auto-reply/command-reply.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/auto-reply/command-reply.ts b/src/auto-reply/command-reply.ts index 1191de241..ec8dddb1c 100644 --- a/src/auto-reply/command-reply.ts +++ b/src/auto-reply/command-reply.ts @@ -22,6 +22,36 @@ import { } from "./tool-meta.js"; import type { ReplyPayload } from "./types.js"; +function stripRpcNoise(raw: string): string { + // Drop rpc streaming scaffolding (toolcall deltas, audio buffer events) before parsing. + const lines = raw.split(/\n+/); + const kept: string[] = []; + for (const line of lines) { + try { + const evt = JSON.parse(line); + const type = evt?.type; + const msg = evt?.message ?? evt?.assistantMessageEvent; + const msgType = msg?.type; + + // Ignore toolcall delta chatter and input buffer append events. + if (type === "message_update" && msgType === "toolcall_delta") continue; + if (type === "input_audio_buffer.append") continue; + + // Ignore assistant messages that have no text content (pure toolcall scaffolding). + if (msg?.role === "assistant" && Array.isArray(msg?.content)) { + const hasText = msg.content.some( + (c: unknown) => (c as { type?: string })?.type === "text", + ); + if (!hasText) continue; + } + } catch { + // not JSON; keep as-is + } + if (line.trim()) kept.push(line); + } + return kept.join("\n"); +} + type CommandReplyConfig = NonNullable["reply"] & { mode: "command"; }; @@ -604,7 +634,7 @@ export async function runCommandReply( }); const rawStdout = stdout.trim(); let mediaFromCommand: string[] | undefined; - const trimmed = rawStdout; + const trimmed = stripRpcNoise(rawStdout); if (stderr?.trim()) { logVerbose(`Command auto-reply stderr: ${stderr.trim()}`); }