Skip to content

fix(agents): deliver DM media completions directly when requester handoff fails#95065

Closed
movefaster wants to merge 1 commit into
openclaw:mainfrom
movefaster:fix/dm-media-completion-direct-delivery
Closed

fix(agents): deliver DM media completions directly when requester handoff fails#95065
movefaster wants to merge 1 commit into
openclaw:mainfrom
movefaster:fix/dm-media-completion-direct-delivery

Conversation

@movefaster

@movefaster movefaster commented Jun 19, 2026

Copy link
Copy Markdown

Problem

Background task completions (e.g. image_generate) were silently dropped for direct-message requesters under the MCP-bridged claude-cli runtime. The task completed and its side effects ran, but the user-requested media/text never arrived — the user got nothing until a later message re-triggered a normal turn.

Root cause

In sendSubagentAnnounceDirectly, the requester's captured completion origin can carry no deliverable channel: the MCP-bridged CLI runtime builds tools with an empty agentChannel, so the origin collapses to the internal webchat channel. stripNonDeliverableChannelForCompletionOrigin then strips it, leaving deliveryTarget.deliver = false.

With no deliverable target, the existing direct-delivery fallbacks (deliverGeneratedMediaCompletionDirect / deliverTextCompletionDirect) all no-op, and the woken requester-agent handoff turn — running under message_tool_only — isn't guaranteed to call the message tool. The result is a silent drop with no error.

(Native runtimes avoid this because they build tools per-turn with the live inbound origin. The last-mile delivery path itself is shared across all runtimes, so the fix lives at that shared layer.)

Fix

In sendSubagentAnnounceDirectly:

  1. Backfill the completion origin from the requester session's persisted delivery context (deliveryContextFromSession(requesterEntry)) when the captured origin has no deliverable channel. This restores a real target so the existing fallbacks can fire.
  2. Deliver generated media directly for DM targets when the requester-agent handoff fails — previously gated only on session-write-lock errors.

Real behavior proof

Behavior or issue addressed: A background image_generate completion to a Telegram DM was silently dropped — the generated image never reached the user until they sent another message. After the fix the completion delivers the image to the DM autonomously.

Real environment tested: Live OpenClaw gateway on the patched build, claude-cli runtime over the MCP bridge, real Telegram DM channel. User/bot IDs and meal content redacted.

Exact steps or command run after fix: In a real Telegram DM, sent a request that fires a background image_generate, then left the session idle (no further messages, no manual ping) and watched the gateway journal for the completion delivery.

Evidence after fix: redacted runtime log (2026-06-18) — the background completion wakes the idle session and delivers the image with no ping and no "delivery not confirmed" warning:

17:21:03 [telegram/inbound]    Inbound message telegram:<dm-user> -> @<bot> (direct)
17:21:04 [agent/cli-backend]   cli exec: trigger=user useResume=true        # turn fires background image_generate
17:21:36 [agent/cli-backend]   claude live session close: reason=restart    # session goes idle
            (~54s idle while the background image is generated)
17:22:30 [agent/cli-backend]   cli exec: useResume=false reuse=invalidated  # completion wakes a fresh turn (promptChars=11911)
17:23:20 [agent/cli-backend]   claude live session close: reason=restart
17:23:21                       [completion turn produces its reply + the generated image]
17:23:24 [telegram/send]       telegram outbound send ok chatId=<dm-user> messageId=1293 operation=sendPhoto   # delivered, no ping

Observed result after fix: the image (sendPhoto messageId=1293) was delivered to the DM autonomously, with no manual ping. Reproduced across multiple background image completions the same day (sendPhoto messageIds 1287 / 1293 / 1298 / 1304) — every one delivered with no reason=no_active_run drop and no completion delivery was not confirmed after successful generation warning.

Before evidence (optional): diagnosed 2026-06-16/06-17 (those daily logs have since rotated). The same background completion was silently dropped: reason=no_active_run, the fallback requester-agent handoff turn went private-final (never called the message tool under message_tool_only), and the runtime logged ... completion delivery was not confirmed after successful generation (emitted at src/agents/tools/media-generate-background-shared.ts:443). The user received nothing until a manual ping re-triggered a turn.

