docs(specs): add live progress design
This commit is contained in:
@@ -21,8 +21,8 @@ Applies to entire `pi-subagents` package in this repo root.
|
|||||||
- `src/tool.ts` / `src/schema.ts` — tool contract and parameter/result types.
|
- `src/tool.ts` / `src/schema.ts` — tool contract and parameter/result types.
|
||||||
- `src/wrapper/cli.mjs` — child-session wrapper that writes artifacts/results.
|
- `src/wrapper/cli.mjs` — child-session wrapper that writes artifacts/results.
|
||||||
- `src/*.test.ts`, `src/wrapper/*.test.ts` — regression tests.
|
- `src/*.test.ts`, `src/wrapper/*.test.ts` — regression tests.
|
||||||
- `docs/specs/` — design docs created during brainstorming before implementation.
|
- `docs/superpowers/specs/` — design docs created during brainstorming before implementation.
|
||||||
- `docs/plans/` — implementation plans and migration notes.
|
- `docs/superpowers/plans/` — implementation plans and migration notes.
|
||||||
|
|
||||||
## Working rules
|
## Working rules
|
||||||
|
|
||||||
|
|||||||
@@ -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