Skip to content

fix(message-tool): surface missing delivery results#44578

Closed
Fzhiyu1 wants to merge 3 commits into
openclaw:mainfrom
Fzhiyu1:stable-2026.3.11
Closed

fix(message-tool): surface missing delivery results#44578
Fzhiyu1 wants to merge 3 commits into
openclaw:mainfrom
Fzhiyu1:stable-2026.3.11

Conversation

@Fzhiyu1

@Fzhiyu1 Fzhiyu1 commented Mar 13, 2026

Copy link
Copy Markdown

Summary

  • return a tool error when a send action finishes without a concrete delivery messageId
  • preserve the outbound payload details while surfacing an explicit delivery failure to the model
  • add a regression test for core send responses that produce no delivery result

Root Cause

message-tool previously fell through to jsonResult(result.payload) whenever getToolResult(result) returned nothing.

That meant a send action could look successful to the agent even when the underlying provider never produced a confirmed delivery result. In practice this can happen on best-effort / partial-failure paths, which then makes downstream logic more likely to suppress the fallback reply path or collapse into NO_REPLY-looking behavior.

Related

Test Plan

  • pnpm vitest run src/agents/tools/message-tool.test.ts
  • pnpm build

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Mar 13, 2026
@greptile-apps

greptile-apps Bot commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR surfaces missing message delivery results as explicit tool errors rather than silent successes. When a core send action completes but the response carries no result.messageId, the tool now returns a status: "error" payload — preserving the original outbound details — instead of forwarding the raw payload as if the send had succeeded.

Key changes:

  • readMessageDeliveryMessageId: safely traverses sendResult.result (with a payload.result fallback) to extract the delivery messageId.
  • buildMissingDeliveryResultToolResult: produces an error jsonResult by spreading the original outbound payload and overwriting status/error, but only for non-dry-run send results that lack a messageId. Plugin-handled sends are unaffected because they always produce a toolResult (via tryHandleWithPluginAction) which is consumed earlier in the pipeline.
  • A regression test is added for the core-send/no-delivery-result path. One gap worth noting: there is no explicit test for the dryRun: true bypass (confirming that dry-run sends still return the raw payload), which would make the test suite more complete.

Confidence Score: 4/5

  • This PR is safe to merge — the change is narrowly scoped to core send results and does not affect plugin-handled sends or any other action type.
  • The logic is sound: buildMissingDeliveryResultToolResult correctly guards on kind !== "send" and dryRun, and readMessageDeliveryMessageId uses proper runtime type checks before accessing nested properties. Plugin sends always bypass the new check via toolResult. The regression test covers the primary scenario. A minor gap is the absence of a test confirming dryRun: true sends are unaffected, but this is low risk given the explicit guard in the implementation.
  • No files require special attention.

Last reviewed commit: 9f00b90

@Fzhiyu1

Fzhiyu1 commented Mar 13, 2026

Copy link
Copy Markdown
Author

Observed in production on a Feishu delivery path where the outbound action returned payload metadata but no confirmed delivery messageId.

Before this patch, message-tool could still serialize that payload as a successful tool result. The visible symptom was that the assistant looked like it had already sent something and then stopped talking, because downstream logic was more likely to suppress the fallback reply path.

This patch intentionally treats "no concrete delivery result" as a tool error so the failure is surfaced instead of being mistaken for a successful send.

@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Apr 28, 2026
@clawsweeper

clawsweeper Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Keep open. The underlying missing-delivery-result bug is credible, but this PR is not merge-ready because its receipt predicate is too strict for current accepted send-success shapes, the branch is currently conflicting, and no after-fix real behavior proof has been supplied.

Canonical path: Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review.

So I’m closing this here because the remaining work is already tracked in the canonical issue.

Review details

Best possible solution:

Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review.

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

Yes, at source level. Current main falls back to jsonResult(result.payload) when a send returns no toolResult, so a stubbed non-dry-run send payload without a delivery receipt can be reported as success; I did not run tests in this read-only review.

Is this the best way to solve the issue?

