diff --git a/src/acp-agent.ts b/src/acp-agent.ts index 6466e750..abb587d1 100644 --- a/src/acp-agent.ts +++ b/src/acp-agent.ts @@ -3207,7 +3207,11 @@ export function streamEventToAcpNotifications( taskState: options?.taskState, }, ); - // No content + // No content. `ping` is a Messages-API keep-alive event that the SDK's + // `BetaRawMessageStreamEvent` union doesn't include even though the + // wire format emits it; the `as never` cast lets us no-op it here + // instead of letting it fall through to `unreachable`. + case "ping" as never: case "message_start": case "message_delta": case "message_stop": diff --git a/src/tests/acp-agent.test.ts b/src/tests/acp-agent.test.ts index b01dbe77..85d79ca0 100644 --- a/src/tests/acp-agent.test.ts +++ b/src/tests/acp-agent.test.ts @@ -32,6 +32,7 @@ import { ClaudeAcpAgent, claudeCliPath, describeAlwaysAllow, + streamEventToAcpNotifications, type SDKMessageFilter, } from "../acp-agent.js"; import { Pushable } from "../utils.js"; @@ -3872,3 +3873,38 @@ describe("post-error recovery", () => { expect(session.pendingMessages.size).toBe(0); }); }); + +describe("streamEventToAcpNotifications", () => { + it("treats `ping` keep-alive events as no-ops without logging to stderr", () => { + const errors: unknown[][] = []; + const logger = { + log: () => {}, + error: (...args: unknown[]) => { + errors.push(args); + }, + }; + const pingMessage = { + type: "stream_event", + parent_tool_use_id: null, + uuid: randomUUID(), + session_id: "test-session", + // The SDK's typed `BetaRawMessageStreamEvent` union doesn't include + // `ping`, but the API emits it on the wire and the SDK passes it + // through. Cast through `unknown` to feed the realistic runtime shape. + event: { type: "ping" } as unknown, + } as Parameters[0]; + + const result = streamEventToAcpNotifications( + pingMessage, + "test-session", + {}, + { sessionUpdate: async () => {} } as unknown as Parameters< + typeof streamEventToAcpNotifications + >[3], + logger, + ); + + expect(result).toEqual([]); + expect(errors).toEqual([]); + }); +});