feat(whatsapp): add configurable human cascade delivery - #58703
feat(whatsapp): add configurable human cascade delivery#58703devatnull wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a WhatsApp-specific, configurable “human cascade” delivery style so longer prose replies can be split into a small number of natural chat bubbles while keeping structured/copy-sensitive sections (code blocks, lists/reports, approval gates, links/tails) atomic. This integrates with gateway streaming/status paths so interim/progress messages do not accidentally cascade.
Changes:
- Implement WhatsApp adapter heuristics/config for human-cascade paragraph splitting, atomic section protection, and jittered inter-bubble delays.
- Ensure non-final streaming sends and gateway status/progress sends force single-message delivery style.
- Add extensive WhatsApp formatting tests plus targeted tests for stream/status metadata behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/platforms/whatsapp/adapter.py | Implements configurable human-cascade splitting and send-path changes (IDs, delays). |
| gateway/stream_consumer.py | Forces non-final stream metadata to single delivery style to prevent cascades. |
| gateway/run.py | Forces gateway status/progress sends to single delivery style. |
| tests/gateway/test_whatsapp_formatting.py | Adds comprehensive unit tests for cascade vs atomic behavior across content shapes. |
| tests/gateway/test_stream_consumer.py | Adds tests ensuring non-final/“commentary” sends force single delivery style. |
| tests/gateway/test_gateway_status_delivery_style.py | Adds tests ensuring status/progress sends force single delivery style. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self._human_cascade_min_total_chars = self._coerce_int_extra( | ||
| "human_cascade_min_total_chars", 300 | ||
| ) | ||
| self._human_cascade_min_lead_chars = self._coerce_int_extra( | ||
| "human_cascade_min_lead_chars", 40 | ||
| ) |
| if not final: | ||
| # Stream previews, tool-boundary text, and interim commentary are | ||
| # status/progress UI, not the final assistant reply. Messaging | ||
| # adapters that support natural multi-bubble delivery (WhatsApp) | ||
| # must keep these as one unit so scratch/status text never fans out | ||
| # into a cascade. | ||
| meta.setdefault("delivery_style", "single") |
| metadata = dict(metadata or {}) | ||
| # Status/thinking/progress bubbles are gateway chrome, not the final answer. | ||
| # Keep them single-unit on platforms with natural cascade support. | ||
| metadata.setdefault("delivery_style", "single") |
12762b1 to
4db1058
Compare
teknium1
left a comment
There was a problem hiding this comment.
Thanks for separating the WhatsApp adapter behavior from the gateway delivery safeguards. The proxy-path premise is current: gateway/run.py:17023-17055 still creates a stream consumer for a non-editable adapter, whereas the direct path already skips it at gateway/run.py:18352-18354.
Problems
plugins/platforms/whatsapp/adapter.py:451-490adds default-enabled, user-configurablehuman_cascade_*behavior, but this PR has no documentation change. The existing WhatsApp guide says progressive edited streaming is supported atwebsite/docs/user-guide/messaging/whatsapp.md:187-193; that conflicts with the newSUPPORTS_MESSAGE_EDITING = Falseatadapter.py:388-392. The guide also does not document the cascade opt-out or tuning keys.
Suggested changes
- Update the WhatsApp guide with final-only delivery semantics and a
gateway.platforms.whatsapp.extracascade configuration example, including the disable switch and DM/group defaults.
This is an automated hermes-sweeper review.
| # payloads still fall back to truncate_message(). Config lives in | ||
| # gateway.platforms.whatsapp.extra.* so no new user-facing env knobs are | ||
| # required for this adapter-level behavior. | ||
| self._human_cascade_messages = self._coerce_bool_extra( |
There was a problem hiding this comment.
These default-enabled human_cascade_* controls need user documentation. Please update website/docs/user-guide/messaging/whatsapp.md with the gateway.platforms.whatsapp.extra keys, the opt-out, and the changed final-only delivery behavior introduced by SUPPORTS_MESSAGE_EDITING = False.
4db1058 to
1ff14ba
Compare
1ff14ba to
f173cfb
Compare
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Two PRs address the same WhatsApp delivery problem: #54455 introduced configurable paragraph-based cascade delivery plus gateway safeguards, while #58703 carries a revised implementation with configuration documentation, final-only delivery semantics, message-ID handling, and expanded regression coverage. No recorded verify verdict or best-fix determination selects either PR.
Related pull requests
- #54455 [closed]
duplicate— (+1089/-12) — closed precursor and substantial duplicate of #58703: the diff implements WhatsApp prose cascading, atomic handling for structured or action-sensitive content, single-unit status/preview delivery, and extensive tests. It remains relevant because its contributor explicitly closed the old branch to rebuild the changes cleanly, and #58703 contains the substantially overlapping replacement implementation. - #58703
related— (+895/-15) — keep-open salvage candidate, not a verified best fix: the diff implements configurable WhatsApp cascade heuristics, final-only behavior for the non-editable adapter, single-unit gateway chrome, normalized multi-message ID tracking, tests, and user documentation. The contributor keep_open review identified missing documentation and a conflict with the guide; the current diff explicitly addresses that objection in website/docs/user-guide/messaging/whatsapp.md by documenting final-only delivery, opt-out and tuning keys, and DM/group defaults.
Duplicates
#54455 and #58703 substantially duplicate the same WhatsApp human-cascade implementation; #54455 is the closed precursor, while #58703 contains the updated version and documentation.
Suggested consolidation
Keep #58703 open with a salvage path: retain the WhatsApp adapter cascade behavior, configuration documentation, message-ID compatibility, and focused formatting/status tests, while separating or reducing the broader gateway non-editable-streaming changes if needed for reviewability. This is consistent with the contributor keep_open review after its documented objection was addressed, but it is not a merge recommendation because no verify best_fix was recorded. Keep #54455 closed as the superseded duplicate of #58703.
Complex graph
flowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
subgraph Dup54455 ["PRs duplicating each other"]
P54455["PR #54455 (closed)"]
P58703["PR #58703 (open)"]
end
class P54455 closed
class P58703 open
class P58703 target
click P54455 "https://github.com/NousResearch/hermes-agent/pull/54455"
click P58703 "https://github.com/NousResearch/hermes-agent/pull/58703"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).
Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 109 kB of PR diffs, 4 kB of issue/PR text, 6 kB of discussion (4 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
Summary
raw_response["message_ids"]metadata["delivery_style"] = "single"Stack
This PR is stacked on #58929 (
fix(gateway): preserve final delivery on non-editable streams). Once #58929 lands, this PR can be rebased to show only the WhatsApp adapter cascade layer.Why
WhatsApp is a chat UI, not a markdown document viewer. Large prose replies are hard to read as one wall of text, but blindly splitting every blank line is dangerous for approvals, commands, configs, logs, code, and copy/paste content. This keeps the behavior WhatsApp-specific and conservative.
Behavior
Cascade is gated by:
delivery_style="single"forces atomic delivery;delivery_style="cascade"can force cascade for explicit adapter callersTest plan
python3 -m pytest tests/gateway/test_whatsapp_formatting.py tests/gateway/test_gateway_status_delivery_style.py tests/gateway/test_run_progress_topics.py::test_proxy_non_editable_streaming_uses_final_delivery_only tests/gateway/test_run_progress_topics.py::test_run_agent_non_editable_streaming_uses_final_delivery_only tests/gateway/test_stream_consumer_thread_routing.py::TestInitialReplyToId -qscripts/run_tests.sh tests/gateway/test_whatsapp_formatting.py tests/gateway/test_gateway_status_delivery_style.py tests/gateway/test_run_progress_topics.py tests/gateway/test_stream_consumer_thread_routing.py -qpython3 -m py_compile plugins/platforms/whatsapp/adapter.py gateway/run.py gateway/stream_consumer.py tests/gateway/test_whatsapp_formatting.py tests/gateway/test_gateway_status_delivery_style.py tests/gateway/test_run_progress_topics.py tests/gateway/test_stream_consumer_thread_routing.pygit diff --check origin/main...HEAD