test(extensions): split outbound payload contracts

This commit is contained in:
Peter Steinberger
2026-04-20 19:37:07 +01:00
parent 0a761a9eac
commit b3a0da7c5e
10 changed files with 340 additions and 442 deletions

View File

@@ -1,2 +1,2 @@
15505f02306eb9920e350babf1b290d8fcc1b2338b4fccf65d3525de83d9bbcb plugin-sdk-api-baseline.json
06fc58082be4c2e1df1030fa9e8d965c6d5947984c4aed360c0474c1639a0a84 plugin-sdk-api-baseline.jsonl
db3c843947298c9af4b5f5fa7ecde6656dba32189ec386c29192fe498d64e5e5 plugin-sdk-api-baseline.json
c14586fd393a1375ee02ba507ffc83a2886d97632e323e5661b618c71624d26b plugin-sdk-api-baseline.jsonl

View File

@@ -0,0 +1,38 @@
import {
installChannelOutboundPayloadContractSuite,
primeChannelOutboundSendMock,
type OutboundPayloadHarnessParams,
} from "openclaw/plugin-sdk/testing";
import { describe, vi } from "vitest";
import { discordOutbound } from "./outbound-adapter.js";
function createDiscordHarness(params: OutboundPayloadHarnessParams) {
const sendDiscord = vi.fn();
primeChannelOutboundSendMock(
sendDiscord,
{ messageId: "dc-1", channelId: "123456" },
params.sendResults,
);
const ctx = {
cfg: {},
to: "channel:123456",
text: "",
payload: params.payload,
deps: {
sendDiscord,
},
};
return {
run: async () => await discordOutbound.sendPayload!(ctx),
sendMock: sendDiscord,
to: ctx.to,
};
}
describe("Discord outbound payload contract", () => {
installChannelOutboundPayloadContractSuite({
channel: "discord",
chunking: { mode: "passthrough", longTextLength: 3000 },
createHarness: createDiscordHarness,
});
});

View File

@@ -0,0 +1,11 @@
import { installChannelOutboundPayloadContractSuite } from "openclaw/plugin-sdk/testing";
import { describe } from "vitest";
import { createSlackOutboundPayloadHarness } from "./outbound-payload.test-harness.js";
describe("Slack outbound payload contract", () => {
installChannelOutboundPayloadContractSuite({
channel: "slack",
chunking: { mode: "passthrough", longTextLength: 5000 },
createHarness: createSlackOutboundPayloadHarness,
});
});

View File

@@ -0,0 +1,34 @@
import {
installChannelOutboundPayloadContractSuite,
primeChannelOutboundSendMock,
type OutboundPayloadHarnessParams,
} from "openclaw/plugin-sdk/testing";
import { describe, vi } from "vitest";
import { whatsappOutbound } from "./outbound-adapter.js";
function createWhatsAppHarness(params: OutboundPayloadHarnessParams) {
const sendWhatsApp = vi.fn();
primeChannelOutboundSendMock(sendWhatsApp, { messageId: "wa-1" }, params.sendResults);
const ctx = {
cfg: {},
to: "5511999999999@c.us",
text: "",
payload: params.payload,
deps: {
whatsapp: sendWhatsApp,
},
};
return {
run: async () => await whatsappOutbound.sendPayload!(ctx),
sendMock: sendWhatsApp,
to: ctx.to,
};
}
describe("WhatsApp outbound payload contract", () => {
installChannelOutboundPayloadContractSuite({
channel: "whatsapp",
chunking: { mode: "split", longTextLength: 5000, maxChunkLength: 4000 },
createHarness: createWhatsAppHarness,
});
});

View File

@@ -0,0 +1,45 @@
import {
installChannelOutboundPayloadContractSuite,
primeChannelOutboundSendMock,
type OutboundPayloadHarnessParams,
} from "openclaw/plugin-sdk/testing";
import { describe, vi } from "vitest";
import { zaloPlugin } from "./channel.js";
const { sendZaloTextMock } = vi.hoisted(() => ({
sendZaloTextMock: vi.fn(),
}));
vi.mock("./channel.runtime.js", () => ({
sendZaloText: sendZaloTextMock,
}));
function createZaloHarness(params: OutboundPayloadHarnessParams) {
const sendZalo = vi.fn();
primeChannelOutboundSendMock(sendZalo, { ok: true, messageId: "zl-1" }, params.sendResults);
sendZaloTextMock.mockReset().mockImplementation(
async (nextCtx: { to: string; text: string; mediaUrl?: string }) =>
await sendZalo(nextCtx.to, nextCtx.text, {
mediaUrl: nextCtx.mediaUrl,
}),
);
const ctx = {
cfg: {},
to: "123456789",
text: "",
payload: params.payload,
};
return {
run: async () => await zaloPlugin.outbound!.sendPayload!(ctx),
sendMock: sendZalo,
to: ctx.to,
};
}
describe("Zalo outbound payload contract", () => {
installChannelOutboundPayloadContractSuite({
channel: "zalo",
chunking: { mode: "split", longTextLength: 3000, maxChunkLength: 2000 },
createHarness: createZaloHarness,
});
});

