Skip to content

fix: route subagent announce to originating parent session instead of channel-bound peer session#80242

Merged
steipete merged 4 commits into
openclaw:mainfrom
Jerry-Xin:fix/subagent-announce-wrong-session
May 17, 2026
Merged

fix: route subagent announce to originating parent session instead of channel-bound peer session#80242
steipete merged 4 commits into
openclaw:mainfrom
Jerry-Xin:fix/subagent-announce-wrong-session

Conversation

@Jerry-Xin

Copy link
Copy Markdown
Contributor

Summary

When a subagent is spawned from agent:main:main while a Telegram DM session is active, the completion announce is delivered to the parallel channel-bound session (agent:main:telegram:default:direct:<chat_id>) instead of the originating parent session. The parent never observes the result and any logic gated on completion fails to fire.

Root Cause

Two interacting bugs:

1. Spawn tool receives wrong requester key

The embedded-run pipeline passes sandboxSessionKey (the Telegram peer key) through to createSessionsSpawnTool, which stores it as requesterInternalKey:

attempt.ts:841  → sandboxSessionKey = params.sandboxSessionKey || params.sessionKey
attempt.ts:1010 → sessionKey: sandboxSessionKey  (passed to pi-tools)
pi-tools.ts:797 → agentSessionKey: options?.sessionKey  (= Telegram peer key)
openclaw-tools.ts:402 → createSessionsSpawnTool({ agentSessionKey: ... })
sessions-spawn-tool.ts:394 → requesterInternalKey = resolve(agentSessionKey)

Result: requesterInternalKey = agent:main:telegram:default:direct:<chat_id> instead of agent:main:main.

2. Child binding hijacks delivery target

resolveSubagentCompletionOrigin in subagent-announce-delivery.ts:319-335 checked child session bindings before requester bindings. When both share the same channel + accountId (common for Telegram DMs with a single bot), the child binding won and routed the announce to the Telegram peer session.

Fix

Change 1: Use runSessionKey for spawn tool requester ownership

