Skip to content

feat(delivery): surface deliveryStatus in --json output#1687

Open
BingqingLyu wants to merge 1 commit into
mainfrom
fork-pr-57755-feat-delivery-status-json
Open

feat(delivery): surface deliveryStatus in --json output#1687
BingqingLyu wants to merge 1 commit into
mainfrom
fork-pr-57755-feat-delivery-status-json

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Summary

Design

The JSON envelope now includes deliveryStatus when --deliver is used:

{
  "payloads": [...],
  "meta": {...},
  "deliveryStatus": {
    "requested": true,
    "attempted": true,
    "succeeded": true
  }
}

succeeded is three-state:

  • true — all payloads delivered
  • "partial" — some payloads failed under bestEffort mode
  • false — nothing delivered

Key design decisions:

  • Separate field: deliveryStatus is a new top-level field, not reusing the existing delivery field (which carries channel metadata like messageId)
  • Post-delivery emit: JSON is emitted after delivery so it includes the final status. For non-bestEffort throws, JSON is emitted before re-throw so stdout always has structured output
  • No-payload runs: Include deliveryStatus: {requested: true, attempted: false, succeeded: false} so automation can distinguish "no delivery requested" from "delivery requested but nothing to send"
  • Plain-text suppression: "No reply from agent." is suppressed in JSON mode across all paths

Known limitations

These are inherent to the upstream deliverOutboundPayloads return type and would require upstream changes to address:

  • Hook cancellations: A message_sending hook that cancels all payloads returns [], which is indistinguishable from zero delivery results. Currently reported as succeeded: false rather than a distinct "cancelled" outcome.
  • Non-bestEffort partial throw: When delivery throws mid-stream after some payloads were already sent, the status reports succeeded: false, error: true even though part of the message reached the channel.

Dependencies

Test plan

  • JSON output includes deliveryStatus on successful delivery
  • JSON output includes deliveryStatus on failed delivery
  • JSON output omits deliveryStatus when deliver is false
  • Plain-text warning suppressed in JSON mode
  • No-payload JSON+deliver runs include deliveryStatus
  • Local codex review --base upstream/main — clean (2 P2s documented as known limitations above)

Closes openclaw#57730.

🤖 Generated with Claude Code

Enrich deliverAgentCommandResult with a structured deliveryStatus return
and a diagnostic [delivery] log line, making five previously-invisible
failure paths visible: no channel, internal channel, no target, thrown
error, and empty results.

deliveryStatus contract:
- succeeded: boolean (true when at least one payload delivered)
- hadPartialFailure: true when onError fired but some payloads succeeded
- error: true when delivery threw (bestEffort) or preflight check failed
- Early return (no payloads) includes deliveryStatus when deliver=true
- JSON output (--json --deliver) includes deliveryStatus in the envelope

Factor the JSON envelope emission into a single emitJsonEnvelope helper
so the status can be attached consistently at each return path, and
carry through suppress-on-JSON-mode warnings + restored test spies from
the Greptile/Codex review rounds that landed on this branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(delivery): surface deliveryStatus in --json output for openclaw agent --deliver

2 participants