pi-subagents 0.58.0 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/docs/agents.md +5 -3
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +1 -1
- package/docs/models.md +24 -1
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +93 -5
- package/docs/workflows.md +94 -3
- package/package.json +3 -1
- package/prompts/review-loop.md +2 -2
- package/skills/council-mode/SKILL.md +48 -243
- package/skills/council-mode/references/pass-contracts.md +150 -0
- package/skills/pi-subagents/SKILL.md +87 -37
- package/skills/pi-subagents/references/constraints-and-recipes.md +29 -233
- package/skills/pi-subagents/references/execution-controls.md +52 -7
- package/skills/pi-subagents/references/management-authoring-rpc.md +3 -4
- package/skills/pi-subagents/references/multi-lane-orchestration.md +13 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +54 -26
- package/skills/pi-subagents/references/review-and-validation.md +73 -0
- package/src/agents/agent-management.ts +159 -42
- package/src/agents/agent-serializer.ts +4 -2
- package/src/agents/agents.ts +67 -26
- package/src/agents/runtime-agent-registry.ts +9 -16
- package/src/api/background-work.ts +5 -1
- package/src/api/delegation.ts +0 -7
- package/src/api/preflight.ts +6 -9
- package/src/api/shared-types.ts +2 -0
- package/src/extension/fanout-child.ts +5 -3
- package/src/extension/index.ts +51 -23
- package/src/extension/public-execution.ts +16 -2
- package/src/extension/schemas.ts +36 -10
- package/src/extension/tool-description.ts +24 -5
- package/src/intercom/result-intercom.ts +2 -0
- package/src/profiles/profiles.ts +5 -6
- package/src/runs/background/active-async-capacity.ts +2 -2
- package/src/runs/background/async-execution.ts +52 -37
- package/src/runs/background/async-job-tracker.ts +17 -12
- package/src/runs/background/async-resume.ts +23 -25
- package/src/runs/background/async-status-snapshot.ts +23 -261
- package/src/runs/background/async-status.ts +110 -8
- package/src/runs/background/chain-append.ts +6 -3
- package/src/runs/background/chain-root-attachment.ts +60 -8
- package/src/runs/background/control-channel.ts +3 -2
- package/src/runs/background/fleet-view.ts +21 -11
- package/src/runs/background/notify.ts +158 -6
- package/src/runs/background/result-files.ts +2 -1
- package/src/runs/background/result-watcher.ts +2 -0
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/retained-children.ts +1 -1
- package/src/runs/background/run-status.ts +30 -9
- package/src/runs/background/scheduled-runs.ts +86 -7
- package/src/runs/background/stale-run-reconciler.ts +10 -4
- package/src/runs/background/steering.ts +4 -14
- package/src/runs/background/subagent-runner.ts +351 -358
- package/src/runs/background/subagent-wait.ts +68 -12
- package/src/runs/background/terminal-run-index.ts +1 -1
- package/src/runs/background/wait-completions.ts +25 -1
- package/src/runs/background/wait-config.ts +23 -9
- package/src/runs/background/wait-tool.ts +9 -2
- package/src/runs/foreground/async-steering-action.ts +2 -2
- package/src/runs/foreground/execution.ts +125 -122
- package/src/runs/foreground/foreground-control.ts +3 -0
- package/src/runs/foreground/foreground-history.ts +1 -0
- package/src/runs/foreground/subagent-executor.ts +576 -240
- package/src/runs/foreground/workflow-detach-reconcile.ts +99 -200
- package/src/runs/shared/abort-recovery.ts +119 -0
- package/src/runs/shared/async-status-projection.ts +597 -0
- package/src/runs/shared/background-process-options.ts +9 -0
- package/src/runs/shared/child-identity.ts +19 -4
- package/src/runs/shared/child-launch-plan.ts +151 -0
- package/src/runs/shared/completion-evidence.ts +89 -0
- package/src/runs/shared/completion-guard.ts +1 -1
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/host-step-status.ts +230 -0
- package/src/runs/shared/lane-metadata.ts +105 -0
- package/src/runs/shared/mcp-config-sources.ts +42 -6
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +93 -143
- package/src/runs/shared/mcp-direct-tool-grant.ts +194 -0
- package/src/runs/shared/model-fallback.ts +9 -2
- package/src/runs/shared/mutation-evidence.ts +52 -3
- package/src/runs/shared/nested-events.ts +6 -2
- package/src/runs/shared/nested-render.ts +7 -3
- package/src/runs/shared/parallel-handoff.ts +419 -7
- package/src/runs/shared/parallel-utils.ts +7 -0
- package/src/runs/shared/pi-args.ts +67 -3
- package/src/runs/shared/single-output.ts +72 -22
- package/src/runs/shared/subagent-prompt-runtime.ts +33 -6
- package/src/runs/shared/workflow-graph.ts +15 -0
- package/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/src/runs/shared/worktree.ts +18 -0
- package/src/shared/child-session-name.ts +46 -0
- package/src/shared/extension-context.ts +24 -0
- package/src/shared/formatters.ts +5 -2
- package/src/shared/launch-contract.ts +1 -1
- package/src/shared/settings.ts +9 -103
- package/src/shared/types.ts +232 -30
- package/src/shared/utils.ts +35 -55
- package/src/slash/delegation-adapters.ts +1 -8
- package/src/slash/delegation-request.ts +0 -4
- package/src/slash/slash-bridge.ts +1 -2
- package/src/slash/slash-commands.ts +369 -90
- package/src/slash/slash-live-state.ts +22 -11
- package/src/tui/fleet-status.ts +134 -75
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render-helpers.ts +31 -0
- package/src/tui/render.ts +895 -121
- package/src/watchdog/change-signature.ts +40 -1
- package/src/watchdog/turn-delta.ts +1 -1
- package/src/workflows/chat-progress.ts +6 -3
- package/src/workflows/host-command.ts +235 -0
- package/src/workflows/scripted-workflow.ts +503 -38
- package/src/workflows/workflow-child-summary.ts +9 -5
- package/src/workflows/workflow-preflight.ts +270 -0
- package/src/workflows/workflow-receipt.ts +43 -4
- package/src/workflows/workflow-settlement.ts +246 -0
- package/src/runs/shared/turn-budget.ts +0 -98
|
@@ -72,6 +72,14 @@ function uniqueStrings(values: Array<string | undefined>): string[] {
|
|
|
72
72
|
return result;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
function fleetChildDisplayName(child: { agent?: string; sessionName?: string }, fallback = "subagent"): string {
|
|
76
|
+
return child.sessionName?.trim() || child.agent || fallback;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function fleetStepDisplayName(step: Pick<AsyncJobStep, "agent" | "sessionName" | "label">): string {
|
|
80
|
+
return step.sessionName?.trim() || (step.label ? `${step.label} (${step.agent})` : step.agent);
|
|
81
|
+
}
|
|
82
|
+
|
|
75
83
|
function resolveMaybeRelative(asyncDir: string, filePath: string | undefined): string | undefined {
|
|
76
84
|
if (!filePath) return undefined;
|
|
77
85
|
return path.resolve(asyncDir, filePath);
|
|
@@ -283,7 +291,8 @@ function formatActivityFacts(input: {
|
|
|
283
291
|
}
|
|
284
292
|
|
|
285
293
|
function foregroundModeName(control: ForegroundControl): string {
|
|
286
|
-
|
|
294
|
+
const currentDisplayName = control.sessionName?.trim() || control.currentAgent;
|
|
295
|
+
if (control.mode === "single" && currentDisplayName) return currentDisplayName;
|
|
287
296
|
return control.mode;
|
|
288
297
|
}
|
|
289
298
|
|
|
@@ -302,7 +311,8 @@ function formatForegroundFleetLines(controls: ForegroundControl[]): string[] {
|
|
|
302
311
|
toolCount: control.toolCount,
|
|
303
312
|
...(control.tokens !== undefined ? { tokens: { total: control.tokens } } : {}),
|
|
304
313
|
});
|
|
305
|
-
const
|
|
314
|
+
const currentDisplayName = control.sessionName?.trim() || control.currentAgent;
|
|
315
|
+
const current = currentDisplayName ? ` | ${currentDisplayName}${control.currentIndex !== undefined ? ` #${control.currentIndex}` : ""}` : "";
|
|
306
316
|
lines.push(`- ${control.runId} | running | ${foregroundModeName(control)}${current}${activity ? ` | ${activity}` : ""}`);
|
|
307
317
|
lines.push(` status: subagent({ action: "status", id: "${control.runId}" })`);
|
|
308
318
|
lines.push(" transcript: live in the expanded foreground result; persisted session transcript appears after completion when sessions are enabled.");
|
|
@@ -317,7 +327,7 @@ function formatDetachedForegroundFleetLines(runs: ForegroundRun[]): string[] {
|
|
|
317
327
|
const ordered = [...runs].sort((left, right) => right.updatedAt - left.updatedAt);
|
|
318
328
|
for (const run of ordered) {
|
|
319
329
|
const detachedChildren = run.children.filter((child) => child.status === "detached");
|
|
320
|
-
const childSummary = detachedChildren.map((child) => `${child
|
|
330
|
+
const childSummary = detachedChildren.map((child) => `${fleetChildDisplayName(child)} #${child.index}`).join(", ");
|
|
321
331
|
lines.push(`- ${run.runId} | detached | ${run.mode}${childSummary ? ` | ${childSummary}` : ""}`);
|
|
322
332
|
lines.push(` status: subagent({ action: "status", id: "${run.runId}" })`);
|
|
323
333
|
lines.push(` recovery: reply to the supervisor request first, then wait with subagent_wait({ id: "${run.runId}" }); do not resume or launch a replacement while any child remains detached.`);
|
|
@@ -338,7 +348,7 @@ function formatAsyncFleetLines(runs: AsyncRunSummary[]): string[] {
|
|
|
338
348
|
lines.push(` status: subagent({ action: "status", id: "${run.id}" })`);
|
|
339
349
|
lines.push(` transcript: subagent({ action: "status", id: "${run.id}", view: "transcript" })`);
|
|
340
350
|
for (const step of run.steps) {
|
|
341
|
-
const display =
|
|
351
|
+
const display = fleetStepDisplayName(step);
|
|
342
352
|
const stepContext = contextModeLabel(step.context);
|
|
343
353
|
const phase = step.phase ? `[${step.phase}] ` : "";
|
|
344
354
|
const stepActivity = formatActivityFacts(step);
|
|
@@ -435,7 +445,7 @@ function selectTranscriptStep(status: AsyncStatus, options: TranscriptOptions):
|
|
|
435
445
|
}
|
|
436
446
|
const step = selectedIndex !== undefined ? steps[selectedIndex] : undefined;
|
|
437
447
|
const hint = options.index === undefined && steps.length > 1
|
|
438
|
-
? `Tip: pass index to inspect a specific child transcript (${steps.map((candidate, index) => `${index}=${candidate
|
|
448
|
+
? `Tip: pass index to inspect a specific child transcript (${steps.map((candidate, index) => `${index}=${fleetChildDisplayName(candidate)}`).join(", ")}).`
|
|
439
449
|
: undefined;
|
|
440
450
|
return { index: selectedIndex, step, hint };
|
|
441
451
|
}
|
|
@@ -445,7 +455,7 @@ function stepStateLine(mode: SubagentRunMode, index: number | undefined, step: A
|
|
|
445
455
|
const modelThinking = formatModelThinking(step.model, step.thinking);
|
|
446
456
|
const context = contextModeLabel(step.context);
|
|
447
457
|
const parts = [
|
|
448
|
-
`${mode === "parallel" ? "Agent" : "Step"}: ${index} (${step
|
|
458
|
+
`${mode === "parallel" ? "Agent" : "Step"}: ${index} (${fleetChildDisplayName(step)})${context ? ` ${context}` : ""}`,
|
|
449
459
|
step.status,
|
|
450
460
|
formatActivityFacts(step),
|
|
451
461
|
modelThinking,
|
|
@@ -553,7 +563,7 @@ export function formatNestedRunTranscript(run: NestedRunSummary, options: Transc
|
|
|
553
563
|
`Nested run: ${run.id}`,
|
|
554
564
|
`State: ${run.state}`,
|
|
555
565
|
run.mode ? `Mode: ${run.mode}` : undefined,
|
|
556
|
-
run.agent ? `Agent: ${run.agent}` : run.agents?.length ? `Agents: ${run.agents.join(", ")}` : undefined,
|
|
566
|
+
run.sessionName?.trim() ? `Agent: ${run.sessionName.trim()}` : run.agent ? `Agent: ${run.agent}` : run.agents?.length ? `Agents: ${run.agents.join(", ")}` : undefined,
|
|
557
567
|
].filter((line): line is string => Boolean(line));
|
|
558
568
|
appendKnownArtifacts(lines, { outputPaths: [], sessionFile: run.sessionFile });
|
|
559
569
|
if (!run.sessionFile) {
|
|
@@ -579,14 +589,14 @@ export function formatAsyncResultTranscript(data: {
|
|
|
579
589
|
sessionFile?: string;
|
|
580
590
|
agent?: string;
|
|
581
591
|
exitCode?: number | null;
|
|
582
|
-
results?: Array<{ agent?: string; output?: string; summary?: string; sessionFile?: string; state?: string; success?: boolean; exitCode?: number | null }>;
|
|
592
|
+
results?: Array<{ agent?: string; sessionName?: string; output?: string; summary?: string; sessionFile?: string; state?: string; success?: boolean; exitCode?: number | null }>;
|
|
583
593
|
}, resultPath: string, options: TranscriptOptions = {}): string {
|
|
584
594
|
const lineLimit = transcriptLineLimit(options.lines);
|
|
585
595
|
const runId = data.runId ?? data.id ?? path.basename(resultPath, ".json");
|
|
586
596
|
const children = Array.isArray(data.results)
|
|
587
597
|
? data.results
|
|
588
598
|
: data.agent
|
|
589
|
-
? [{ agent: data.agent, output: data.output, summary: data.summary, sessionFile: data.sessionFile, state: data.state, success: data.success, exitCode: data.exitCode }]
|
|
599
|
+
? [{ agent: data.agent, sessionName: undefined, output: data.output, summary: data.summary, sessionFile: data.sessionFile, state: data.state, success: data.success, exitCode: data.exitCode }]
|
|
590
600
|
: [];
|
|
591
601
|
let index = options.index;
|
|
592
602
|
if (index !== undefined && !Number.isInteger(index)) throw new Error("Transcript index must be an integer.");
|
|
@@ -601,8 +611,8 @@ export function formatAsyncResultTranscript(data: {
|
|
|
601
611
|
const lines = [
|
|
602
612
|
`Run: ${runId}`,
|
|
603
613
|
`State: ${data.state ?? (data.success ? "complete" : "failed")}`,
|
|
604
|
-
index !== undefined && child ? `Child: ${index} (${child
|
|
605
|
-
index === undefined && children.length > 1 ? `Tip: pass index to inspect a specific child transcript (${children.map((candidate, childIndex) => `${childIndex}=${candidate
|
|
614
|
+
index !== undefined && child ? `Child: ${index} (${fleetChildDisplayName(child)})` : undefined,
|
|
615
|
+
index === undefined && children.length > 1 ? `Tip: pass index to inspect a specific child transcript (${children.map((candidate, childIndex) => `${childIndex}=${fleetChildDisplayName(candidate)}`).join(", ")}).` : undefined,
|
|
606
616
|
].filter((line): line is string => Boolean(line));
|
|
607
617
|
appendKnownArtifacts(lines, { outputPaths: [], sessionFile, resultPath });
|
|
608
618
|
appendTranscriptBody(lines, "Result transcript tail", transcriptLines.filter((line) => line.trim()), output.split(/\r?\n/).length > lineLimit);
|
|
@@ -15,9 +15,22 @@ import {
|
|
|
15
15
|
resolveCompletionBatchConfig,
|
|
16
16
|
} from "./completion-batcher.ts";
|
|
17
17
|
import { SUBAGENT_ASYNC_COMPLETE_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, type ParallelHandoffReference, type ScheduleOrigin, type SubagentState } from "../../shared/types.ts";
|
|
18
|
+
import { safeTerminalText } from "../../shared/display-text.ts";
|
|
19
|
+
import { resolveSubagentResultStatus } from "../../intercom/result-intercom.ts";
|
|
18
20
|
import { isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
19
21
|
import type { ResultDeliveryOwnership } from "./result-delivery-ownership.ts";
|
|
20
22
|
|
|
23
|
+
export interface SubagentNotifyChildOutput {
|
|
24
|
+
workflowKey?: string;
|
|
25
|
+
runId?: string;
|
|
26
|
+
agent?: string;
|
|
27
|
+
status: string;
|
|
28
|
+
savedOutputPath?: string;
|
|
29
|
+
preview: string;
|
|
30
|
+
previewTruncated?: boolean;
|
|
31
|
+
previewUnavailableReason?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
export interface SubagentNotifyDetails {
|
|
22
35
|
agent: string;
|
|
23
36
|
status: "completed" | "failed" | "paused" | "stopped";
|
|
@@ -27,6 +40,7 @@ export interface SubagentNotifyDetails {
|
|
|
27
40
|
durationMs?: number;
|
|
28
41
|
workflowRunId?: string;
|
|
29
42
|
childRuns?: Array<{ runId: string; workflowKey?: string; agent?: string; status?: string }>;
|
|
43
|
+
childOutputs?: SubagentNotifyChildOutput[];
|
|
30
44
|
reconciledFromDetachedChild?: string;
|
|
31
45
|
sessionLabel?: string;
|
|
32
46
|
sessionValue?: string;
|
|
@@ -57,7 +71,14 @@ export interface CompletionNotification {
|
|
|
57
71
|
workflowKey?: string;
|
|
58
72
|
agent?: string;
|
|
59
73
|
status?: string;
|
|
74
|
+
state?: string;
|
|
60
75
|
success?: boolean;
|
|
76
|
+
output?: string;
|
|
77
|
+
structuredOutput?: unknown;
|
|
78
|
+
outputState?: "present" | "absent" | "unknown";
|
|
79
|
+
outputReference?: string | { path?: string };
|
|
80
|
+
artifactPaths?: { outputPath?: string };
|
|
81
|
+
detached?: boolean;
|
|
61
82
|
exitCode?: number | null;
|
|
62
83
|
processSignal?: string | null;
|
|
63
84
|
interrupted?: boolean;
|
|
@@ -100,6 +121,115 @@ export interface CompletionNotifier {
|
|
|
100
121
|
dispose(): void;
|
|
101
122
|
}
|
|
102
123
|
|
|
124
|
+
const CHILD_OUTPUT_PREVIEW_MAX_BYTES = 4 * 1024;
|
|
125
|
+
const CHILD_OUTPUT_PREVIEW_COUNT = 8;
|
|
126
|
+
const PREVIEW_TRUNCATION_MARKER = "...[preview truncated]";
|
|
127
|
+
type CompletionChild = NonNullable<CompletionNotification["results"]>[number];
|
|
128
|
+
|
|
129
|
+
function truncateUtf8Head(value: string, maxBytes: number): { text: string; truncated: boolean } {
|
|
130
|
+
const bytes = Buffer.from(value, "utf8");
|
|
131
|
+
if (bytes.length <= maxBytes) return { text: value, truncated: false };
|
|
132
|
+
const markerBytes = Buffer.byteLength(PREVIEW_TRUNCATION_MARKER, "utf8");
|
|
133
|
+
const contentBytes = Math.max(0, maxBytes - markerBytes);
|
|
134
|
+
let end = contentBytes;
|
|
135
|
+
while (end > 0 && (bytes[end]! & 0xc0) === 0x80) end -= 1;
|
|
136
|
+
return {
|
|
137
|
+
text: `${bytes.subarray(0, end).toString("utf8")}${PREVIEW_TRUNCATION_MARKER}`,
|
|
138
|
+
truncated: true,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function boundedSafeText(value: string, maxBytes = 1_024): string {
|
|
143
|
+
return truncateUtf8Head(safeTerminalText(value).replace(/\n/g, "\\n"), maxBytes).text;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function outputPathFromReference(value: CompletionChild["outputReference"]): string | undefined {
|
|
147
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
148
|
+
if (value && typeof value === "object" && typeof value.path === "string" && value.path.trim()) return value.path.trim();
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function childSavedOutputPath(child: CompletionChild): string | undefined {
|
|
153
|
+
return outputPathFromReference(child.outputReference);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function childStatus(child: CompletionChild, workflowState?: string): string {
|
|
157
|
+
const knownStatus = child.status === "complete"
|
|
158
|
+
? "completed"
|
|
159
|
+
: child.status === "completed" || child.status === "failed" || child.status === "paused" || child.status === "stopped" || child.status === "detached"
|
|
160
|
+
? child.status
|
|
161
|
+
: undefined;
|
|
162
|
+
if (knownStatus) return knownStatus;
|
|
163
|
+
return resolveSubagentResultStatus({
|
|
164
|
+
success: child.success,
|
|
165
|
+
state: child.state ?? (child.success === undefined ? workflowState : undefined),
|
|
166
|
+
interrupted: child.interrupted,
|
|
167
|
+
detached: child.detached,
|
|
168
|
+
processSignal: child.processSignal,
|
|
169
|
+
timedOut: child.timedOut,
|
|
170
|
+
stopped: child.stopped,
|
|
171
|
+
turnBudgetExceeded: child.turnBudgetExceeded,
|
|
172
|
+
exitCode: typeof child.exitCode === "number" ? child.exitCode : undefined,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function structuredOutputText(value: unknown): string | undefined {
|
|
177
|
+
if (value === undefined) return undefined;
|
|
178
|
+
try {
|
|
179
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
180
|
+
return typeof serialized === "string" ? serialized : undefined;
|
|
181
|
+
} catch {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function childInlinePreview(child: CompletionChild): { preview?: string; truncated?: boolean; unavailableReason?: string } {
|
|
187
|
+
const output = typeof child.output === "string" ? child.output : "";
|
|
188
|
+
const outputReference = childSavedOutputPath(child);
|
|
189
|
+
const referenceOnly = Boolean(outputReference && output.trim().startsWith("Output saved to:"));
|
|
190
|
+
const raw = child.outputState === "absent" || referenceOnly ? structuredOutputText(child.structuredOutput) : output || structuredOutputText(child.structuredOutput);
|
|
191
|
+
if (!raw?.trim()) {
|
|
192
|
+
return { unavailableReason: referenceOnly ? "saved output is file-only" : "no safe inline output" };
|
|
193
|
+
}
|
|
194
|
+
const safe = safeTerminalText(raw);
|
|
195
|
+
if (!safe.trim()) return { unavailableReason: "no safe inline output" };
|
|
196
|
+
const bounded = truncateUtf8Head(safe, CHILD_OUTPUT_PREVIEW_MAX_BYTES);
|
|
197
|
+
return { preview: bounded.text, ...(bounded.truncated ? { truncated: true } : {}) };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function formatChildOutputBlock(children: SubagentNotifyChildOutput[] | undefined): string | undefined {
|
|
201
|
+
if (!children?.length) return undefined;
|
|
202
|
+
const lines = ["Child outputs:"];
|
|
203
|
+
for (let index = 0; index < children.length; index++) {
|
|
204
|
+
const child = children[index]!;
|
|
205
|
+
const key = child.workflowKey ? boundedSafeText(child.workflowKey) : "unavailable";
|
|
206
|
+
const runId = child.runId ? boundedSafeText(child.runId) : "unavailable";
|
|
207
|
+
const status = boundedSafeText(child.status) || "unavailable";
|
|
208
|
+
lines.push(`- key=${key} run=${runId} status=${status}`);
|
|
209
|
+
lines.push(` Saved output: ${child.savedOutputPath ? boundedSafeText(child.savedOutputPath) : "unavailable"}`);
|
|
210
|
+
if (index >= CHILD_OUTPUT_PREVIEW_COUNT) {
|
|
211
|
+
lines.push(" Preview: unavailable (notice preview budget exceeded)");
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (!child.preview) {
|
|
215
|
+
lines.push(` Preview: unavailable (${child.previewUnavailableReason ?? "no safe inline output"})`);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
lines.push(" Preview:");
|
|
219
|
+
for (const line of child.preview.split("\n")) lines.push(` | ${line}`);
|
|
220
|
+
}
|
|
221
|
+
if (children.length > CHILD_OUTPUT_PREVIEW_COUNT) {
|
|
222
|
+
lines.push(`- ${children.length - CHILD_OUTPUT_PREVIEW_COUNT} additional child preview(s) omitted by notice budget; child run metadata is retained below.`);
|
|
223
|
+
}
|
|
224
|
+
return lines.join("\n");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function formatResultPreview(details: SubagentNotifyDetails): string {
|
|
228
|
+
const summary = details.resultPreview.trim() ? details.resultPreview : "(no output)";
|
|
229
|
+
const childOutputs = formatChildOutputBlock(details.childOutputs);
|
|
230
|
+
return childOutputs ? `${summary}\n\n${childOutputs}` : summary;
|
|
231
|
+
}
|
|
232
|
+
|
|
103
233
|
function formatSessionLine(details: SubagentNotifyDetails): string | undefined {
|
|
104
234
|
if (!details.sessionValue) return undefined;
|
|
105
235
|
return details.sessionLabel ? `${details.sessionLabel}: ${details.sessionValue}` : details.sessionValue;
|
|
@@ -131,7 +261,7 @@ export function formatSingleCompletion(details: SubagentNotifyDetails): string {
|
|
|
131
261
|
"",
|
|
132
262
|
scheduleLine,
|
|
133
263
|
scheduleLine ? "" : undefined,
|
|
134
|
-
|
|
264
|
+
formatResultPreview(details),
|
|
135
265
|
details.handoffPath ? "" : undefined,
|
|
136
266
|
details.handoffPath ? `Parallel handoff: ${details.handoffPath}` : undefined,
|
|
137
267
|
correlationLines.length && !details.handoffPath ? "" : undefined,
|
|
@@ -218,7 +348,7 @@ export function formatGroupedCompletion(details: SubagentNotifyDetails[]): strin
|
|
|
218
348
|
if (!detail) continue;
|
|
219
349
|
const sessionLine = formatSessionLine(detail);
|
|
220
350
|
blocks.push(`${index + 1}. ${detail.agent}${detail.taskInfo ?? ""}${detail.scheduleOrigin ? ` — scheduled run from ${detail.scheduleOrigin.name ?? detail.scheduleOrigin.id} (schedule ${detail.scheduleOrigin.id})` : ""}`);
|
|
221
|
-
blocks.push(
|
|
351
|
+
blocks.push(formatResultPreview(detail));
|
|
222
352
|
if (detail.handoffPath) blocks.push(`Parallel handoff: ${detail.handoffPath}`);
|
|
223
353
|
blocks.push(...formatCorrelationLines(detail));
|
|
224
354
|
if (sessionLine) blocks.push(sessionLine);
|
|
@@ -275,6 +405,7 @@ export function buildCompletionDetails(result: CompletionNotification): Subagent
|
|
|
275
405
|
const paused = !stopped && !result.success && (
|
|
276
406
|
result.exitCode === 0
|
|
277
407
|
|| result.state === "paused"
|
|
408
|
+
|| result.interrupted === true
|
|
278
409
|
|| summary.startsWith("Paused after interrupt.")
|
|
279
410
|
);
|
|
280
411
|
const status = stopped ? "stopped" : paused ? "paused" : result.success ? "completed" : "failed";
|
|
@@ -290,14 +421,34 @@ export function buildCompletionDetails(result: CompletionNotification): Subagent
|
|
|
290
421
|
const rawRunId = typeof result.runId === "string" ? result.runId : typeof result.id === "string" ? result.id : undefined;
|
|
291
422
|
const workflowRunId = (result.mode === "workflow" || agent === "workflow") && rawRunId ? rawRunId : undefined;
|
|
292
423
|
const childRuns = result.results?.flatMap((child) => {
|
|
293
|
-
|
|
424
|
+
const runId = typeof child.runId === "string" && child.runId.trim() ? child.runId.trim() : undefined;
|
|
425
|
+
const workflowKey = typeof child.workflowKey === "string" && child.workflowKey.trim() ? child.workflowKey.trim() : undefined;
|
|
426
|
+
if (!runId && (!workflowRunId || !workflowKey)) return [];
|
|
294
427
|
return [{
|
|
295
|
-
runId:
|
|
296
|
-
...(
|
|
428
|
+
runId: runId ?? "unavailable",
|
|
429
|
+
...(workflowKey ? { workflowKey } : {}),
|
|
297
430
|
...(typeof child.agent === "string" ? { agent: child.agent } : {}),
|
|
298
|
-
|
|
431
|
+
status: childStatus(child, workflowRunId ? result.state : undefined),
|
|
299
432
|
}];
|
|
300
433
|
}) ?? [];
|
|
434
|
+
const childOutputs = workflowRunId && result.results?.length
|
|
435
|
+
? result.results.map((child) => {
|
|
436
|
+
const inline = childInlinePreview(child);
|
|
437
|
+
const workflowKey = typeof child.workflowKey === "string" && child.workflowKey.trim() ? child.workflowKey.trim() : undefined;
|
|
438
|
+
const runId = typeof child.runId === "string" && child.runId.trim() ? child.runId.trim() : undefined;
|
|
439
|
+
const savedOutputPath = childSavedOutputPath(child);
|
|
440
|
+
return {
|
|
441
|
+
...(workflowKey ? { workflowKey } : {}),
|
|
442
|
+
...(runId ? { runId } : {}),
|
|
443
|
+
...(typeof child.agent === "string" ? { agent: child.agent } : {}),
|
|
444
|
+
status: childStatus(child, result.state),
|
|
445
|
+
...(savedOutputPath ? { savedOutputPath } : {}),
|
|
446
|
+
...(inline.preview ? { preview: inline.preview } : { preview: "" }),
|
|
447
|
+
...(inline.truncated ? { previewTruncated: true } : {}),
|
|
448
|
+
...(inline.unavailableReason ? { previewUnavailableReason: inline.unavailableReason } : {}),
|
|
449
|
+
};
|
|
450
|
+
})
|
|
451
|
+
: undefined;
|
|
301
452
|
const reconciledFromDetachedChild = typeof result.reconciledFromDetachedChild === "string" ? result.reconciledFromDetachedChild : undefined;
|
|
302
453
|
const session =
|
|
303
454
|
result.shareUrl
|
|
@@ -322,6 +473,7 @@ export function buildCompletionDetails(result: CompletionNotification): Subagent
|
|
|
322
473
|
...(handoffPath ? { handoffPath } : {}),
|
|
323
474
|
...(workflowRunId ? { workflowRunId } : {}),
|
|
324
475
|
...(childRuns.length ? { childRuns } : {}),
|
|
476
|
+
...(childOutputs?.length ? { childOutputs } : {}),
|
|
325
477
|
...(reconciledFromDetachedChild ? { reconciledFromDetachedChild } : {}),
|
|
326
478
|
...(session ? { sessionLabel: session.label, sessionValue: session.value } : {}),
|
|
327
479
|
};
|
|
@@ -343,7 +343,8 @@ export function resultPayloadPathForMissionObserverRun(resultsDir: string, runId
|
|
|
343
343
|
if (!entry || entry.runId !== runId) return undefined;
|
|
344
344
|
return resultPayloadLocationFromIndex(resultsDir, entry)?.path;
|
|
345
345
|
} catch (error) {
|
|
346
|
-
|
|
346
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
347
|
+
if (code !== "ENOENT" && code !== "ENOTDIR" && !isUnaddressableResultCandidate(error)) console.error(`Ignoring invalid async result observer index for '${runId}':`, error);
|
|
347
348
|
return undefined;
|
|
348
349
|
}
|
|
349
350
|
}
|
|
@@ -67,6 +67,7 @@ type ResultWatcherDeps = {
|
|
|
67
67
|
|
|
68
68
|
type ResultFileChild = {
|
|
69
69
|
agent?: string;
|
|
70
|
+
sessionName?: string;
|
|
70
71
|
output?: string;
|
|
71
72
|
structuredOutput?: unknown;
|
|
72
73
|
outputState?: SubagentOutputState;
|
|
@@ -482,6 +483,7 @@ export function createResultWatcher(
|
|
|
482
483
|
: undefined;
|
|
483
484
|
return {
|
|
484
485
|
agent: result.agent ?? data.agent ?? `step-${index + 1}`,
|
|
486
|
+
...(result.sessionName ? { sessionName: result.sessionName } : {}),
|
|
485
487
|
status: resolveSubagentResultStatus({
|
|
486
488
|
success: result.success,
|
|
487
489
|
state: childState,
|
|
@@ -39,7 +39,7 @@ export function formatResumeFirstFailedRunDetail(run: AsyncRunSummary): string |
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export function formatResumeFirstFailedRunsNote(runs: AsyncRunSummary[]): string {
|
|
42
|
-
const failedRuns = runs.filter((run) => run.state === "failed");
|
|
42
|
+
const failedRuns = runs.filter((run) => run.state === "failed" || run.state === "partial");
|
|
43
43
|
const detachGuidance = failedRuns
|
|
44
44
|
.map(formatIntercomDetachGuidance)
|
|
45
45
|
.filter((guidance): guidance is string => Boolean(guidance));
|
|
@@ -27,7 +27,7 @@ export interface RetainedChild {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function isRetainedChildState(state: AsyncRunSummary["state"]): state is RetainedChildState {
|
|
30
|
-
return state === "complete" || state === "failed" || state === "paused" || state === "stopped";
|
|
30
|
+
return state === "complete" || state === "failed" || state === "partial" || state === "paused" || state === "stopped";
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function isTerminalStepStatus(status: AsyncRunSummary["steps"][number]["status"]): boolean {
|
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
4
4
|
import { safeTerminalText } from "../../shared/display-text.ts";
|
|
5
|
-
import { formatAsyncRunList, formatAsyncRunOutputPath, formatAsyncRunProgressLabel, listAsyncRuns } from "./async-status.ts";
|
|
5
|
+
import { formatAsyncRunList, formatAsyncRunOutputPath, formatAsyncRunProgressLabel, formatWorkflowStageLine, listAsyncRuns } from "./async-status.ts";
|
|
6
6
|
import { formatAsyncResultTranscript, formatAsyncRunTranscript, formatNestedRunTranscript, inspectSubagentFleet } from "./fleet-view.ts";
|
|
7
7
|
import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
|
|
8
8
|
import { formatModelThinking } from "../../shared/formatters.ts";
|
|
@@ -23,8 +23,11 @@ import { attachRootChildrenToSteps, findNestedRouteForRootId, projectNestedRegis
|
|
|
23
23
|
import { readMissionBinding } from "../../missions/lifecycle.ts";
|
|
24
24
|
import { formatWorkflowJsonPreview } from "../../workflows/scripted-workflow.ts";
|
|
25
25
|
import { parseWorkflowChildSummary } from "../../workflows/workflow-child-summary.ts";
|
|
26
|
+
import { formatWorkflowPreflightPlanSummary, formatWorkflowPreflightWarningSummary } from "../../workflows/workflow-preflight.ts";
|
|
26
27
|
import { formatRunFanoutBudget, getRunFanoutBudgetSnapshot, readRunFanoutBudgetDescriptor } from "../shared/run-fanout-budget.ts";
|
|
28
|
+
import { workflowGraphStageNodes } from "../shared/workflow-graph.ts";
|
|
27
29
|
import { getExternalJobProvider } from "../../api/external-job-provider.ts";
|
|
30
|
+
import { formatTimeoutRecoveryLines } from "../shared/mutation-evidence.ts";
|
|
28
31
|
|
|
29
32
|
interface RunStatusParams {
|
|
30
33
|
action?: string;
|
|
@@ -64,13 +67,14 @@ function formatCapacityOwner(inspect: ActiveAsyncCapacityInspection): string[] {
|
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
function formatWorkflowDebug(status: AsyncStatus): string[] {
|
|
67
|
-
if (status.mode !== "workflow" && !status.parentWorkflowRunId && !status.workflowKey) return [];
|
|
70
|
+
if (status.mode !== "workflow" && !status.parentWorkflowRunId && !status.workflowKey && !status.lane) return [];
|
|
68
71
|
const lines = [
|
|
69
72
|
status.parentWorkflowRunId ? `Workflow parent: ${status.parentWorkflowRunId}${status.workflowKey ? ` (${status.workflowKey})` : ""}` : undefined,
|
|
70
73
|
status.mode === "workflow" ? `Workflow children: ${(status.steps ?? []).length}` : undefined,
|
|
74
|
+
status.lane ? `Lane: ${status.lane.key}${status.lane.mode ? ` (${status.lane.mode})` : ""}` : undefined,
|
|
71
75
|
].filter((line): line is string => line !== undefined);
|
|
72
76
|
for (const [index, step] of (status.steps ?? []).entries()) {
|
|
73
|
-
lines.push(` ${index + 1}. key ${step.workflowKey ?? "n/a"} · ${step
|
|
77
|
+
lines.push(` ${index + 1}. key ${step.workflowKey ?? "n/a"} · ${runStatusStepDisplayName(step)} · ${step.status} · async ${step.async === undefined ? "unknown" : step.async ? "yes" : "no"}${step.runId ? ` · run ${step.runId}` : ""}${step.lane ? ` · lane ${step.lane.key}` : ""}${step.worktreePath ? ` · worktree ${step.worktreePath} · branch ${step.branch ?? "unknown"}` : ""}`);
|
|
74
78
|
}
|
|
75
79
|
return lines;
|
|
76
80
|
}
|
|
@@ -88,6 +92,7 @@ function formatRunLifecycleDebug(input: { status: AsyncStatus; asyncDir: string;
|
|
|
88
92
|
`Mode: ${status.mode}`,
|
|
89
93
|
status.parentWorkflowRunId ? `Workflow parent: ${status.parentWorkflowRunId}` : undefined,
|
|
90
94
|
status.workflowKey ? `Workflow key: ${status.workflowKey}` : undefined,
|
|
95
|
+
status.lane ? `Lane: ${status.lane.key}${status.lane.mode ? ` (${status.lane.mode})` : ""}` : undefined,
|
|
91
96
|
`Status process terminal: ${formatProcessTerminal(overlayProcessTerminal)}`,
|
|
92
97
|
`Sidecar process terminal: ${formatProcessTerminal(sidecarProcessTerminal)}`,
|
|
93
98
|
...formatCapacityOwner(capacity),
|
|
@@ -152,7 +157,12 @@ function stepLineLabel(status: AsyncStatus, index: number): string {
|
|
|
152
157
|
return `Step ${index + 1}`;
|
|
153
158
|
}
|
|
154
159
|
|
|
160
|
+
function runStatusStepDisplayName(step: { agent: string; sessionName?: string; label?: string }): string {
|
|
161
|
+
return step.sessionName?.trim() || (step.label ? `${step.label} (${step.agent})` : step.agent);
|
|
162
|
+
}
|
|
163
|
+
|
|
155
164
|
function nestedRunDisplayName(run: NestedRunSummary): string {
|
|
165
|
+
if (run.sessionName?.trim()) return run.sessionName.trim();
|
|
156
166
|
if (run.agent) return run.agent;
|
|
157
167
|
if (run.agents?.length) return run.agents.join(", ");
|
|
158
168
|
return run.id;
|
|
@@ -197,7 +207,7 @@ function formatRememberedForegroundStatus(run: ForegroundResumeRun): string {
|
|
|
197
207
|
for (const child of run.children) {
|
|
198
208
|
const output = rememberedForegroundChildOutput(child).trim().split(/\r?\n/).find((line) => line.trim());
|
|
199
209
|
const parts = [
|
|
200
|
-
`${child.index + 1}. ${child.agent} ${child.status}`,
|
|
210
|
+
`${child.index + 1}. ${child.sessionName?.trim() || child.agent} ${child.status}`,
|
|
201
211
|
child.exitCode !== undefined ? `exit ${child.exitCode}` : undefined,
|
|
202
212
|
child.detachedReason ? `detached: ${child.detachedReason}` : undefined,
|
|
203
213
|
child.acceptance ? `acceptance: ${child.acceptance.status}` : undefined,
|
|
@@ -241,7 +251,7 @@ function formatRememberedForegroundTranscript(run: ForegroundResumeRun, options:
|
|
|
241
251
|
const lines = [
|
|
242
252
|
`Run: ${run.runId}`,
|
|
243
253
|
`State: ${child.status}`,
|
|
244
|
-
`Child: ${index} (${child.agent})`,
|
|
254
|
+
`Child: ${index} (${child.sessionName?.trim() || child.agent})`,
|
|
245
255
|
child.sessionFile ? `Session: ${child.sessionFile}` : undefined,
|
|
246
256
|
child.transcriptPath ? `Transcript: ${child.transcriptPath}` : undefined,
|
|
247
257
|
child.artifactPaths?.outputPath ? `Output: ${child.artifactPaths.outputPath}` : undefined,
|
|
@@ -277,7 +287,7 @@ function formatNestedExactStatus(rootRunId: string, run: NestedRunSummary): stri
|
|
|
277
287
|
for (const [index, step] of run.steps.entries()) {
|
|
278
288
|
const activity = step.status === "running" ? formatActivityLabel(step.lastActivityAt, step.activityState) : undefined;
|
|
279
289
|
const budget = step.turnBudget ? `, turn budget: ${step.turnBudget.turnCount}/${step.turnBudget.maxTurns}+${step.turnBudget.graceTurns} (${step.turnBudget.outcome})` : "";
|
|
280
|
-
lines.push(` ${index + 1}. ${step.agent} ${step.status}${activity ? `, ${activity}` : ""}${budget}${step.error ? `, error: ${step.error}` : ""}`);
|
|
290
|
+
lines.push(` ${index + 1}. ${step.sessionName?.trim() || step.agent} ${step.status}${activity ? `, ${activity}` : ""}${budget}${step.error ? `, error: ${step.error}` : ""}`);
|
|
281
291
|
lines.push(...formatNestedRunStatusLines(step.children, { indent: " ", commandHints: true }));
|
|
282
292
|
}
|
|
283
293
|
}
|
|
@@ -473,6 +483,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
473
483
|
currentStep: status.currentStep,
|
|
474
484
|
chainStepCount: status.chainStepCount,
|
|
475
485
|
parallelGroups: status.parallelGroups,
|
|
486
|
+
workflowGraph: status.workflowGraph,
|
|
476
487
|
steps: (status.steps ?? []).map((step, index) => ({ index, agent: step.agent, status: step.status })),
|
|
477
488
|
});
|
|
478
489
|
const started = new Date(status.startedAt).toISOString();
|
|
@@ -504,6 +515,8 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
504
515
|
statusActivityText ? `Activity: ${statusActivityText}` : undefined,
|
|
505
516
|
steeringText ? `Steering: ${steeringText}` : undefined,
|
|
506
517
|
`Mode: ${status.mode}`,
|
|
518
|
+
...(status.preflight ? [formatWorkflowPreflightPlanSummary(status.preflight)] : []),
|
|
519
|
+
...(status.workflow?.preflightWarnings?.length ? [formatWorkflowPreflightWarningSummary(status.workflow.preflightWarnings)] : []),
|
|
507
520
|
runFanoutBudget ? formatRunFanoutBudget(runFanoutBudget) : undefined,
|
|
508
521
|
status.parentWorkflowRunId ? `Workflow parent: ${status.parentWorkflowRunId}${status.workflowKey ? ` (${status.workflowKey})` : ""}` : undefined,
|
|
509
522
|
status.mode === "workflow" && workflowReturnPreview !== undefined ? `Return: ${workflowReturnPreview}` : undefined,
|
|
@@ -535,9 +548,10 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
535
548
|
const errorText = step.error ? `, error: ${step.error}` : "";
|
|
536
549
|
const acceptanceText = step.acceptance?.status ? `, acceptance: ${step.acceptance.status}` : "";
|
|
537
550
|
const budgetText = step.turnBudget ? `, turn budget: ${step.turnBudget.turnCount}/${step.turnBudget.maxTurns}+${step.turnBudget.graceTurns} (${step.turnBudget.outcome})` : "";
|
|
538
|
-
const display =
|
|
551
|
+
const display = runStatusStepDisplayName(step);
|
|
539
552
|
const phase = step.phase ? `[${step.phase}] ` : "";
|
|
540
553
|
lines.push(`${stepLineLabel(status, index)}: ${phase}${display} ${step.status}${modelText}${stepActivityText ? `, ${stepActivityText}` : ""}${steeringSuffix}${acceptanceText}${budgetText}${errorText}`);
|
|
554
|
+
lines.push(...formatTimeoutRecoveryLines(step.timeoutRecovery, " "));
|
|
541
555
|
if (step.runner?.type === "external-cli") {
|
|
542
556
|
const runner = normalizeExternalCliRunnerStatus(step.runner);
|
|
543
557
|
if (runner) {
|
|
@@ -583,6 +597,11 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
583
597
|
lines.push(" Steer: unavailable; external runners do not accept live messages.");
|
|
584
598
|
}
|
|
585
599
|
}
|
|
600
|
+
const loadedWorkflowKeys = new Set((status.steps ?? []).flatMap((step) => step.workflowKey ? [step.workflowKey] : []));
|
|
601
|
+
const graphStages = status.mode === "workflow" ? workflowGraphStageNodes(status.workflowGraph) : [];
|
|
602
|
+
for (const [index, node] of graphStages.entries()) {
|
|
603
|
+
if (!loadedWorkflowKeys.has(node.id)) lines.push(` ${formatWorkflowStageLine(node, index, graphStages.length)}`);
|
|
604
|
+
}
|
|
586
605
|
const attached = new Set((status.steps ?? []).flatMap((step) => step.children?.map((child) => child.id) ?? []));
|
|
587
606
|
const unattached = nestedChildren.filter((child) => !attached.has(child.id));
|
|
588
607
|
lines.push(...formatNestedRunStatusLines(unattached, { indent: "", commandHints: true, maxLines: 20 }));
|
|
@@ -608,7 +627,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
608
627
|
|
|
609
628
|
const workflowChildren = parseWorkflowChildSummary(status.workflowChildren);
|
|
610
629
|
if (workflowChildren && workflowChildren.workflowRunId !== status.runId) throw new Error("workflowChildren.workflowRunId does not match async status runId.");
|
|
611
|
-
return { content: [{ type: "text", text: lines.join("\n") }], details: { mode: "single", results: [], ...(workflowChildren ? { workflowChildren } : {}), ...(runFanoutBudget ? { runFanoutBudget } : {}), ...(processTerminal ? { lifecycleStatus: { processTerminal } } : {}) } };
|
|
630
|
+
return { content: [{ type: "text", text: lines.join("\n") }], details: { mode: "single", results: [], ...(status.preflight ? { preflight: status.preflight } : {}), ...(status.workflow?.preflightWarnings?.length ? { preflightWarnings: status.workflow.preflightWarnings } : {}), ...(workflowChildren ? { workflowChildren } : {}), ...(runFanoutBudget ? { runFanoutBudget } : {}), ...(processTerminal ? { lifecycleStatus: { processTerminal } } : {}) } };
|
|
612
631
|
}
|
|
613
632
|
}
|
|
614
633
|
|
|
@@ -622,7 +641,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
622
641
|
}
|
|
623
642
|
try {
|
|
624
643
|
const raw = fs.readFileSync(resultPath, "utf-8");
|
|
625
|
-
const data = JSON.parse(raw) as { id?: string; runId?: string; toolCallId?: string; agent?: string; success?: boolean; summary?: string; output?: string; exitCode?: number; state?: string; stopped?: boolean; timedOut?: boolean; turnBudgetExceeded?: boolean; processSignal?: string | null; sessionFile?: string; parallelHandoff?: { path?: string }; results?: Array<{ agent?: string; runId?: string; workflowKey?: string; output?: string; summary?: string; sessionFile?: string; state?: string; success?: boolean; exitCode?: number | null; stopped?: boolean; timedOut?: boolean; turnBudgetExceeded?: boolean; interrupted?: boolean; processSignal?: string | null }> };
|
|
644
|
+
const data = JSON.parse(raw) as { id?: string; runId?: string; toolCallId?: string; agent?: string; success?: boolean; summary?: string; output?: string; exitCode?: number; state?: string; stopped?: boolean; timedOut?: boolean; turnBudgetExceeded?: boolean; processSignal?: string | null; sessionFile?: string; timeoutRecovery?: unknown; parallelHandoff?: { path?: string }; results?: Array<{ agent?: string; sessionName?: string; runId?: string; workflowKey?: string; output?: string; summary?: string; sessionFile?: string; state?: string; success?: boolean; exitCode?: number | null; stopped?: boolean; timedOut?: boolean; turnBudgetExceeded?: boolean; interrupted?: boolean; processSignal?: string | null; timeoutRecovery?: unknown }> };
|
|
626
645
|
if (params.view === "transcript") {
|
|
627
646
|
try {
|
|
628
647
|
return { content: [{ type: "text", text: formatAsyncResultTranscript(data, resultPath, { index: params.index, lines: params.lines }) }], details: { mode: "single", results: [] } };
|
|
@@ -650,6 +669,8 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
650
669
|
const lines = [`Run: ${runId}`, data.toolCallId ? `Tool call: ${data.toolCallId}` : undefined, `State: ${status}`, `Result: ${resultPath}`].filter((line): line is string => Boolean(line));
|
|
651
670
|
if (data.parallelHandoff?.path) lines.push(`Parallel handoff: ${data.parallelHandoff.path}`);
|
|
652
671
|
const children = Array.isArray(data.results) ? data.results : data.agent ? [{ agent: data.agent, sessionFile: data.sessionFile }] : [];
|
|
672
|
+
lines.push(...formatTimeoutRecoveryLines(data.timeoutRecovery, " "));
|
|
673
|
+
for (const child of children) lines.push(...formatTimeoutRecoveryLines(child.timeoutRecovery, " "));
|
|
653
674
|
lines.push(formatResumeGuidance(runId, children, data.sessionFile, { stopped: status === "stopped" }));
|
|
654
675
|
if (data.summary) lines.push("", data.summary);
|
|
655
676
|
const workflowChildren = parseWorkflowChildSummary((data as unknown as Record<string, unknown>).workflowChildren);
|