返回 DeepSeek-Reasonix
SUBAGENT_PROGRESS.md
根目录 / docs / SUBAGENT_PROGRESS.md
1 # Local Sub-Agent Progress
2
3 Status: **implemented** — per-child progress previews for local sub-agent runs
4 (`task`, `read_only_task`, `parallel_tasks`, `fleet`) in the desktop app and the
5 CLI, on top of the persisted transcripts and `read_subagent_result` (see
6 [`CHECKPOINTS.md`](CHECKPOINTS.md) for the persistence model).
7
8 ## Goal
9
10 While a sub-agent works, the user should see **what it is doing** without the
11 sub-agent's reasoning/text bodies entering the parent conversation: a progress
12 card shows the child's phase, running elapsed time, and recent activity; the
13 desktop card can be expanded for a bounded reasoning / response / notice
14 preview, and the CLI shows the same previews in `/verbose` mode. Everything is
15 zero-configuration — there are no new settings.
16
17 ## Wire contract
18
19 Progress previews reuse the existing `ToolProgress` event with four reserved
20 `Tool.Name` values. These names are an internal contract between the agent
21 progress tracker and local frontends; they must never be presented as
22 provider-visible tool names:
23
24 | Name | Payload |
25 |---|---|
26 | `reasonix.subagent.status` | exactly one of `queued`, `running`, `reasoning`, `responding`, `tool`, `retrying`, `completed`, `failed`, `cancelled` |
27 | `reasonix.subagent.reasoning` | bounded UTF-8 text delta (the child's thinking) |
28 | `reasonix.subagent.text` | bounded UTF-8 text delta (the child's response preview) |
29 | `reasonix.subagent.notice` | bounded UTF-8 text delta (the child's notices) |
30
31 Field conventions:
32
33 - `Tool.ID` — the child task card ID (progress lookup is by ID, never by body).
34 - `Tool.Output` — the phase value (status) or a text delta (previews).
35 - `Tool.Truncated` — set when this round's preview was truncated or merged.
36 - `Tool.DurationMs` — the final duration, carried on terminal status events.
37 - `Tool.ParentID` — follows the existing nesting relationship (empty for a
38 top-level `task`; the group call ID for `parallel_tasks`/`fleet` children).
39
40 ## Behavior
41
42 State machine (emitted by the unified run chain in `RunProfileSpec`, shared by
43 `task`, `read_only_task`, `parallel_tasks`, and `fleet` — no per-entry copies):
44
45 - Foreground runs start with `running`.
46 - Background runs emit `queued` at registration and `running` once the job
47 acquires its execution slot.
48 - `parallel_tasks`/`fleet` group cards get an explicit lifecycle of their own:
49 `running` when children start and exactly one terminal after every child
50 settles (`completed`, `cancelled` for cancellation/deadline, `failed` when
51 any child failed or the call errored — including validation failures).
52 Frontends never infer group completion from the children observed so far,
53 since background children dispatch asynchronously and a fast first child
54 can finish before later ones appear.
55 - The child's `Reasoning` / `Text` / `Notice` / `Retrying` events become the
56 corresponding preview channels; the child's real tool activity flips the
57 phase to `tool` while the nested tool cards render as before.
58 - Every run emits exactly **one** terminal status: `completed` on success,
59 `cancelled` for context cancellation or deadline, `failed` for provider,
60 tool, storage, or panic errors. Pending previews are flushed synchronously
61 before the terminal; events arriving after the terminal are ignored.
62
63 Pacing and memory bounds (per parent task group):
64
65 - One pending slot per (child, channel); previews merge for up to 250 ms before
66 one event is emitted, so deltas never accumulate unboundedly.
67 - At most 32 non-terminal events/sec per group — phase transitions and content
68 previews share the same budget, round-robined across children so one hot
69 child cannot starve the others. Only the initial `queued`/`running` states
70 and the terminal event bypass the limit.
71 - When the budget trims buffered content, the loss is flagged `Truncated` on
72 the next actually-emitted channel (or surfaced as a truncated notice at the
73 terminal flush), so frontends always learn that some preview was dropped.
74 - Each child's unsent pending buffer is capped at 8 KiB total (notice is
75 dropped first, then reasoning, then text); overflow keeps a UTF-8-safe tail
76 and sets `Truncated`. The desktop retains per-channel preview caps (8 KiB
77 reasoning/text, 2 KiB notice); the CLI keeps 4 KiB reasoning/text tails for
78 `/verbose`.
79
80 What is **not** done:
81
82 - The child's `Message`, reasoning, and text bodies never enter the parent
83 transcript or provider context.
84 - No new event kinds, no new wire fields, no provider tool list/schema/system
85 prompt changes, no configuration.
86 - Previews are never persisted: after a restart the complete sub-agent
87 transcript (and `read_subagent_result`) remains the source of truth.
88 - ACP and bot consumers keep ignoring `ToolProgress` bodies entirely.
89
90 ## Desktop
91
92 - A sub-agent tool card shows a phase chip (phase + running elapsed + "N s
93 ago" recent activity) in its header; the chip ticks once a second while the
94 child is live and settles to a phase + duration summary.
95 - Expanding the card shows isolated reasoning / response preview / notices —
96 never mixed with ordinary tool output.
97 - A background call that already returned its job id stays in the running
98 state while child progress is non-terminal; `parallel_tasks`/`fleet` group
99 cards settle only from their own lifecycle terminal event, so neither a
100 job-id result arriving before any child nor a fast first child finishing
101 before later children dispatch can settle the group prematurely.
102 - `completed` / `failed` / `cancelled` reuse the existing done / error /
103 stopped visuals; after a terminal the card folds by default unless the user
104 explicitly expanded it.
105
106 ## CLI
107
108 - Each child keeps its own progress state and a fixed transcript slot keyed by
109 its call ID — independent of the single live tool stream, so concurrent
110 children never cross-stream.
111 - By default only the phase, elapsed, and recent activity are shown; the
112 reasoning/text bodies appear in `/verbose` (Ctrl+O) mode, bounded to the
113 recent 4 KiB tails.
114 - Terminal children fold to a one-line summary; verbose keeps the bounded
115 preview.
116 - Terminals without in-place redraw (Termux native scrollback) print a status
117 line on phase changes and terminal only; verbose previews print at most once
118 every 2 seconds per child.
119
120 ## Contract stability
121
122 Frontends match the reserved names by the `reasonix.subagent.` prefix, so a
123 future channel added by a newer agent is ignored (never appended to ordinary
124 tool output) by older frontends.
125
125 lines MARKDOWN