pi-subagents 0.59.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 +37 -0
- package/docs/tool-reference.md +4 -1
- package/docs/workflows.md +2 -2
- package/package.json +1 -1
- 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 +47 -6
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/multi-lane-orchestration.md +13 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +34 -27
- package/skills/pi-subagents/references/review-and-validation.md +73 -0
- package/src/agents/agent-management.ts +154 -25
- package/src/api/shared-types.ts +2 -0
- package/src/extension/public-execution.ts +1 -0
- package/src/extension/schemas.ts +1 -0
- package/src/extension/tool-description.ts +8 -4
- package/src/runs/background/async-execution.ts +2 -2
- package/src/runs/background/async-job-tracker.ts +3 -0
- package/src/runs/background/async-status.ts +45 -2
- package/src/runs/background/control-channel.ts +3 -2
- package/src/runs/background/run-status.ts +13 -2
- package/src/runs/background/subagent-runner.ts +5 -1
- package/src/runs/background/subagent-wait.ts +10 -2
- package/src/runs/background/wait-completions.ts +3 -0
- package/src/runs/foreground/execution.ts +11 -2
- package/src/runs/foreground/subagent-executor.ts +98 -1
- package/src/runs/shared/async-status-projection.ts +138 -4
- package/src/runs/shared/background-process-options.ts +9 -0
- package/src/runs/shared/mcp-direct-tool-grant.ts +2 -5
- package/src/runs/shared/mutation-evidence.ts +52 -3
- package/src/runs/shared/pi-args.ts +47 -1
- package/src/runs/shared/single-output.ts +45 -18
- package/src/runs/shared/subagent-prompt-runtime.ts +20 -2
- package/src/runs/shared/workflow-graph.ts +15 -0
- package/src/shared/types.ts +34 -1
- package/src/tui/fleet-status.ts +11 -3
- package/src/tui/render-helpers.ts +31 -0
- package/src/tui/render.ts +597 -112
- package/src/watchdog/change-signature.ts +40 -1
- package/src/workflows/host-command.ts +6 -1
- package/src/workflows/scripted-workflow.ts +53 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { formatDuration, formatModelThinking, formatTokens, shortenPath } from "../../shared/formatters.ts";
|
|
4
|
+
import { previewDisplayText } from "../../shared/display-text.ts";
|
|
4
5
|
import { formatActivityLabel, formatParallelOutcome } from "../../shared/status-format.ts";
|
|
5
|
-
import { type ActivityState, type AsyncJobStep, type AsyncParallelGroupStatus, type AsyncStatus, type CostSummary, type Details, type HostStepNodeV1, type HostStepState, type LaunchResolvedChildExtensionsV1, type RuntimeAcknowledgedChildExtensionsV1, type NestedRunSummary, type SteeringStatus, type SubagentRunMode, type TokenUsage, type TurnBudgetState, type UsageBudgetState, type WorkflowPreflightV1 } from "../../shared/types.ts";
|
|
6
|
+
import { type ActivityState, type AsyncJobStep, type AsyncParallelGroupStatus, type AsyncStatus, type CostSummary, type Details, type HostStepNodeV1, type HostStepState, type LaunchResolvedChildExtensionsV1, type RuntimeAcknowledgedChildExtensionsV1, type NestedRunSummary, type SteeringStatus, type SubagentRunMode, type TimeoutRecoveryProjection, type TokenUsage, type TurnBudgetState, type UsageBudgetState, type WorkflowPreflightV1, type WorkflowGraphSnapshot } from "../../shared/types.ts";
|
|
6
7
|
import type { ResolvedSubagentCapabilityCeiling, SubagentCapabilityAudit } from "../shared/capability-ceiling.ts";
|
|
7
8
|
import { readStatus } from "../../shared/utils.ts";
|
|
8
9
|
import { attachRootChildrenToSteps, buildNestedRouteIndex, findNestedRouteForRootId, type NestedRoute, projectNestedEvents } from "../shared/nested-events.ts";
|
|
@@ -21,6 +22,8 @@ import { assertWorkflowGraphHostSteps, hostStepReportName, hostStepVerdictLabel,
|
|
|
21
22
|
import { projectAsyncWorkflowRows } from "../shared/async-status-projection.ts";
|
|
22
23
|
import { validateAsyncStatusLaneMetadata } from "../shared/lane-metadata.ts";
|
|
23
24
|
import { formatWorkflowPreflightPlanSummary, formatWorkflowPreflightWarningSummary } from "../../workflows/workflow-preflight.ts";
|
|
25
|
+
import { workflowGraphStageNodes } from "../shared/workflow-graph.ts";
|
|
26
|
+
import { formatTimeoutRecoveryLines, projectTimeoutRecovery } from "../shared/mutation-evidence.ts";
|
|
24
27
|
|
|
25
28
|
interface AsyncRunStepSummary {
|
|
26
29
|
index: number;
|
|
@@ -75,6 +78,7 @@ interface AsyncRunStepSummary {
|
|
|
75
78
|
review?: AsyncJobStep["review"];
|
|
76
79
|
effects?: AsyncJobStep["effects"];
|
|
77
80
|
processTerminal?: AsyncJobStep["processTerminal"];
|
|
81
|
+
timeoutRecovery?: TimeoutRecoveryProjection;
|
|
78
82
|
launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
|
|
79
83
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
|
|
80
84
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
@@ -116,6 +120,7 @@ export interface AsyncRunSummary {
|
|
|
116
120
|
pendingAppends?: number;
|
|
117
121
|
parallelGroups?: AsyncParallelGroupStatus[];
|
|
118
122
|
hostSteps?: HostStepNodeV1[];
|
|
123
|
+
workflowGraph?: AsyncStatus["workflowGraph"];
|
|
119
124
|
steps: AsyncRunStepSummary[];
|
|
120
125
|
sessionDir?: string;
|
|
121
126
|
outputFile?: string;
|
|
@@ -282,6 +287,7 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
282
287
|
const summarizedSteps = steps.map((step, index) => {
|
|
283
288
|
const stepActivityState = step.activityState;
|
|
284
289
|
const stepLastActivityAt = step.lastActivityAt;
|
|
290
|
+
const timeoutRecovery = projectTimeoutRecovery(step.timeoutRecovery);
|
|
285
291
|
return {
|
|
286
292
|
index,
|
|
287
293
|
childId: asyncStatusChildIdentity(step, index),
|
|
@@ -341,6 +347,7 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
341
347
|
...(step.effects ? { effects: step.effects } : {}),
|
|
342
348
|
...(step.watchdog ? { watchdog: step.watchdog } : {}),
|
|
343
349
|
...(step.processTerminal ? { processTerminal: sanitizeProcessTerminal(step.processTerminal, { runId: status.runId, runnerProcessInstanceId: step.processTerminal.runnerProcessInstanceId }, `${path.join(asyncDir, "status.json")} step ${index}`) } : {}),
|
|
350
|
+
...(timeoutRecovery ? { timeoutRecovery } : {}),
|
|
344
351
|
...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
|
|
345
352
|
...(step.capabilityAudit ? { capabilityAudit: step.capabilityAudit } : {}),
|
|
346
353
|
...(step.children?.length ? { children: step.children } : {}),
|
|
@@ -381,6 +388,7 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
381
388
|
...(status.pendingAppends !== undefined ? { pendingAppends: status.pendingAppends } : {}),
|
|
382
389
|
...(parallelGroups.length ? { parallelGroups } : {}),
|
|
383
390
|
...(hostSteps.length ? { hostSteps } : {}),
|
|
391
|
+
...(status.mode === "workflow" && status.workflowGraph ? { workflowGraph: status.workflowGraph } : {}),
|
|
384
392
|
steps: summarizedSteps,
|
|
385
393
|
...(nestedChildren.length ? { nestedChildren } : {}),
|
|
386
394
|
...(nestedWarnings.length ? { nestedWarnings } : {}),
|
|
@@ -575,12 +583,41 @@ function formatHostStepLine(row: ReturnType<typeof projectAsyncWorkflowRows>[num
|
|
|
575
583
|
return `host ${row.kind}: ${row.name} | ${state}${details.length ? ` | ${details.join(" | ")}` : ""}`;
|
|
576
584
|
}
|
|
577
585
|
|
|
586
|
+
function workflowStageStateLabel(status: WorkflowGraphSnapshot["nodes"][number]["status"]): string {
|
|
587
|
+
switch (status) {
|
|
588
|
+
case "completed":
|
|
589
|
+
return "complete";
|
|
590
|
+
case "detached":
|
|
591
|
+
return "paused";
|
|
592
|
+
default:
|
|
593
|
+
return status;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
export function formatWorkflowStageLine(node: WorkflowGraphSnapshot["nodes"][number], index: number, total: number): string {
|
|
598
|
+
const state = workflowStageStateLabel(node.status);
|
|
599
|
+
const id = previewDisplayText(node.id, 160);
|
|
600
|
+
const label = node.label ? previewDisplayText(node.label, 160) : "";
|
|
601
|
+
const display = label && label !== id ? ` | ${label}` : "";
|
|
602
|
+
const agent = node.agent ? ` | ${previewDisplayText(node.agent, 80)}` : "";
|
|
603
|
+
const error = node.error ? ` | ${previewDisplayText(node.error, 240)}` : "";
|
|
604
|
+
return `stage ${index + 1}/${total}: ${id}${display}${agent} | ${state}${error}`;
|
|
605
|
+
}
|
|
606
|
+
|
|
578
607
|
export function formatAsyncRunOutputPath(run: Pick<AsyncRunSummary, "asyncDir" | "outputFile">): string | undefined {
|
|
579
608
|
if (!run.outputFile) return undefined;
|
|
580
609
|
return path.isAbsolute(run.outputFile) ? run.outputFile : path.join(run.asyncDir, run.outputFile);
|
|
581
610
|
}
|
|
582
611
|
|
|
583
|
-
export function formatAsyncRunProgressLabel(run: Pick<AsyncRunSummary, "mode" | "state" | "currentStep" | "chainStepCount" | "parallelGroups" | "steps">): string {
|
|
612
|
+
export function formatAsyncRunProgressLabel(run: Pick<AsyncRunSummary, "mode" | "state" | "currentStep" | "chainStepCount" | "parallelGroups" | "steps"> & { workflowGraph?: WorkflowGraphSnapshot }): string {
|
|
613
|
+
const graphStages = run.mode === "workflow" ? workflowGraphStageNodes(run.workflowGraph) : [];
|
|
614
|
+
if (graphStages.length > 0) {
|
|
615
|
+
const currentNode = graphStages.find((node) => node.id === run.workflowGraph?.currentNodeId);
|
|
616
|
+
if (currentNode && currentNode.status !== "completed") return `stage ${graphStages.indexOf(currentNode) + 1}/${graphStages.length}`;
|
|
617
|
+
const activeNode = graphStages.find((node) => node.status === "running") ?? graphStages.find((node) => node.status !== "completed");
|
|
618
|
+
if (activeNode) return `stage ${graphStages.indexOf(activeNode) + 1}/${graphStages.length}`;
|
|
619
|
+
return `stage ${graphStages.length}/${graphStages.length}`;
|
|
620
|
+
}
|
|
584
621
|
const stepCount = run.steps.length || 1;
|
|
585
622
|
const chainStepCount = run.chainStepCount ?? stepCount;
|
|
586
623
|
const groups = normalizeParallelGroups(run.parallelGroups, run.steps.length, chainStepCount);
|
|
@@ -622,8 +659,14 @@ export function formatAsyncRunList(runs: AsyncRunSummary[], heading = "Active as
|
|
|
622
659
|
if (preflightWarning) lines.push(preflightWarning);
|
|
623
660
|
for (const step of run.steps) {
|
|
624
661
|
lines.push(` ${formatStepLine(step)}`);
|
|
662
|
+
lines.push(...formatTimeoutRecoveryLines(step.timeoutRecovery, " "));
|
|
625
663
|
lines.push(...formatNestedRunStatusLines(step.children, { indent: " ", maxLines: 12 }));
|
|
626
664
|
}
|
|
665
|
+
const loadedWorkflowKeys = new Set(run.steps.flatMap((step) => step.workflowKey ? [step.workflowKey] : []));
|
|
666
|
+
const graphStages = run.mode === "workflow" ? workflowGraphStageNodes(run.workflowGraph) : [];
|
|
667
|
+
for (const [index, node] of graphStages.entries()) {
|
|
668
|
+
if (!loadedWorkflowKeys.has(node.id)) lines.push(` ${formatWorkflowStageLine(node, index, graphStages.length)}`);
|
|
669
|
+
}
|
|
627
670
|
for (const row of projectAsyncWorkflowRows([], run.hostSteps)) {
|
|
628
671
|
const line = formatHostStepLine(row);
|
|
629
672
|
if (line) lines.push(` ${line}`);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cross-OS control channel for async subagent runs.
|
|
3
3
|
*
|
|
4
|
-
* Background runs
|
|
5
|
-
*
|
|
4
|
+
* Background runs use child processes. Unix detaches them from the parent process.
|
|
5
|
+
* The original control path delivered an interrupt with
|
|
6
|
+
* `process.kill(pid, SIGUSR2|SIGBREAK)`, but Windows cannot
|
|
6
7
|
* deliver those signals cross-process via `process.kill` and throws `ENOSYS`,
|
|
7
8
|
* which left async runs uninterruptible (no stop, no live steer) on Windows.
|
|
8
9
|
*
|
|
@@ -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";
|
|
@@ -25,7 +25,9 @@ import { formatWorkflowJsonPreview } from "../../workflows/scripted-workflow.ts"
|
|
|
25
25
|
import { parseWorkflowChildSummary } from "../../workflows/workflow-child-summary.ts";
|
|
26
26
|
import { formatWorkflowPreflightPlanSummary, formatWorkflowPreflightWarningSummary } from "../../workflows/workflow-preflight.ts";
|
|
27
27
|
import { formatRunFanoutBudget, getRunFanoutBudgetSnapshot, readRunFanoutBudgetDescriptor } from "../shared/run-fanout-budget.ts";
|
|
28
|
+
import { workflowGraphStageNodes } from "../shared/workflow-graph.ts";
|
|
28
29
|
import { getExternalJobProvider } from "../../api/external-job-provider.ts";
|
|
30
|
+
import { formatTimeoutRecoveryLines } from "../shared/mutation-evidence.ts";
|
|
29
31
|
|
|
30
32
|
interface RunStatusParams {
|
|
31
33
|
action?: string;
|
|
@@ -481,6 +483,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
481
483
|
currentStep: status.currentStep,
|
|
482
484
|
chainStepCount: status.chainStepCount,
|
|
483
485
|
parallelGroups: status.parallelGroups,
|
|
486
|
+
workflowGraph: status.workflowGraph,
|
|
484
487
|
steps: (status.steps ?? []).map((step, index) => ({ index, agent: step.agent, status: step.status })),
|
|
485
488
|
});
|
|
486
489
|
const started = new Date(status.startedAt).toISOString();
|
|
@@ -548,6 +551,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
548
551
|
const display = runStatusStepDisplayName(step);
|
|
549
552
|
const phase = step.phase ? `[${step.phase}] ` : "";
|
|
550
553
|
lines.push(`${stepLineLabel(status, index)}: ${phase}${display} ${step.status}${modelText}${stepActivityText ? `, ${stepActivityText}` : ""}${steeringSuffix}${acceptanceText}${budgetText}${errorText}`);
|
|
554
|
+
lines.push(...formatTimeoutRecoveryLines(step.timeoutRecovery, " "));
|
|
551
555
|
if (step.runner?.type === "external-cli") {
|
|
552
556
|
const runner = normalizeExternalCliRunnerStatus(step.runner);
|
|
553
557
|
if (runner) {
|
|
@@ -593,6 +597,11 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
593
597
|
lines.push(" Steer: unavailable; external runners do not accept live messages.");
|
|
594
598
|
}
|
|
595
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
|
+
}
|
|
596
605
|
const attached = new Set((status.steps ?? []).flatMap((step) => step.children?.map((child) => child.id) ?? []));
|
|
597
606
|
const unattached = nestedChildren.filter((child) => !attached.has(child.id));
|
|
598
607
|
lines.push(...formatNestedRunStatusLines(unattached, { indent: "", commandHints: true, maxLines: 20 }));
|
|
@@ -632,7 +641,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
632
641
|
}
|
|
633
642
|
try {
|
|
634
643
|
const raw = fs.readFileSync(resultPath, "utf-8");
|
|
635
|
-
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; 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 }> };
|
|
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 }> };
|
|
636
645
|
if (params.view === "transcript") {
|
|
637
646
|
try {
|
|
638
647
|
return { content: [{ type: "text", text: formatAsyncResultTranscript(data, resultPath, { index: params.index, lines: params.lines }) }], details: { mode: "single", results: [] } };
|
|
@@ -660,6 +669,8 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
660
669
|
const lines = [`Run: ${runId}`, data.toolCallId ? `Tool call: ${data.toolCallId}` : undefined, `State: ${status}`, `Result: ${resultPath}`].filter((line): line is string => Boolean(line));
|
|
661
670
|
if (data.parallelHandoff?.path) lines.push(`Parallel handoff: ${data.parallelHandoff.path}`);
|
|
662
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, " "));
|
|
663
674
|
lines.push(formatResumeGuidance(runId, children, data.sessionFile, { stopped: status === "stopped" }));
|
|
664
675
|
if (data.summary) lines.push("", data.summary);
|
|
665
676
|
const workflowChildren = parseWorkflowChildSummary((data as unknown as Record<string, unknown>).workflowChildren);
|
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
DEFAULT_GLOBAL_CONCURRENCY_LIMIT,
|
|
76
76
|
Semaphore,
|
|
77
77
|
} from "../shared/parallel-utils.ts";
|
|
78
|
-
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
|
|
78
|
+
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, deriveForkPromptCacheKey, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
|
|
79
79
|
import { deriveChildSessionName } from "../../shared/child-session-name.ts";
|
|
80
80
|
import { readRuntimeAcknowledgedExtensions } from "../shared/runtime-acknowledged-extensions.ts";
|
|
81
81
|
import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.ts";
|
|
@@ -1640,6 +1640,7 @@ async function runSingleStepInner(
|
|
|
1640
1640
|
const writerProcesses: PiWriterProcessInstanceExitV1[] = [];
|
|
1641
1641
|
let writerAttemptCount = 0;
|
|
1642
1642
|
const attemptNotes: string[] = [];
|
|
1643
|
+
let finalRequiredOutputMissing: boolean | undefined;
|
|
1643
1644
|
const eventsPath = path.join(path.dirname(ctx.outputFile), "events.jsonl");
|
|
1644
1645
|
let finalResult: RunPiStreamingResult | undefined;
|
|
1645
1646
|
let finalOutputSnapshot: SingleOutputSnapshot | undefined;
|
|
@@ -1698,6 +1699,7 @@ async function runSingleStepInner(
|
|
|
1698
1699
|
: undefined;
|
|
1699
1700
|
const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit, warnings } = buildPiArgs(omitUndefinedProperties({
|
|
1700
1701
|
parentSessionId: step.parentSessionId,
|
|
1702
|
+
forkCacheKey: step.context === "fork" ? deriveForkPromptCacheKey(step.parentSessionId) : undefined,
|
|
1701
1703
|
baseArgs: ["--mode", "json", "-p"],
|
|
1702
1704
|
task: attemptTask,
|
|
1703
1705
|
taskDelivery: taskDeliveryOverride,
|
|
@@ -1929,6 +1931,7 @@ async function runSingleStepInner(
|
|
|
1929
1931
|
: effectiveStructuredOutput
|
|
1930
1932
|
? { kind: "structured" as const, path: effectiveStructuredOutput.outputPath, missing: !fs.existsSync(effectiveStructuredOutput.outputPath) }
|
|
1931
1933
|
: undefined;
|
|
1934
|
+
finalRequiredOutputMissing = requiredOutput?.missing;
|
|
1932
1935
|
const missingRequiredOutputError = formatRequiredOutputError(requiredOutput);
|
|
1933
1936
|
const missingRequiredOutputAfterMutation = Boolean(missingRequiredOutputError) && (mutationAttemptObserved || Boolean(mutationEvidence.changedFiles.length));
|
|
1934
1937
|
const effectiveExitCode = toolAvailabilityError || completionEvidence.legacyFailureError || midToolExitError || structuredError || emptyOutputError || missingRequiredOutputError
|
|
@@ -2117,6 +2120,7 @@ async function runSingleStepInner(
|
|
|
2117
2120
|
? buildTimeoutRecoverySummary({
|
|
2118
2121
|
termination: "timed-out",
|
|
2119
2122
|
evidence: finalMutationEvidence,
|
|
2123
|
+
requiredOutputMissing: finalRequiredOutputMissing,
|
|
2120
2124
|
currentTool: finalResult?.currentTool,
|
|
2121
2125
|
currentToolArgs: finalResult?.currentToolArgs,
|
|
2122
2126
|
currentPath: finalResult?.currentPath,
|
|
@@ -65,6 +65,7 @@ import { formatDuration, shortenPath } from "../../shared/formatters.ts";
|
|
|
65
65
|
import { toAgentToolUsage } from "../../shared/utils.ts";
|
|
66
66
|
import { collectWaitCompletions } from "./wait-completions.ts";
|
|
67
67
|
import { formatResumeFirstFailedRunsNote } from "./resume-guidance.ts";
|
|
68
|
+
import { formatTimeoutRecoveryLines } from "../shared/mutation-evidence.ts";
|
|
68
69
|
export { WAIT_TOOL_DEFAULT_TIMEOUT_MS_ENV, WAIT_TOOL_ENABLED_ENV, resolveWaitToolConfig, type ResolvedWaitToolConfig } from "./wait-config.ts";
|
|
69
70
|
|
|
70
71
|
/** States that mean a run is still in flight (not yet resolved). */
|
|
@@ -349,6 +350,12 @@ function result(text: string, isError = false, completions?: WaitCompletion[]):
|
|
|
349
350
|
};
|
|
350
351
|
}
|
|
351
352
|
|
|
353
|
+
function formatCompletionRecovery(completions: WaitCompletion[] | undefined): string {
|
|
354
|
+
const lines = (completions ?? []).flatMap((completion) =>
|
|
355
|
+
(completion.results ?? []).flatMap((child) => formatTimeoutRecoveryLines(child.timeoutRecovery)));
|
|
356
|
+
return lines.length > 0 ? `\n${lines.join("\n")}` : "";
|
|
357
|
+
}
|
|
358
|
+
|
|
352
359
|
function windowElapsedResult(
|
|
353
360
|
text: string,
|
|
354
361
|
activeRunIds: string[],
|
|
@@ -685,6 +692,7 @@ export async function waitForSubagents(
|
|
|
685
692
|
+ providerActive.filter((item) => initialProviderIds.has(backgroundWorkIdentity(item))).length;
|
|
686
693
|
const elapsed = formatDuration(now() - startedAt);
|
|
687
694
|
const outcome = terminalSummary ? ` Outcome: ${terminalSummary}.` : "";
|
|
695
|
+
const recoveryNote = formatCompletionRecovery(completions);
|
|
688
696
|
|
|
689
697
|
if (waitForAll) {
|
|
690
698
|
const scope = params.id
|
|
@@ -694,7 +702,7 @@ export async function waitForSubagents(
|
|
|
694
702
|
: `${initialAsyncIds.size} async run(s) and ${initialProviderIds.size} provider item(s)`;
|
|
695
703
|
const status = relevantAttention.length > 0 ? "attention required" : "done";
|
|
696
704
|
return result(
|
|
697
|
-
`Waited ${elapsed} for ${scope}; ${status}.${outcome}${resumeGuidance}${attentionNote} Completion/control events have been observed; inspect status if a notification is not visible yet.`,
|
|
705
|
+
`Waited ${elapsed} for ${scope}; ${status}.${outcome}${recoveryNote}${resumeGuidance}${attentionNote} Completion/control events have been observed; inspect status if a notification is not visible yet.`,
|
|
698
706
|
(deps.failOnFailedRuns === true && failedAsyncCount > 0) || (deps.failOnAttention === true && relevantAttention.length > 0),
|
|
699
707
|
completions,
|
|
700
708
|
);
|
|
@@ -711,7 +719,7 @@ export async function waitForSubagents(
|
|
|
711
719
|
? `${relevantAttention.length} of ${initialCount} ${subject} need attention`
|
|
712
720
|
: `${finishedCount} of ${initialCount} ${subject} finished`;
|
|
713
721
|
return result(
|
|
714
|
-
`Waited ${elapsed}; ${progress}.${outcome}${resumeGuidance}${attentionNote}${remainder} Relevant completion/control events have been observed; inspect status if a notification is not visible yet.`,
|
|
722
|
+
`Waited ${elapsed}; ${progress}.${outcome}${recoveryNote}${resumeGuidance}${attentionNote}${remainder} Relevant completion/control events have been observed; inspect status if a notification is not visible yet.`,
|
|
715
723
|
(deps.failOnFailedRuns === true && failedAsyncCount > 0) || (deps.failOnAttention === true && relevantAttention.length > 0),
|
|
716
724
|
completions,
|
|
717
725
|
);
|
|
@@ -4,6 +4,7 @@ import type { AsyncRunSummary } from "./async-status.ts";
|
|
|
4
4
|
import { readCompletionReplay, writeCompletionReplay } from "./completion-replay.ts";
|
|
5
5
|
import { fallbackResultPayloadPathForSessionRun, resultFilePath, resultPayloadPathForSessionRun } from "./result-files.ts";
|
|
6
6
|
import { parseWorkflowChildSummary } from "../../workflows/workflow-child-summary.ts";
|
|
7
|
+
import { projectTimeoutRecovery } from "../shared/mutation-evidence.ts";
|
|
7
8
|
|
|
8
9
|
function asNonEmptyString(value: unknown): string | undefined {
|
|
9
10
|
return typeof value === "string" && value ? value : undefined;
|
|
@@ -65,6 +66,7 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
65
66
|
const error = asNonEmptyString(child.error);
|
|
66
67
|
const model = asNonEmptyString(child.model);
|
|
67
68
|
const contextOverflow = child.contextOverflow === true;
|
|
69
|
+
const timeoutRecovery = projectTimeoutRecovery(child.timeoutRecovery);
|
|
68
70
|
return [{
|
|
69
71
|
...(agent ? { agent } : {}),
|
|
70
72
|
...(childRunId ? { runId: childRunId } : {}),
|
|
@@ -76,6 +78,7 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
76
78
|
...(model ? { model } : {}),
|
|
77
79
|
...(contextOverflow ? { contextOverflow: true } : {}),
|
|
78
80
|
...(artifactPaths ? { artifactPaths } : {}),
|
|
81
|
+
...(timeoutRecovery ? { timeoutRecovery } : {}),
|
|
79
82
|
}];
|
|
80
83
|
})
|
|
81
84
|
: undefined;
|
|
@@ -66,7 +66,7 @@ import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
|
|
|
66
66
|
import { createOrcaProgressTab, type OrcaProgressTab } from "../shared/orca-progress-tabs.ts";
|
|
67
67
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
68
68
|
import { resolvePermissionRules } from "../shared/permissions.ts";
|
|
69
|
-
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
|
|
69
|
+
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, deriveForkPromptCacheKey, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
|
|
70
70
|
import { deriveChildSessionName } from "../../shared/child-session-name.ts";
|
|
71
71
|
import { readRuntimeAcknowledgedExtensions } from "../shared/runtime-acknowledged-extensions.ts";
|
|
72
72
|
import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV } from "../shared/capability-ceiling.ts";
|
|
@@ -76,7 +76,7 @@ import { MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput, readStructu
|
|
|
76
76
|
import { formatMidToolExitError, formatProcessSignalError, isOrdinaryToolForMidToolExit, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
77
77
|
import { readChildToolDiagnosticError } from "../shared/tool-availability.ts";
|
|
78
78
|
import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.ts";
|
|
79
|
-
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
79
|
+
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, hasSingleOutputChangedSinceSnapshot, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
80
80
|
import {
|
|
81
81
|
buildModelCandidates,
|
|
82
82
|
formatSubagentModelVerificationError,
|
|
@@ -380,6 +380,7 @@ async function runSingleAttempt(
|
|
|
380
380
|
parentCapabilityToken: options.nestedRoute?.capabilityToken,
|
|
381
381
|
runFanoutBudget: options.runFanoutBudget,
|
|
382
382
|
parentSessionId: options.parentSessionId,
|
|
383
|
+
forkCacheKey: options.context === "fork" ? deriveForkPromptCacheKey(options.parentSessionId) : undefined,
|
|
383
384
|
steerInboxDir: options.steerInboxDir,
|
|
384
385
|
steerCapabilityPath: options.steerCapabilityPath,
|
|
385
386
|
steerAckDir: options.steerAckDir,
|
|
@@ -1527,9 +1528,17 @@ async function runSingleAttempt(
|
|
|
1527
1528
|
result.outputState = fullOutput.trim() || result.structuredOutput !== undefined ? "present" : "absent";
|
|
1528
1529
|
if (result.timedOut) {
|
|
1529
1530
|
const timeoutMessage = formatTimeoutMessage(options.timeoutMs ?? 0);
|
|
1531
|
+
let requiredOutputMissing: boolean | undefined;
|
|
1532
|
+
if (options.outputMode === "file-only" && options.outputPath) {
|
|
1533
|
+
const outputChanged = hasSingleOutputChangedSinceSnapshot(options.outputPath, shared.outputSnapshot);
|
|
1534
|
+
requiredOutputMissing = outputChanged === undefined ? undefined : !outputChanged;
|
|
1535
|
+
} else if (options.structuredOutput) {
|
|
1536
|
+
requiredOutputMissing = !existsSync(options.structuredOutput.outputPath);
|
|
1537
|
+
}
|
|
1530
1538
|
result.timeoutRecovery = buildTimeoutRecoverySummary({
|
|
1531
1539
|
termination: "timed-out",
|
|
1532
1540
|
evidence: mutationEvidence,
|
|
1541
|
+
requiredOutputMissing,
|
|
1533
1542
|
currentTool: progress.currentTool,
|
|
1534
1543
|
currentToolArgs: progress.currentToolArgs,
|
|
1535
1544
|
currentPath: progress.currentPath,
|
|
@@ -112,7 +112,7 @@ import { createMissionWorkflowState } from "../../missions/workflow-state.ts";
|
|
|
112
112
|
import { resolveAuthorityDecision } from "../../policy/authority.ts";
|
|
113
113
|
import { handleHerdrInspectorAction, HERDR_INSPECTOR_ACTIONS } from "../../inspectors/herdr/actions.ts";
|
|
114
114
|
import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.ts";
|
|
115
|
-
import { previewSimpleWorkflowRun, runWorkflowScript, validateWorkflowScript, WorkflowScriptError, type WorkflowReceiptResumeReference, type WorkflowScriptChildResult, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
|
|
115
|
+
import { previewSimpleWorkflowRun, runWorkflowScript, validateWorkflowScript, WorkflowScriptError, type WorkflowLanePlan, type WorkflowReceiptResumeReference, type WorkflowScriptChildResult, type WorkflowScriptTraceEntry, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
|
|
116
116
|
import { executeWorkflowHostCommand, resolveWorkflowHostOutputClaimPath, type WorkflowHostCommandParams, type WorkflowHostCommandResult } from "../../workflows/host-command.ts";
|
|
117
117
|
import { buildWorkflowReceipt, resolveWorkflowReceiptResumeEntry, writeWorkflowReceipt, type WorkflowReceipt, type WorkflowReceiptState } from "../../workflows/workflow-receipt.ts";
|
|
118
118
|
import { upsertHostStep, validHostStepNodes } from "../shared/host-step-status.ts";
|
|
@@ -160,6 +160,9 @@ import {
|
|
|
160
160
|
type ToolBudgetConfig,
|
|
161
161
|
type Usage,
|
|
162
162
|
type UsageBudgetConfig,
|
|
163
|
+
type WorkflowGraphNode,
|
|
164
|
+
type WorkflowGraphSnapshot,
|
|
165
|
+
type WorkflowNodeStatus,
|
|
163
166
|
type WorkflowTerminalOutcome,
|
|
164
167
|
type SubagentRunMode,
|
|
165
168
|
type SubagentState,
|
|
@@ -295,6 +298,7 @@ export interface SubagentParamsLike {
|
|
|
295
298
|
type?: string;
|
|
296
299
|
agent?: string;
|
|
297
300
|
task?: string;
|
|
301
|
+
capabilities?: boolean;
|
|
298
302
|
extensionBindings?: ExtensionBindings;
|
|
299
303
|
/** Retained async child run id. Valid only on workflow runs.run items. */
|
|
300
304
|
resume?: string;
|
|
@@ -4411,6 +4415,90 @@ function formatWorkflowValue(value: unknown): string {
|
|
|
4411
4415
|
}
|
|
4412
4416
|
}
|
|
4413
4417
|
|
|
4418
|
+
function buildWorkflowLaneGraph(runId: string, lanes: WorkflowLanePlan[], existing?: WorkflowGraphSnapshot): WorkflowGraphSnapshot {
|
|
4419
|
+
const plannedIds = new Set(lanes.flatMap((lane) => lane.stages.map((stage) => stage.generatedKey)));
|
|
4420
|
+
const previousById = new Map((existing?.nodes ?? []).map((node) => [node.id, node]));
|
|
4421
|
+
const nodes: WorkflowGraphNode[] = [];
|
|
4422
|
+
const phases: WorkflowGraphSnapshot["phases"] = [];
|
|
4423
|
+
let flatIndex = 0;
|
|
4424
|
+
for (const lane of lanes) {
|
|
4425
|
+
const nodeIds: string[] = [];
|
|
4426
|
+
for (const [stageIndex, stage] of lane.stages.entries()) {
|
|
4427
|
+
const previous = previousById.get(stage.generatedKey);
|
|
4428
|
+
const outputName = stage.outputName || previous?.outputName;
|
|
4429
|
+
const structured = stage.structured ?? previous?.structured;
|
|
4430
|
+
const node: WorkflowGraphNode = {
|
|
4431
|
+
id: stage.generatedKey,
|
|
4432
|
+
kind: "step",
|
|
4433
|
+
agent: stage.agent ?? previous?.agent,
|
|
4434
|
+
phase: stage.phase ?? previous?.phase,
|
|
4435
|
+
label: stage.label ?? stage.key,
|
|
4436
|
+
status: previous?.status ?? (stageIndex === 0 ? "running" : "pending"),
|
|
4437
|
+
flatIndex,
|
|
4438
|
+
stepIndex: flatIndex,
|
|
4439
|
+
...(outputName ? { outputName } : {}),
|
|
4440
|
+
...(structured !== undefined ? { structured } : {}),
|
|
4441
|
+
...(previous?.acceptanceStatus ? { acceptanceStatus: previous.acceptanceStatus } : {}),
|
|
4442
|
+
...(previous?.error ? { error: previous.error } : {}),
|
|
4443
|
+
};
|
|
4444
|
+
nodes.push(node);
|
|
4445
|
+
nodeIds.push(node.id);
|
|
4446
|
+
flatIndex++;
|
|
4447
|
+
}
|
|
4448
|
+
if (nodeIds.length > 0) phases.push({ title: lane.key, nodeIds });
|
|
4449
|
+
}
|
|
4450
|
+
for (const node of existing?.nodes ?? []) {
|
|
4451
|
+
if (!plannedIds.has(node.id)) nodes.push(node);
|
|
4452
|
+
}
|
|
4453
|
+
for (const phase of existing?.phases ?? []) {
|
|
4454
|
+
const retainedNodeIds = phase.nodeIds.filter((nodeId) => !plannedIds.has(nodeId));
|
|
4455
|
+
if (retainedNodeIds.length === 0) continue;
|
|
4456
|
+
const currentPhase = phases.find((candidate) => candidate.title === phase.title);
|
|
4457
|
+
if (currentPhase) currentPhase.nodeIds.push(...retainedNodeIds);
|
|
4458
|
+
else phases.push({ title: phase.title, nodeIds: retainedNodeIds });
|
|
4459
|
+
}
|
|
4460
|
+
const currentNodeId = nodes.find((node) => node.status === "running")?.id ?? existing?.currentNodeId;
|
|
4461
|
+
return { runId, mode: "workflow", phases, nodes, ...(currentNodeId ? { currentNodeId } : {}) };
|
|
4462
|
+
}
|
|
4463
|
+
|
|
4464
|
+
function workflowLaneTraceStatus(state: WorkflowScriptTraceEntry["state"]): WorkflowNodeStatus | undefined {
|
|
4465
|
+
switch (state) {
|
|
4466
|
+
case "started":
|
|
4467
|
+
return "running";
|
|
4468
|
+
case "reused":
|
|
4469
|
+
return undefined;
|
|
4470
|
+
case "completed":
|
|
4471
|
+
return "completed";
|
|
4472
|
+
case "failed":
|
|
4473
|
+
return "failed";
|
|
4474
|
+
case "detached":
|
|
4475
|
+
return "detached";
|
|
4476
|
+
case "stopped":
|
|
4477
|
+
return "stopped";
|
|
4478
|
+
default:
|
|
4479
|
+
return undefined;
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
|
|
4483
|
+
function applyWorkflowLaneTrace(graph: WorkflowGraphSnapshot, trace: WorkflowScriptTraceEntry[]): void {
|
|
4484
|
+
const nodesById = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
4485
|
+
for (const entry of trace) {
|
|
4486
|
+
if (entry.operation !== "run") continue;
|
|
4487
|
+
const node = nodesById.get(entry.key);
|
|
4488
|
+
if (!node) continue;
|
|
4489
|
+
const status = workflowLaneTraceStatus(entry.state);
|
|
4490
|
+
if (status) node.status = status;
|
|
4491
|
+
if (entry.agent) node.agent = entry.agent;
|
|
4492
|
+
if (entry.phase && (entry.phase !== "auto-resume" || node.phase === undefined)) node.phase = entry.phase;
|
|
4493
|
+
if (entry.label) node.label = entry.label;
|
|
4494
|
+
if (entry.error) node.error = entry.error;
|
|
4495
|
+
else if (status === "completed" || status === "running") delete node.error;
|
|
4496
|
+
}
|
|
4497
|
+
const currentNodeId = graph.nodes.find((node) => node.status === "running")?.id;
|
|
4498
|
+
if (currentNodeId) graph.currentNodeId = currentNodeId;
|
|
4499
|
+
else delete graph.currentNodeId;
|
|
4500
|
+
}
|
|
4501
|
+
|
|
4414
4502
|
function workflowChatProgressUpdate(
|
|
4415
4503
|
runId: string,
|
|
4416
4504
|
chatProgress: WorkflowChatProgressProjection,
|
|
@@ -4800,6 +4888,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4800
4888
|
liveJob.toolCount = status.toolCount;
|
|
4801
4889
|
liveJob.currentStep = status.currentStep;
|
|
4802
4890
|
liveJob.preflight = status.preflight;
|
|
4891
|
+
liveJob.workflowGraph = status.workflowGraph;
|
|
4803
4892
|
if (status.steps) {
|
|
4804
4893
|
liveJob.steps = status.steps.map((step, index) => ({ ...step, index }));
|
|
4805
4894
|
liveJob.agents = status.steps.map((step) => step.agent);
|
|
@@ -4883,6 +4972,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4883
4972
|
trace: projectedTrace,
|
|
4884
4973
|
...(preflightWarnings.length ? { preflightWarnings } : {}),
|
|
4885
4974
|
};
|
|
4975
|
+
if (status.workflowGraph) applyWorkflowLaneTrace(status.workflowGraph, trace);
|
|
4886
4976
|
const rebuild = trace.length < projectedTraceLength
|
|
4887
4977
|
|| (projectedTraceLength > 0 && trace[projectedTraceLength - 1] !== projectedTraceTail);
|
|
4888
4978
|
if (rebuild) {
|
|
@@ -4986,6 +5076,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4986
5076
|
},
|
|
4987
5077
|
...(workflowState ? { state: workflowState } : {}),
|
|
4988
5078
|
onTrace: updateTrace,
|
|
5079
|
+
onLanePlan: (lanes) => {
|
|
5080
|
+
status.workflowGraph = buildWorkflowLaneGraph(workflowRunId, lanes, status.workflowGraph);
|
|
5081
|
+
applyWorkflowLaneTrace(status.workflowGraph, status.workflow?.trace ?? []);
|
|
5082
|
+
persist({ tolerateStatusWriteFailure: true });
|
|
5083
|
+
},
|
|
4989
5084
|
host: runHostCommand,
|
|
4990
5085
|
onHostStep: (hostStep) => {
|
|
4991
5086
|
status = upsertHostStep({ status, hostStep, persist: (nextStatus) => {
|
|
@@ -5121,6 +5216,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5121
5216
|
}
|
|
5122
5217
|
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, workflowChildren, results: workflow.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), ...(status.steps?.find((step) => step.workflowKey === child.key)?.sessionName ? { sessionName: status.steps?.find((step) => step.workflowKey === child.key)?.sessionName } : {}), ...workflowChildAccountingFields(child), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.outputReference ? { outputReference: child.outputReference } : {}), ...(child.outputPathMapping ? { outputPathMapping: child.outputPathMapping } : {}), ...(child.stopped ? { stopped: true } : {}), ...(child.interrupted ? { interrupted: true } : {}), ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
5123
5218
|
persist();
|
|
5219
|
+
deps.refreshResultDelivery?.();
|
|
5124
5220
|
persistClosed = true;
|
|
5125
5221
|
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}) });
|
|
5126
5222
|
} catch (error) {
|
|
@@ -5166,6 +5262,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5166
5262
|
}
|
|
5167
5263
|
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: status.state === "complete", state: status.state, summary: resultSummary, error: status.state === "complete" ? undefined : status.error, stopped: status.stopped, activityState: status.activityState, workflowChildren, ...(terminalOutcome ? { terminalOutcome } : {}), results: partial.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), ...(status.steps?.find((step) => step.workflowKey === child.key)?.sessionName ? { sessionName: status.steps?.find((step) => step.workflowKey === child.key)?.sessionName } : {}), ...workflowChildAccountingFields(child), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.outputReference ? { outputReference: child.outputReference } : {}), ...(child.terminalOutcome ? { terminalOutcome: child.terminalOutcome } : {}), ...(child.outputPathMapping ? { outputPathMapping: child.outputPathMapping } : {}), ...(child.stopped ? { stopped: true } : {}), ...(child.interrupted ? { interrupted: true } : {}), ...(child.detached && status.state !== "complete" ? { detached: true } : {}), ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
5168
5264
|
persist();
|
|
5265
|
+
deps.refreshResultDelivery?.();
|
|
5169
5266
|
persistClosed = true;
|
|
5170
5267
|
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(terminalOutcome ? { terminalOutcome } : {}), ...(status.error ? { error: status.error } : {}), ...(status.activityState ? { activityState: status.activityState } : {}) });
|
|
5171
5268
|
} finally {
|