fix(agents): clean subagent fallback scaffolding#78700
Conversation
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: yes. at source level. Current main returns raw Real behavior proof Next step before merge Security Review findings
Review detailsBest possible solution: Keep the layered fallback and queue hardening, but narrow prompt-data unwrapping so only generated wrapper blocks are removed while literal tag examples are preserved. Do we have a high-confidence way to reproduce the issue? Yes, at source level. Current main returns raw Is this the best way to solve the issue? No, not as currently written. The fallback and queue direction is maintainable, but Full review comments:
Overall correctness: patch is incorrect Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 58fa23b4a2f2. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e73c149919
ℹ️ 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".
| if (isPromptDataTagLine(line, "open") || isPromptDataTagLine(line, "close")) { | ||
| changed = true; | ||
| continue; |
There was a problem hiding this comment.
Only unwrap prompt-data tags when in generated wrapper
stripInternalRuntimeScaffolding now drops any standalone <prompt-data>/</prompt-data> (and <untrusted-text>) lines unconditionally, even when they are literal user-facing content rather than OpenClaw scaffolding. Because this sanitizer is applied broadly in outbound delivery paths, legitimate XML/code examples that include these tags on their own lines will be silently altered before send and before queued retry persistence. The unwrap should be gated to an actual generated wrapper pattern (header + matching open/close) instead of removing every matching tag line globally.
Useful? React with 👍 / 👎.
3772103 to
ceea202
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ceea202337
ℹ️ 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".
| if (isPromptDataTagLine(line, "open") || isPromptDataTagLine(line, "close")) { | ||
| changed = true; | ||
| continue; |
There was a problem hiding this comment.
Gate prompt-tag stripping on full generated wrapper
unwrapPromptDataWrapperLines removes any standalone <prompt-data> / </prompt-data> (and legacy <untrusted-text>) lines even when there is no generated OpenClaw wrapper header, so user-authored examples/XML snippets that place these tags on their own lines are silently altered before outbound delivery and queue persistence. This should only unwrap when a full generated wrapper pattern is detected (header + matching open/close), otherwise legitimate content is corrupted.
Useful? React with 👍 / 👎.
|
Landed via squash merge.
|
…eway fallthrough
When a subagent completes and the parent session has an active but
non-consuming embedded Pi run (between turns, idle), the completion
announcement was silently dropped instead of being delivered.
The early return at the 'if (requesterActivity.isActive)' block returned
{ delivered: false } as a dead-end, preventing fallthrough to the
requester-agent handoff (callGateway with expectFinal: true) that
exists later in the function.
Removing the early return allows the code to reach callGateway, which
starts a proper new agent turn that rewrites and delivers the child
result through the requester session — preserving the delivery contract
established by PR openclaw#78700.
No new code, types, or dependencies. The callGateway path was always
there; we just stopped blocking it.
Fixes openclaw#79053
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix(agents): clean subagent completion fallback scaffolding * refactor(agents): use prompt data blocks for child results * fix(agents): satisfy sanitizer lint * refactor(agents): remove raw subagent completion fallback
* fix(agents): clean subagent completion fallback scaffolding * refactor(agents): use prompt data blocks for child results * fix(agents): satisfy sanitizer lint * refactor(agents): remove raw subagent completion fallback
…eway fallthrough
When a subagent completes and the parent session has an active but
non-consuming embedded Pi run (between turns, idle), the completion
announcement was silently dropped instead of being delivered.
The early return at the 'if (requesterActivity.isActive)' block returned
{ delivered: false } as a dead-end, preventing fallthrough to the
requester-agent handoff (callGateway with expectFinal: true) that
exists later in the function.
Removing the early return allows the code to reach callGateway, which
starts a proper new agent turn that rewrites and delivers the child
result through the requester session — preserving the delivery contract
established by PR openclaw#78700.
No new code, types, or dependencies. The callGateway path was always
there; we just stopped blocking it.
Fixes openclaw#79053
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix(agents): clean subagent completion fallback scaffolding * refactor(agents): use prompt data blocks for child results * fix(agents): satisfy sanitizer lint * refactor(agents): remove raw subagent completion fallback
* fix(agents): clean subagent completion fallback scaffolding * refactor(agents): use prompt data blocks for child results * fix(agents): satisfy sanitizer lint * refactor(agents): remove raw subagent completion fallback
* fix(agents): clean subagent completion fallback scaffolding * refactor(agents): use prompt data blocks for child results * fix(agents): satisfy sanitizer lint * refactor(agents): remove raw subagent completion fallback
* fix(agents): clean subagent completion fallback scaffolding * refactor(agents): use prompt data blocks for child results * fix(agents): satisfy sanitizer lint * refactor(agents): remove raw subagent completion fallback
Summary
<<<BEGIN_UNTRUSTED_CHILD_RESULT>>>prompt sentinels with neutral<prompt-data>child-result blocks for parent-agent announce promptsFixes #78531.
Real behavior proof
tbx_01kr071t6gf9j80yhfpe94ezj2running the rebased branch against current OpenClaw source.env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm check:changedcheck:changed lanes=core, coreTests, docs,Found 0 warnings and 0 errors,Import cycle check: 0 runtime value cycle(s)., and final JSON{"provider":"blacksmith-testbox","leaseId":"tbx_01kr071t6gf9j80yhfpe94ezj2","exitCode":0}.Verification
pnpm test src/agents/subagent-announce-delivery.test.ts src/agents/subagent-announce-dispatch.test.ts src/agents/subagent-announce.format.e2e.test.ts -- --reporter=verbosepnpm test src/agents/sanitize-for-prompt.test.ts src/agents/subagent-announce-delivery.test.ts src/infra/outbound/sanitize-text.test.ts src/infra/outbound/deliver.test.ts src/agents/subagent-announce.format.e2e.test.ts src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts -- --reporter=verbosepnpm exec oxfmt --check --threads=1 src/agents/subagent-announce-delivery.ts src/agents/subagent-announce-delivery.test.ts src/agents/subagent-announce-dispatch.ts docs/tools/subagents.md CHANGELOG.mdgit diff --checkpnpm changed:lanes --jsonpnpm check:changedon rebased headtbx_01kr071t6gf9j80yhfpe94ezj2(exitCode=0)