docs(specs): add live progress design
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
# Subagent Live Progress Rendering Design
|
||||
|
||||
**Date:** 2026-04-12
|
||||
**Package:** `pi-subagents`
|
||||
|
||||
## Goal
|
||||
|
||||
Make a running subagent show what the child agent is actually doing instead of collapsing every live update to raw event names like `tool_call` and `tool_result`.
|
||||
|
||||
## Current state
|
||||
|
||||
Today `src/tool.ts` handles every child event with the same parent-facing update:
|
||||
|
||||
- `Running subagent: ${event.type}`
|
||||
|
||||
That loses the useful semantics already present in normalized events:
|
||||
|
||||
- assistant turns may already contain human-readable status text
|
||||
- tool calls carry actionable args like file paths and commands
|
||||
- tool results can tell whether a step finished or failed
|
||||
|
||||
`src/wrapper/render.mjs` already renders transcript lines, but its tool fallback is still JSON-shaped and the parent live UI does not reuse it. As a result, the live progress display is much less informative than the underlying event stream.
|
||||
|
||||
## Chosen approach
|
||||
|
||||
Use a **shared progress formatter**.
|
||||
|
||||
Behavior order:
|
||||
|
||||
1. prefer child `assistant_text` when it contains non-empty text
|
||||
2. otherwise render humanized tool activity from normalized tool events
|
||||
3. use concise completion/failure wording for tool results based on remembered tool context
|
||||
|
||||
Use the same formatter for:
|
||||
|
||||
- parent live progress updates in `src/tool.ts`
|
||||
- transcript event rendering in `src/wrapper/render.mjs`
|
||||
|
||||
Keep the wrapper event protocol, runner behavior, artifacts, and `result.json` semantics unchanged.
|
||||
|
||||
## Scope
|
||||
|
||||
### Modify
|
||||
|
||||
- `src/tool.ts`
|
||||
- `src/wrapper/render.mjs`
|
||||
- new shared formatter module for normalized progress events
|
||||
- `src/tool.test.ts`
|
||||
- `src/wrapper/render.test.ts`
|
||||
|
||||
### Do not modify
|
||||
|
||||
- `index.ts`
|
||||
- `src/process-runner.ts`
|
||||
- `src/tmux-runner.ts`
|
||||
- `src/wrapper/cli.mjs` event/result lifecycle
|
||||
- `src/wrapper/normalize.mjs`
|
||||
- artifact layout or `result.json` fields
|
||||
|
||||
## Design
|
||||
|
||||
### 1. Progress priority
|
||||
|
||||
When a normalized event is `assistant_text` and `text` is non-empty:
|
||||
|
||||
- show that text to the parent as the live status
|
||||
- render that same text in the transcript as today
|
||||
- do not replace it with a generic tool label
|
||||
|
||||
This matches the product goal best because the child assistant can express intent directly, for example:
|
||||
|
||||
- `I’m inspecting the auth flow now.`
|
||||
- `I found the schema; next I’m checking validation.`
|
||||
|
||||
Blank assistant text should not generate a noisy no-op status line.
|
||||
|
||||
### 2. Tool activity fallback
|
||||
|
||||
When there is no usable assistant text, render normalized tool events into action text.
|
||||
|
||||
Examples of desired fallback wording:
|
||||
|
||||
- `read` -> `Reading src/auth.ts`
|
||||
- `grep` -> `Searching code for auth`
|
||||
- `find` -> `Scanning for *.test.ts`
|
||||
- `ls` -> `Listing src/`
|
||||
- `edit` -> `Editing src/tool.ts`
|
||||
- `write` -> `Writing README.md`
|
||||
- `bash` -> keep the shortened shell command, because the command already states the action
|
||||
- unknown tool -> `Running <toolName>`
|
||||
|
||||
The formatter should use available arguments conservatively:
|
||||
|
||||
- prefer exact paths, patterns, and commands already present in the event
|
||||
- do not invent missing detail
|
||||
- if args are absent, fall back to a generic tool name message instead of guessing
|
||||
|
||||
### 3. Tool result wording
|
||||
|
||||
`tool_result` should not surface as bare `tool_result`.
|
||||
|
||||
Instead, it should render a concise completion/failure message tied to the most recent relevant tool context when available, for example:
|
||||
|
||||
- `Finished reading src/auth.ts`
|
||||
- `Search finished`
|
||||
- `Edit failed: src/tool.ts`
|
||||
|
||||
If no matching prior tool context is available, use a conservative generic result line such as:
|
||||
|
||||
- `read finished`
|
||||
- `grep failed`
|
||||
|
||||
This keeps progress understandable without requiring protocol changes.
|
||||
|
||||
### 4. Shared rendering boundary
|
||||
|
||||
The new shared formatter module owns conversion from normalized child events to user-facing progress text.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- map known tools to humanized action strings
|
||||
- preserve assistant text when present
|
||||
- derive concise result wording from recent tool context
|
||||
- keep unknown tools conservative
|
||||
|
||||
`src/tool.ts` should use this formatter for parent `onUpdate` messages.
|
||||
|
||||
`src/wrapper/render.mjs` should use the same formatter for transcript event lines so live UI and transcript do not drift.
|
||||
|
||||
The existing transcript header stays unchanged and generic.
|
||||
|
||||
### 5. Failure and noise handling
|
||||
|
||||
Keep behavior minimal and predictable:
|
||||
|
||||
- blank assistant text -> emit nothing
|
||||
- unknown tool -> generic `Running <toolName>` / `<toolName> finished` / `<toolName> failed`
|
||||
- no tool context for a result -> generic result wording
|
||||
- artifact/result writing behavior stays unchanged
|
||||
- no new event types, no wrapper protocol expansion
|
||||
|
||||
## Testing strategy
|
||||
|
||||
Follow TDD.
|
||||
|
||||
### First failing tests
|
||||
|
||||
1. `src/tool.test.ts`
|
||||
- assistant text is surfaced directly when present
|
||||
- fallback tool updates are humanized
|
||||
- parent progress no longer shows raw `tool_call` / `tool_result`
|
||||
|
||||
2. `src/wrapper/render.test.ts`
|
||||
- known tools render as action text instead of JSON-shaped fallback lines
|
||||
- result lines use completion/failure wording
|
||||
- bash still renders as shortened command text
|
||||
|
||||
### Verification after implementation
|
||||
|
||||
Run at least:
|
||||
|
||||
- targeted test files for touched units
|
||||
- full package suite: `npm test`
|
||||
|
||||
## Non-goals
|
||||
|
||||
- changing child wrapper completion behavior
|
||||
- changing normalized event schema
|
||||
- adding runner-specific progress logic
|
||||
- redesigning artifact files or transcript headers
|
||||
- inventing semantic summaries beyond the data already present in events
|
||||
|
||||
## Expected outcome
|
||||
|
||||
After the change, a running subagent will show meaningful status like assistant intent text or readable tool activity instead of raw event-type labels. The parent live UI and saved transcript will use the same progress language while keeping runner behavior, wrapper semantics, and result artifacts stable.
|
||||
Reference in New Issue
Block a user