feat: mirror delivered outbound messages (#1031)

Co-authored-by: T Savo <TSavo@users.noreply.github.com>
This commit is contained in:
Peter Steinberger
2026-01-17 01:48:02 +00:00
parent 3fb699a84b
commit fdaeada3ec
26 changed files with 697 additions and 29 deletions

View File

@@ -17,6 +17,7 @@ const mocks = vi.hoisted(() => ({
sendMessageSlack: vi.fn(async () => ({ messageId: "m1", channelId: "c1" })),
sendMessageTelegram: vi.fn(async () => ({ messageId: "m1", chatId: "c1" })),
sendMessageWhatsApp: vi.fn(async () => ({ messageId: "m1", toJid: "jid" })),
deliverOutboundPayloads: vi.fn(),
}));
vi.mock("../../discord/send.js", () => ({
@@ -37,12 +38,25 @@ vi.mock("../../telegram/send.js", () => ({
vi.mock("../../web/outbound.js", () => ({
sendMessageWhatsApp: mocks.sendMessageWhatsApp,
}));
vi.mock("../../infra/outbound/deliver.js", async () => {
const actual = await vi.importActual<typeof import("../../infra/outbound/deliver.js")>(
"../../infra/outbound/deliver.js",
);
return {
...actual,
deliverOutboundPayloads: mocks.deliverOutboundPayloads,
};
});
const actualDeliver = await vi.importActual<typeof import("../../infra/outbound/deliver.js")>(
"../../infra/outbound/deliver.js",
);
const { routeReply } = await import("./route-reply.js");
describe("routeReply", () => {
beforeEach(() => {
setActivePluginRegistry(emptyRegistry);
mocks.deliverOutboundPayloads.mockImplementation(actualDeliver.deliverOutboundPayloads);
});
afterEach(() => {
@@ -261,6 +275,25 @@ describe("routeReply", () => {
}),
);
});
it("passes mirror data when sessionKey is set", async () => {
mocks.deliverOutboundPayloads.mockResolvedValue([]);
await routeReply({
payload: { text: "hi" },
channel: "slack",
to: "channel:C123",
sessionKey: "agent:main:main",
cfg: {} as never,
});
expect(mocks.deliverOutboundPayloads).toHaveBeenCalledWith(
expect.objectContaining({
mirror: expect.objectContaining({
sessionKey: "agent:main:main",
text: "hi",
}),
}),
);
});
});
const createRegistry = (channels: PluginRegistry["channels"]): PluginRegistry => ({

View File

@@ -113,7 +113,16 @@ export async function routeReply(params: RouteReplyParams): Promise<RouteReplyRe
replyToId: replyToId ?? null,
threadId: threadId ?? null,
abortSignal,
mirror: params.sessionKey
? {
sessionKey: params.sessionKey,
agentId: resolveSessionAgentId({ sessionKey: params.sessionKey, config: cfg }),
text,
mediaUrls,
}
: undefined,
});
const last = results.at(-1);
return { ok: true, messageId: last?.messageId };
} catch (err) {