Fix WhatsApp connection test delivery without touching DSH sessions.

Send the probe to the bound private-chat target, falling back to Message Yourself via live LID so Baileys no longer reports success while the phone never receives it.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-08 20:05:57 +08:00
parent d8c7671bd7
commit 0bc0992330
5 changed files with 396 additions and 206 deletions

View file

@ -5,11 +5,37 @@ import {
enrichWhatsappInboundIdentities,
isWhatsappLidJid,
rememberWhatsappLidPnPairs,
resolveWhatsappSelfChatJid,
stripWhatsappBotMentionText,
whatsappBotMentionTokens,
} from '../../../src/channels/whatsapp/whatsapp-identity.mjs';
describe('whatsapp-identity', () => {
it('resolves self-chat jid to live LID before stored PN', async () => {
const accountJid = '8615601877957@s.whatsapp.net';
const lid = '111222333444555@lid';
assert.equal(await resolveWhatsappSelfChatJid({
accountJid,
socket: { user: { id: accountJid, lid } },
}), lid);
assert.equal(await resolveWhatsappSelfChatJid({
accountJid,
socket: {
signalRepository: {
lidMapping: {
getLIDForPN: async (pn) => (pn === accountJid ? lid : null),
},
},
},
}), lid);
assert.equal(await resolveWhatsappSelfChatJid({
accountJid,
lidPnCache: new Map([['111222333444555', accountJid]]),
}), lid);
assert.equal(await resolveWhatsappSelfChatJid({ accountJid }), accountJid);
});
it('recognizes lid jids', () => {
assert.equal(isWhatsappLidJid('91010910658657@lid'), true);
assert.equal(isWhatsappLidJid('8618142387786@s.whatsapp.net'), false);

View file

@ -18,6 +18,7 @@ import {
OutboundArtifactRegistry,
createOutboundArtifactTool,
} from '../../../src/channels/shared/semantic/artifact.mjs';
import { rememberConnectionTestTarget } from '../../../src/channels/shared/connection-test.mjs';
import {
WHATSAPP_ACCESS_MODES,
WhatsappConfigStore,
@ -1481,6 +1482,86 @@ test('WhatsApp runtime sends a connection test to self and suppresses its outbou
await runtime.stop();
});
test('WhatsApp connection test prefers bound private chat then live LID, never Harness ask', async () => {
const sent = [];
const accountLid = '987654321098765@lid';
const peerJid = '16505550999@s.whatsapp.net';
const state = {
hasSeen: () => false,
markSeen: async () => {},
sessionFor: () => 'session-connection-test-bound',
sessionExists: async () => true,
};
rememberConnectionTestTarget(state, { jid: peerJid, selfChat: false });
let askCount = 0;
const runtime = new WhatsappRuntime({
config: linkedConfig(),
authDir: '/tmp/test-whatsapp-connection-test-bound',
harness: {
ensureRunning: async () => {},
sessionExists: async () => true,
ask: async () => { askCount += 1; return 'unexpected'; },
},
state,
createSession: async () => ({
socket: {
user: { id: ACCOUNT_JID, lid: accountLid },
sendPresenceUpdate: async () => {},
readMessages: async () => {},
sendMessage: async (jid, content) => {
sent.push([jid, content]);
return { key: { id: `ct-${sent.length}` } };
},
},
ready: Promise.resolve({ accountJid: ACCOUNT_JID, name: 'Harness WhatsApp' }),
close: async () => {},
logout: async () => {},
}),
});
await runtime.start();
assert.deepEqual(await runtime.sendConnectionTest('bound probe'), { sent: true });
assert.deepEqual(sent, [[peerJid, { text: 'bound probe' }]]);
assert.equal(askCount, 0);
const unbound = {
hasSeen: () => false,
markSeen: async () => {},
sessionFor: () => 'session-connection-test-lid',
sessionExists: async () => true,
};
const lidRuntime = new WhatsappRuntime({
config: linkedConfig(),
authDir: '/tmp/test-whatsapp-connection-test-lid',
harness: {
ensureRunning: async () => {},
sessionExists: async () => true,
ask: async () => { askCount += 1; return 'unexpected'; },
},
state: unbound,
createSession: async () => ({
socket: {
user: { id: ACCOUNT_JID, lid: accountLid },
sendPresenceUpdate: async () => {},
readMessages: async () => {},
sendMessage: async (jid, content) => {
sent.push([jid, content]);
return { key: { id: `ct-${sent.length}` } };
},
},
ready: Promise.resolve({ accountJid: ACCOUNT_JID, name: 'Harness WhatsApp' }),
close: async () => {},
logout: async () => {},
}),
});
await lidRuntime.start();
assert.deepEqual(await lidRuntime.sendConnectionTest('lid probe'), { sent: true });
assert.deepEqual(sent.at(-1), [accountLid, { text: 'lid probe' }]);
assert.equal(askCount, 0);
await runtime.stop();
await lidRuntime.stop();
});
test('WhatsApp controller delegates connection test copy to the current runtime', async (t) => {
const root = await mkdtemp(join(tmpdir(), 'dsh-im-whatsapp-test-message-'));
const configStore = await new WhatsappConfigStore(join(root, 'config.json')).load();