fix(agents): prefer target agent's bound Matrix account for subagent spawns#67508
Conversation
Greptile SummaryThis PR fixes a bug where Matrix (and other-channel) subagent spawns inherited the caller's Confidence Score: 5/5Safe to merge — no P0 or P1 issues found; the bug fix is correct and comprehensively tested. The four-tier precedence model in No files require special attention. Reviews (2): Last reviewed commit: "fix(agents): let id-embedded kind marker..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a0506b007
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 00b393064c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f8430fd70b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d662dc529b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3d8c0f635
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3d8c0f635
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3f673354a4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 173827d6a9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Install Smoke root cause identified — pre-existing build-system gap, not from this PR.
Why it surfaced here and not elsewhere: most recent Proposed one-line fix for - "build:docker": "node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && node scripts/build-stamp.mjs && …",
+ "build:docker": "node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && node --import tsx scripts/write-npm-update-compat-sidecars.ts && node scripts/build-stamp.mjs && …",(Insert Happy to include that fix in this PR if you'd like — it's pure build-script, trivially reviewable, and gets Install Smoke green. Otherwise I'll leave this PR focused on the routing fix and file the build gap separately. Your call. The CI |
|
@codex review |
|
Codex Review: Didn't find any major issues. Chef's kiss. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
ec114e7 to
9300111
Compare
|
Merged via squash.
Thanks @lukeboyett! |
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…spawns (openclaw#67508) Merged via squash. Prepared head SHA: 9300111 Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
Summary
Fixes Matrix (and other-channel) subagent spawns inheriting the caller's
accountIdinstead of the target agent's bound account, and hardensresolveFirstBoundAccountIdwith kind-aware multi-tier matching for peer bindings.src/agents/subagent-spawn.ts: addsresolveRequesterOriginForChild(...)that prefers the target agent's bound account viaresolveFirstBoundAccountId({ cfg, channelId, agentId: targetAgentId, peerId, peerKind })before falling back to the caller'saccountId. Same-agent spawns short-circuit the lookup and preserve the caller's account. A newextractRequesterPeerhelper peels known delivery-target prefixes (<channel>:namespace, then a generic<word>:loop) fromagentToto produce the raw peer id and — for channels whose plugin does not implementinferTargetChatType— inferpeerKindfrom kind-prefixes (room:/channel:/chat:→ channel,group:/team:→ group,user:/dm:/pm:→ direct) and id-embedded markers (Matrix!/@, IRC#). Id-embedded kind markers take precedence over prefix-derived kind so wrappers likeroom:@user:serverclassify correctly.src/routing/bound-account-read.ts:resolveFirstBoundAccountIdnow accepts optionalpeerIdandpeerKind, and uses a four-tier precedence model:peer.id: "*") match — only when the caller supplies a peer AND both sides declare a matching kind (treatinggroup/channelas equivalent, mirroringpeerKindMatchesinresolve-route.ts).peerId— preserves the pre-existing first-match semantics for cron delivery resolution.delivery-target.tscaller is unaffected: it still passes nopeerId/peerKind, and the helper returns the same binding it would have before on realistic configs.Why
A Matrix-bound parent session spawning a child for another agent could seed
deliveryContext.accountIdwith the caller's account before target bindings were consulted. A child intended to post as the target agent's bound identity could end up posting as the caller — broken speaker identity in shared rooms, nondeterministic debugging, and wrong attribution in multi-agent deployments.The original
resolveFirstBoundAccountIdalso matched only on channel + agent, so multi-room-bound agents with different accounts per room got "first binding wins" regardless of active room. The peer-id/peer-kind aware matching fixes that while staying backward-compatible for callers that don't pass a peer (cron).Regression coverage
Twelve unit tests in
src/routing/bound-account-read.test.ts(new file) exercise the four-tier lookup: exact peer match, wildcard peer beats channel-only (with caller kind), channel-only beats wildcard (no caller kind), peer-specific fallback for peerless callers, non-matching peer skipped, channel mismatch, kind filtering, kind-unknown wildcard skip, exact id with unknown kind, group/channel equivalence, and the agent-on-different-channel no-match case.Fifteen lifecycle tests in
src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts(eleven new):agentTobefore lookup (Matrixroom:<id>).<channel>:<kind>:<id>targets peel both prefixes (LINEline:group:<id>) and pick thegroup-kinded binding over a conflictingdirect-kinded wildcard.conversation:<id>prefix stripped for Teams-style targets.room:@user:serverclassified asdirect, notchannel, so direct-peer bindings match.Validation
pnpm build✓pnpm check✓ (typecheck, lint, import cycles, boundary checks)pnpm test:changed✓ (3777 passed on round 1)Review iterations
This PR went through eight rounds of bot review (Codex + Greptile) before final approval. Commit history reflects each iteration:
5d11d7bb1e5d0027479e*treated as literal → three-tier precedence00b393064cf8430fd70bpeer.kind→ kind-aware matching + plugin inferenced662dc529bnormalizeRequesterPeerId3f673354a4<channel>:<kind>:<id>parsing; peerless wildcard fallback restored;group/channelkind equivalence173827d6a9conversation:<id>→ generic^[a-z][a-z0-9_-]*:peeler249b292111room:@user→ direct)Final state: all twelve bot review threads resolved, Codex
Didn't find any major issueson the current HEAD.AI-assisted
Authored with Claude Code (Claude Opus 4.6, 1M-context). Fully tested locally. I've reviewed the change and understand what it does.
Related / prior art
deliveryContextfrom spawn params at the gateway layer — complementary, different layer.accountIdforwarding insendMessage.Known-red CI
Install Smokeis red due to a pre-existing build-system gap (build:dockerinpackage.jsondoesn't runscripts/write-npm-update-compat-sidecars.ts, unlikebuild-all.mjs). Root cause documented in this comment with a proposed one-line fix — happy to include here or split out per maintainer preference.Run the GPT-5.4 / Opus 4.6 parity gate against the qa-lab mockis red and looks unrelated to this PR.