From 0c04e86efd6137920586719a27b2eb61a1956f0d Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 28 Jul 2026 07:34:49 +0000 Subject: [PATCH] fix(acp): kept hub job-wait results visible Only a peer-scoped wait (from, no ids) is internal messaging; bare and ids waits settle on background-job delivery whose snapshot is the job result. Fixes #6872 --- .../src/modes/acp/acp-event-mapper.ts | 5 +- .../test/acp-event-mapper.test.ts | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/src/modes/acp/acp-event-mapper.ts b/packages/coding-agent/src/modes/acp/acp-event-mapper.ts index a1a9e81f0..f069819b9 100644 --- a/packages/coding-agent/src/modes/acp/acp-event-mapper.ts +++ b/packages/coding-agent/src/modes/acp/acp-event-mapper.ts @@ -165,7 +165,10 @@ function isInternalHubMessageTool(toolName: string, args: unknown): boolean { case "send": return typeof Reflect.get(hubArgs, "to") === "string"; case "wait": - return typeof Reflect.get(hubArgs, "name") !== "string"; + // A bare wait or an `ids` wait settles on background-job delivery, + // whose snapshot IS the job result (hub.md) — keep those visible. + // Only a peer-scoped wait (`from`, no jobs) is internal messaging. + return typeof Reflect.get(hubArgs, "from") === "string" && Reflect.get(hubArgs, "ids") === undefined; default: return false; } diff --git a/packages/coding-agent/test/acp-event-mapper.test.ts b/packages/coding-agent/test/acp-event-mapper.test.ts index 0de2a75d2..7432837e1 100644 --- a/packages/coding-agent/test/acp-event-mapper.test.ts +++ b/packages/coding-agent/test/acp-event-mapper.test.ts @@ -302,6 +302,61 @@ describe("ACP event mapper", () => { ); }); + it("keeps background job-wait results visible over ACP", () => { + const events = [ + { + type: "tool_execution_start", + toolCallId: "tc-hub-job-wait", + toolName: "hub", + args: { op: "wait", ids: ["bash_a1b2c3"] }, + }, + { + type: "tool_execution_end", + toolCallId: "tc-hub-job-wait", + toolName: "hub", + isError: false, + result: { content: [{ type: "text", text: "job output" }] }, + }, + ] satisfies AgentSessionEvent[]; + + const updates = events.flatMap(event => + mapAgentSessionEventToAcpSessionUpdates(event, "session-1", { + getToolArgs: () => ({ op: "wait", ids: ["bash_a1b2c3"] }), + }), + ); + + expect(updates.map(update => update.update.sessionUpdate)).toEqual(["tool_call", "tool_call_update"]); + }); + + it("keeps a bare Hub wait visible so job deliveries reach ACP", () => { + const updates = mapAgentSessionEventToAcpSessionUpdates( + { + type: "tool_execution_start", + toolCallId: "tc-hub-bare-wait", + toolName: "hub", + args: { op: "wait" }, + }, + "session-1", + ); + + expect(updates).toHaveLength(1); + expect(updates[0]?.update.sessionUpdate).toBe("tool_call"); + }); + + it("hides a peer-scoped Hub wait from ACP", () => { + const updates = mapAgentSessionEventToAcpSessionUpdates( + { + type: "tool_execution_start", + toolCallId: "tc-hub-peer-wait", + toolName: "hub", + args: { op: "wait", from: "Scout" }, + }, + "session-1", + ); + + expect(updates).toEqual([]); + }); + it("uses command text for a new command tool even when intent is generic", () => { const updates = mapAgentSessionEventToAcpSessionUpdates( {