What was not tested: the active-session steered path (a completion landing in a genuinely active run) is intentionally unchanged — it stays delegated to that turn to avoid double-messaging a live conversation, so it was not separately exercised here.

Testing (supplemental)

  • New regression test supplies no deliverable origin in any param and asserts delivery routes to the backfilled target. Negative-control verified: it fails if the backfill is removed.
  • Full subagent-announce-delivery suite: 102 passing.

Notes

This intentionally does not change the active-session steered path (covered by does not also direct-run a queued active completion): a completion landing in a genuinely active run is still delegated to that turn, to avoid double-messaging a live conversation.

🤖 Generated with Claude Code

…doff fails

Background image_generate completions were silently dropped when the requester session's captured origin had no deliverable channel: the MCP-bridged claude-cli runtime collapses it to the internal "webchat" channel, so deliveryTarget.deliver was false and every direct-delivery fallback no-op'd. Backfill the completion origin from the requester session's persisted delivery context (deliveryContextFromSession), and deliver generated media directly for DM targets when the requester-agent handoff fails, not only on session-write-lock errors.

Adds a regression test that supplies no deliverable origin in any param and asserts delivery routes to the backfilled target (negative-control verified: fails without the backfill). Full delivery suite: 102 passing.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 19, 2026
@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

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

Close as superseded: the useful stored-origin backfill is already covered by an open proof-positive PR, while this draft's unique generic DM handoff-error fallback is unsafe and lacks real behavior proof.

Root-cause cluster
Relationship: superseded
Canonical: #89949
Summary: The current PR overlaps the missing-target generated-media backfill already owned by a proof-positive open PR; its remaining generic handoff-error fallback is adjacent but not a safe canonical path.

Members:

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

Canonical path: Review or land #89949 for the session-store origin backfill, and require any future DM handoff-error media fallback to preserve terminal partial-send outcomes and prove no duplicate delivery.

So I’m closing this here and keeping the remaining discussion on #89949.

Review details

Best possible solution:

Review or land #89949 for the session-store origin backfill, and require any future DM handoff-error media fallback to preserve terminal partial-send outcomes and prove no duplicate delivery.

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

Partially. Source inspection and the added tests show the missing-target path when completion origin lacks a deliverable route, but this PR does not provide a real MCP-bridged or live DM media reproduction after the patch.

Is this the best way to solve the issue?

No. The stored-origin backfill is the right layer but is already covered by #89949, and this PR's generic DM handoff-error fallback is broader than the current no-unknown-side-effect guard.

Security review:

Security review cleared: The diff changes agent delivery logic and tests only; no dependency, workflow, secret, package, or supply-chain surface is changed.

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • vincentkoc: Current-main blame for the delivery-origin merge and generated-media handoff guard region points to the recent checkout commit, and GitHub commit metadata maps that commit to this handle. (role: recent area contributor; confidence: medium; commits: dc16aedd2efd; files: src/agents/subagent-announce-delivery.ts, src/agents/subagent-announce-delivery.test.ts)
  • fuller-stack-dev: Authored the generated-media SessionWriteLock fallback commit whose message explicitly preserves visible failure for generic handoff errors. (role: adjacent fallback contributor; confidence: high; commits: 8a007c987d44; files: src/agents/subagent-announce-delivery.ts)
  • maxpetrusenko: Authored prior completion announce delivery-target inheritance work in the same module. (role: adjacent completion-routing contributor; confidence: medium; commits: 8262078ee50c; files: src/agents/subagent-announce-delivery.ts)
  • joshavant: Authored a recent subagent DM completion delivery fix touching the same decision surface. (role: adjacent direct-message delivery contributor; confidence: medium; commits: 5d3a6909fb20; files: src/agents/subagent-announce-delivery.ts)

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

@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. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 19, 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 Jun 19, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 19, 2026
@movefaster

Copy link
Copy Markdown
Author

Closing as a duplicate of #89949, which implements the same fix — backfilling the completion delivery origin from the requester session entry via deliveryContextFromSession so DM media completions aren't silently dropped when the captured origin has no deliverable channel. #89949 predates this and is already proof-sufficient / ready for maintainer review. (This PR additionally broadened the DM catch-block direct-delivery on handoff failure, but that's largely redundant once the origin backfill lands.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant