# Sub-agent announce

> How a sub-agent reports its result back, the announce context block, and why sessionshistory is preferred

- 网址：https://funcoding.ai/agents/openclaw/tools/subagents/announce/
- 来源：OpenClaw 官方文档原文（英文），MIT 许可，同步于 2026-10-11
- 官方原文：https://docs.openclaw.ai/zh-CN/tools/subagents/announce

---
## Announce

Sub-agents report back through completion delivery:

- The completed child's result is handed to the requester; delivery does not ask the child to generate a separate announcement.
- Runs spawned with `expectsCompletionMessage: false` skip completion delivery entirely; the run registry records their delivery as not required.
- Subagents must return a meaningful result or a concrete blocker. An exact child `NO_REPLY` response or no output cannot satisfy a missing child result and triggers normal missing-answer recovery. A retained completion without a visible result is handed to the requester as `(no output)`, including when several child results are collected together.
- Duplicate delivery is suppressed through recorded completion and source-message delivery facts. Subagents and internal parent review turns do not use silent tokens for deduplication.

By default, delivery depends on requester depth:

- Top-level requester sessions use a follow-up `agent` call. External conversations use `deliver=true`; WebChat conversations stay in-session with `deliver=false`.
- Nested requester subagent sessions receive an internal follow-up injection (`deliver=false`) so the orchestrator can synthesize child results in-session.
- If a nested requester subagent session is gone, OpenClaw falls back to that session's requester when available.

The requester turn's captured origin owns completion routing, including after
`sessions_yield` and for child pause notices. A WebChat origin does not inherit a
previous external destination from the session. Without a captured origin, the
stored delivery route remains the fallback; explicit external routing remains
supported without clearing that history.

For top-level requester sessions, completion-mode direct delivery first
resolves any bound conversation/thread route and hook override, then fills
missing channel-target fields from the requester's origin and compatible stored route.
That keeps completions on the right chat/topic even when the completion
origin only identifies the channel. When an override selects a different
chat or topic, it does not inherit the previous route's thread. An explicit
thread from the binding or hook is preserved.

Child completion aggregation is scoped to the current requester run when
building nested completion findings, preventing stale prior-run child
outputs from leaking into the current announce. Announce replies preserve
thread/topic routing when available on channel adapters.

After `sessions_yield`, the frozen batch waits for its own children and their
descendants to settle. A still-running child from an earlier requester turn does
not delay that batch's result; the earlier batch retains its own completion wake.

Completion inputs retain their own turn identity across compaction and runtime
context messages. If transcript persistence rejects a completion because its
keyed input belongs to a closed turn, delivery records a permanent failure with
the error. It does not retry other models or keep scheduling the same completion.

If a chunk in a direct-message text fallback fails or is aborted after earlier
chunks were sent, OpenClaw records an incomplete delivery. It stops automatic
retries to avoid duplicating chunks the recipient already received. A successful
child's result remains available for recovery.

### Private parent completion

Set `completionTarget: "parent"` on `sessions_spawn` to return the result in a
private turn of the original requester session. The parent reviews the result,
continues unfinished work, and records the reviewed outcome in its internal final
reply. OpenClaw does not automatically send the child result, parent final, or
generated media to a channel. The parent can still choose to send a message
through its permitted tools.

If the parent called `sessions_yield` while waiting for private children, the
yield hands the conversation back to it. When those children settle, the parent
resumes and answers the original conversation under its normal reply rules: with
automatic replies its final text is delivered; with `visibleReplies:
"message_tool"` it must send the answer with the `message` tool, and plain final
text stays internal. Child results stay internal input, and nothing is sent
automatically on the child's behalf. The resumed turn stays bound to the parent
session that spawned the children: if that session is reset (for example with
`/new`) or replaced before the parent resumes, the results are dropped and
nothing is sent.

This option supports hidden, native, one-shot runs only. It cannot be combined
with ACP, `collect: true`, `visible: true`, `thread: true`, `mode: "session"`, or
`expectsCompletionMessage: false`. It does not change the default completion mode.

Finished private results remain in the registry until the spawning parent turn
settles. A normal parent finish releases each ready result for private review;
`sessions_yield` hands the results to its existing child batch instead. A reset or
removed parent does not transfer the result to another session. When a settled
batch contains a private result, the child findings stay private input to the
parent's review or yielded continuation; ordinary siblings retain their individual
completion delivery.

Inspecting a completed child's status before yielding does not consume or invalidate
its private result.

Waiting for the spawning parent turn does not consume a private result's delivery
retry window. A normal parent finish starts that window when it releases the
result. After `sessions_yield`, the yielded batch owns delivery; individual child
cleanup cannot expire or suspend that batch's result.

Use a build that supports this option throughout the run. Older builds cannot
resume private completion handoffs and may discard them after a downgrade;
existing session transcripts remain separate.

### Announce context

Announce context is normalized to a stable internal event block:

| Field          | Source                                                                                                   |
| -------------- | -------------------------------------------------------------------------------------------------------- |
| Source         | `subagent` or `cron`                                                                                     |
| Session ids    | Child session key/id                                                                                     |
| Type           | Announce type + task label                                                                               |
| Status         | Derived from runtime outcome (`ok`, `error`, `timeout`, or `unknown`) — **not** inferred from model text |
| Result content | Latest visible assistant text from the child                                                             |
| Follow-up      | Instruction to review the result, continue unfinished work, and report the outcome                       |

The result is the child's complete visible final answer for the completed run,
including ACP-backed runs and CLI fallback transcripts. A later turn in the same
child session does not replace that run's answer.

If completion receipts for the same run arrive out of order, the receipt with
the newer producer end time owns the reply. Equal end times retain the first
accepted reply; a correction with a newer end time can replace it.

OpenClaw preserves prompt-data escaping and stable order when it delivers several
results together. It does not shorten an answer to fit the former announce
projection limits. The bounded lifecycle snapshot remains separate from the
complete answer sent to the parent.

A successful child with an empty final reply remains in the batch with its task
identity, `ok` status, and `(no output)` result. Its successful execution status
does not satisfy the required result.

For nested work, descendant findings help the child form its answer. The child's
own final answer is what travels onward to its parent. A final answer delivered
through the message tool remains authoritative through its recorded source
delivery, even if a later terminal response is empty or silent.

Completion delivery can read an existing registered archive when child cleanup
finishes before the parent resumes. The Control UI's **Tasks** inspector also
reads the completed run's retained transcript after cleanup removes its live
session. Paging stays bound to that run's archive, even if the session key is reused.
After deletion, child-specific sharing metadata is no longer available. Archived
previews therefore require existing session access that does not depend on that
metadata, such as Gateway administrator access. Profile-scoped readers cannot
recover a deleted child's entitlement from access to its parent task. Keeping the
child session preserves its normal sharing checks.
Oversized text records use the normal history size notice. A single archived
record above 8 MiB makes Tasks history unavailable before the reader decodes it,
to bound per-record decoding memory. This limit also applies to other retained
generations with the same session key: run membership is stored inside transcript
records, so an unreadable candidate prevents the reader from establishing a unique
match, even when the requested run's own archive is small. The reader reports
unavailable rather than skipping an unclassified generation. This read limit does
not change retained archives or completion delivery's final-answer scanner.
Tasks reports this as a non-retryable preview limit; refreshing cannot resolve it.

Terminal failed runs report failure status without replaying captured
reply text. When completion is recovered from the child's stored session, its
recorded failure or timeout diagnostic is preserved for the parent.
Tool/toolResult output is not promoted into child result text.

### Stats line

Default announce payloads include a stats line at the end (even when wrapped).
Private parent completions omit mutable usage statistics so a retried handoff
keeps the same input:

- Runtime (e.g. `runtime 5m12s`).
- Token usage (input/output/total).
- Estimated cost when model pricing is configured (`models.providers.*.models[].cost`).
- `sessionKey`, `sessionId`, and transcript path so the main agent can fetch history via `sessions_history` or inspect the file on disk.

Internal metadata is meant for orchestration only; user-facing replies
should be rewritten in normal assistant voice.

### Why prefer `sessions_history`

`sessions_history` is the safer orchestration path for reading a child's
transcript from within an agent turn:

- Redacts credential/token-like text even when general-purpose log redaction is disabled.
- Truncates long text blocks (4000 chars per block) and drops thinking signatures, reasoning replay payloads, and inline image data.
- Caps returned messages at 80 KB; older rows can be dropped or an oversized row replaced with `[sessions_history omitted: message too large]`.
- Use `nextOffset` when present to page backward through older transcript windows.
- Returns structured history rather than `/subagents log`'s plain chat lines. Reasoning tags, `<relevant-memories>` / `<relevant_memories>` scaffolding, and tool-call XML can remain in message text: `sessions_history` does not apply the log command's assistant prose sanitizer. See [Session tools](https://funcoding.ai/agents/openclaw/concepts/session-tool/#listing-and-reading-sessions) for the recall guarantees.
- Raw on-disk transcript inspection is the fallback when you need the full byte-for-byte transcript.
