feat(tui): subagent spawn observability overlay
Adds a live + post-hoc audit surface for recursive delegate_task fan-out. None of cc/oc/oclaw tackle nested subagent trees inside an Ink overlay; this ships a view-switched dashboard that handles arbitrary depth + width. Python - delegate_tool: every subagent event now carries subagent_id, parent_id, depth, model, tool_count; subagent.complete also ships input/output/ reasoning tokens, cost, api_calls, files_read/files_written, and a tail of tool-call outputs - delegate_tool: new subagent.spawn_requested event + _active_subagents registry so the overlay can kill a branch by id and pause new spawns - tui_gateway: new RPCs delegation.status, delegation.pause, subagent.interrupt, spawn_tree.save/list/load (disk under \$HERMES_HOME/spawn-trees/<session>/<ts>.json) TUI - /agents overlay: full-width list mode (gantt strip + row picker) and Enter-to-drill full-width scrollable detail mode; inverse+amber selection, heat-coloured branch markers, wall-clock gantt with tick ruler, per-branch rollups - Detail pane: collapsible accordions (Budget, Files, Tool calls, Output, Progress, Summary); open-state persists across agents + mode switches via a shared atom - /replay [N|last|list|load <path>] for in-memory + disk history; /replay-diff <a> <b> for side-by-side tree comparison - Status-bar SpawnHud warns as depth/concurrency approaches caps; overlay auto-follows the just-finished turn onto history[1] - Theme: bump DARK dim #B8860B → #CC9B1F for readable secondary text globally; keep LIGHT untouched Tests: +29 new subagentTree unit tests; 215/215 passing.
This commit is contained in:
@@ -280,15 +280,85 @@ export interface ReloadMcpResponse {
|
||||
// ── Subagent events ──────────────────────────────────────────────────
|
||||
|
||||
export interface SubagentEventPayload {
|
||||
api_calls?: number
|
||||
cost_usd?: number
|
||||
depth?: number
|
||||
duration_seconds?: number
|
||||
files_read?: string[]
|
||||
files_written?: string[]
|
||||
goal: string
|
||||
status?: 'completed' | 'failed' | 'interrupted' | 'running'
|
||||
input_tokens?: number
|
||||
iteration?: number
|
||||
model?: string
|
||||
output_tail?: { is_error?: boolean; preview?: string; tool?: string }[]
|
||||
output_tokens?: number
|
||||
parent_id?: null | string
|
||||
reasoning_tokens?: number
|
||||
status?: 'completed' | 'failed' | 'interrupted' | 'queued' | 'running'
|
||||
subagent_id?: string
|
||||
summary?: string
|
||||
task_count?: number
|
||||
task_index: number
|
||||
text?: string
|
||||
tool_count?: number
|
||||
tool_name?: string
|
||||
tool_preview?: string
|
||||
toolsets?: string[]
|
||||
}
|
||||
|
||||
// ── Delegation control RPCs ──────────────────────────────────────────
|
||||
|
||||
export interface DelegationStatusResponse {
|
||||
active?: {
|
||||
depth?: number
|
||||
goal?: string
|
||||
model?: null | string
|
||||
parent_id?: null | string
|
||||
started_at?: number
|
||||
status?: string
|
||||
subagent_id?: string
|
||||
tool_count?: number
|
||||
}[]
|
||||
max_concurrent_children?: number
|
||||
max_spawn_depth?: number
|
||||
paused?: boolean
|
||||
}
|
||||
|
||||
export interface DelegationPauseResponse {
|
||||
paused?: boolean
|
||||
}
|
||||
|
||||
export interface SubagentInterruptResponse {
|
||||
found?: boolean
|
||||
subagent_id?: string
|
||||
}
|
||||
|
||||
// ── Spawn-tree snapshots ─────────────────────────────────────────────
|
||||
|
||||
export interface SpawnTreeListEntry {
|
||||
count: number
|
||||
finished_at?: number
|
||||
label?: string
|
||||
path: string
|
||||
session_id?: string
|
||||
started_at?: number | null
|
||||
}
|
||||
|
||||
export interface SpawnTreeListResponse {
|
||||
entries?: SpawnTreeListEntry[]
|
||||
}
|
||||
|
||||
export interface SpawnTreeLoadResponse {
|
||||
finished_at?: number
|
||||
label?: string
|
||||
session_id?: string
|
||||
started_at?: null | number
|
||||
subagents?: unknown[]
|
||||
}
|
||||
|
||||
export interface SpawnTreeSaveResponse {
|
||||
path?: string
|
||||
session_id?: string
|
||||
}
|
||||
|
||||
export type GatewayEvent =
|
||||
@@ -320,6 +390,7 @@ export type GatewayEvent =
|
||||
| { payload: { env_var: string; prompt: string; request_id: string }; session_id?: string; type: 'secret.request' }
|
||||
| { payload: { task_id: string; text: string }; session_id?: string; type: 'background.complete' }
|
||||
| { payload: { text: string }; session_id?: string; type: 'btw.complete' }
|
||||
| { payload: SubagentEventPayload; session_id?: string; type: 'subagent.spawn_requested' }
|
||||
| { payload: SubagentEventPayload; session_id?: string; type: 'subagent.start' }
|
||||
| { payload: SubagentEventPayload; session_id?: string; type: 'subagent.thinking' }
|
||||
| { payload: SubagentEventPayload; session_id?: string; type: 'subagent.tool' }
|
||||
|
||||
Reference in New Issue
Block a user