diff --git a/src/auto-reply/reply/dispatch-acp-delivery.test.ts b/src/auto-reply/reply/dispatch-acp-delivery.test.ts index 73c36847ab2..df604555c59 100644 --- a/src/auto-reply/reply/dispatch-acp-delivery.test.ts +++ b/src/auto-reply/reply/dispatch-acp-delivery.test.ts @@ -1,4 +1,5 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +import type { OpenClawConfig } from "../../config/config.js"; import { createAcpDispatchDeliveryCoordinator } from "./dispatch-acp-delivery.js"; import type { ReplyDispatcher } from "./reply-dispatcher.js"; import { buildTestCtx } from "./test-ctx.js"; @@ -273,4 +274,30 @@ describe("createAcpDispatchDeliveryCoordinator", () => { }), ); }); + + it("routes ACP replies when cfg.channels is missing", async () => { + const coordinator = createAcpDispatchDeliveryCoordinator({ + cfg: {} as OpenClawConfig, + ctx: buildTestCtx({ + Provider: "discord", + Surface: "discord", + SessionKey: "agent:codex-acp:session-1", + }), + dispatcher: createDispatcher(), + inboundAudio: false, + shouldRouteToOriginating: true, + originatingChannel: "discord", + originatingTo: "channel:thread-1", + }); + + await coordinator.deliver("block", { text: "hello" }, { skipTts: true }); + + expect(deliveryMocks.routeReply).toHaveBeenCalledWith( + expect.objectContaining({ + channel: "discord", + to: "channel:thread-1", + accountId: undefined, + }), + ); + }); }); diff --git a/src/auto-reply/reply/dispatch-acp-delivery.ts b/src/auto-reply/reply/dispatch-acp-delivery.ts index b268e2fd5c1..7cdf54e23aa 100644 --- a/src/auto-reply/reply/dispatch-acp-delivery.ts +++ b/src/auto-reply/reply/dispatch-acp-delivery.ts @@ -43,8 +43,8 @@ function resolveDeliveryAccountId(params: { return undefined; } const channelCfg = ( - params.cfg.channels as Record - )[channelId]; + params.cfg.channels as Record | undefined + )?.[channelId]; const configuredDefault = channelCfg?.defaultAccount; return typeof configuredDefault === "string" && configuredDefault.trim() ? configuredDefault.trim()