Skip to content

fix(gateway): config-driven text-debounce batching for WhatsApp + Weixin - #35391

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-fbddb5e9
May 30, 2026
Merged

fix(gateway): config-driven text-debounce batching for WhatsApp + Weixin#35391
teknium1 merged 2 commits into
mainfrom
hermes/hermes-fbddb5e9

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

WhatsApp and Weixin now batch rapid-fire text bursts into one agent invocation, with the debounce delays configured in config.yaml (not env vars).

Salvages @redpiggy-cyber's PR #35302 (closes #35301) and converts its HERMES_* env-var config to the config.yaml path per our ".env is for secrets only" policy.

Changes

  • gateway/platforms/whatsapp.py, weixin.py: text-debounce batching (contributor commit), delays read via _coerce_float_extra(config.extra) instead of os.getenv(); finite/non-negative guard so bad YAML falls back to defaults instead of crashing asyncio.sleep()
  • Config keys: gateway.platforms.{whatsapp,weixin}.extra.text_batch_delay_seconds / text_batch_split_delay_seconds (defaults 5/10s WhatsApp, 3/5s Weixin)
  • Tests: updated Weixin content-dedup regression test for the deferred-dispatch path; new debounce coverage for both adapters (defaults, config override, bad-value fallback, env-ignored, burst-collapse, lone-message)
  • Docs: WhatsApp + Weixin config keys

Validation

Result
Affected gateway tests 174/174 pass (whatsapp×5, weixin, text_batching)
E2E (real adapter, real config.extra) defaults + override + bad-value guard + env-ignored; 3 rapid texts → 1 combined handle_message

Dedup still runs before enqueue in Weixin _process_message, so the #16182 duplicate-drop fix is preserved.

Closes #35301. Supersedes #35302 (@redpiggy-cyber, authorship preserved via cherry-pick) and #17165 (@keiravoss94, WhatsApp-only).

Infographic

text-debounce-batching-whatsapp-weixin

redpiggy-cyber and others added 2 commits May 30, 2026 07:15
WhatsApp and WeChat (Weixin/iLink) both deliver messages individually
without any client-side batching, so rapid multi-message bursts (forwarded
batches, paste-splits, etc.) each trigger a separate agent invocation.

This wastes tokens (redundant system prompts / context for each fragment)
and degrades UX (the user receives reply fragments instead of a single
coherent response).

Both adapters now mirror the Telegram adapter's proven text-debounce
pattern:

- _text_batch_delay_seconds / _text_batch_split_delay_seconds
  (configurable via env vars)
- _pending_text_batches dict for per-session aggregation
- _enqueue_text_event() concatenates successive TEXT messages and
  resets the flush timer
- _flush_text_batch() dispatches after the quiet period expires

Configurable via env vars:
  HERMES_WHATSAPP_TEXT_BATCH_DELAY_SECONDS (default 5.0)
  HERMES_WHATSAPP_TEXT_BATCH_SPLIT_DELAY_SECONDS (default 10.0)
  HERMES_WEIXIN_TEXT_BATCH_DELAY_SECONDS (default 3.0)
  HERMES_WEIXIN_TEXT_BATCH_SPLIT_DELAY_SECONDS (default 5.0)
Convert the salvaged text-debounce delays from HERMES_* env vars to
config.yaml (gateway.platforms.<name>.extra.text_batch_delay_seconds /
text_batch_split_delay_seconds), per the '.env is for secrets only'
policy. Adds a finite/non-negative guard so bad YAML values fall back to
the defaults instead of crashing asyncio.sleep().

- whatsapp.py / weixin.py: read delays via _coerce_float_extra(config.extra)
- update Weixin content-dedup regression test for the deferred dispatch path
- add text-debounce coverage (whatsapp + weixin): defaults, config override,
  bad-value fallback, env-var-ignored, burst-collapse, lone-message
- docs: WhatsApp + Weixin config keys
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-fbddb5e9 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9512 on HEAD, 9507 on base (🆕 +5)

🆕 New issues (3):

Rule Count
unresolved-attribute 2
invalid-assignment 1
First entries
gateway/platforms/whatsapp.py:1224: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_last_chunk_len` on type `MessageEvent`
gateway/platforms/weixin.py:1488: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_last_chunk_len` on type `MessageEvent`
tests/gateway/test_weixin.py:950: [invalid-assignment] invalid-assignment: Object of type `def _capture(event) -> CoroutineType[Any, Any, Unknown]` is not assignable to attribute `handle_message` of type `def handle_message(self, event: MessageEvent) -> CoroutineType[Any, Any, None]`

✅ Fixed issues: none

Unchanged: 4931 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/whatsapp WhatsApp Business adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WhatsApp and WeChat forward multiple messages without debounce, wasting tokens and degrading UX

3 participants