No. The proposed nested-messageId check is too strict; the maintainable fix should reuse or introduce an accepted delivery-success predicate that preserves current internal-source and receipt-based success contracts.

Security review:

Security review cleared: The diff only changes message-tool result classification and focused tests; it does not touch dependencies, workflows, secrets, publishing, downloads, or other supply-chain surfaces.

What I checked:

  • stale F-rated PR: PR was opened 2026-03-13T03:03:23Z, is older than 60 days, and the latest review rated it F.
  • proof blocker: real behavior proof is missing and proof tier is F, so this branch is not merge-ready without contributor follow-up.
  • no human follow-up: live comments and timeline hydrated by apply contain no non-automation activity after the ClawSweeper review.

Likely related people:

  • pashpashpash: Authored and merged the internal WebChat/TUI message-tool source-reply routing that created the current internal-ui success envelope affected by this PR. (role: feature owner; confidence: high; commits: ca463326f775, 78eb92e62277; files: src/agents/tools/message-tool.ts, src/infra/outbound/message-action-runner.ts, src/infra/outbound/message-action-runner.send-validation.test.ts)
  • vincentkoc: Authored adjacent rich internal source-reply preservation work included in the same merged routing feature. (role: adjacent contributor; confidence: medium; commits: 3ce4a87e19d4, 78eb92e62277; files: src/agents/pi-embedded-runner/run/payloads.ts, src/infra/outbound/message-action-runner.ts)
  • steipete: Committed and merged the earlier silent message-tool drop fix that this PR explicitly follows up on. (role: prior bug-fix author and merger; confidence: medium; commits: 99fcc8270543, 225b44ad3ab0; files: src/agents/tools/message-tool.ts, src/agents/pi-embedded-subscribe.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 5fbaf2a8a236.

@Fzhiyu1

Fzhiyu1 commented Apr 28, 2026

Copy link
Copy Markdown
Author

Status update on this PR:

Added regression coverage for the two paths the Codex review flagged as missing (commit 4b01122c):

  • does not flag missing delivery result on dry-run sends — verifies dryRun: true does not get caught by the new missing-delivery guard.
  • returns the payload as-is when delivery yields a concrete messageId — verifies the success path still returns the raw payload (with result.messageId) untouched.

Local verification on the rebased branch:

  • pnpm vitest run src/agents/tools/message-tool.test.ts → 19 passed.
  • pnpm tsgo → clean.
  • pnpm check → clean.

On rebase: I attempted git rebase upstream/main and hit ~40 add/add conflicts across ui/src/ui/views/**, ui/vite.config.ts, ui/vitest.config.ts, vendor/a2ui/renderers/lit/tsconfig.json etc. — these look like upstream UI restructuring rather than anything message-tool related, and resolving them speculatively would add a lot of churn unrelated to this fix. The branch's existing merge commit (2faf9e6c) is from 2026-03-13 against an old main.

Would maintainers prefer:

  1. I cherry-pick 9f00b90 + the new test commit onto current main and force-push (clean two-commit branch, drops the old merge), or
  2. I do an in-place merge of current upstream/main into this branch (preserves history but adds a new merge commit), or
  3. Maintainers handle the rebase as part of merge?

Happy to take whichever route; just want to avoid blindly resolving the UI-tree conflicts without context.

cc the production Feishu signal noted in the PR body — the silent-success fallback is still present in src/agents/tools/message-tool.ts on current main per the Codex review comment above.

@openclaw-barnacle openclaw-barnacle Bot removed the stale Marked as stale due to inactivity label Apr 29, 2026
@clawsweeper clawsweeper Bot added the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label May 11, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 11, 2026
@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. impact:message-loss Channel message delivery can be lost, duplicated, or misrouted. and removed mantis: telegram-visible-proof Mantis should capture Telegram visible proof. labels May 11, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. and removed impact:message-loss Channel message delivery can be lost, duplicated, or misrouted. labels May 18, 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.

@clawsweeper

clawsweeper Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

@clawsweeper clawsweeper Bot closed this May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant