reporters/picture¶
Source: src/reporters/picture.ts
The picture of a run: the event stream folded, once, into what every reader wants to know - who is alive, under whom, doing what, at what cost.
The TUI widget, the console, usage.json, an experiment’s cell and the
tool’s own result all read this. None of them folds the stream itself: a fix
to how the picture is built reaches every one of them, and a reader that
kept its own copy of a fact would be the copy that drifts.
Nothing here draws. Formatting is tui.ts, and it takes a snapshot in;
putting a child under its parent is tree.ts.
createRunPicture¶
function
export function createRunPicture(): RunPicture { /* … */ }
Folds subagent events into a picture.
A fan-out reads top to bottom in the order the branches were launched, not in
the order they finish and not in the order their sessions came up. The last
one is why this sorts rather than trusting arrival: spawn cannot be emitted
before the session exists, since it carries the model pi resolved, and three
scouts launched together drew as scout#2, scout#1, scout#3.
RunPicture¶
type
export type RunPicture = {
/** Subscribe this to the event bus. */
reporter: EventListener;
/** The current picture. Cheap enough to call on every frame. */
snapshot(): RunSnapshot;
/** One subagent, or nothing if the picture never saw it spawn. */
of(id: string): SubagentSnapshot | undefined;
/** Called on every event, so a display knows when to redraw. */
onChange(listener: () => void): void;
};
The live picture of a run: subscribe it, then read it whenever you draw.
RunSnapshot¶
type
export type RunSnapshot = {
/** In launch order, so a fan-out reads top to bottom as it was launched. */
subagents: SubagentSnapshot[];
/** Finished, whatever the outcome. */
done: number;
/** Currently working. */
running: number;
/** Finished with `ok: false`. Counted apart: `2/3 done` hides a crash. */
failed: number;
/** Spawned so far, which is what `done` and `running` are counted against. */
total: number;
/** Sum over every subagent. `wallMs` is filled in by the caller. */
usage: Usage;
};
The whole picture: every subagent, plus what it adds up to.
snapshotFrom¶
function
export function snapshotFrom(subagents: readonly SubagentSnapshot[]): RunSnapshot { /* … */ }
What a list of subagents adds up to, in the order it was given.
The one place the counts and the total are derived: the live picture calls it on every frame, and a reader handed the subagents alone - the tool’s result, once pi has serialised it - calls it to get the same picture back.
wallMs stays 0: a list of subagents cannot know the elapsed time, and the
caller passes the real one to formatUsage/usageReport when it has one.
SubagentSnapshot¶
type
export type SubagentSnapshot = {
/** The subagent, e.g. `scout#1`. Unique for the life of the process. */
id: string;
/** The agent it came from. Several subagents may share one agent. */
agent: string;
/** The lifetime it is running with - the row says whether it will remember. */
lifetime: string;
/** What it is doing right now. `"done"` covers success and failure alike. */
status: SubagentStatus;
/** The task it was given. Empty until the first `ask`. */
task: string;
/** Every tool call so far, in order. The last one is what the collapsed row shows. */
tools: ToolCall[];
/** Assistant text, accumulated from the deltas. */
output: string;
/** Cumulative since spawn - for a persistent subagent, that is several turns. */
usage: Usage;
/**
* How far under a root it sits: `0` for a root, one more per level of
* delegation. Decided when it spawns, from the parent the picture had seen
* by then - a parent it never saw leaves the child a root, never lost.
*/
depth: number;
/** `provider/id` as pi resolved it, when it could. */
model?: string;
/** The subagent that had this one spawned. Absent on a root. */
parentId?: string;
/**
* Monotonic instant the current turn began, while one is running.
*
* `usage.busyMs` only lands when the turn ends, so without this the widget
* would read `0.0s` for the whole wait and then jump straight to the total.
*/
startedAt?: number;
/** Whether its last turn succeeded. Absent until it has finished one. */
ok?: boolean;
/** The failure, when there was one - shown on the row rather than swallowed. */
error?: string;
};
Everything known about one subagent, at one instant.
ToolCall¶
type
export type ToolCall = {
/** The tool pi ran, e.g. `read` or `bash`. */
name: string;
/** Its arguments, untouched: the expanded view formats them, we only keep them. */
args: unknown;
/** pi's id for the call, when it gave one. */
call?: string;
/** What pi said when the call came back an error: refused, or failed while it ran. */
error?: string;
};
A tool call as it happened, kept for the expanded view.