|
1 | 1 | import fs from "node:fs/promises"; |
2 | 2 | import os from "node:os"; |
3 | 3 | import path from "node:path"; |
4 | | -import { afterAll, beforeAll, beforeEach, describe, expect, it, type Mock } from "vitest"; |
| 4 | +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi, type Mock } from "vitest"; |
| 5 | +import { testing as agentStepTesting } from "../agents/tools/agent-step.js"; |
| 6 | +import { runSessionsSendA2AFlow } from "../agents/tools/sessions-send-tool.a2a.js"; |
5 | 7 | import { resolveSessionTranscriptPath } from "../config/sessions.js"; |
6 | 8 | import type { OpenClawConfig } from "../config/types.openclaw.js"; |
7 | 9 | import { emitAgentEvent } from "../infra/agent-events.js"; |
| 10 | +import { createOutboundTestPlugin, createTestRegistry } from "../test-utils/channel-plugins.js"; |
8 | 11 | import { captureEnv } from "../test-utils/env.js"; |
9 | 12 | import { |
10 | 13 | agentCommand, |
11 | 14 | getFreePort, |
12 | 15 | installGatewayTestHooks, |
13 | 16 | startGatewayServer, |
| 17 | + setTestPluginRegistry, |
14 | 18 | testState, |
15 | 19 | writeSessionStore, |
16 | 20 | } from "./test-helpers.js"; |
@@ -171,6 +175,114 @@ describe("sessions_send gateway loopback", () => { |
171 | 175 | expect(firstCall?.inputProvenance?.kind).toBe("inter_session"); |
172 | 176 | expect(firstCall?.inputProvenance?.sourceTool).toBe("sessions_send"); |
173 | 177 | }); |
| 178 | + |
| 179 | + it( |
| 180 | + "announces through gateway send using external deliveryContext over stale webchat session fields", |
| 181 | + { timeout: SESSION_SEND_E2E_TIMEOUT_MS }, |
| 182 | + async () => { |
| 183 | + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-send-route-")); |
| 184 | + const sendCalls: Array<{ |
| 185 | + to?: string; |
| 186 | + text?: string; |
| 187 | + accountId?: string | null; |
| 188 | + threadId?: string | number | null; |
| 189 | + }> = []; |
| 190 | + setTestPluginRegistry( |
| 191 | + createTestRegistry([ |
| 192 | + { |
| 193 | + pluginId: "whatsapp", |
| 194 | + source: "test", |
| 195 | + plugin: createOutboundTestPlugin({ |
| 196 | + id: "whatsapp", |
| 197 | + label: "WhatsApp", |
| 198 | + outbound: { |
| 199 | + deliveryMode: "direct", |
| 200 | + resolveTarget: ({ to }) => { |
| 201 | + const target = to?.trim(); |
| 202 | + return target |
| 203 | + ? { ok: true, to: target } |
| 204 | + : { ok: false, error: new Error("missing target") }; |
| 205 | + }, |
| 206 | + sendText: async (ctx) => { |
| 207 | + sendCalls.push({ |
| 208 | + to: ctx.to, |
| 209 | + text: ctx.text, |
| 210 | + accountId: ctx.accountId, |
| 211 | + threadId: ctx.threadId, |
| 212 | + }); |
| 213 | + return { channel: "whatsapp", messageId: "wa-proof-msg" }; |
| 214 | + }, |
| 215 | + }, |
| 216 | + messaging: { |
| 217 | + normalizeTarget: (raw) => raw, |
| 218 | + }, |
| 219 | + }), |
| 220 | + }, |
| 221 | + ]), |
| 222 | + ); |
| 223 | + |
| 224 | + testState.sessionStorePath = path.join(dir, "sessions.json"); |
| 225 | + try { |
| 226 | + await writeSessionStore({ |
| 227 | + entries: { |
| 228 | + "agent:main:whatsapp:direct:peer-1": { |
| 229 | + sessionId: "sess-whatsapp-peer", |
| 230 | + updatedAt: Date.now(), |
| 231 | + channel: "webchat", |
| 232 | + lastChannel: "webchat", |
| 233 | + lastTo: "session:dashboard", |
| 234 | + route: { |
| 235 | + channel: "webchat", |
| 236 | + target: { to: "session:dashboard" }, |
| 237 | + }, |
| 238 | + deliveryContext: { |
| 239 | + channel: "whatsapp", |
| 240 | + to: "peer-1", |
| 241 | + }, |
| 242 | + origin: { |
| 243 | + provider: "whatsapp", |
| 244 | + accountId: "work", |
| 245 | + threadId: "thread-77", |
| 246 | + }, |
| 247 | + }, |
| 248 | + }, |
| 249 | + }); |
| 250 | + |
| 251 | + agentStepTesting.setDepsForTest({ |
| 252 | + agentCommandFromIngress: async () => ({ |
| 253 | + payloads: [{ text: "announce through channel", mediaUrl: null }], |
| 254 | + meta: { durationMs: 1 }, |
| 255 | + }), |
| 256 | + }); |
| 257 | + |
| 258 | + await runSessionsSendA2AFlow({ |
| 259 | + targetSessionKey: "agent:main:whatsapp:direct:peer-1", |
| 260 | + displayKey: "agent:main:whatsapp:direct:peer-1", |
| 261 | + message: "ping", |
| 262 | + announceTimeoutMs: 5_000, |
| 263 | + maxPingPongTurns: 0, |
| 264 | + roundOneReply: "target response", |
| 265 | + }); |
| 266 | + |
| 267 | + await vi.waitFor( |
| 268 | + () => |
| 269 | + expect(sendCalls).toEqual([ |
| 270 | + { |
| 271 | + to: "peer-1", |
| 272 | + text: "announce through channel", |
| 273 | + accountId: "work", |
| 274 | + threadId: "thread-77", |
| 275 | + }, |
| 276 | + ]), |
| 277 | + { timeout: 5_000 }, |
| 278 | + ); |
| 279 | + } finally { |
| 280 | + agentStepTesting.setDepsForTest(); |
| 281 | + testState.sessionStorePath = undefined; |
| 282 | + await fs.rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 }); |
| 283 | + } |
| 284 | + }, |
| 285 | + ); |
174 | 286 | }); |
175 | 287 |
|
176 | 288 | describe("sessions_send label lookup", () => { |
|
0 commit comments