View File

@@ -1,4 +1,8 @@
import { primeChannelOutboundSendMock } from "openclaw/plugin-sdk/testing";
import {
installChannelOutboundPayloadContractSuite,
primeChannelOutboundSendMock,
type OutboundPayloadHarnessParams,
} from "openclaw/plugin-sdk/testing";
import { beforeEach, describe, expect, it, vi } from "vitest";
import "./accounts.test-mocks.js";
import "./zalo-js.test-mocks.js";
@@ -109,6 +113,38 @@ describe("zalouserPlugin outbound sendPayload", () => {
});
});
describe("zalouserPlugin outbound payload contract", () => {
function createZalouserHarness(params: OutboundPayloadHarnessParams) {
const mockedSend = vi.mocked(sendModule.sendMessageZalouser);
setZalouserRuntime({
channel: {
text: {
resolveChunkMode: vi.fn(() => "length"),
resolveTextChunkLimit: vi.fn(() => 1200),
},
},
} as never);
primeChannelOutboundSendMock(mockedSend, { ok: true, messageId: "zlu-1" }, params.sendResults);
const ctx = {
cfg: {},
to: "user:987654321",
text: "",
payload: params.payload,
};
return {
run: async () => await zalouserPlugin.outbound!.sendPayload!(ctx),
sendMock: mockedSend,
to: "987654321",
};
}
installChannelOutboundPayloadContractSuite({
channel: "zalouser",
chunking: { mode: "passthrough", longTextLength: 3000 },
createHarness: createZalouserHarness,
});
});
describe("zalouserPlugin messaging target normalization", () => {
it("normalizes user/group aliases to canonical targets", () => {
const normalize = zalouserPlugin.messaging?.normalizeTarget;

View File

@@ -0,0 +1,134 @@
import { beforeEach, expect, it, type Mock } from "vitest";
import type { ReplyPayload } from "../../../plugin-sdk/reply-payload.js";
import { resetGlobalHookRunner } from "../../../plugins/hook-runner-global.js";
type PayloadLike = Pick<ReplyPayload, "mediaUrl" | "mediaUrls" | "text">;
type SendResultLike = {
messageId: string;
[key: string]: unknown;
};
type ChunkingMode =
| {
longTextLength: number;
maxChunkLength: number;
mode: "split";
}
| {
longTextLength: number;
mode: "passthrough";
};
type OutboundPayloadHarness = {
run: () => Promise<Record<string, unknown>>;
sendMock: Mock;
to: string;
};
export type OutboundPayloadHarnessParams = {
payload: PayloadLike;
sendResults?: SendResultLike[];
};
export function installChannelOutboundPayloadContractSuite(params: {
channel: string;
chunking: ChunkingMode;
createHarness: (
params: OutboundPayloadHarnessParams,
) => OutboundPayloadHarness | Promise<OutboundPayloadHarness>;
}) {
beforeEach(() => {
resetGlobalHookRunner();
});
it("text-only delegates to sendText", async () => {
const { run, sendMock, to } = await params.createHarness({
payload: { text: "hello" },
});
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(1);
expect(sendMock).toHaveBeenCalledWith(to, "hello", expect.any(Object));
expect(result).toMatchObject({ channel: params.channel });
});
it("single media delegates to sendMedia", async () => {
const { run, sendMock, to } = await params.createHarness({
payload: { text: "cap", mediaUrl: "https://example.com/a.jpg" },
});
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(1);
expect(sendMock).toHaveBeenCalledWith(
to,
"cap",
expect.objectContaining({ mediaUrl: "https://example.com/a.jpg" }),
);
expect(result).toMatchObject({ channel: params.channel });
});
it("multi-media iterates URLs with caption on first", async () => {
const { run, sendMock, to } = await params.createHarness({
payload: {
text: "caption",
mediaUrls: ["https://example.com/1.jpg", "https://example.com/2.jpg"],
},
sendResults: [{ messageId: "m-1" }, { messageId: "m-2" }],
});
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(2);
expect(sendMock).toHaveBeenNthCalledWith(
1,
to,
"caption",
expect.objectContaining({ mediaUrl: "https://example.com/1.jpg" }),
);
expect(sendMock).toHaveBeenNthCalledWith(
2,
to,
"",
expect.objectContaining({ mediaUrl: "https://example.com/2.jpg" }),
);
expect(result).toMatchObject({ channel: params.channel, messageId: "m-2" });
});
it("empty payload returns no-op", async () => {
const { run, sendMock } = await params.createHarness({ payload: {} });
const result = await run();
expect(sendMock).not.toHaveBeenCalled();
expect(result).toEqual({ channel: params.channel, messageId: "" });
});
if (params.chunking.mode === "passthrough") {
it("text exceeding chunk limit is sent as-is when chunker is null", async () => {
const text = "a".repeat(params.chunking.longTextLength);
const { run, sendMock, to } = await params.createHarness({ payload: { text } });
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(1);
expect(sendMock).toHaveBeenCalledWith(to, text, expect.any(Object));
expect(result).toMatchObject({ channel: params.channel });
});
return;
}
const chunking = params.chunking;
it("chunking splits long text", async () => {
const text = "a".repeat(chunking.longTextLength);
const { run, sendMock } = await params.createHarness({
payload: { text },
sendResults: [{ messageId: "c-1" }, { messageId: "c-2" }],
});
const result = await run();
expect(sendMock.mock.calls.length).toBeGreaterThanOrEqual(2);
for (const call of sendMock.mock.calls) {
expect((call[1] as string).length).toBeLessThanOrEqual(chunking.maxChunkLength);
}
expect(result).toMatchObject({ channel: params.channel });
});
}

View File

@@ -1,35 +1,40 @@
import { describe } from "vitest";
import { describe, vi } from "vitest";
import { createDirectTextMediaOutbound } from "../outbound/direct-text-media.js";
import {
installDirectTextMediaOutboundPayloadContractSuite,
installDiscordOutboundPayloadContractSuite,
installSlackOutboundPayloadContractSuite,
installWhatsAppOutboundPayloadContractSuite,
installZaloOutboundPayloadContractSuite,
installZalouserOutboundPayloadContractSuite,
} from "../../../../test/helpers/channels/outbound-payload-contract.js";
installChannelOutboundPayloadContractSuite,
type OutboundPayloadHarnessParams,
} from "./outbound-payload-testkit.js";
import { primeChannelOutboundSendMock } from "./test-helpers.js";
function createDirectTextMediaHarness(params: OutboundPayloadHarnessParams) {
const sendFn = vi.fn();
primeChannelOutboundSendMock(sendFn, { messageId: "m1" }, params.sendResults);
const outbound = createDirectTextMediaOutbound({
channel: "direct-text-media",
resolveSender: () => sendFn,
resolveMaxBytes: () => undefined,
buildTextOptions: (opts) => opts as never,
buildMediaOptions: (opts) => opts as never,
});
const ctx = {
cfg: {},
to: "user1",
text: "",
payload: params.payload,
};
return {
run: async () => await outbound.sendPayload!(ctx),
sendMock: sendFn,
to: ctx.to,
};
}
describe("outbound payload contracts", () => {
describe("discord", () => {
installDiscordOutboundPayloadContractSuite();
});
describe("imessage", () => {
installDirectTextMediaOutboundPayloadContractSuite();
});
describe("slack", () => {
installSlackOutboundPayloadContractSuite();
});
describe("whatsapp", () => {
installWhatsAppOutboundPayloadContractSuite();
});
describe("zalo", () => {
installZaloOutboundPayloadContractSuite();
});
describe("zalouser", () => {
installZalouserOutboundPayloadContractSuite();
describe("direct text/media", () => {
installChannelOutboundPayloadContractSuite({
channel: "direct-text-media",
chunking: { mode: "split", longTextLength: 5000, maxChunkLength: 4000 },
createHarness: createDirectTextMediaHarness,
});
});
});

View File

@@ -6,6 +6,10 @@ export {
expectChannelInboundContextContract,
primeChannelOutboundSendMock,
} from "../channels/plugins/contracts/test-helpers.js";
export {
installChannelOutboundPayloadContractSuite,
type OutboundPayloadHarnessParams,
} from "../channels/plugins/contracts/outbound-payload-testkit.js";
export { buildDispatchInboundCaptureMock } from "../channels/plugins/contracts/inbound-testkit.js";
export {
createCliRuntimeCapture,

View File

@@ -1,409 +0,0 @@
import { beforeEach, expect, it, type Mock, vi } from "vitest";
import type { ReplyPayload } from "../../../src/auto-reply/types.js";
import { primeChannelOutboundSendMock } from "../../../src/channels/plugins/contracts/test-helpers.js";
import { createDirectTextMediaOutbound } from "../../../src/channels/plugins/outbound/direct-text-media.js";
import type { ChannelOutboundAdapter } from "../../../src/channels/plugins/types.js";
import { sendPayloadWithChunkedTextAndMedia } from "../../../src/plugin-sdk/reply-payload.js";
import { chunkTextForOutbound } from "../../../src/plugin-sdk/text-chunking.js";
import { resetGlobalHookRunner } from "../../../src/plugins/hook-runner-global.js";
import { resolveRelativeBundledPluginPublicModuleId } from "../../../src/test-utils/bundled-plugin-public-surface.js";
type CreateSlackOutboundPayloadHarness = (params: PayloadHarnessParams) => {
run: () => Promise<Record<string, unknown>>;
sendMock: Mock;
to: string;
};
const discordOutboundAdapterModuleId = resolveRelativeBundledPluginPublicModuleId({
fromModuleUrl: import.meta.url,
pluginId: "discord",
artifactBasename: "src/outbound-adapter.js",
});
const slackTestApiModuleId = resolveRelativeBundledPluginPublicModuleId({
fromModuleUrl: import.meta.url,
pluginId: "slack",
artifactBasename: "outbound-payload-test-api.js",
});
const whatsappTestApiModuleId = resolveRelativeBundledPluginPublicModuleId({
fromModuleUrl: import.meta.url,
pluginId: "whatsapp",
artifactBasename: "outbound-payload-test-api.js",
});
let discordOutboundCache: Promise<ChannelOutboundAdapter> | undefined;
let slackTestApiPromise:
| Promise<{
createSlackOutboundPayloadHarness: CreateSlackOutboundPayloadHarness;
}>
| undefined;
let whatsappTestApiPromise:
| Promise<{
whatsappOutbound: ChannelOutboundAdapter;
}>
| undefined;
async function getDiscordOutbound(): Promise<ChannelOutboundAdapter> {
discordOutboundCache ??= (async () => {
const module = (await import(discordOutboundAdapterModuleId)) as {
discordOutbound: ChannelOutboundAdapter;
};
return module.discordOutbound;
})();
return await discordOutboundCache;
}
async function getCreateSlackOutboundPayloadHarness(): Promise<CreateSlackOutboundPayloadHarness> {
slackTestApiPromise ??= import(slackTestApiModuleId) as Promise<{
createSlackOutboundPayloadHarness: CreateSlackOutboundPayloadHarness;
}>;
const { createSlackOutboundPayloadHarness } = await slackTestApiPromise;
return createSlackOutboundPayloadHarness;
}
async function getWhatsAppOutboundAsync(): Promise<ChannelOutboundAdapter> {
whatsappTestApiPromise ??= import(whatsappTestApiModuleId) as Promise<{
whatsappOutbound: ChannelOutboundAdapter;
}>;
const { whatsappOutbound } = await whatsappTestApiPromise;
return whatsappOutbound;
}
type PayloadHarnessParams = {
payload: ReplyPayload;
sendResults?: Array<{ messageId: string }>;
};
type PayloadLike = {
mediaUrl?: string;
mediaUrls?: string[];
text?: string;
};
type SendResultLike = {
messageId: string;
[key: string]: unknown;
};
type ChunkingMode =
| {
longTextLength: number;
maxChunkLength: number;
mode: "split";
}
| {
longTextLength: number;
mode: "passthrough";
};
function installChannelOutboundPayloadContractSuite(params: {
channel: string;
chunking: ChunkingMode;
createHarness: (params: { payload: PayloadLike; sendResults?: SendResultLike[] }) =>
| {
run: () => Promise<Record<string, unknown>>;
sendMock: Mock;
to: string;
}
| Promise<{
run: () => Promise<Record<string, unknown>>;
sendMock: Mock;
to: string;
}>;
}) {
beforeEach(() => {
resetGlobalHookRunner();
});
it("text-only delegates to sendText", async () => {
const { run, sendMock, to } = await params.createHarness({
payload: { text: "hello" },
});
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(1);
expect(sendMock).toHaveBeenCalledWith(to, "hello", expect.any(Object));
expect(result).toMatchObject({ channel: params.channel });
});
it("single media delegates to sendMedia", async () => {
const { run, sendMock, to } = await params.createHarness({
payload: { text: "cap", mediaUrl: "https://example.com/a.jpg" },
});
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(1);
expect(sendMock).toHaveBeenCalledWith(
to,
"cap",
expect.objectContaining({ mediaUrl: "https://example.com/a.jpg" }),
);
expect(result).toMatchObject({ channel: params.channel });
});
it("multi-media iterates URLs with caption on first", async () => {
const { run, sendMock, to } = await params.createHarness({
payload: {
text: "caption",
mediaUrls: ["https://example.com/1.jpg", "https://example.com/2.jpg"],
},
sendResults: [{ messageId: "m-1" }, { messageId: "m-2" }],
});
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(2);
expect(sendMock).toHaveBeenNthCalledWith(
1,
to,
"caption",
expect.objectContaining({ mediaUrl: "https://example.com/1.jpg" }),
);
expect(sendMock).toHaveBeenNthCalledWith(
2,
to,
"",
expect.objectContaining({ mediaUrl: "https://example.com/2.jpg" }),
);
expect(result).toMatchObject({ channel: params.channel, messageId: "m-2" });
});
it("empty payload returns no-op", async () => {
const { run, sendMock } = await params.createHarness({ payload: {} });
const result = await run();
expect(sendMock).not.toHaveBeenCalled();
expect(result).toEqual({ channel: params.channel, messageId: "" });
});
if (params.chunking.mode === "passthrough") {
it("text exceeding chunk limit is sent as-is when chunker is null", async () => {
const text = "a".repeat(params.chunking.longTextLength);
const { run, sendMock, to } = await params.createHarness({ payload: { text } });
const result = await run();
expect(sendMock).toHaveBeenCalledTimes(1);
expect(sendMock).toHaveBeenCalledWith(to, text, expect.any(Object));
expect(result).toMatchObject({ channel: params.channel });
});
return;
}
const chunking = params.chunking;
it("chunking splits long text", async () => {
const text = "a".repeat(chunking.longTextLength);
const { run, sendMock } = await params.createHarness({
payload: { text },
sendResults: [{ messageId: "c-1" }, { messageId: "c-2" }],
});
const result = await run();
expect(sendMock.mock.calls.length).toBeGreaterThanOrEqual(2);
for (const call of sendMock.mock.calls) {
expect((call[1] as string).length).toBeLessThanOrEqual(chunking.maxChunkLength);
}
expect(result).toMatchObject({ channel: params.channel });
});
}
function buildChannelSendResult(channel: string, result: Record<string, unknown>) {
return {
channel,
messageId: typeof result.messageId === "string" ? result.messageId : "",
};
}
function createDiscordHarness(params: PayloadHarnessParams) {
const sendDiscord = vi.fn();
primeChannelOutboundSendMock(
sendDiscord,
{ messageId: "dc-1", channelId: "123456" },
params.sendResults,
);
const ctx = {
cfg: {},
to: "channel:123456",
text: "",
payload: params.payload,
deps: {
sendDiscord,
},
};
return {
run: async () => await (await getDiscordOutbound()).sendPayload!(ctx),
sendMock: sendDiscord,
to: ctx.to,
};
}
function createWhatsAppHarness(params: PayloadHarnessParams) {
const sendWhatsApp = vi.fn();
primeChannelOutboundSendMock(sendWhatsApp, { messageId: "wa-1" }, params.sendResults);
const ctx = {
cfg: {},
to: "5511999999999@c.us",
text: "",
payload: params.payload,
deps: {
whatsapp: sendWhatsApp,
},
};
return {
run: async () => await (await getWhatsAppOutboundAsync()).sendPayload!(ctx),
sendMock: sendWhatsApp,
to: ctx.to,
};
}
function createDirectTextMediaHarness(params: PayloadHarnessParams) {
const sendFn = vi.fn();
primeChannelOutboundSendMock(sendFn, { messageId: "m1" }, params.sendResults);
const outbound = createDirectTextMediaOutbound({
channel: "imessage",
resolveSender: () => sendFn,
resolveMaxBytes: () => undefined,
buildTextOptions: (opts) => opts as never,
buildMediaOptions: (opts) => opts as never,
});
const ctx = {
cfg: {},
to: "user1",
text: "",
payload: params.payload,
};
return {
run: async () => await outbound.sendPayload!(ctx),
sendMock: sendFn,
to: ctx.to,
};
}
function createZaloHarness(params: PayloadHarnessParams) {
const sendZalo = vi.fn();
primeChannelOutboundSendMock(sendZalo, { ok: true, messageId: "zl-1" }, params.sendResults);
const ctx = {
cfg: {},
to: "123456789",
text: "",
payload: params.payload,
};
return {
run: async () =>
await sendPayloadWithChunkedTextAndMedia({
ctx,
textChunkLimit: 2000,
chunker: chunkTextForOutbound,
sendText: async (nextCtx) =>
buildChannelSendResult(
"zalo",
await sendZalo(nextCtx.to, nextCtx.text, {
accountId: undefined,
cfg: nextCtx.cfg,
}),
),
sendMedia: async (nextCtx) =>
buildChannelSendResult(
"zalo",
await sendZalo(nextCtx.to, nextCtx.text, {
accountId: undefined,
cfg: nextCtx.cfg,
mediaUrl: nextCtx.mediaUrl,
}),
),
emptyResult: { channel: "zalo", messageId: "" },
}),
sendMock: sendZalo,
to: ctx.to,
};
}
function createZalouserHarness(params: PayloadHarnessParams) {
const sendZalouser = vi.fn();
primeChannelOutboundSendMock(sendZalouser, { ok: true, messageId: "zlu-1" }, params.sendResults);
const ctx = {
cfg: {},
to: "987654321",
text: "",
payload: params.payload,
};
return {
run: async () =>
await sendPayloadWithChunkedTextAndMedia({
ctx,
sendText: async (nextCtx) => {
return buildChannelSendResult(
"zalouser",
await sendZalouser(nextCtx.to, nextCtx.text, {
profile: "default",
isGroup: false,
textMode: "markdown",
textChunkMode: "length",
textChunkLimit: 1200,
}),
);
},
sendMedia: async (nextCtx) => {
return buildChannelSendResult(
"zalouser",
await sendZalouser(nextCtx.to, nextCtx.text, {
profile: "default",
isGroup: false,
mediaUrl: nextCtx.mediaUrl,
textMode: "markdown",
textChunkMode: "length",
textChunkLimit: 1200,
}),
);
},
emptyResult: { channel: "zalouser", messageId: "" },
}),
sendMock: sendZalouser,
to: ctx.to,
};
}
export function installSlackOutboundPayloadContractSuite() {
installChannelOutboundPayloadContractSuite({
channel: "slack",
chunking: { mode: "passthrough", longTextLength: 5000 },
createHarness: async (params) => (await getCreateSlackOutboundPayloadHarness())(params),
});
}
export function installDiscordOutboundPayloadContractSuite() {
installChannelOutboundPayloadContractSuite({
channel: "discord",
chunking: { mode: "passthrough", longTextLength: 3000 },
createHarness: createDiscordHarness,
});
}
export function installWhatsAppOutboundPayloadContractSuite() {
installChannelOutboundPayloadContractSuite({
channel: "whatsapp",
chunking: { mode: "split", longTextLength: 5000, maxChunkLength: 4000 },
createHarness: createWhatsAppHarness,
});
}
export function installZaloOutboundPayloadContractSuite() {
installChannelOutboundPayloadContractSuite({
channel: "zalo",
chunking: { mode: "split", longTextLength: 3000, maxChunkLength: 2000 },
createHarness: createZaloHarness,
});
}
export function installZalouserOutboundPayloadContractSuite() {
installChannelOutboundPayloadContractSuite({
channel: "zalouser",
chunking: { mode: "passthrough", longTextLength: 3000 },
createHarness: createZalouserHarness,
});
}
export function installDirectTextMediaOutboundPayloadContractSuite() {
installChannelOutboundPayloadContractSuite({
channel: "imessage",
chunking: { mode: "split", longTextLength: 5000, maxChunkLength: 4000 },
createHarness: createDirectTextMediaHarness,
});
}