# src/agents/openclaw-tools.ts:402
createSessionsSpawnTool({
-  agentSessionKey: options?.agentSessionKey,
+  agentSessionKey: options?.runSessionKey ?? options?.agentSessionKey,

The runSessionKey (e.g., agent:main:main) is already threaded through from attempt.ts:1014 and the CreateOpenClawToolsOptions interface. The ?? fallback preserves behavior when no separate run key exists.

Change 2: Check requester binding first, child binding as fallback

# src/agents/subagent-announce-delivery.ts:319-352
- check child session binding FIRST → requester SECOND
+ check requester session binding FIRST → child as FALLBACK

This ensures the parent session's own binding (if any) determines where the announce is delivered, rather than being hijacked by the child's inherited binding.

Tests Added

  • sessions-spawn-tool.test.ts: Verifies agentSessionKey flows correctly to spawnSubagentDirect context, and that the Telegram peer key is not used when a run session key is available.
  • subagent-announce-delivery.test.ts: Verifies requester binding takes priority when both child and requester share the same channel + accountId; verifies child binding still works as fallback when requester has no binding.

Fixes #80201

@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 May 10, 2026
@clawsweeper

clawsweeper Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
The PR adds a completionOwnerKey separate from agentSessionKey for sessions_spawn/subagent registration, prefers requester bindings over child bindings for completion origin, and adds targeted regression tests.

Reproducibility: yes. from source inspection and the linked issue: current main passes the sandbox/channel peer key into sessions_spawn ownership and checks the child binding before the requester binding. I did not run a live Telegram reproduction in this read-only review.

Real behavior proof
Needs real behavior proof before merge: No after-fix real Telegram proof is present in the PR body or comments; the contributor should add redacted screenshot, recording, terminal output, copied live output, linked artifact, or logs and update the PR body for re-review.

Next step before merge
Contributor action is needed for real Telegram proof before merge; there is no narrow ClawSweeper code repair to queue from this pass.

Security
Cleared: The diff changes internal session routing keys and tests only; it does not add dependencies, workflows, permissions, lifecycle scripts, downloads, or secret-handling changes.

Review details

Best possible solution:

Land this routing fix after redacted real Telegram proof shows completion returns to the originating parent session while sandbox policy remains tied to the channel peer session.

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

Yes from source inspection and the linked issue: current main passes the sandbox/channel peer key into sessions_spawn ownership and checks the child binding before the requester binding. I did not run a live Telegram reproduction in this read-only review.

Is this the best way to solve the issue?

Yes. Separating completion ownership from sandbox policy and preferring requester binding before child fallback is the narrow maintainable fix; the remaining blocker is proof, not a different code shape.

Acceptance criteria:

  • node scripts/run-vitest.mjs src/agents/subagent-announce-delivery.test.ts
  • node scripts/run-vitest.mjs src/agents/tools/sessions-spawn-tool.test.ts
  • Redacted real Telegram proof showing the completion announce returns to agent:main:main instead of the channel-bound peer session

What I checked:

  • Live PR state: Unauthenticated GitHub API shows the PR is open at head e21d650 and still carries triage: needs-real-behavior-proof plus mantis: telegram-visible-proof. (e21d6506e0ac)
  • Current-main requester key path: Current main constructs sessions_spawn with options.agentSessionKey only; runSessionKey exists on createOpenClawTools but is not passed as a completion owner. (src/agents/openclaw-tools.ts:429, 42435d110baa)
  • Current-main registration owner: Current main resolves requesterInternalKey from opts.agentSessionKey and registers requesterSessionKey from that value, so the sandbox/channel peer key can become the subagent completion owner. (src/agents/tools/sessions-spawn-tool.ts:423, 42435d110baa)
  • Current-main child-first routing: resolveSubagentCompletionOrigin checks the child session binding before the requester binding, matching the reported wrong-session route when both bindings share a Telegram channel/account. (src/agents/subagent-announce-delivery.ts:365, 42435d110baa)
  • PR completion owner split: The PR diff passes completionOwnerKey from runSessionKey and uses it only for registerSubagentRun requester ownership while preserving agentSessionKey for sandbox/policy identity. (src/agents/tools/sessions-spawn-tool.ts:461, e21d6506e0ac)
  • PR requester-first routing: The PR diff changes completion origin resolution to inspect the requester binding before falling back to the child binding, and adds regression coverage for the shared channel/account case. (src/agents/subagent-announce-delivery.ts:363, e21d6506e0ac)

Likely related people:

  • Kaspre: Blame on the current createOpenClawTools, sessions_spawn, subagent spawn, and completion-origin lines points to the recent gateway model run-session isolation work that now carries the affected code. (role: recent area contributor; confidence: medium; commits: 0fd152b28623; files: src/agents/openclaw-tools.ts, src/agents/tools/sessions-spawn-tool.ts, src/agents/subagent-spawn.ts)
  • steipete: History on the subagent announce path includes Peter Steinberger's subagent announce helper split and earlier subagent announce/archive work that this routing path builds on. (role: feature-history contributor; confidence: medium; commits: b75be0914491, 75c66acfd828, 9b698ce0d6d2; files: src/agents/subagent-announce-delivery.ts, src/agents/subagent-announce.ts, src/agents/openclaw-tools.ts)
  • onutc: The thread-bound subagents work introduced much of the bound-session routing surface that this completion-delivery fix interacts with. (role: feature-history contributor; confidence: medium; commits: 8178ea472db1; files: src/agents/subagent-spawn.ts, src/agents/tools/sessions-spawn-tool.ts, src/agents/subagent-registry.ts)
  • Josh Avant: A recent subagent completion announce timing fix touched the same delivery and lifecycle files, making this a useful routing-review contact even though the PR addresses a narrower key-ownership bug. (role: recent adjacent contributor; confidence: medium; commits: 903d9c13f3ee; files: src/agents/subagent-announce-delivery.ts, src/agents/subagent-registry-lifecycle.ts, src/agents/subagent-registry-run-manager.ts)

Remaining risk / open question:

  • No after-fix real Telegram proof is present, so the wrong-session behavior has not been demonstrated in a real Telegram setup after the patch.
  • Focused tests were not run in this read-only review.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 42435d110baa.

@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from a87beda to 99079b9 Compare May 10, 2026 12:12
@clawsweeper clawsweeper Bot added the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label May 10, 2026
@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 99079b9 to 45e8c13 Compare May 10, 2026 14:05
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (9e31c5f, clean rebase, no conflicts).

@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 45e8c13 to 8baabd5 Compare May 10, 2026 16:05
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (6c21472, clean rebase, no conflicts).

@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 8baabd5 to 1058390 Compare May 10, 2026 18:04
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (41859bb, clean rebase, no conflicts).

@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 1058390 to 7bf0226 Compare May 10, 2026 20:04
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (f885c39, clean rebase, no conflicts).

@clawsweeper clawsweeper Bot added mantis: telegram-visible-proof Mantis should capture Telegram visible proof. and removed mantis: telegram-visible-proof Mantis should capture Telegram visible proof. labels May 10, 2026
@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 7bf0226 to a6d61c1 Compare May 10, 2026 22:05
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (5c7b203, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Addressed P2 finding in fa8d742 — removed subagent_announce from AGENT_MEDIATED_COMPLETION_TOOLS. This addition was unrelated to the routing fix and could silently drop group/channel subagent completions when the subagent provides a normal final reply without using the message tool. The mediated-delivery behavior for subagent completions should be coordinated with message-tool-only guidance (tracked separately in #80223).

@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from fa8d742 to 77e13b6 Compare May 11, 2026 00:05
@clawsweeper clawsweeper Bot removed the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label May 11, 2026
@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 77e13b6 to c770193 Compare May 11, 2026 02:05
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (e8a870c, clean rebase, no conflicts).

@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from c770193 to 1d612aa Compare May 11, 2026 04:05
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (bb207ad, clean rebase, no conflicts).

@clawsweeper clawsweeper Bot added mantis: telegram-visible-proof Mantis should capture Telegram visible proof. and removed mantis: telegram-visible-proof Mantis should capture Telegram visible proof. labels May 11, 2026
@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 1d612aa to b236e60 Compare May 11, 2026 06:06
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (384d74d, clean rebase, no conflicts).

@clawsweeper clawsweeper Bot added the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label May 11, 2026
@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch 2 times, most recently from 11653f1 to 54e5250 Compare May 15, 2026 06:15
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (7289e14, clean rebase, no conflicts).

@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch from 54e5250 to 7cd4f67 Compare May 15, 2026 08:07
@clawsweeper clawsweeper Bot removed the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label May 15, 2026
@Jerry-Xin Jerry-Xin force-pushed the fix/subagent-announce-wrong-session branch 2 times, most recently from 229f21b to 47a278c Compare May 15, 2026 14:09
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (adac07f, clean rebase, no conflicts).

@clawsweeper clawsweeper Bot added the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label May 15, 2026
@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (65dd71d, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (192caba, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (777d289, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (a1d0b27). Resolved conflict in src/agents/subagent-announce-delivery.ts — upstream added image_generate to AGENT_MEDIATED_COMPLETION_TOOLS; preserved both upstream addition and our routing changes. All changes preserved.

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (c2e9091, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (9e67f53, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (ab2943e, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (a5b1177, clean rebase, no conflicts).

@Jerry-Xin

Copy link
Copy Markdown
Contributor Author

Rebased on latest upstream/main (bf51933, clean rebase, no conflicts).

忻役 and others added 4 commits May 17, 2026 12:11
… channel-bound peer session

When a subagent is spawned from agent:main:main while a Telegram DM is active,
the completion announce was delivered to the parallel Telegram channel session
instead of the originating parent.

Two interacting bugs:

1. The spawn tool received the sandbox/policy session key (Telegram peer key)
   as the requester, instead of the real run session key. Fixed by passing
   runSessionKey to createSessionsSpawnTool so the registered requester
   points to the actual parent session.

2. resolveSubagentCompletionOrigin checked child session bindings before
   requester bindings. When both share the same channel+accountId (common
   for Telegram DMs), the child binding hijacked the delivery target.
   Fixed by checking requester binding first, with child as fallback.

Fixes openclaw#80201
The subagent_announce addition to AGENT_MEDIATED_COMPLETION_TOOLS was
unrelated to the routing fix and could cause group/channel completions
to fail silently when the subagent does not use the message tool.

This should be addressed separately with proper message-tool-only
guidance (tracked in openclaw#80223).
PR openclaw#80242 passed runSessionKey as agentSessionKey to createSessionsSpawnTool,
which caused spawnSubagentDirect to use the run session key for sandbox policy
checks (resolveSandboxRuntimeStatus). This could make a sandboxed channel run
appear unsandboxed.

Introduce completionOwnerKey as a separate field that is only used for
registerSubagentRun routing (requesterSessionKey), keeping agentSessionKey
for sandbox enforcement, callerDepth, activeChildren, and all other policy
checks.
@steipete

Copy link
Copy Markdown
Contributor

Maintainer fixup pushed and verified.

Proof:

  • git diff --check
  • node scripts/run-vitest.mjs src/agents/subagent-spawn.test.ts src/agents/subagent-spawn.thread-binding.test.ts src/agents/tools/sessions-spawn-tool.test.ts src/agents/subagent-announce-delivery.test.ts -> 8 files / 210 tests passed
  • codex-review --mode auto -> clean, no accepted/actionable findings
  • GitHub checks on 6823dd589899a2d0161e15392d27aede46458074 -> no live failing check-runs; Real behavior proof passed via maintainer proof: override because this is a maintainer-patched external PR with focused local regression proof

What changed:

  • centralizes subagent spawn ownership resolution
  • keeps sandbox peer/session as controller and thread-binding requester
  • routes completion ownership to the originating run session
  • covers direct subagent and ACP registry registration paths

Thanks @Jerry-Xin.

@steipete

Copy link
Copy Markdown
Contributor

Landed via squash merge.

  • Head/fixup SHA: 6823dd589899a2d0161e15392d27aede46458074
  • Merge commit: 3e9e1d6
  • Gate: focused local Vitest, git diff --check, Codex review clean, and GitHub checks green/neutral/skipped on the final head. The external-PR proof gate passed via maintainer proof: override after local regression proof.

Thanks @Jerry-Xin!

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

Labels

agents Agent runtime and tooling impact:message-loss Channel message delivery can be lost, duplicated, or misrouted. impact:session-state Session, memory, transcript, context, or agent state can drift or corrupt. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. P1 High-priority user-facing bug, regression, or broken workflow. proof: override Maintainer override for the external PR real behavior proof gate. size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Subagent announce delivered to parallel Telegram channel session instead of originating parent session (single-user, intra-agent)

2 participants