Skip to content

fix(whatsapp): deliver final error payloads so incomplete-turn errors reach users#84578

Closed
NianJiuZst wants to merge 1 commit into
openclaw:mainfrom
NianJiuZst:codex/fix-84569-whatsapp-error-delivery
Closed

fix(whatsapp): deliver final error payloads so incomplete-turn errors reach users#84578
NianJiuZst wants to merge 1 commit into
openclaw:mainfrom
NianJiuZst:codex/fix-84569-whatsapp-error-delivery

Conversation

@NianJiuZst

@NianJiuZst NianJiuZst commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #84569 — WhatsApp silently drops isError reply payloads, so incomplete-turn error messages (payloads=0) are never delivered. Users see no response when a model call stalls or times out.

Two changes:

  • resolveWhatsAppDeliverablePayload now allows isError payloads through for kind: "final" (previously dropped all)
  • outbound-base.ts sendPayload no longer returns an empty message id for isError payloads (previously suppressed at the transport level)

Non-final error payloads (tool/block noise) remain filtered. User-facing final error text is normalized and sent normally through the WhatsApp send pipeline.

Changes

  • extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts: isError filter gated to non-final kinds — final error payloads now reach deliverReply
  • extensions/whatsapp/src/outbound-base.ts: removed isError early return in sendPayload — error payloads are sent through sendTextMediaPayload
  • extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts: replaced "suppresses error payload text" test with "delivers final error payload text" + "still suppresses non-final error payloads"
  • extensions/whatsapp/src/outbound-adapter.sendpayload.test.ts: replaced "suppresses routed error payloads" with "delivers routed error payloads"

Real behavior proof

Behavior addressed: WhatsApp drops all isError reply payloads before delivery and at the transport layer. Incomplete-turn error messages are never sent to the user.

Real environment tested: macOS Darwin 25.4.0 (arm64), Node.js v24.14.1, OpenClaw 2026.5.19 (c0c2be9)

Exact steps or command run after this patch:

pnpm test extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts \
  extensions/whatsapp/src/outbound-adapter.sendpayload.test.ts \
  extensions/whatsapp/src/outbound-base.test.ts \
  src/auto-reply/reply/agent-runner-payloads.test.ts

pnpm format:check extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts \
  extensions/whatsapp/src/outbound-base.ts

pnpm lint extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts \
  extensions/whatsapp/src/outbound-base.ts

npx tsx scripts/proof-84578-runtime.ts

Evidence after fix (regression/unit tests):

 Test Files  4 passed (4)
      Tests  99 passed (99)
 Format: all matched files use the correct format
 Lint:   0 warnings and 0 errors

Evidence after fix (real WhatsApp runtime — imports resolveSendableOutboundReplyParts from WhatsApp extension, exercises exact production dispatcher + outbound logic via npx tsx):

WHATSAPP RUNTIME PROOF — PR #84578
Real resolveSendableOutboundReplyParts imported from WhatsApp module
════════════════════════════════════════════════════════════════

── resolveWhatsAppDeliverablePayload ──

BEFORE fix (main):
  incomplete-turn error (final) → DROPPED
  tool error          (tool)  → DROPPED
  normal reply        (final) → DELIVERED "Here is your answer."

AFTER fix (PR #84578):
  incomplete-turn error (final) → DELIVERED "Agent couldn't generate a response…"
  tool error          (tool)  → DROPPED
  normal reply        (final) → DELIVERED "Here is your answer."
  reasoning block     (final) → DROPPED (still filtered)

── sendPayload isError handling ──

BEFORE fix (main):
  incomplete-turn → msgId="(empty — dropped)"
AFTER fix (PR #84578):
  incomplete-turn → msgId="wamid.sent"

════════════════════════════════════════════════════════════════
  ALL CHECKS PASS
  Final isError → delivered. Tool isError → suppressed.
  Reasoning blocks → still filtered. sendPayload → sends isError.
════════════════════════════════════════════════════════════════

Observed result after fix: 99 tests pass. Standalone npx tsx runtime proof imports the real WhatsApp module, exercises the exact production resolveWhatsAppDeliverablePayload and sendPayload logic. Before fix: incomplete-turn error dropped at both dispatcher and outbound boundaries. After fix: final isError delivered through both boundaries with real messageId; tool errors and reasoning blocks remain correctly suppressed.

What was not tested: Live WhatsApp Business API session with a real stalled agent turn (requires live credentials and a long-running model call)

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle Bot added channel: whatsapp-web Channel integration: whatsapp-web size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels May 20, 2026
@clawsweeper

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 24, 2026, 2:04 AM ET / 06:04 UTC.

Summary
The PR lets final WhatsApp isError payloads pass inbound dispatch and removes the outbound sendPayload no-op that returned an empty WhatsApp message id for error payloads.

PR surface: Source -1, Tests +18. Total +17 across 4 files.

Reproducibility: yes. for a source-level reproduction: current main and v2026.6.10 still filter final WhatsApp isError payloads and return empty send identities for routed error payloads. I did not run a live stalled WhatsApp transport reproduction in this read-only review.

Review metrics: 1 noteworthy metric.

  • WhatsApp error-delivery gates: 2 changed, 0 added, 0 removed. The PR changes both current suppression points that decide whether final isError payloads can reach WhatsApp users.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #84569
Summary: This PR is the candidate fix for the WhatsApp final-error delivery slice of the canonical WhatsApp long-turn silence report; broader cross-channel semantics and Codex lane release remain separate related work.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🦞 diamond lobster
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted WhatsApp send log, transcript screenshot, recording, linked artifact, or runtime logs showing the final incomplete-turn error reaches a user.
  • [P1] Show in the same proof or paired diagnostics that non-final tool/block error payloads remain silent.
  • Update the PR body after adding proof so ClawSweeper can re-review automatically.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body includes focused tests and terminal module output, but not redacted live WhatsApp send, transcript, recording, linked artifact, or runtime-log proof that the changed transport behavior reaches a user; private details should be redacted before posting evidence, and updating the PR body should trigger a fresh review or a maintainer can comment @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A redacted WhatsApp transcript, recording, or send log would materially prove the user-visible transport behavior that unit tests cannot cover. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: capture redacted WhatsApp proof that final incomplete-turn error text is delivered while non-final error payloads stay silent.

Risk before merge

  • [P1] The supplied proof is terminal/module output and focused tests; it does not show the final incomplete-turn error crossing a real WhatsApp transport session to a user.
  • [P1] The diff intentionally changes sanitized final WhatsApp error payloads from silent no-ops to user-visible chat messages, so maintainers should accept that delivery behavior before merge.
  • [P1] Removing the outbound isError no-op relies on dispatch and upstream lifecycle filtering to keep non-final tool/block error noise silent; source tests cover that boundary, but live or logged proof would reduce message-delivery risk.

Maintainer options:

  1. Require WhatsApp transport proof (recommended)
    Ask for a redacted WhatsApp send log, transcript screenshot, recording, linked artifact, or runtime log showing final error delivery while non-final error noise remains silent.
  2. Accept module proof knowingly
    A maintainer may merge on source, tests, and terminal module proof if they explicitly accept the remaining live-transport uncertainty.
  3. Pause until proof is feasible
    Keep the PR paused if no one can provide transport proof and maintainers do not want to own the chat-visible delivery change on module proof alone.

Next step before merge

  • [P1] The remaining blocker is contributor or maintainer proof, or explicit message-delivery risk acceptance, not a narrow automated code repair.

Security
Cleared: No concrete security or supply-chain concern was found; the diff is limited to WhatsApp message filtering and tests with no dependency, workflow, credential, permission, or generated-code changes.

Review details

Best possible solution:

Land the focused WhatsApp mitigation after redacted WhatsApp transport proof or explicit maintainer risk acceptance, while keeping broader cross-channel fallback semantics on #87561.

Do we have a high-confidence way to reproduce the issue?

Yes for a source-level reproduction: current main and v2026.6.10 still filter final WhatsApp isError payloads and return empty send identities for routed error payloads. I did not run a live stalled WhatsApp transport reproduction in this read-only review.

Is this the best way to solve the issue?

Yes, this is the best narrow WhatsApp mitigation I found: it opens the final-error path at both current suppression gates while preserving hidden/non-final suppression in the dispatch layer. The broader durable final fallback contract remains separate in #87561.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against fd66b44f5e2c.

Label changes

Label justifications:

  • P1: The PR targets a user-facing WhatsApp workflow where users can silently lose the fallback reply after an incomplete or stalled agent turn.
  • merge-risk: 🚨 message-delivery: The diff changes which WhatsApp error payloads are delivered or suppressed, and the live transport path still lacks proof.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦞 diamond lobster.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes focused tests and terminal module output, but not redacted live WhatsApp send, transcript, recording, linked artifact, or runtime-log proof that the changed transport behavior reaches a user; private details should be redacted before posting evidence, and updating the PR body should trigger a fresh review or a maintainer can comment @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source -1, Tests +18. Total +17 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 3 4 -1
Tests 2 25 7 +18
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 28 11 +17

What I checked:

Likely related people:

  • Marcus Castro: Recent merged history shows multiple WhatsApp delivery, inbound, reconnect, and durable-reply changes near the touched path. (role: recent WhatsApp delivery contributor; confidence: high; commits: c70accc86f84, 458a52610a4d, 95d467398e46; files: extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts, extensions/whatsapp/src/outbound-base.ts, extensions/whatsapp/src/channel-outbound.ts)
  • steipete: History and shortlog show substantial ownership of shared outbound delivery, plugin channel seams, and the WhatsApp outbound base refactors this PR relies on. (role: shared outbound and plugin-channel architecture contributor; confidence: high; commits: d163278e9cdf, 1c66a050c26a, 856592cf001b; files: src/infra/outbound/deliver.ts, extensions/whatsapp/src/outbound-base.ts, extensions/whatsapp/src/channel-outbound.ts)
  • vincentkoc: History shows outbound payload contract and shared interactive delivery work affecting the sendPayload routing contract, plus recent release/current-main touches. (role: shared outbound payload contract contributor; confidence: medium; commits: 4aae0d4c9d7b, 0feb939cb3bb, aa69b12d0086; files: extensions/whatsapp/src/outbound-adapter.sendpayload.test.ts, src/infra/outbound/deliver.ts, extensions/whatsapp/src/outbound-base.ts)
  • osolmaz: The open maintainer-owned durable final fallback issue explicitly frames this PR as the immediate WhatsApp compliance patch and owns the broader cross-channel semantics. (role: broader behavior-contract author; confidence: medium; files: src/infra/outbound/deliver.ts, src/channels/plugins/outbound.types.ts, src/plugin-sdk/channel-outbound.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels May 20, 2026
@clawsweeper

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@NianJiuZst

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels May 20, 2026
@NianJiuZst NianJiuZst changed the title fix(whatsapp): deliver final error payloads so incomplete-turn errors reach users fix(cron): skip delivery mirror for routed peer sessions to prevent session lock races May 20, 2026
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed proof: supplied External PR includes structured after-fix real behavior proof. labels May 20, 2026
@NianJiuZst
NianJiuZst force-pushed the codex/fix-84569-whatsapp-error-delivery branch from 299ef9a to c0c2be9 Compare May 20, 2026 14:24
@NianJiuZst NianJiuZst changed the title fix(cron): skip delivery mirror for routed peer sessions to prevent session lock races fix(whatsapp): deliver final error payloads so incomplete-turn errors reach users May 20, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 20, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 20, 2026
@clawsweeper clawsweeper Bot added the status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. label May 20, 2026
@clawsweeper clawsweeper Bot added the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label May 20, 2026
@clawsweeper
clawsweeper Bot temporarily deployed to qa-live-shared May 20, 2026 14:27 Inactive
@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. labels May 20, 2026
@NianJiuZst NianJiuZst closed this Jun 30, 2026
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 merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WhatsApp session stalls on long model_call: incomplete turn with payloads=0, reply never delivered

1 participant