fix(gateway): emit subagent_ended hook for api.runtime.subagent.run() (#59164)#87698
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed May 31, 2026, 1:00 PM ET / 17:00 UTC. Summary PR surface: Source +91, Tests +277. Total +368 across 2 files. Reproducibility: unclear. the prompt includes source-repro context for the original issue, but this run could not inspect current source or execute/read the focused paths directly. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: A maintainer should require a fresh source-level review of the Gateway plugin SDK subagent path, task-ledger ownership, and installed-plugin proof before merge. Do we have a high-confidence way to reproduce the issue? Unclear: the prompt includes source-repro context for the original issue, but this run could not inspect current source or execute/read the focused paths directly. Is this the best way to solve the issue? Unclear: the proposed direction appears plausible, but prior review context says task-ledger ownership and installed-plugin proof still need maintainer review before this is the best merge path. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model gpt-5.5, reasoning high; reviewed against 0ee5f47fbabb. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +91, Tests +277. Total +368 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
openclaw#59164) ClawSweeper P1 follow-up on openclaw#87698: the original helper registered plugin SDK subagent runs with `cleanup: "delete"`, which made the registry delete the child session as soon as subagent_ended fired. Plugins that follow the documented flow `api.runtime.subagent.run()` → `waitForRun()` → `getSessionMessages()` would race the auto-delete and lose the transcript before reading it back. Default to `cleanup: "keep"` instead so the child session survives completion. Explicit teardown stays with the plugin via `api.runtime.subagent.deleteSession()`, matching the `sessions_spawn` default for the same readability reason. The subagent_ended hook still fires in `completeSubagentRun` — cleanup only governs whether the session is deleted afterward. Adds a regression test covering the full plugin contract: run → waitForRun → getSessionMessages (transcript readable) → deleteSession (transcript gone). Existing cleanup-mode assertion updated from `"delete"` to `"keep"`.
f3d2753 to
2defa69
Compare
|
@clawsweeper re-review P1 finding addressed in 2defa69:
PR body has a new "ClawSweeper P1 follow-up" section with the details. |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review — added a live-capture proof ( |
|
🦞👀 Command router queued. I will update this comment with the next step. |
|
@clawsweeper re-review — the prior re-review (05:10 UTC) failed mid-run (execution error, incomplete AGENTS.md read). Real behavior proof is in place: |
|
🦞👀 Command router queued. I will update this comment with the next step. |
bdbfd48 to
762754b
Compare
Plugin SDK subagent runs now register at the Gateway agent acceptance boundary so subagent_ended hooks fire without creating duplicate CLI task rows. The registration stays best-effort: if the subagent registry cannot persist tracking state, the run still dispatches and falls back to the existing CLI task tracking path. Closes openclaw#59164 Co-authored-by: Cornna <[email protected]>
|
Land-ready after rewrite. What changed:
Local proof:
CI proof:
Known proof gap:
Thanks @ymylive for the original PR. |
Summary
api.runtime.subagent.run()marks the internal Gatewayagentrequest instead of registering after dispatch.agenthandler now registers plugin subagent runs at the accepted-run boundary, which givessubagent_endedhooks a realSubagentRunRecordwhile avoiding duplicateruntime: "cli"task rows.Closes #59164
Real behavior proof
Behavior addressed: plugin SDK subagent runs dispatched through
api.runtime.subagent.run()were not represented in the subagent registry, sosubagent_endedhooks did not fire for that run path. The rewritten fix moves registration intosrc/gateway/server-methods/agent.ts, suppresses the generic CLI task only after subagent registration succeeds, and falls back to CLI task tracking on registry failure.Real environment tested: local OpenClaw source checkout on macOS, exercising the in-process plugin runtime adapter plus the real Gateway
agenthandler, task registry, and subagent registry code paths with Vitest. The model turn is mocked atagentCommandFromIngress, matching the existing Gateway method test style.Exact steps or command run after this patch:
Evidence after fix:
Observed result after fix:
createGatewaySubagentRuntime().run()sends the internalagentRunTracking: "plugin_subagent"marker through the Gateway client. The Gatewayagenthandler creates exactly one task row for the run, withruntime: "subagent", the plugin label,cleanup: "keep",expectsCompletionMessage: false, and no duplicateruntime: "cli"task. A cached retry with the same idempotency key does not re-register or start a second run. A multi-agent child session such asagent:work:subagent:plugin-helperis owned byagent:work:main, not the default main agent. If registry persistence throws, the public run still dispatches and records a fallback CLI task.What was not tested: no external packaged plugin process was run against a separately started gateway. The covered runtime boundary is in-process Gateway/plugin runtime code with the model execution mocked, so it proves registration, task ownership, retry behavior, best-effort fallback, and plugin readback/delete behavior without live model/provider credentials.
Regression coverage
src/gateway/server-plugins.subagent-ended-hook.test.tsverifies the plugin runtime marks Gatewayagentcalls for plugin subagent tracking, preserves plugin identity, keeps no-context dispatch behavior unchanged, and preserves transcript readback until explicitdeleteSession().src/gateway/server-methods/agent.test.tsverifies the real Gatewayagenthandler creates a single subagent task/registry row, avoids cached retry re-registration, handles non-default agent ownership, and falls back to CLI task tracking if registry persistence fails.Risk
Highest-risk surface is duplicate task or registry state for a run that already has Gateway task tracking. The fix keeps a single tracking owner: successful plugin subagent registration suppresses CLI task creation; failed registration falls back to the existing CLI task path so public SDK behavior remains best-effort.