diff --git a/src/infra/outbound/best-effort-delivery.test.ts b/src/infra/outbound/best-effort-delivery.test.ts index 5d5e4b35a6d..e551f2d5ce6 100644 --- a/src/infra/outbound/best-effort-delivery.test.ts +++ b/src/infra/outbound/best-effort-delivery.test.ts @@ -1,21 +1,28 @@ -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import { resolveExternalBestEffortDeliveryTarget, shouldDowngradeDeliveryToSessionOnly, } from "./best-effort-delivery.js"; +vi.mock("../../utils/message-channel.js", () => ({ + INTERNAL_MESSAGE_CHANNEL: "webchat", + isDeliverableMessageChannel: (value: string) => ["alpha", "richchat"].includes(value), + normalizeMessageChannel: (value?: string | null) => + typeof value === "string" ? value.trim().toLowerCase() : undefined, +})); + describe("best-effort delivery helpers", () => { it("resolves external delivery targets only for deliverable channels with to", () => { expect( resolveExternalBestEffortDeliveryTarget({ - channel: "discord", + channel: "richchat", to: "channel:123", accountId: "default", threadId: "thread-1", }), ).toEqual({ deliver: true, - channel: "discord", + channel: "richchat", to: "channel:123", accountId: "default", threadId: "thread-1", @@ -40,7 +47,7 @@ describe("best-effort delivery helpers", () => { it("returns session-only when to is missing", () => { expect( resolveExternalBestEffortDeliveryTarget({ - channel: "telegram", + channel: "alpha", }), ).toEqual({ deliver: false, @@ -72,7 +79,7 @@ describe("best-effort delivery helpers", () => { shouldDowngradeDeliveryToSessionOnly({ wantsDelivery: true, bestEffortDeliver: true, - resolvedChannel: "discord", + resolvedChannel: "richchat", }), ).toBe(false); }); diff --git a/src/infra/outbound/bound-delivery-router.test.ts b/src/infra/outbound/bound-delivery-router.test.ts index 7077d92348e..bd36180aef0 100644 --- a/src/infra/outbound/bound-delivery-router.test.ts +++ b/src/infra/outbound/bound-delivery-router.test.ts @@ -8,7 +8,7 @@ import { const TARGET_SESSION_KEY = "agent:main:subagent:child"; -function createDiscordBinding( +function createRuntimeBinding( targetSessionKey: string, conversationId: string, boundAt: number, @@ -19,7 +19,7 @@ function createDiscordBinding( targetSessionKey, targetKind: "subagent", conversation: { - channel: "discord", + channel: "richchat", accountId: "runtime", conversationId, parentConversationId, @@ -29,12 +29,12 @@ function createDiscordBinding( }; } -function registerDiscordSessionBindings( +function registerRuntimeSessionBindings( targetSessionKey: string, bindings: SessionBindingRecord[], ): void { registerSessionBindingAdapter({ - channel: "discord", + channel: "richchat", accountId: "runtime", listBySession: (requestedSessionKey) => requestedSessionKey === targetSessionKey ? bindings : [], @@ -54,7 +54,7 @@ describe("bound delivery router", () => { failClosed?: boolean; }) => { if (params.bindings) { - registerDiscordSessionBindings( + registerRuntimeSessionBindings( params.targetSessionKey ?? TARGET_SESSION_KEY, params.bindings, ); @@ -65,7 +65,7 @@ describe("bound delivery router", () => { ...(params.requesterConversationId !== undefined ? { requester: { - channel: "discord", + channel: "richchat", accountId: "runtime", conversationId: params.requesterConversationId, }, @@ -78,7 +78,7 @@ describe("bound delivery router", () => { it.each([ { name: "resolves to a bound destination when a single active binding exists", - bindings: [createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1, "parent-1")], + bindings: [createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1, "parent-1")], requesterConversationId: "parent-1", expected: { mode: "bound", @@ -98,8 +98,8 @@ describe("bound delivery router", () => { { name: "fails closed when multiple bindings exist without requester signal", bindings: [ - createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1), - createDiscordBinding(TARGET_SESSION_KEY, "thread-2", 2), + createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1), + createRuntimeBinding(TARGET_SESSION_KEY, "thread-2", 2), ], failClosed: true, expected: { @@ -111,8 +111,8 @@ describe("bound delivery router", () => { { name: "selects requester-matching conversation when multiple bindings exist", bindings: [ - createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1), - createDiscordBinding(TARGET_SESSION_KEY, "thread-2", 2), + createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1), + createRuntimeBinding(TARGET_SESSION_KEY, "thread-2", 2), ], requesterConversationId: "thread-2", failClosed: true, @@ -126,17 +126,17 @@ describe("bound delivery router", () => { name: "normalizes adapter binding conversations before requester matching", bindings: [ { - ...createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1), + ...createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1), conversation: { - channel: " discord ", + channel: " richchat ", accountId: " runtime ", conversationId: " thread-1 ", }, }, { - ...createDiscordBinding(TARGET_SESSION_KEY, "thread-2", 2), + ...createRuntimeBinding(TARGET_SESSION_KEY, "thread-2", 2), conversation: { - channel: " DISCORD ", + channel: " RICHCHAT ", accountId: " Runtime ", conversationId: " thread-2 ", }, @@ -152,7 +152,7 @@ describe("bound delivery router", () => { }, { name: "falls back for invalid requester conversation values", - bindings: [createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1)], + bindings: [createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1)], requesterConversationId: " ", failClosed: true, expected: { diff --git a/src/infra/outbound/directory-cache.test.ts b/src/infra/outbound/directory-cache.test.ts index 1f6781d552c..9ccd586d6a2 100644 --- a/src/infra/outbound/directory-cache.test.ts +++ b/src/infra/outbound/directory-cache.test.ts @@ -7,21 +7,21 @@ describe("buildDirectoryCacheKey", () => { it.each([ { input: { - channel: "slack", + channel: "workspace", kind: "channel", source: "cache", }, - expected: "slack:default:channel:cache:default", + expected: "workspace:default:channel:cache:default", }, { input: { - channel: "discord", + channel: "richchat", accountId: "work", kind: "user", source: "live", signature: "v2", }, - expected: "discord:work:user:live:v2", + expected: "richchat:work:user:live:v2", }, ] satisfies Array<{ input: DirectoryCacheKey; expected: string }>)( "includes account and signature fallbacks for %j", diff --git a/src/infra/outbound/envelope.test.ts b/src/infra/outbound/envelope.test.ts index 7db40ed5f73..f68ffe917b8 100644 --- a/src/infra/outbound/envelope.test.ts +++ b/src/infra/outbound/envelope.test.ts @@ -5,7 +5,7 @@ import type { OutboundDeliveryJson } from "./format.js"; describe("buildOutboundResultEnvelope", () => { const delivery: OutboundDeliveryJson = { - channel: "telegram", + channel: "alpha", via: "direct", to: "123", messageId: "m1", diff --git a/src/infra/outbound/format.test.ts b/src/infra/outbound/format.test.ts index 37e5b4607f6..440bbeec465 100644 --- a/src/infra/outbound/format.test.ts +++ b/src/infra/outbound/format.test.ts @@ -5,7 +5,19 @@ import { formatOutboundDeliverySummary, } from "./format.js"; -const getChannelPluginMock = vi.hoisted(() => vi.fn((_channel: unknown) => undefined)); +const getChannelPluginMock = vi.hoisted(() => + vi.fn((channel: string) => { + const labels: Record = { + alpha: "Alpha", + localchat: "Local Chat", + richchat: "Rich Chat", + workspace: "Workspace", + teamchat: "Team Chat", + }; + const label = labels[channel]; + return label ? { meta: { label } } : undefined; + }), +); vi.mock("../../channels/plugins/index.js", () => ({ getLoadedChannelPlugin: getChannelPluginMock, @@ -14,50 +26,50 @@ vi.mock("../../channels/plugins/index.js", () => ({ describe("formatOutboundDeliverySummary", () => { it.each([ { - channel: "telegram" as const, + channel: "alpha" as const, result: undefined, - expected: "✅ Sent via Telegram. Message ID: unknown", + expected: "✅ Sent via Alpha. Message ID: unknown", }, { - channel: "imessage" as const, + channel: "localchat" as const, result: undefined, - expected: "✅ Sent via iMessage. Message ID: unknown", + expected: "✅ Sent via Local Chat. Message ID: unknown", }, { - channel: "telegram" as const, + channel: "alpha" as const, result: { - channel: "telegram" as const, + channel: "alpha" as const, messageId: "m1", chatId: "c1", }, - expected: "✅ Sent via Telegram. Message ID: m1 (chat c1)", + expected: "✅ Sent via Alpha. Message ID: m1 (chat c1)", }, { - channel: "discord" as const, + channel: "richchat" as const, result: { - channel: "discord" as const, + channel: "richchat" as const, messageId: "d1", channelId: "chan", }, - expected: "✅ Sent via Discord. Message ID: d1 (channel chan)", + expected: "✅ Sent via Rich Chat. Message ID: d1 (channel chan)", }, { - channel: "slack" as const, + channel: "workspace" as const, result: { - channel: "slack" as const, + channel: "workspace" as const, messageId: "s1", roomId: "room-1", }, - expected: "✅ Sent via Slack. Message ID: s1 (room room-1)", + expected: "✅ Sent via Workspace. Message ID: s1 (room room-1)", }, { - channel: "msteams" as const, + channel: "teamchat" as const, result: { - channel: "msteams" as const, + channel: "teamchat" as const, messageId: "t1", conversationId: "conv-1", }, - expected: "✅ Sent via Microsoft Teams. Message ID: t1 (conversation conv-1)", + expected: "✅ Sent via Team Chat. Message ID: t1 (conversation conv-1)", }, ])("formats delivery summary for %j", ({ channel, result, expected }) => { expect(formatOutboundDeliverySummary(channel, result)).toBe(expected); @@ -68,13 +80,13 @@ describe("buildOutboundDeliveryJson", () => { it.each([ { input: { - channel: "telegram" as const, + channel: "alpha" as const, to: "123", - result: { channel: "telegram" as const, messageId: "m1", chatId: "c1" }, + result: { channel: "alpha" as const, messageId: "m1", chatId: "c1" }, mediaUrl: "https://example.com/a.png", }, expected: { - channel: "telegram", + channel: "alpha", via: "direct", to: "123", messageId: "m1", @@ -84,12 +96,12 @@ describe("buildOutboundDeliveryJson", () => { }, { input: { - channel: "whatsapp" as const, + channel: "directchat" as const, to: "+1", - result: { channel: "whatsapp" as const, messageId: "w1", toJid: "jid" }, + result: { channel: "directchat" as const, messageId: "w1", toJid: "jid" }, }, expected: { - channel: "whatsapp", + channel: "directchat", via: "direct", to: "+1", messageId: "w1", @@ -99,12 +111,12 @@ describe("buildOutboundDeliveryJson", () => { }, { input: { - channel: "signal" as const, + channel: "pager" as const, to: "+1", - result: { channel: "signal" as const, messageId: "s1", timestamp: 123 }, + result: { channel: "pager" as const, messageId: "s1", timestamp: 123 }, }, expected: { - channel: "signal", + channel: "pager", via: "direct", to: "+1", messageId: "s1", @@ -114,7 +126,7 @@ describe("buildOutboundDeliveryJson", () => { }, { input: { - channel: "discord" as const, + channel: "richchat" as const, to: "channel:1", via: "gateway" as const, result: { @@ -124,7 +136,7 @@ describe("buildOutboundDeliveryJson", () => { }, }, expected: { - channel: "discord", + channel: "richchat", via: "gateway", to: "channel:1", messageId: "g1", @@ -141,12 +153,12 @@ describe("buildOutboundDeliveryJson", () => { describe("formatGatewaySummary", () => { it.each([ { - input: { channel: "whatsapp", messageId: "m1" }, - expected: "✅ Sent via gateway (whatsapp). Message ID: m1", + input: { channel: "directchat", messageId: "m1" }, + expected: "✅ Sent via gateway (directchat). Message ID: m1", }, { - input: { action: "Poll sent", channel: "discord", messageId: "p1" }, - expected: "✅ Poll sent via gateway (discord). Message ID: p1", + input: { action: "Poll sent", channel: "richchat", messageId: "p1" }, + expected: "✅ Poll sent via gateway (richchat). Message ID: p1", }, { input: {}, diff --git a/src/infra/outbound/outbound.test.ts b/src/infra/outbound/outbound.test.ts index 2db64bce180..c7e25a575e7 100644 --- a/src/infra/outbound/outbound.test.ts +++ b/src/infra/outbound/outbound.test.ts @@ -60,23 +60,23 @@ describe("DirectoryCache", () => { }); describe("buildOutboundResultEnvelope", () => { - const whatsappDelivery: OutboundDeliveryJson = { - channel: "whatsapp", + const directChatDelivery: OutboundDeliveryJson = { + channel: "directchat", via: "gateway", to: "+1", messageId: "m1", mediaUrl: null, }; - const telegramDelivery: OutboundDeliveryJson = { - channel: "telegram", + const alphaDelivery: OutboundDeliveryJson = { + channel: "alpha", via: "direct", to: "123", messageId: "m2", mediaUrl: null, chatId: "c1", }; - const discordDelivery: OutboundDeliveryJson = { - channel: "discord", + const richChatDelivery: OutboundDeliveryJson = { + channel: "richchat", via: "gateway", to: "channel:C1", messageId: "m3", @@ -92,8 +92,8 @@ describe("buildOutboundResultEnvelope", () => { }>([ { name: "flatten delivery by default", - input: { delivery: whatsappDelivery }, - expected: whatsappDelivery, + input: { delivery: directChatDelivery }, + expected: directChatDelivery, }, { name: "keep payloads + meta", @@ -108,17 +108,17 @@ describe("buildOutboundResultEnvelope", () => { }, { name: "include delivery when payloads exist", - input: { payloads: [], delivery: telegramDelivery, meta: { ok: true } }, + input: { payloads: [], delivery: alphaDelivery, meta: { ok: true } }, expected: { payloads: [], meta: { ok: true }, - delivery: telegramDelivery, + delivery: alphaDelivery, }, }, { name: "keep wrapped delivery when flatten disabled", - input: { delivery: discordDelivery, flattenDelivery: false }, - expected: { delivery: discordDelivery }, + input: { delivery: richChatDelivery, flattenDelivery: false }, + expected: { delivery: richChatDelivery }, }, ]), )("$name", ({ input, expected }) => {