fix(whatsapp): gate poll-vote events to Hermes-created polls + salvage follow-ups

- bridge: only enqueue poll_update events for polls Hermes itself created
  (tracked via recentlySentIds when /send-poll returns) so arbitrary human
  polls in group chats don't inject agent-visible messages on every vote
- update test_already_whatsapp_italic for the new markdown-italic mapping
- AUTHOR_MAP entry for @devatnull (PR #58704 salvage)
This commit is contained in:
teknium1 2026-07-05 06:02:10 -07:00 committed by Teknium
parent 11627fdcb9
commit b0f2bdbe8b
3 changed files with 14 additions and 3 deletions

View file

@ -45,6 +45,7 @@ ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
# Auto-extracted from noreply emails + manual overrides
AUTHOR_MAP = {
"perkintahmaz50@gmail.com": "devatnull", # PR #58704 salvage (whatsapp: native Baileys polls, clarify-as-poll, location pins, structured quoted replies, PTT/audio split, bridge_helpers extraction)
"tim@iteachyouai.com": "tjp2021", # PR #4097 salvage (copilot: per-turn x-initiator header so user prompts bill as premium requests; #3040)
"3723267+kevinrajaram@users.noreply.github.com": "kevinrajaram", # PR #3850 salvage (gateway: add POSIX system dirs to PATH so launchctl/systemctl resolve under UV's minimal-PATH bundled Python; #3849)
"lord-dubious@users.noreply.github.com": "lord-dubious", # PR #58453 salvage (preserve static custom provider models declared as dict rows)

View file

@ -304,6 +304,15 @@ function enqueuePollUpdateEvent({ key, update, selectedOptions, aggregation }) {
|| update?.pollUpdates?.[0]?.pollCreationMessageKey?.id
|| update?.pollUpdates?.[0]?.pollUpdateMessageKey?.id
|| '';
// Only surface votes on polls Hermes itself created (tracked when
// /send-poll returns). Arbitrary human polls in a group chat must not
// inject agent-visible messages on every vote.
if (!pollId || !recentlySentIds.has(pollId)) {
if (WHATSAPP_DEBUG) {
try { console.log(JSON.stringify({ event: 'ignored', reason: 'foreign_poll_update', pollId })); } catch {}
}
return;
}
const chosenText = selectedOptions.length ? selectedOptions.join(', ') : `[Poll update${pollId ? `: ${pollId}` : ''}]`;
const dedupeId = `poll:${pollId}:${senderId}:${selectedOptions.join('|')}`;
if (recentlyProcessedPollUpdates.has(dedupeId)) return;

View file

@ -141,10 +141,11 @@ class TestFormatMessage:
assert adapter.format_message("hello world") == "hello world"
def test_already_whatsapp_italic(self):
"""Single *italic* should pass through unchanged."""
"""Markdown *italic* converts to WhatsApp _italic_ (PR #58704)."""
adapter = _make_adapter()
# After bold conversion, *text* is WhatsApp italic
assert adapter.format_message("*italic*") == "*italic*"
assert adapter.format_message("*italic*") == "_italic_"
# Already-WhatsApp _italic_ passes through unchanged
assert adapter.format_message("_italic_") == "_italic_"
def test_multiline_mixed(self):
adapter = _make_adapter()