pi-subagents 0.72.0 → 0.73.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 +29 -0
- package/docs/agents.md +1 -1
- package/docs/standalone-background.md +1 -1
- package/docs/tool-reference.md +1 -1
- package/docs/workflows.md +5 -1
- package/package.json +1 -1
- package/src/extension/index.d.ts.map +1 -1
- package/src/extension/index.js +2 -0
- package/src/extension/index.js.map +1 -1
- package/src/extension/tool-activation.js +1 -1
- package/src/extension/tool-activation.js.map +1 -1
- package/src/runs/background/run-status.d.ts.map +1 -1
- package/src/runs/background/run-status.js +1 -0
- package/src/runs/background/run-status.js.map +1 -1
- package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/src/runs/foreground/subagent-executor.js +142 -64
- package/src/runs/foreground/subagent-executor.js.map +1 -1
- package/src/runs/shared/async-status-projection.d.ts +3 -0
- package/src/runs/shared/async-status-projection.d.ts.map +1 -1
- package/src/runs/shared/async-status-projection.js +3 -0
- package/src/runs/shared/async-status-projection.js.map +1 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.d.ts.map +1 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.js +11 -12
- package/src/runs/shared/mcp-direct-tool-allowlist.js.map +1 -1
- package/src/shared/extension-context.d.ts +2 -0
- package/src/shared/extension-context.d.ts.map +1 -1
- package/src/shared/extension-context.js +4 -0
- package/src/shared/extension-context.js.map +1 -1
- package/src/shared/model-info.d.ts +4 -0
- package/src/shared/model-info.d.ts.map +1 -1
- package/src/shared/model-info.js +9 -0
- package/src/shared/model-info.js.map +1 -1
- package/src/shared/types.d.ts +2 -0
- package/src/shared/types.d.ts.map +1 -1
- package/src/shared/types.js.map +1 -1
- package/src/tui/fleet-status.d.ts.map +1 -1
- package/src/tui/fleet-status.js +12 -6
- package/src/tui/fleet-status.js.map +1 -1
- package/src/tui/fleet.d.ts.map +1 -1
- package/src/tui/fleet.js +12 -1
- package/src/tui/fleet.js.map +1 -1
- package/src/tui/render.d.ts.map +1 -1
- package/src/tui/render.js +54 -34
- package/src/tui/render.js.map +1 -1
- package/src/tui/running-tone.d.ts +11 -0
- package/src/tui/running-tone.d.ts.map +1 -0
- package/src/tui/running-tone.js +23 -0
- package/src/tui/running-tone.js.map +1 -0
- package/src/workflows/scripted-workflow.d.ts +6 -4
- package/src/workflows/scripted-workflow.d.ts.map +1 -1
- package/src/workflows/scripted-workflow.js +100 -35
- package/src/workflows/scripted-workflow.js.map +1 -1
- package/src/workflows/workflow-checklist.d.ts +4 -0
- package/src/workflows/workflow-checklist.d.ts.map +1 -1
- package/src/workflows/workflow-checklist.js +3 -0
- package/src/workflows/workflow-checklist.js.map +1 -1
|
@@ -101,7 +101,7 @@ import { deepFreezeWorkflowArgs, normalizeWorkflowArgs, resolveWorkflowResource
|
|
|
101
101
|
import { stableJsonDigest } from "../../shared/launch-contract.js";
|
|
102
102
|
import { cleanupWorktrees, createWorktrees, preflightWorktreeSource, withWorktreeTransaction, diffWorktrees, formatWorktreeDiffSummary, } from "../shared/worktree.js";
|
|
103
103
|
import { createWorktreeCleanupPlan, formatWorktreeCleanupPlan } from "../shared/worktree-cleanup-plan.js";
|
|
104
|
-
import { DIRS, DEFAULT_ARTIFACT_CONFIG, DEFAULT_FORK_PREAMBLE, SUBAGENT_ACTIONS, SUBAGENT_ASYNC_STARTED_EVENT, SUBAGENT_CHILD_STATUS_EVENT, SUBAGENT_CONTROL_EVENT, SUBAGENT_CONTROL_INTERCOM_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, checkSubagentDepth, resolveChildMaxSubagentDepth, resolveCurrentMaxSubagentDepth, resolveMaxSubagentSpawnsPerRun, wrapForkTask, } from "../../shared/types.js";
|
|
104
|
+
import { DIRS, DEFAULT_ARTIFACT_CONFIG, DEFAULT_MAX_OUTPUT, DEFAULT_FORK_PREAMBLE, SUBAGENT_ACTIONS, SUBAGENT_ASYNC_STARTED_EVENT, SUBAGENT_CHILD_STATUS_EVENT, SUBAGENT_CONTROL_EVENT, SUBAGENT_CONTROL_INTERCOM_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, checkSubagentDepth, resolveChildMaxSubagentDepth, resolveCurrentMaxSubagentDepth, resolveMaxSubagentSpawnsPerRun, truncateOutput, wrapForkTask, } from "../../shared/types.js";
|
|
105
105
|
import { deriveChildSessionName } from "../../shared/child-session-name.js";
|
|
106
106
|
const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure", "mission.create", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "inspector.open", "inspector.close", "project.open", "project.close", "worktree.discard", "worktree.cleanup", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.rollback", "dismiss", "schedule.create", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"]);
|
|
107
107
|
const DESTRUCTIVE_MANAGEMENT_ACTIONS = new Set(["delete", "eject", "disable", "reset", "mission.close", "worktree.discard", "refine.rollback", "inspector.close", "project.close", "stop", "interrupt", "schedule.delete"]);
|
|
@@ -1518,6 +1518,14 @@ async function resumeAsyncRun(input) {
|
|
|
1518
1518
|
details: { mode: "management", results: [] },
|
|
1519
1519
|
};
|
|
1520
1520
|
}
|
|
1521
|
+
const timeoutOverflowError = timerDelayOverflowError("timeoutMs", input.params.timeoutMs);
|
|
1522
|
+
if (timeoutOverflowError) {
|
|
1523
|
+
return {
|
|
1524
|
+
content: [{ type: "text", text: timeoutOverflowError }],
|
|
1525
|
+
isError: true,
|
|
1526
|
+
details: { mode: "management", results: [] },
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1521
1529
|
if (input.params.model !== undefined) {
|
|
1522
1530
|
return {
|
|
1523
1531
|
content: [{ type: "text", text: "action='resume' reuses the persisted child model and does not accept a model override." }],
|
|
@@ -2134,6 +2142,28 @@ function canonicalizeAgentName(name, agents, diagnostics, context) {
|
|
|
2134
2142
|
return { error: formatUnknownAgentError(name, context) };
|
|
2135
2143
|
return { name: resolved.agent.name };
|
|
2136
2144
|
}
|
|
2145
|
+
// Mirrors child launch: workflow children without their own cwd/agentScope discover agents at the workflow cwd and scope.
|
|
2146
|
+
function workflowValidationOptions(deps, params, runtimeCwd, parentModelProvider) {
|
|
2147
|
+
const cwd = resolveRequestedCwd(runtimeCwd, params.cwd);
|
|
2148
|
+
const scope = resolveExecutionAgentScope(params.agentScope);
|
|
2149
|
+
let discovered;
|
|
2150
|
+
return {
|
|
2151
|
+
maxSubagentSpawnsPerRun: params.maxSubagentSpawnsPerRun ?? resolveMaxSubagentSpawnsPerRun(deps.config.maxSubagentSpawnsPerRun),
|
|
2152
|
+
agentNameError: (name) => {
|
|
2153
|
+
discovered ??= deps.discoverAgents(cwd, scope, parentModelProvider());
|
|
2154
|
+
const { agents } = discovered;
|
|
2155
|
+
const resolved = resolveAgentName(name, agents);
|
|
2156
|
+
if (resolved.agent || resolved.error)
|
|
2157
|
+
return canonicalizeAgentName(name, agents, discovered.agentDiagnostics, diagnosticContextFromDiscovery(discovered, cwd, scope)).error;
|
|
2158
|
+
const requested = name.trim().toLowerCase();
|
|
2159
|
+
const suggestion = [...new Set(agents.flatMap((agent) => [agent.name, ...(agent.localName ? [agent.localName] : []), ...(agent.aliases ?? [])]))]
|
|
2160
|
+
.map((candidate) => ({ candidate, distance: editDistance(requested, candidate.toLowerCase()) }))
|
|
2161
|
+
.filter(({ candidate, distance }) => distance <= Math.max(1, Math.floor(candidate.length / 4)) || hasSingleAdjacentTransposition(requested, candidate.toLowerCase()))
|
|
2162
|
+
.sort((left, right) => left.distance - right.distance || left.candidate.localeCompare(right.candidate))[0]?.candidate;
|
|
2163
|
+
return `Unknown agent '${name}'.${suggestion ? ` Did you mean '${suggestion}'?` : ""} Use subagent({ action: "list" }) to inspect agents.`;
|
|
2164
|
+
},
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2137
2167
|
function canonicalizeExecutionParams(params, agents, diagnostics, context) {
|
|
2138
2168
|
const resolve = (name, location) => {
|
|
2139
2169
|
const result = canonicalizeAgentName(name, agents, diagnostics, context);
|
|
@@ -2535,6 +2565,11 @@ export { DEFAULT_ASYNC_TIMEOUT_MS };
|
|
|
2535
2565
|
* for a timer must stay within this bound.
|
|
2536
2566
|
*/
|
|
2537
2567
|
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
2568
|
+
function timerDelayOverflowError(name, value) {
|
|
2569
|
+
return typeof value === "number" && value > MAX_TIMER_DELAY_MS
|
|
2570
|
+
? `${name} must be a positive integer no larger than ${MAX_TIMER_DELAY_MS}.`
|
|
2571
|
+
: undefined;
|
|
2572
|
+
}
|
|
2538
2573
|
/**
|
|
2539
2574
|
* Resolve the optional global default runtime deadline from extension config
|
|
2540
2575
|
* (`config.timeoutMs`). Returns undefined for unset or invalid values so callers
|
|
@@ -2559,6 +2594,9 @@ export function resolveForegroundTimeout(params, defaultTimeoutMs) {
|
|
|
2559
2594
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
2560
2595
|
return { error: `${name} must be a positive integer.` };
|
|
2561
2596
|
}
|
|
2597
|
+
const overflowError = timerDelayOverflowError(name, value);
|
|
2598
|
+
if (overflowError)
|
|
2599
|
+
return { error: overflowError };
|
|
2562
2600
|
}
|
|
2563
2601
|
if (rawTimeout !== undefined && rawMaxRuntime !== undefined && rawTimeout !== rawMaxRuntime) {
|
|
2564
2602
|
return { error: "timeoutMs and maxRuntimeMs are aliases; provide only one value or use the same value for both." };
|
|
@@ -3170,6 +3208,36 @@ function writeWorkflowAggregateOutput(outputPath, text, producedChildOutputPaths
|
|
|
3170
3208
|
function appendWorkflowOutputWarning(text, warning) {
|
|
3171
3209
|
return warning ? `${text}\n\n${warning}` : text;
|
|
3172
3210
|
}
|
|
3211
|
+
const WORKFLOW_TRACE_ERROR_MAX_CHARS = 500;
|
|
3212
|
+
// Return, emits, console, and trace errors (which carry child text) have no size limit of their
|
|
3213
|
+
// own, so only they are cut; other host sections stay whole. The saved full result is uncut.
|
|
3214
|
+
function formatWorkflowResultText(input) {
|
|
3215
|
+
const traceSection = (error) => input.trace.length > 0
|
|
3216
|
+
? [`Call trace:\n${input.trace.map((entry) => `${entry.line}${entry.error ? ` — ${error(entry.error)}` : ""}`).join("\n")}`]
|
|
3217
|
+
: [];
|
|
3218
|
+
const fullText = [...input.head, ...input.script, ...traceSection((error) => error), ...input.tail].join("\n\n");
|
|
3219
|
+
const outputWarning = writeWorkflowAggregateOutput(input.aggregateOutputPath, fullText, input.producedChildOutputPaths);
|
|
3220
|
+
const scriptText = input.script.join("\n\n");
|
|
3221
|
+
const config = { ...DEFAULT_MAX_OUTPUT, ...input.maxOutput };
|
|
3222
|
+
const scriptCut = truncateOutput(scriptText, config).truncated;
|
|
3223
|
+
const traceCut = input.trace.some((entry) => (entry.error?.length ?? 0) > WORKFLOW_TRACE_ERROR_MAX_CHARS);
|
|
3224
|
+
let shownScriptText = scriptText;
|
|
3225
|
+
let saveWarning;
|
|
3226
|
+
let savedPath;
|
|
3227
|
+
if (scriptCut || traceCut) {
|
|
3228
|
+
const aggregateHoldsFullText = input.aggregateOutputPath !== undefined && !outputWarning
|
|
3229
|
+
&& !input.producedChildOutputPaths.has(resolveWorkflowHostOutputClaimPath(input.aggregateOutputPath));
|
|
3230
|
+
if (!aggregateHoldsFullText)
|
|
3231
|
+
saveWarning = writeWorkflowAggregateOutput(input.fullResultPath, fullText, new Set());
|
|
3232
|
+
savedPath = aggregateHoldsFullText ? input.aggregateOutputPath : saveWarning ? undefined : input.fullResultPath;
|
|
3233
|
+
if (scriptCut)
|
|
3234
|
+
shownScriptText = truncateOutput(scriptText, config, savedPath).text;
|
|
3235
|
+
}
|
|
3236
|
+
const shownTrace = traceSection((error) => error.length > WORKFLOW_TRACE_ERROR_MAX_CHARS ? `${error.slice(0, WORKFLOW_TRACE_ERROR_MAX_CHARS)}… (+${error.length - WORKFLOW_TRACE_ERROR_MAX_CHARS} chars)` : error);
|
|
3237
|
+
const traceNote = traceCut && !scriptCut && savedPath ? [`[TRUNCATED: trace errors shortened - full output at ${savedPath}]`] : [];
|
|
3238
|
+
const text = [...input.head, ...(shownScriptText ? [shownScriptText] : []), ...shownTrace, ...input.tail, ...traceNote].join("\n\n");
|
|
3239
|
+
return appendWorkflowOutputWarning(appendWorkflowOutputWarning(text, outputWarning), saveWarning);
|
|
3240
|
+
}
|
|
3173
3241
|
export function resolveWorkflowChildLocalCwd(input) {
|
|
3174
3242
|
if (input.params.machine !== undefined)
|
|
3175
3243
|
return input.workflowCwd;
|
|
@@ -4536,6 +4604,15 @@ export function createSubagentExecutor(deps) {
|
|
|
4536
4604
|
if (capacityOverrideError)
|
|
4537
4605
|
return buildRequestedModeError(requestParams, capacityOverrideError);
|
|
4538
4606
|
let workflowPreflight;
|
|
4607
|
+
// Only workflow requests read the session here; other actions (for example doctor) must not.
|
|
4608
|
+
const resolveWorkflowParentModel = () => parentModelOverride !== undefined
|
|
4609
|
+
? parentModelOverride
|
|
4610
|
+
: (() => {
|
|
4611
|
+
const currentParentModel = normalizeParentModel(ctx.model);
|
|
4612
|
+
return (preserveActiveSession
|
|
4613
|
+
? currentParentModel
|
|
4614
|
+
: rememberParentModel(deps.state, resolveCurrentSessionId(ctx.sessionManager), currentParentModel)) ?? null;
|
|
4615
|
+
})();
|
|
4539
4616
|
try {
|
|
4540
4617
|
if (requestParams.preflight !== undefined && requestParams.workflowScript === undefined && requestParams.workflowScriptPath === undefined) {
|
|
4541
4618
|
throw new Error("preflight requires workflowScript or workflowScriptPath.");
|
|
@@ -4547,9 +4624,7 @@ export function createSubagentExecutor(deps) {
|
|
|
4547
4624
|
catch (error) {
|
|
4548
4625
|
const message = error instanceof Error ? error.message : String(error);
|
|
4549
4626
|
if (requestParams.action?.trim() === "validate") {
|
|
4550
|
-
const validation = validateWorkflowScript(requestParams.workflowScript ?? "",
|
|
4551
|
-
maxSubagentSpawnsPerRun: requestParams.maxSubagentSpawnsPerRun ?? resolveMaxSubagentSpawnsPerRun(deps.config.maxSubagentSpawnsPerRun),
|
|
4552
|
-
});
|
|
4627
|
+
const validation = validateWorkflowScript(requestParams.workflowScript ?? "", workflowValidationOptions(deps, requestParams, ctx.cwd, () => resolveWorkflowParentModel()?.provider));
|
|
4553
4628
|
const invalidValidation = { ...validation, ok: false, errors: [...validation.errors, { message }] };
|
|
4554
4629
|
return {
|
|
4555
4630
|
content: [{ type: "text", text: JSON.stringify(invalidValidation) }],
|
|
@@ -4560,9 +4635,7 @@ export function createSubagentExecutor(deps) {
|
|
|
4560
4635
|
return buildRequestedModeError(requestParams, message);
|
|
4561
4636
|
}
|
|
4562
4637
|
if (requestParams.action?.trim() === "validate") {
|
|
4563
|
-
const validation = validateWorkflowScript(requestParams.workflowScript ?? "",
|
|
4564
|
-
maxSubagentSpawnsPerRun: requestParams.maxSubagentSpawnsPerRun ?? resolveMaxSubagentSpawnsPerRun(deps.config.maxSubagentSpawnsPerRun),
|
|
4565
|
-
});
|
|
4638
|
+
const validation = validateWorkflowScript(requestParams.workflowScript ?? "", workflowValidationOptions(deps, requestParams, ctx.cwd, () => resolveWorkflowParentModel()?.provider));
|
|
4566
4639
|
return buildWorkflowValidationResult(validation, "management", workflowPreflight);
|
|
4567
4640
|
}
|
|
4568
4641
|
const normalizedAction = typeof requestParams.action === "string" ? requestParams.action.trim() : requestParams.action;
|
|
@@ -4581,14 +4654,13 @@ export function createSubagentExecutor(deps) {
|
|
|
4581
4654
|
const workflowArgsEvidence = requestParams.args === undefined ? undefined : { args: requestParams.args, argsDigest: stableJsonDigest(requestParams.args) };
|
|
4582
4655
|
const workflowArgs = workflowArgsEvidence?.args;
|
|
4583
4656
|
const workflowArgsDigest = workflowArgsEvidence?.argsDigest;
|
|
4584
|
-
const
|
|
4585
|
-
|
|
4586
|
-
});
|
|
4657
|
+
const workflowParentModel = resolveWorkflowParentModel();
|
|
4658
|
+
const workflowValidation = validateWorkflowScript(requestParams.workflowScript, workflowValidationOptions(deps, requestParams, ctx.cwd, () => workflowParentModel?.provider));
|
|
4587
4659
|
if (!workflowValidation.ok && publicExecution)
|
|
4588
4660
|
return buildWorkflowValidationResult(workflowValidation, "workflow", workflowPreflight);
|
|
4589
|
-
const
|
|
4590
|
-
if (
|
|
4591
|
-
return buildRequestedModeError(requestParams, `Workflow '${_id}' validation failed before child launch; no children launched. ${
|
|
4661
|
+
const launchBlockingErrors = workflowValidation.errors.filter((error) => error.kind === "spawn-budget" || error.kind === "agent");
|
|
4662
|
+
if (launchBlockingErrors.length > 0) {
|
|
4663
|
+
return buildRequestedModeError(requestParams, `Workflow '${_id}' validation failed before child launch; no children launched. ${launchBlockingErrors.map((error) => error.message).join(" ")}`);
|
|
4592
4664
|
}
|
|
4593
4665
|
for (const warning of workflowValidation.warnings ?? [])
|
|
4594
4666
|
console.warn(`[pi-subagents] ${warning.message}`);
|
|
@@ -4603,14 +4675,6 @@ export function createSubagentExecutor(deps) {
|
|
|
4603
4675
|
if (requestParams.async !== false)
|
|
4604
4676
|
return buildRequestedModeError(requestParams, "Workflow child permit supports foreground workflow roots only; set async:false.");
|
|
4605
4677
|
}
|
|
4606
|
-
const workflowParentModel = parentModelOverride !== undefined
|
|
4607
|
-
? parentModelOverride
|
|
4608
|
-
: (() => {
|
|
4609
|
-
const currentParentModel = normalizeParentModel(ctx.model);
|
|
4610
|
-
return (preserveActiveSession
|
|
4611
|
-
? currentParentModel
|
|
4612
|
-
: rememberParentModel(deps.state, resolveCurrentSessionId(ctx.sessionManager), currentParentModel)) ?? null;
|
|
4613
|
-
})();
|
|
4614
4678
|
if (requestParams.extensionBindings !== undefined) {
|
|
4615
4679
|
try {
|
|
4616
4680
|
requestParams.extensionBindings = normalizeExtensionBindings(requestParams.extensionBindings).value;
|
|
@@ -4620,6 +4684,13 @@ export function createSubagentExecutor(deps) {
|
|
|
4620
4684
|
}
|
|
4621
4685
|
}
|
|
4622
4686
|
const parentCwd = ctx.cwd;
|
|
4687
|
+
for (const [name, value] of [["timeoutMs", requestParams.timeoutMs], ["maxRuntimeMs", requestParams.maxRuntimeMs]]) {
|
|
4688
|
+
if (value === undefined)
|
|
4689
|
+
continue;
|
|
4690
|
+
const overflowError = timerDelayOverflowError(name, value);
|
|
4691
|
+
if (overflowError)
|
|
4692
|
+
return buildRequestedModeError(requestParams, overflowError);
|
|
4693
|
+
}
|
|
4623
4694
|
const timeout = requestParams.timeoutMs ?? requestParams.maxRuntimeMs ?? (requestParams.async === false ? resolveConfigDefaultTimeoutMs(deps.config.timeoutMs) ?? DEFAULT_FOREGROUND_TIMEOUT_MS : undefined);
|
|
4624
4695
|
const workflowUsageBudget = validateUsageBudgetConfig(requestParams.usageBudget ?? deps.config.usageBudget, requestParams.usageBudget ? "usageBudget" : "config.usageBudget");
|
|
4625
4696
|
if (workflowUsageBudget.error)
|
|
@@ -5522,10 +5593,13 @@ export function createSubagentExecutor(deps) {
|
|
|
5522
5593
|
});
|
|
5523
5594
|
const finalPreflightWarnings = workflowPreflightWarnings(workflowPreflight, workflow.trace, { settled: true });
|
|
5524
5595
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(workflow.trace, workflowPreflight);
|
|
5525
|
-
const
|
|
5526
|
-
const
|
|
5596
|
+
const returnText = formatWorkflowValue(workflow.value);
|
|
5597
|
+
const emitText = workflow.emits.map(formatWorkflowValue).join(", ");
|
|
5598
|
+
const returnPreview = returnText.length > 1_000 ? `${returnText.slice(0, 1_000)}…` : returnText;
|
|
5599
|
+
const emitPreview = workflow.emits.length > 0 ? ` Emitted: ${emitText.length > 1_000 ? `${emitText.slice(0, 1_000)}…` : emitText}` : "";
|
|
5600
|
+
const previewNote = returnText.length > 1_000 || emitText.length > 1_000 ? ` (truncated; full return value and emits: ${statusPath} (workflow.value, workflow.emits))` : "";
|
|
5527
5601
|
const runningSummary = workflowRunningChildrenSummary(workflow.children);
|
|
5528
|
-
const summary = `${runningSummary ? `Workflow dispatch completed; ${runningSummary}` : `Workflow completed with ${workflow.children.length} child run(s).`} Return: ${returnPreview}${emitPreview} Trace: ${workflow.trace.length} event(s).${workflowOutputPathMappingSummary(workflow.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
|
|
5602
|
+
const summary = `${runningSummary ? `Workflow dispatch completed; ${runningSummary}` : `Workflow completed with ${workflow.children.length} child run(s).`} Return: ${returnPreview}${emitPreview}${previewNote} Trace: ${workflow.trace.length} event(s).${workflowOutputPathMappingSummary(workflow.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
|
|
5529
5603
|
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, summary, producedChildOutputPaths);
|
|
5530
5604
|
const resultSummary = appendWorkflowOutputWarning(summary, outputWarning);
|
|
5531
5605
|
const workflowUsage = sumResultsUsage(workflowResults);
|
|
@@ -5576,15 +5650,17 @@ export function createSubagentExecutor(deps) {
|
|
|
5576
5650
|
const workflowChildren = workflowChildSummary({ parentToolCallId: toolCallId, workflowRunId, workflowState, inventoryComplete: true, trace: partial.trace, children: partial.children, steps: status.steps });
|
|
5577
5651
|
const finalPreflightWarnings = workflowPreflightWarnings(workflowPreflight, partial.trace, { settled: true });
|
|
5578
5652
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(partial.trace, workflowPreflight);
|
|
5579
|
-
status = compactOptional({ ...status, state, stopped: stopped || undefined, activityState: pauseForDetached || status.activityState === "needs_attention" ? "needs_attention" : undefined, error: workflowFailureMessage(error, workflowRunId, partial.children), endedAt: Date.now(), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}) }, workflowChildren });
|
|
5653
|
+
status = compactOptional({ ...status, state, stopped: stopped || undefined, activityState: pauseForDetached || status.activityState === "needs_attention" ? "needs_attention" : undefined, error: workflowFailureMessage(error, workflowRunId, partial.children), endedAt: Date.now(), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(error instanceof WorkflowScriptError && error.errorKind ? { failureKind: error.errorKind } : {}), ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}) }, workflowChildren });
|
|
5580
5654
|
if (pauseForDetached) {
|
|
5581
5655
|
const promoted = promotePausedWorkflowIfSettled(status);
|
|
5582
5656
|
if (promoted)
|
|
5583
5657
|
status = promoted;
|
|
5584
5658
|
}
|
|
5659
|
+
// A script can throw an error of any size; status.json keeps the full text.
|
|
5660
|
+
const errorPreview = status.error && status.error.length > 1_000 ? `${status.error.slice(0, 1_000)}… (truncated; full error: ${statusPath} (error))` : status.error;
|
|
5585
5661
|
const terminalSummary = `${status.state === "complete"
|
|
5586
5662
|
? "Workflow completed after detached child finished."
|
|
5587
|
-
:
|
|
5663
|
+
: errorPreview ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.")}${workflowOutputPathMappingSummary(partial.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
|
|
5588
5664
|
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, terminalSummary, producedChildOutputPaths);
|
|
5589
5665
|
const resultSummary = appendWorkflowOutputWarning(terminalSummary, outputWarning);
|
|
5590
5666
|
const receiptState = status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
|
|
@@ -5632,6 +5708,9 @@ export function createSubagentExecutor(deps) {
|
|
|
5632
5708
|
const workflowOutput = typeof workflowChildDefaults.output === "string" || typeof workflowChildDefaults.output === "boolean" ? workflowChildDefaults.output : undefined;
|
|
5633
5709
|
const configuredOutputBaseDir = resolveConfiguredSingleRunOutputBaseDir(deps);
|
|
5634
5710
|
const workflowAggregateOutputPath = resolveSingleOutputPath(workflowOutput, ctx.cwd, workflowCwd, resolveSingleRunOutputBaseDir(deps, workflowArtifactsDir, foregroundWorkflowRunId));
|
|
5711
|
+
// A top-level artifact file: outside outputs/, where children save their reports, and
|
|
5712
|
+
// within artifact retention, which only removes top-level files.
|
|
5713
|
+
const workflowFullResultPath = path.join(workflowArtifactsDir, `${sanitizeRunPathSegment(foregroundWorkflowRunId)}_workflow-result.md`);
|
|
5635
5714
|
const claimedOutputPaths = new Map();
|
|
5636
5715
|
const childOutputOverrides = new Map();
|
|
5637
5716
|
const childOutputClaimPaths = new Map();
|
|
@@ -5810,27 +5889,26 @@ export function createSubagentExecutor(deps) {
|
|
|
5810
5889
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(workflow.trace, workflowPreflight);
|
|
5811
5890
|
const workflowChildren = workflowChildSummary({ parentToolCallId: _id, workflowRunId: foregroundWorkflowRunId, workflowState: "completed", inventoryComplete: true, trace: workflow.trace, children: workflow.children });
|
|
5812
5891
|
const receipt = terminalWorkflowReceipt(foregroundWorkflowRunId, "complete", workflow.children, workflowChildren, undefined, [...workflowHostSteps.values()], workflowResource?.provenance, workflowArgsDigest);
|
|
5813
|
-
const
|
|
5892
|
+
const trace = finalPreflightTrace.map((entry) => ({ line: `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.durationMs !== undefined ? ` in ${entry.durationMs}ms` : ""}${entry.warning ? ` — ${entry.warning}` : ""}`, error: entry.error }));
|
|
5814
5893
|
const runningSummary = workflowRunningChildrenSummary(workflow.children);
|
|
5815
|
-
const sections = [
|
|
5816
|
-
...(workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : []),
|
|
5817
|
-
runningSummary ? `Workflow dispatch completed; ${runningSummary}` : "Workflow completed.",
|
|
5818
|
-
`Return:\n${formatWorkflowValue(workflow.value)}`,
|
|
5819
|
-
];
|
|
5820
|
-
if (workflow.emits.length > 0)
|
|
5821
|
-
sections.push(`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5822
|
-
if (workflow.console.length > 0)
|
|
5823
|
-
sections.push(`Console:\n${workflow.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5824
|
-
if (traceLines.length > 0)
|
|
5825
|
-
sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
5826
|
-
if (finalPreflightWarnings.length > 0)
|
|
5827
|
-
sections.push(formatWorkflowPreflightWarnings(finalPreflightWarnings));
|
|
5828
5894
|
const outputMappings = workflowOutputPathMappingSummary(workflow.children).trim();
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5895
|
+
const displayText = formatWorkflowResultText({
|
|
5896
|
+
head: [...(workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : []), runningSummary ? `Workflow dispatch completed; ${runningSummary}` : "Workflow completed."],
|
|
5897
|
+
script: [
|
|
5898
|
+
`Return:\n${formatWorkflowValue(workflow.value)}`,
|
|
5899
|
+
...(workflow.emits.length > 0 ? [`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`] : []),
|
|
5900
|
+
...(workflow.console.length > 0 ? [`Console:\n${workflow.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`] : []),
|
|
5901
|
+
],
|
|
5902
|
+
trace,
|
|
5903
|
+
tail: [
|
|
5904
|
+
...(finalPreflightWarnings.length > 0 ? [formatWorkflowPreflightWarnings(finalPreflightWarnings)] : []),
|
|
5905
|
+
...(outputMappings ? [outputMappings] : []),
|
|
5906
|
+
],
|
|
5907
|
+
maxOutput: requestParams.maxOutput,
|
|
5908
|
+
aggregateOutputPath: workflowAggregateOutputPath,
|
|
5909
|
+
fullResultPath: workflowFullResultPath,
|
|
5910
|
+
producedChildOutputPaths,
|
|
5911
|
+
});
|
|
5834
5912
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5835
5913
|
content: [{ type: "text", text: displayText }],
|
|
5836
5914
|
details: compactOptional({ mode: "workflow", runId: foregroundWorkflowRunId, results: workflowDetailsResults(workflow.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: finalPreflightTrace, emits: workflow.emits, console: workflow.console, ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
@@ -5841,32 +5919,32 @@ export function createSubagentExecutor(deps) {
|
|
|
5841
5919
|
const text = workflowFailureMessage(error, foregroundWorkflowRunId, partial.children);
|
|
5842
5920
|
const finalPreflightWarnings = workflowPreflightWarnings(workflowPreflight, partial.trace, { settled: true });
|
|
5843
5921
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(partial.trace, workflowPreflight);
|
|
5844
|
-
const
|
|
5845
|
-
const sections = [
|
|
5846
|
-
...(workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : []),
|
|
5847
|
-
`Workflow failed: ${text}`,
|
|
5848
|
-
];
|
|
5849
|
-
if (partial.emits.length > 0)
|
|
5850
|
-
sections.push(`Emitted:\n${partial.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5851
|
-
if (partial.console.length > 0)
|
|
5852
|
-
sections.push(`Console:\n${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5853
|
-
if (traceLines.length > 0)
|
|
5854
|
-
sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
5855
|
-
if (finalPreflightWarnings.length > 0)
|
|
5856
|
-
sections.push(formatWorkflowPreflightWarnings(finalPreflightWarnings));
|
|
5922
|
+
const trace = finalPreflightTrace.map((entry) => ({ line: `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.warning ? ` — ${entry.warning}` : ""}`, error: entry.error }));
|
|
5857
5923
|
const outputMappings = workflowOutputPathMappingSummary(partial.children).trim();
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5924
|
+
const displayText = formatWorkflowResultText({
|
|
5925
|
+
head: workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : [],
|
|
5926
|
+
script: [
|
|
5927
|
+
`Workflow failed: ${text}`,
|
|
5928
|
+
...(partial.emits.length > 0 ? [`Emitted:\n${partial.emits.map(formatWorkflowValue).join("\n")}`] : []),
|
|
5929
|
+
...(partial.console.length > 0 ? [`Console:\n${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`] : []),
|
|
5930
|
+
],
|
|
5931
|
+
trace,
|
|
5932
|
+
tail: [
|
|
5933
|
+
...(finalPreflightWarnings.length > 0 ? [formatWorkflowPreflightWarnings(finalPreflightWarnings)] : []),
|
|
5934
|
+
...(outputMappings ? [outputMappings] : []),
|
|
5935
|
+
],
|
|
5936
|
+
maxOutput: requestParams.maxOutput,
|
|
5937
|
+
aggregateOutputPath: workflowAggregateOutputPath,
|
|
5938
|
+
fullResultPath: workflowFullResultPath,
|
|
5939
|
+
producedChildOutputPaths,
|
|
5940
|
+
});
|
|
5863
5941
|
const workflowChildren = workflowChildSummary({ parentToolCallId: _id, workflowRunId: foregroundWorkflowRunId, workflowState: "failed", inventoryComplete: true, trace: partial.trace, children: partial.children });
|
|
5864
5942
|
const terminalOutcome = workflowFailureTerminalOutcome(error, partial.children, usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)));
|
|
5865
5943
|
const receipt = terminalWorkflowReceipt(foregroundWorkflowRunId, "failed", partial.children, workflowChildren, terminalOutcome, [...workflowHostSteps.values()], workflowResource?.provenance, workflowArgsDigest);
|
|
5866
5944
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5867
5945
|
content: [{ type: "text", text: displayText }],
|
|
5868
5946
|
isError: true,
|
|
5869
|
-
details: compactOptional({ mode: "workflow", runId: foregroundWorkflowRunId, results: workflowDetailsResults(partial.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5947
|
+
details: compactOptional({ mode: "workflow", runId: foregroundWorkflowRunId, results: workflowDetailsResults(partial.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(error instanceof WorkflowScriptError && error.errorKind ? { failureKind: error.errorKind } : {}), ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5870
5948
|
}, workflowFanoutBudget));
|
|
5871
5949
|
}
|
|
5872
5950
|
finally {
|