* feat: visualize ordinary session plan execution * fix(web-shell): complete plan workflow rendering * fix: preserve authoritative plan state * fix(core): isolate teammate todo state * fix: reject ambiguous empty plan snapshots * test(web-shell): cover workflow dialog wiring * feat(web-shell): preview workflow before execution * feat(web-shell): inspect workflow step details * feat(web-shell): preserve session workflow history * test: align failing CI tests with plan-isolation behavior SubAgentTracker: the emitter now guards subagent TodoWrite results (tool-call-emitter emitResult early-returns on subagentMeta), so a subagent todo no longer promotes into a session-level plan. Flip the stale assertion to expect no plan emission, mirroring the dedicated guard test in tool-call-emitter.test.ts. HistoricalPlanExecution: the pagination fixture's onLoadOlderHistory returned Promise<void>, but PlanExecutionHistoryProvider requires Promise<boolean> and throws 'Unable to load earlier session history' on a falsy resolution. Production wires loadOlderHistory (resolves true after layout); return true in the fixture to model a successful load. * refactor: simplify session plan execution workflow * fix(web-shell): preserve split plan approval workflow --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
4.2 KiB
Ordinary Session Plan Execution
Goal
Show an ordinary session's Todo plan as a dependency graph and connect each node to the Agent executions that implement it. Reuse the existing ACP plan stream, session task snapshot, and subagent detail session.
This feature is observational. It does not schedule, retry, unblock, or complete work.
Data contract
todo_write accepts optional blockedBy Todo IDs. The runtime validates that
IDs are unique, references exist, dependencies are not duplicated or
self-referential, and the graph is acyclic.
The Todo sidecar stores a runtime-generated planId with the current snapshot.
The ID remains stable while an active plan is revised. Clearing a plan, or
starting non-empty work after the prior plan completed, starts a new plan.
Todo result displays carry the planId, so live ACP projection and the
ordinary transcript replay path preserve the same plan metadata:
- plan update
_meta.qwenTodoPlan.id: stable plan identity - plan update
_meta.qwenTranscript.planToolCallId: source Todo tool call - plan entry
_meta.qwenTodo.id: original Todo ID - plan entry
_meta.qwenTodo.blockedBy: dependency IDs when present
Clients that ignore _meta continue to receive standard ACP plan entries.
The Agent tool accepts optional todo_id. It is guidance, not a runtime gate:
top-level Agent calls should provide it when an active Todo graph exists.
Existing AgentTask.toolUseId joins the Agent tool call to live task status, so
the task API needs no additional field.
UI flow
The active Todo pill continues to render the existing compact list. Clicking it opens the existing Tasks dialog. When plan metadata is present, that dialog adds a native CSS plan-execution section above the existing task tree:
- Topologically layer nodes from
blockedBy. - Group top-level Agent tool calls by
args.todo_id. - Join live task rows through
task.toolUseId === tool.callId. - Keep nested Agent rows under the root via
parentAgentId. - Select a workflow node to inspect its full Todo content, status, dependencies, and linked Agent executions below the graph.
- Open the existing live subagent detail panel from a linked Agent execution; it remains the source for streamed progress, tool calls, and final output.
- Put missing or unknown
todo_idbindings in an Unassigned group.
No graph library is added. Plans without dependency metadata keep list-style presentation.
Plan Mode approval
Plan Mode is the opt-in execution gate for users who want to review a workflow
before work begins. When exit_plan_mode requests permission, Web Shell shows
the authoritative ACP plan body followed by the active Todo workflow in the
existing approval panel. The Todo view is supplemental because its snapshot can
differ from the submitted plan text. A dependency-aware workflow is rendered as
the same DAG used by the Tasks dialog; a workflow without dependencies keeps the
list presentation.
The existing permission lifecycle remains authoritative: approving exits Plan Mode and starts execution, while rejecting keeps the session in Plan Mode. If there is no active Todo snapshot, the approval keeps its existing text-only presentation using the plan body carried by ACP. Sessions that do not enter Plan Mode are unchanged.
Status composition
Todo status remains the business source of truth. Agent state is an execution overlay:
- Any linked execution running: Running
- Otherwise, any linked execution paused: Paused
- Todo completed: Completed
- Any dependency Todo incomplete: Blocked
- Todo in progress: In progress
- Otherwise: Ready
A failed or cancelled execution adds a Needs attention badge without changing the Todo status.
Compatibility and boundaries
- Old Todo snapshots without IDs or dependencies remain readable.
- Agent calls without
todo_idremain valid. - Empty Todo snapshots must clear active state immediately.
- Full subagent results stay out of the three-second task polling response.
- Todo nodes do not invent step output; execution detail comes from linked Agent tool calls and the existing subagent detail session.
- Strict plan-first enforcement for every session remains out of scope because a session-level existence check could accept a stale plan.