Skip to content

fix(whatsapp): restore config-driven block streaming for WhatsApp delivery#47391

Open
ignasicambra wants to merge 2 commits intoopenclaw:mainfrom
ignasicambra:fix/whatsapp-block-streaming
Open

fix(whatsapp): restore config-driven block streaming for WhatsApp delivery#47391
ignasicambra wants to merge 2 commits intoopenclaw:mainfrom
ignasicambra:fix/whatsapp-block-streaming

Conversation

@ignasicambra
Copy link
Copy Markdown

Summary

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • When blockStreamingDefault: "on" and blockStreamingBreak: "text_end" are configured, WhatsApp now delivers messages progressively at text boundaries instead of batching everything at the end.
  • Per-account channels.whatsapp.blockStreaming: true/false config is now respected (was ignored since fix(whatsapp): suppress reasoning/thinking content from WhatsApp delivery #24962).
  • Default behavior (no config set) is unchanged — block streaming remains off unless explicitly enabled.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 25
  • Model/provider: Anthropic Claude
  • Integration/channel: WhatsApp
  • Relevant config:
    {
      "agents": { "defaults": { "blockStreamingDefault": "on", "blockStreamingBreak": "text_end" } },
      "channels": { "whatsapp": { "blockStreaming": true } }
    }

Steps

  1. Configure block streaming as above
  2. Send a message on WhatsApp that triggers a long response
  3. Observe message delivery behavior

Expected

Messages are delivered progressively at text_end boundaries during streaming.

Actual (before fix)

All messages are batched and sent at once when the agent finishes.

Evidence

  • Failing test/log before + passing after
  • Tested on live WhatsApp with block streaming enabled — messages arrive progressively. No reasoning or tool call blocks were leaked to WhatsApp. The fix works exactly as expected.
  • All 13 inbound contract tests pass (pnpm test -- extensions/whatsapp/src/auto-reply/monitor/process-message.inbound-contract.test.ts)

Human Verification (required)

  • Verified scenarios: Live WhatsApp DM with blockStreamingDefault: "on" and blockStreamingBreak: "text_end" — blocks delivered progressively. Confirmed no reasoning content or tool call blocks leak to WhatsApp.
  • Edge cases checked: Reasoning content does NOT leak (verified both in live testing and via shouldSuppressReasoningPayload filtering upstream); tool payloads still suppressed; unconfigured accounts fall through to global default
  • What you did not verify: Group chat behavior; multiple WhatsApp accounts

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No — existing config keys (blockStreaming, blockStreamingDefault, blockStreamingBreak) are already defined; this PR makes WhatsApp respect them
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Set channels.whatsapp.blockStreaming: false in config, or remove blockStreamingDefault from agent defaults
  • Files/config to restore: extensions/whatsapp/src/auto-reply/monitor/process-message.ts
  • Known bad symptoms reviewers should watch for: Reasoning/thinking content appearing in WhatsApp messages (would indicate upstream filter regression)

Risks and Mitigations

  • Risk: If shouldSuppressReasoningPayload in dispatch-from-config.ts were ever removed or bypassed, reasoning blocks could leak to WhatsApp.
    • Mitigation: That function is used by all channels on the generic dispatch path (not just WhatsApp), so removing it would break multiple channels simultaneously — making it very unlikely to be removed silently.

@openclaw-barnacle openclaw-barnacle bot added channel: whatsapp-web Channel integration: whatsapp-web size: S labels Mar 15, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 15, 2026

Greptile Summary

This PR restores config-driven block streaming for WhatsApp by unwinding the hardcoded disableBlockStreaming: true introduced in #24962. The fix is well-scoped and correctly relies on the existing shouldSuppressReasoningPayload upstream filter in dispatch-from-config.ts to ensure reasoning/thinking content never reaches the deliver callback.

Key changes:

  • The deliver callback now only short-circuits on kind === "tool"; kind === "block" and kind === "final" both flow through to deliverWebReply, enabling progressive delivery when block streaming is configured.
  • disableBlockStreaming is now derived from account.blockStreaming (per-account config, falling back to root channels.whatsapp config). When not set, it is undefined, allowing agents.defaults.blockStreamingDefault to govern behavior as it does for other channels.
  • resolveWhatsAppAccount is called once in processMessage using params.route.accountId, consistent with how chunkMode and tableMode are resolved.
  • Tests are updated with a renamed case and two new cases covering the main config branches.

Observations:

  • The deliver callback previously acted as a secondary guard against reasoning-block leaks (by blocking all non-final kinds). That safety net is now removed; the code relies solely on shouldSuppressReasoningPayload in dispatch-from-config.ts. Adding a payload.isReasoning check inside deliver would restore belt-and-suspenders protection at negligible cost.
  • The test suite covers blockStreaming: true and blockStreaming: undefined but is missing a case for blockStreaming: falsedisableBlockStreaming: true, leaving the boolean inversion logic partially untested.

Confidence Score: 4/5

  • Safe to merge with minor improvements recommended; functional logic is correct and the original reasoning-leak bugs remain fixed.
  • The change is logically sound and well-reasoned. The upstream shouldSuppressReasoningPayload filter is consistently applied on all paths that flow into deliver. The config-driven disableBlockStreaming inversion is correct. Score is 4 rather than 5 because the secondary reasoning-block guard has been removed from deliver without replacement, and one config branch (blockStreaming: false) lacks a test.
  • process-message.ts — verify comfort level with removing the secondary reasoning-block guard from deliver.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/whatsapp/src/auto-reply/monitor/process-message.ts
Line: 405-411

Comment:
**Consider belt-and-suspenders guard against reasoning leaks**

The previous code blocked every non-`final` kind in `deliver`, providing a second line of defense against reasoning/thinking content reaching WhatsApp. This PR removes that safety net and now relies solely on `shouldSuppressReasoningPayload` (which checks `payload.isReasoning === true`) in `dispatch-from-config.ts`.

If a reasoning payload were ever produced without `isReasoning: true` set — or a new code path were introduced that bypasses `dispatch-from-config.ts` — reasoning content would silently leak to WhatsApp end users with no fallback guard.

A low-cost additional check here would re-establish belt-and-suspenders protection without breaking the new block-streaming behavior:

```suggestion
      deliver: async (payload: ReplyPayload, info) => {
        if (info.kind === "tool" || payload.isReasoning) {
          // Tool updates are internal-only; don't deliver to WhatsApp.
          // Reasoning blocks are suppressed upstream by shouldSuppressReasoningPayload,
          // but we guard here too in case that filter is ever bypassed.
          return;
        }
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/whatsapp/src/auto-reply/monitor/process-message.inbound-contract.test.ts
Line: 304-334

Comment:
**Missing test case for `blockStreaming: false`**

Two of the three config-driven cases are now covered:
- `blockStreaming: true``disableBlockStreaming: false`- `blockStreaming` absent → `disableBlockStreaming: undefined` ✓

The third case — `blockStreaming: false``disableBlockStreaming: true` — has no corresponding test. Adding it would fully document and protect the inversion logic (`!account.blockStreaming`) at `process-message.ts:455`, ensuring a future accidental removal of the negation is caught immediately.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 2003dbd

xuwei-xy pushed a commit to xuwei-xy/openclaw that referenced this pull request Mar 15, 2026
- openclaw#47391 fix(whatsapp): restore config-driven block streaming for WhatsApp delivery
- openclaw#47388 fix(gateway): restore handshake timeout to 10s to fix devices list on slow systems, solve openclaw#47103
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: whatsapp-web Channel integration: whatsapp-web size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant