openclaw/src/auto-reply/reply/session-delivery.test.ts
brokemac79 623ba14031 fix(session): preserve external channel route when webchat views session (#47745)
When a Telegram/WhatsApp/iMessage session was viewed or messaged from the
dashboard/webchat, resolveLastChannelRaw() unconditionally returned 'webchat'
for any isDirectSessionKey() or isMainSessionKey() match, overwriting the
persisted external delivery route.

This caused subagent completion events to be delivered to the webchat/dashboard
instead of the original channel (Telegram, WhatsApp, etc.), silently dropping
messages for the channel user.

Fix: only allow webchat to own routing when no external delivery route has been
established (no persisted external lastChannel, no external channel hint in the
session key). If an external route exists, webchat is treated as admin/monitoring
access and must not mutate the delivery route.

Updated/added tests to document the correct behaviour.

Fixes #47745
2026-03-15 23:37:59 -07:00

62 lines
2.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { resolveLastChannelRaw, resolveLastToRaw } from "./session-delivery.js";
describe("session delivery direct-session routing overrides", () => {
it.each([
"agent:main:direct:user-1",
"agent:main:telegram:direct:123456",
"agent:main:telegram:account-a:direct:123456",
"agent:main:telegram:dm:123456",
"agent:main:telegram:direct:123456:thread:99",
"agent:main:telegram:account-a:direct:123456:topic:ops",
])(
"preserves persisted external route when webchat accesses channel-peer session %s (fixes #47745)",
(sessionKey) => {
// Webchat/dashboard viewing an external-channel session must not overwrite
// the delivery route — subagents must still deliver to the original channel.
expect(
resolveLastChannelRaw({
originatingChannelRaw: "webchat",
persistedLastChannel: "telegram",
sessionKey,
}),
).toBe("telegram");
expect(
resolveLastToRaw({
originatingChannelRaw: "webchat",
originatingToRaw: "session:dashboard",
persistedLastChannel: "telegram",
persistedLastTo: "123456",
sessionKey,
}),
).toBe("123456");
},
);
it.each([
"agent:main:main:direct",
"agent:main:cron:job-1:dm",
"agent:main:subagent:worker:direct:user-1",
"agent:main:telegram:channel:direct",
"agent:main:telegram:account-a:direct",
"agent:main:telegram:direct:123456:cron:job-1",
])("keeps persisted external routes for malformed direct-like key %s", (sessionKey) => {
expect(
resolveLastChannelRaw({
originatingChannelRaw: "webchat",
persistedLastChannel: "telegram",
sessionKey,
}),
).toBe("telegram");
expect(
resolveLastToRaw({
originatingChannelRaw: "webchat",
originatingToRaw: "session:dashboard",
persistedLastChannel: "telegram",
persistedLastTo: "group:12345",
sessionKey,
}),
).toBe("group:12345");
});
});