Skip to content

Commit c3390e6

Browse files
committed
feat(qa): wire crabline whatsapp transport
1 parent 2cc43ae commit c3390e6

4 files changed

Lines changed: 95 additions & 8 deletions

File tree

extensions/qa-lab/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"@openclaw/plugin-sdk": "workspace:*",
1717
"@openclaw/slack": "workspace:*",
1818
"@openclaw/whatsapp": "workspace:*",
19-
"@openclaw/crabline": "0.1.3",
19+
"@openclaw/crabline": "0.1.4",
2020
"openclaw": "2026.5.28"
2121
},
2222
"peerDependencies": {

extensions/qa-lab/src/crabline-transport.test.ts

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { describe, expect, it } from "vitest";
88
import { createQaBusState } from "./bus-state.js";
99
import { createQaCrablineTransportAdapter } from "./crabline-transport.js";
1010

11-
function createSelection(channel: "slack" | "telegram" = "telegram") {
11+
function createSelection(channel: "slack" | "telegram" | "whatsapp" = "telegram") {
1212
return {
1313
capabilityMatrixPath: "crabline-fake-provider-capabilities.json",
1414
channel,
@@ -160,6 +160,91 @@ describe("crabline transport", () => {
160160
});
161161
});
162162

163+
it("configures OpenClaw's WhatsApp plugin against a Crabline Baileys WebSocket server", async () => {
164+
await withTempDir("qa-crabline-transport-", async (outputDir) => {
165+
const transport = await createQaCrablineTransportAdapter({
166+
outputDir,
167+
selection: createSelection("whatsapp"),
168+
state: createQaBusState(),
169+
});
170+
171+
try {
172+
expect(transport.id).toBe("crabline");
173+
expect(transport.requiredPluginIds).toEqual(["whatsapp"]);
174+
expect(transport.createGatewayConfig({ baseUrl: "http://127.0.0.1:1" })).toMatchObject({
175+
channels: {
176+
whatsapp: {
177+
allowFrom: ["*"],
178+
dmPolicy: "open",
179+
enabled: true,
180+
groupAllowFrom: ["*"],
181+
groupPolicy: "open",
182+
},
183+
},
184+
});
185+
expect(transport.buildAgentDelivery({ target: "[email protected]" })).toEqual({
186+
channel: "whatsapp",
187+
188+
replyChannel: "whatsapp",
189+
replyTo: "[email protected]",
190+
});
191+
const env = transport.createRuntimeEnvPatch?.() ?? {};
192+
expect(env).toMatchObject({
193+
CRABLINE_WHATSAPP_ADMIN_TOKEN: expect.any(String),
194+
CRABLINE_WHATSAPP_RECORDER_PATH: expect.stringMatching(/whatsapp-fake-provider\.jsonl$/u),
195+
CRABLINE_WHATSAPP_SELF_JID: "[email protected]",
196+
OPENCLAW_WHATSAPP_WEB_SOCKET_URL: expect.stringMatching(
197+
/^ws:\/\/127\.0\.0\.1:\d+\/crabline\/whatsapp\/ws\/chat\?access_token=/u,
198+
),
199+
});
200+
expect(env.CRABLINE_WHATSAPP_ACCESS_TOKEN).toBeUndefined();
201+
expect(env.CRABLINE_WHATSAPP_API_ROOT).toBeUndefined();
202+
203+
const manifest = JSON.parse(
204+
await fs.readFile(path.join(outputDir, OPENCLAW_CRABLINE_MANIFEST_PATH), "utf8"),
205+
) as {
206+
provider?: string;
207+
};
208+
expect(manifest.provider).toBe("whatsapp");
209+
} finally {
210+
await transport.cleanup?.();
211+
}
212+
});
213+
});
214+
215+
it("injects WhatsApp inbound messages through Crabline into normalized state", async () => {
216+
await withTempDir("qa-crabline-transport-", async (outputDir) => {
217+
const transport = await createQaCrablineTransportAdapter({
218+
outputDir,
219+
selection: createSelection("whatsapp"),
220+
state: createQaBusState(),
221+
});
222+
223+
try {
224+
const message = await transport.state.addInboundMessage({
225+
conversation: {
226+
227+
kind: "direct",
228+
},
229+
senderId: "[email protected]",
230+
senderName: "Alice",
231+
text: "WhatsApp baseline marker check.",
232+
});
233+
expect(message).toMatchObject({
234+
conversation: {
235+
236+
kind: "direct",
237+
},
238+
direction: "inbound",
239+
senderId: "[email protected]",
240+
text: "WhatsApp baseline marker check.",
241+
});
242+
} finally {
243+
await transport.cleanup?.();
244+
}
245+
});
246+
});
247+
163248
it("injects inbound messages through Crabline and mirrors Telegram sends into normalized state", async () => {
164249
await withTempDir("qa-crabline-transport-", async (outputDir) => {
165250
const transport = await createQaCrablineTransportAdapter({

pnpm-lock.yaml

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ packages:
77
minimumReleaseAge: 2880
88

99
minimumReleaseAgeExclude:
10-
- "@openclaw/[email protected].3"
10+
- "@openclaw/[email protected].4"
1111
- "@openclaw/[email protected]"
1212
- "@openclaw/[email protected]"
1313
- "acpx"

0 commit comments

Comments
 (0)