pi-subagents 0.77.0 → 0.79.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 +93 -0
- package/agents/evidence-auditor.md +1 -0
- package/agents/oracle.md +1 -0
- package/agents/reviewer.md +1 -0
- package/docs/agents.md +4 -2
- package/docs/configuration.md +22 -6
- package/docs/extension-api.md +9 -1
- package/docs/observability.md +11 -3
- package/docs/tool-reference.md +14 -3
- package/docs/workflows.md +6 -4
- package/package.json +1 -1
- package/skills/pi-subagents/SKILL.md +2 -1
- package/skills/pi-subagents/references/execution-controls.md +2 -0
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/src/api/external-runs.d.ts.map +1 -1
- package/src/api/external-runs.js +5 -4
- package/src/api/external-runs.js.map +1 -1
- package/src/api/preflight.js +1 -1
- package/src/api/preflight.js.map +1 -1
- package/src/extension/active-runs-prompt.d.ts +8 -0
- package/src/extension/active-runs-prompt.d.ts.map +1 -0
- package/src/extension/active-runs-prompt.js +30 -0
- package/src/extension/active-runs-prompt.js.map +1 -0
- package/src/extension/config.d.ts.map +1 -1
- package/src/extension/config.js +6 -0
- package/src/extension/config.js.map +1 -1
- package/src/extension/declaration-pinning.d.ts +5 -0
- package/src/extension/declaration-pinning.d.ts.map +1 -1
- package/src/extension/declaration-pinning.js +24 -3
- package/src/extension/declaration-pinning.js.map +1 -1
- package/src/extension/index.d.ts +0 -1
- package/src/extension/index.d.ts.map +1 -1
- package/src/extension/index.js +73 -18
- package/src/extension/index.js.map +1 -1
- package/src/extension/public-execution.d.ts +1 -0
- package/src/extension/public-execution.d.ts.map +1 -1
- package/src/extension/public-execution.js +3 -0
- package/src/extension/public-execution.js.map +1 -1
- package/src/extension/rpc.d.ts.map +1 -1
- package/src/extension/rpc.js +5 -3
- package/src/extension/rpc.js.map +1 -1
- package/src/extension/schemas.d.ts +2 -0
- package/src/extension/schemas.d.ts.map +1 -1
- package/src/extension/schemas.js +1 -0
- package/src/extension/schemas.js.map +1 -1
- package/src/extension/tool-activation.d.ts.map +1 -1
- package/src/extension/tool-activation.js +25 -6
- package/src/extension/tool-activation.js.map +1 -1
- package/src/intercom/native-supervisor-channel.d.ts +18 -2
- package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
- package/src/intercom/native-supervisor-channel.js +130 -15
- package/src/intercom/native-supervisor-channel.js.map +1 -1
- package/src/runs/background/active-async-capacity.d.ts +2 -1
- package/src/runs/background/active-async-capacity.d.ts.map +1 -1
- package/src/runs/background/active-async-capacity.js +10 -6
- package/src/runs/background/active-async-capacity.js.map +1 -1
- package/src/runs/background/async-execution.js +3 -3
- package/src/runs/background/async-execution.js.map +1 -1
- package/src/runs/background/async-resume.d.ts.map +1 -1
- package/src/runs/background/async-resume.js +5 -2
- package/src/runs/background/async-resume.js.map +1 -1
- package/src/runs/background/async-status-snapshot.d.ts.map +1 -1
- package/src/runs/background/async-status-snapshot.js +4 -2
- package/src/runs/background/async-status-snapshot.js.map +1 -1
- package/src/runs/background/async-status.d.ts.map +1 -1
- package/src/runs/background/async-status.js +10 -6
- package/src/runs/background/async-status.js.map +1 -1
- package/src/runs/background/chain-root-attachment.js +4 -4
- package/src/runs/background/chain-root-attachment.js.map +1 -1
- package/src/runs/background/control-channel.d.ts +1 -0
- package/src/runs/background/control-channel.d.ts.map +1 -1
- package/src/runs/background/control-channel.js +27 -3
- package/src/runs/background/control-channel.js.map +1 -1
- package/src/runs/background/inspect-rpc.d.ts +5 -0
- package/src/runs/background/inspect-rpc.d.ts.map +1 -1
- package/src/runs/background/inspect-rpc.js +20 -3
- package/src/runs/background/inspect-rpc.js.map +1 -1
- package/src/runs/background/notify.d.ts +1 -1
- package/src/runs/background/notify.d.ts.map +1 -1
- package/src/runs/background/notify.js +8 -4
- package/src/runs/background/notify.js.map +1 -1
- package/src/runs/background/result-delivery-ownership.d.ts +0 -2
- package/src/runs/background/result-delivery-ownership.d.ts.map +1 -1
- package/src/runs/background/result-delivery-ownership.js +5 -21
- package/src/runs/background/result-delivery-ownership.js.map +1 -1
- package/src/runs/background/result-files.d.ts +5 -3
- package/src/runs/background/result-files.d.ts.map +1 -1
- package/src/runs/background/result-files.js +10 -6
- package/src/runs/background/result-files.js.map +1 -1
- package/src/runs/background/result-watcher.d.ts.map +1 -1
- package/src/runs/background/result-watcher.js +15 -8
- package/src/runs/background/result-watcher.js.map +1 -1
- package/src/runs/background/resume-guidance.d.ts.map +1 -1
- package/src/runs/background/resume-guidance.js +3 -2
- package/src/runs/background/resume-guidance.js.map +1 -1
- package/src/runs/background/run-child-session.d.ts.map +1 -1
- package/src/runs/background/run-child-session.js +13 -17
- package/src/runs/background/run-child-session.js.map +1 -1
- package/src/runs/background/run-status.d.ts.map +1 -1
- package/src/runs/background/run-status.js +11 -4
- package/src/runs/background/run-status.js.map +1 -1
- package/src/runs/background/runner-aliases.d.ts.map +1 -1
- package/src/runs/background/runner-aliases.js +11 -8
- package/src/runs/background/runner-aliases.js.map +1 -1
- package/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/src/runs/background/subagent-runner.js +212 -283
- package/src/runs/background/subagent-runner.js.map +1 -1
- package/src/runs/background/workflow-terminal-proof.d.ts +1 -1
- package/src/runs/background/workflow-terminal-proof.d.ts.map +1 -1
- package/src/runs/background/workflow-terminal-proof.js +12 -3
- package/src/runs/background/workflow-terminal-proof.js.map +1 -1
- package/src/runs/foreground/async-dismiss-action.d.ts.map +1 -1
- package/src/runs/foreground/async-dismiss-action.js +2 -1
- package/src/runs/foreground/async-dismiss-action.js.map +1 -1
- package/src/runs/foreground/async-steering-action.d.ts.map +1 -1
- package/src/runs/foreground/async-steering-action.js +3 -2
- package/src/runs/foreground/async-steering-action.js.map +1 -1
- package/src/runs/foreground/async-stop-action.d.ts +1 -0
- package/src/runs/foreground/async-stop-action.d.ts.map +1 -1
- package/src/runs/foreground/async-stop-action.js +9 -8
- package/src/runs/foreground/async-stop-action.js.map +1 -1
- package/src/runs/foreground/command-action.d.ts.map +1 -1
- package/src/runs/foreground/command-action.js +2 -1
- package/src/runs/foreground/command-action.js.map +1 -1
- package/src/runs/foreground/execution.d.ts.map +1 -1
- package/src/runs/foreground/execution.js +67 -60
- package/src/runs/foreground/execution.js.map +1 -1
- package/src/runs/foreground/subagent-executor.d.ts +2 -0
- package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/src/runs/foreground/subagent-executor.js +124 -67
- package/src/runs/foreground/subagent-executor.js.map +1 -1
- package/src/runs/shared/async-status-projection.d.ts +4 -0
- package/src/runs/shared/async-status-projection.d.ts.map +1 -1
- package/src/runs/shared/async-status-projection.js +23 -1
- package/src/runs/shared/async-status-projection.js.map +1 -1
- package/src/runs/shared/child-commands.d.ts +2 -0
- package/src/runs/shared/child-commands.d.ts.map +1 -1
- package/src/runs/shared/child-commands.js +4 -0
- package/src/runs/shared/child-commands.js.map +1 -1
- package/src/runs/shared/child-runtime-config.d.ts +6 -0
- package/src/runs/shared/child-runtime-config.d.ts.map +1 -1
- package/src/runs/shared/child-runtime-config.js +6 -0
- package/src/runs/shared/child-runtime-config.js.map +1 -1
- package/src/runs/shared/child-session.d.ts +2 -2
- package/src/runs/shared/child-session.d.ts.map +1 -1
- package/src/runs/shared/child-session.js +104 -42
- package/src/runs/shared/child-session.js.map +1 -1
- package/src/runs/shared/effective-system-prompt.d.ts +4 -4
- package/src/runs/shared/effective-system-prompt.d.ts.map +1 -1
- package/src/runs/shared/effective-system-prompt.js +5 -4
- package/src/runs/shared/effective-system-prompt.js.map +1 -1
- package/src/runs/shared/external-cli-runner.d.ts.map +1 -1
- package/src/runs/shared/external-cli-runner.js +3 -2
- package/src/runs/shared/external-cli-runner.js.map +1 -1
- package/src/runs/shared/long-running-guard.d.ts +3 -1
- package/src/runs/shared/long-running-guard.d.ts.map +1 -1
- package/src/runs/shared/long-running-guard.js +4 -14
- package/src/runs/shared/long-running-guard.js.map +1 -1
- package/src/runs/shared/model-resolution-diagnostic.d.ts +7 -5
- package/src/runs/shared/model-resolution-diagnostic.d.ts.map +1 -1
- package/src/runs/shared/model-resolution-diagnostic.js +13 -10
- package/src/runs/shared/model-resolution-diagnostic.js.map +1 -1
- package/src/runs/shared/model-resolution.d.ts +5 -1
- package/src/runs/shared/model-resolution.d.ts.map +1 -1
- package/src/runs/shared/model-resolution.js +8 -1
- package/src/runs/shared/model-resolution.js.map +1 -1
- package/src/runs/shared/nested-events.d.ts.map +1 -1
- package/src/runs/shared/nested-events.js +2 -0
- package/src/runs/shared/nested-events.js.map +1 -1
- package/src/runs/shared/orca-progress-tabs.js +1 -1
- package/src/runs/shared/orca-progress-tabs.js.map +1 -1
- package/src/runs/shared/partial-output.d.ts +7 -0
- package/src/runs/shared/partial-output.d.ts.map +1 -1
- package/src/runs/shared/partial-output.js +7 -0
- package/src/runs/shared/partial-output.js.map +1 -1
- package/src/runs/shared/run-ownership.d.ts +4 -0
- package/src/runs/shared/run-ownership.d.ts.map +1 -0
- package/src/runs/shared/run-ownership.js +9 -0
- package/src/runs/shared/run-ownership.js.map +1 -0
- package/src/runs/shared/single-output.d.ts +11 -1
- package/src/runs/shared/single-output.d.ts.map +1 -1
- package/src/runs/shared/single-output.js +48 -26
- package/src/runs/shared/single-output.js.map +1 -1
- package/src/runs/shared/structured-output.d.ts +2 -0
- package/src/runs/shared/structured-output.d.ts.map +1 -1
- package/src/runs/shared/structured-output.js +9 -0
- package/src/runs/shared/structured-output.js.map +1 -1
- package/src/runs/shared/subagent-control.d.ts +1 -0
- package/src/runs/shared/subagent-control.d.ts.map +1 -1
- package/src/runs/shared/subagent-control.js +2 -1
- package/src/runs/shared/subagent-control.js.map +1 -1
- package/src/runs/shared/subagent-prompt-runtime.d.ts +56 -0
- package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
- package/src/runs/shared/subagent-prompt-runtime.js +192 -6
- package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
- package/src/runs/shared/tool-budget.js +1 -1
- package/src/runs/shared/tool-budget.js.map +1 -1
- package/src/shared/child-transcript.js +1 -1
- package/src/shared/child-transcript.js.map +1 -1
- package/src/shared/extension-context.d.ts +5 -0
- package/src/shared/extension-context.d.ts.map +1 -1
- package/src/shared/extension-context.js +7 -0
- package/src/shared/extension-context.js.map +1 -1
- package/src/shared/file-lease.d.ts +7 -1
- package/src/shared/file-lease.d.ts.map +1 -1
- package/src/shared/file-lease.js +8 -2
- package/src/shared/file-lease.js.map +1 -1
- package/src/shared/fork-context.d.ts +3 -1
- package/src/shared/fork-context.d.ts.map +1 -1
- package/src/shared/fork-context.js +23 -13
- package/src/shared/fork-context.js.map +1 -1
- package/src/shared/parent-wake.d.ts +6 -0
- package/src/shared/parent-wake.d.ts.map +1 -1
- package/src/shared/parent-wake.js +11 -0
- package/src/shared/parent-wake.js.map +1 -1
- package/src/shared/session-succession.d.ts +5 -0
- package/src/shared/session-succession.d.ts.map +1 -0
- package/src/shared/session-succession.js +25 -0
- package/src/shared/session-succession.js.map +1 -0
- package/src/shared/types.d.ts +22 -9
- package/src/shared/types.d.ts.map +1 -1
- package/src/shared/types.js +7 -4
- package/src/shared/types.js.map +1 -1
- package/src/shared/utils.d.ts +13 -0
- package/src/shared/utils.d.ts.map +1 -1
- package/src/shared/utils.js +19 -0
- package/src/shared/utils.js.map +1 -1
- package/src/slash/slash-commands.d.ts.map +1 -1
- package/src/slash/slash-commands.js +22 -11
- package/src/slash/slash-commands.js.map +1 -1
- package/src/slash/subagents-admin.d.ts.map +1 -1
- package/src/slash/subagents-admin.js +3 -2
- package/src/slash/subagents-admin.js.map +1 -1
- package/src/tui/fleet-status.d.ts +5 -0
- package/src/tui/fleet-status.d.ts.map +1 -1
- package/src/tui/fleet-status.js +24 -3
- package/src/tui/fleet-status.js.map +1 -1
- package/src/tui/fleet.js +2 -2
- package/src/tui/fleet.js.map +1 -1
- package/src/watchdog/change-signature.d.ts.map +1 -1
- package/src/watchdog/change-signature.js +1 -3
- package/src/watchdog/change-signature.js.map +1 -1
- package/src/watchdog/register-main.js +2 -2
- package/src/watchdog/register-main.js.map +1 -1
- package/src/watchdog/runtime.d.ts.map +1 -1
- package/src/watchdog/runtime.js +3 -5
- package/src/watchdog/runtime.js.map +1 -1
- package/src/workflows/scripted-workflow.d.ts +1 -1
- package/src/workflows/scripted-workflow.d.ts.map +1 -1
- package/src/workflows/scripted-workflow.js +13 -4
- package/src/workflows/scripted-workflow.js.map +1 -1
- package/src/workflows/workflow-child-summary.d.ts +5 -0
- package/src/workflows/workflow-child-summary.d.ts.map +1 -1
- package/src/workflows/workflow-child-summary.js +10 -0
- package/src/workflows/workflow-child-summary.js.map +1 -1
- package/src/workflows/workflow-reuse.d.ts +6 -1
- package/src/workflows/workflow-reuse.d.ts.map +1 -1
- package/src/workflows/workflow-reuse.js +22 -1
- package/src/workflows/workflow-reuse.js.map +1 -1
- package/src/runs/shared/run-history.d.ts +0 -67
- package/src/runs/shared/run-history.d.ts.map +0 -1
- package/src/runs/shared/run-history.js +0 -270
- package/src/runs/shared/run-history.js.map +0 -1
|
@@ -27,7 +27,6 @@ import { normalizeParentModel, resolveEffectiveSubagentModel, resolveModelOrigin
|
|
|
27
27
|
import { projectChainOutputSchemas, resolveEffectiveOutputSchema } from "../shared/child-launch-plan.js";
|
|
28
28
|
import { formatRetainedChildren, listRetainedChildren } from "../background/retained-children.js";
|
|
29
29
|
import { resolveModelScopesForAgent } from "../shared/model-scope.js";
|
|
30
|
-
import { recordRun } from "../shared/run-history.js";
|
|
31
30
|
import { getStepAgents, isParallelStep, isDynamicParallelStep, resolveExistingReadPaths, } from "../../shared/settings.js";
|
|
32
31
|
import { normalizeSkillInput } from "../../agents/skills.js";
|
|
33
32
|
import { buildAsyncRunnerSteps, DEFAULT_ASYNC_TIMEOUT_MS, executeAsyncChain, executeAsyncSingle, formatAsyncStartedMessage, isAsyncAvailable, workflowAwaitedAsyncResultPath } from "../background/async-execution.js";
|
|
@@ -69,6 +68,7 @@ import { canQueueRetainedAsyncFollowUp, steerAsyncRun } from "./async-steering-a
|
|
|
69
68
|
import { resolveWorkflowForegroundSteeringTarget, steerWorkflowForegroundTarget, steerWorkflowRun, } from "./workflow-foreground-steering.js";
|
|
70
69
|
import { stopAsyncRun } from "./async-stop-action.js";
|
|
71
70
|
import { dismissRecoveredWorkflow } from "./async-dismiss-action.js";
|
|
71
|
+
import { inheritedSessionIds } from "../../shared/session-succession.js";
|
|
72
72
|
import { promotePausedWorkflowIfSettled, reconcileDetachedWorkflowChildCompletion } from "./workflow-detach-reconcile.js";
|
|
73
73
|
import { reconcileAsyncRun } from "../background/stale-run-reconciler.js";
|
|
74
74
|
import { resolveAsyncRootResultPath, waitForImportedAsyncRoot } from "../background/chain-root-attachment.js";
|
|
@@ -95,7 +95,7 @@ import { getInspectorPlugins } from "../../inspectors/plugins.js";
|
|
|
95
95
|
import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.js";
|
|
96
96
|
import { previewSimpleWorkflowRun, runWorkflowScript, validateWorkflowScript, WorkflowScriptError } from "../../workflows/scripted-workflow.js";
|
|
97
97
|
import { formatIncrementalChildCompletion, incrementalChildCompletionTriggersTurn } from "../background/notify.js";
|
|
98
|
-
import { appendWorkflowChildJournal, findWorkflowReuseSource, matchWorkflowReuse, workflowChildFingerprint, workflowScriptDigest, workflowStopCause
|
|
98
|
+
import { appendWorkflowChildJournal, findWorkflowReuseSource, matchWorkflowReuse, readNamedWorkflowReuseSource, workflowChildFingerprint, workflowRuntimeReplacedRelaunchNotice, workflowScriptDigest, workflowStopCause } from "../../workflows/workflow-reuse.js";
|
|
99
99
|
import { executeWorkflowHostCommand, resolveWorkflowHostOutputClaimPath } from "../../workflows/host-command.js";
|
|
100
100
|
import { buildWorkflowReceipt, readWorkflowReceipt, workflowReceiptPath, resolveWorkflowReceiptResumeEntry, writeWorkflowReceipt } from "../../workflows/workflow-receipt.js";
|
|
101
101
|
import { formatWorkflowKeyRevival, recordWorkflowRevival, withWorkflowRevivals } from "../../workflows/workflow-revival.js";
|
|
@@ -271,11 +271,12 @@ function nestedResolutionScopeForExecutor(deps) {
|
|
|
271
271
|
...(address ? { descendantOf: { parentRunId: address.parentRunId, ...(address.parentStepIndex !== undefined ? { parentStepIndex: address.parentStepIndex } : {}) } } : {}),
|
|
272
272
|
};
|
|
273
273
|
}
|
|
274
|
-
function
|
|
274
|
+
function trustedSessionRoots(parentSessionFile, deps) {
|
|
275
275
|
const roots = deps.config.defaultSessionDir ? [path.resolve(deps.expandTilde(deps.config.defaultSessionDir))] : [];
|
|
276
|
-
|
|
276
|
+
// Inherited runs keep their children under the root of the session that launched them.
|
|
277
277
|
if (parentSessionFile)
|
|
278
|
-
|
|
278
|
+
for (const sessionFile of [parentSessionFile, ...inheritedSessionIds(parentSessionFile)])
|
|
279
|
+
roots.push(deps.getSubagentSessionRoot(sessionFile));
|
|
279
280
|
return [...new Set(roots)];
|
|
280
281
|
}
|
|
281
282
|
/** Children follow the launching session's trust; hosts older than Pi's trust concept keep Pi's default. */
|
|
@@ -637,6 +638,7 @@ function resolveForegroundResumeTarget(params, state, options = {}) {
|
|
|
637
638
|
...(child.thinking ? { thinking: child.thinking } : {}),
|
|
638
639
|
...(child.launchContractDigest ? { launchContractDigest: child.launchContractDigest } : {}),
|
|
639
640
|
...(child.resumeContract ? { resumeContract: child.resumeContract } : {}),
|
|
641
|
+
...(child.savedOutputPath ? { savedOutputPath: child.savedOutputPath } : {}),
|
|
640
642
|
...(child.extensionBindings ? { extensionBindings: normalizeExtensionBindings(child.extensionBindings).value } : {}),
|
|
641
643
|
...(child.requiredExtensions ? { requiredExtensions: child.requiredExtensions } : {}),
|
|
642
644
|
...(child.capabilityCeiling ? { capabilityCeiling: child.capabilityCeiling } : {}),
|
|
@@ -1129,7 +1131,7 @@ function pathWithin(base, candidate) {
|
|
|
1129
1131
|
const resolvedCandidate = path.resolve(candidate);
|
|
1130
1132
|
return resolvedCandidate === resolvedBase || resolvedCandidate.startsWith(`${resolvedBase}${path.sep}`);
|
|
1131
1133
|
}
|
|
1132
|
-
function validateNestedSessionFile(run, trustedSessionRoots) {
|
|
1134
|
+
function validateNestedSessionFile(run, trustedSessionRoots, resolveSource, visited = []) {
|
|
1133
1135
|
const sessionFile = nestedRunSessionFile(run);
|
|
1134
1136
|
if (!sessionFile)
|
|
1135
1137
|
throw new Error(`Nested run '${run.id}' does not have a persisted session file to resume from.`);
|
|
@@ -1151,7 +1153,24 @@ function validateNestedSessionFile(run, trustedSessionRoots) {
|
|
|
1151
1153
|
throw new Error(`Nested run '${run.id}' session file is outside trusted nested session roots: ${sessionFile}`);
|
|
1152
1154
|
}
|
|
1153
1155
|
if (!realSessionFile.split(path.sep).includes(run.id)) {
|
|
1154
|
-
|
|
1156
|
+
// A resume replacement continues its source's session; accept it only when that source,
|
|
1157
|
+
// resolved in the caller's own scope, is one the caller could resume itself (the states
|
|
1158
|
+
// resolveNestedResumeTarget refuses), validates on its own and owns this same file.
|
|
1159
|
+
const sourceId = run.revivedFrom;
|
|
1160
|
+
const chain = [...visited, run.id];
|
|
1161
|
+
const source = sourceId && chain.length <= 8 && !chain.includes(sourceId) ? resolveSource(sourceId) : undefined;
|
|
1162
|
+
let sourceFile;
|
|
1163
|
+
if (source && source.state !== "running" && source.state !== "queued" && source.state !== "stopped") {
|
|
1164
|
+
try {
|
|
1165
|
+
sourceFile = validateNestedSessionFile(source, trustedSessionRoots, resolveSource, chain);
|
|
1166
|
+
}
|
|
1167
|
+
catch {
|
|
1168
|
+
sourceFile = undefined;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (sourceFile !== realSessionFile) {
|
|
1172
|
+
throw new Error(`Nested run '${run.id}' session file is not under that nested run's session directory: ${sessionFile}`);
|
|
1173
|
+
}
|
|
1155
1174
|
}
|
|
1156
1175
|
return realSessionFile;
|
|
1157
1176
|
}
|
|
@@ -1165,7 +1184,7 @@ export function readNestedRecoveryDescriptor(asyncDir, runId, agent) {
|
|
|
1165
1184
|
throw new Error(`Nested run '${runId}' has a recovery descriptor for a different agent.`);
|
|
1166
1185
|
return recoveryDescriptor;
|
|
1167
1186
|
}
|
|
1168
|
-
function resolveNestedResumeTarget(match, trustedSessionRoots) {
|
|
1187
|
+
function resolveNestedResumeTarget(match, trustedSessionRoots, resolveSource) {
|
|
1169
1188
|
const run = match.match.run;
|
|
1170
1189
|
if (run.state === "running" || run.state === "queued")
|
|
1171
1190
|
throw new Error(`Nested run '${run.id}' is live; route the follow-up to the owner process instead.`);
|
|
@@ -1185,7 +1204,7 @@ function resolveNestedResumeTarget(match, trustedSessionRoots) {
|
|
|
1185
1204
|
agent,
|
|
1186
1205
|
index: 0,
|
|
1187
1206
|
cwd: asyncDir ? path.dirname(asyncDir) : undefined,
|
|
1188
|
-
sessionFile: validateNestedSessionFile(run, trustedSessionRoots),
|
|
1207
|
+
sessionFile: validateNestedSessionFile(run, trustedSessionRoots, resolveSource),
|
|
1189
1208
|
...(run.capabilityCeiling ? { capabilityCeiling: run.capabilityCeiling } : {}),
|
|
1190
1209
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
1191
1210
|
});
|
|
@@ -1522,9 +1541,10 @@ async function resumeExternalJobFollowUp(input) {
|
|
|
1522
1541
|
}
|
|
1523
1542
|
function resolveRequestedResumeTarget(params, deps, parentSessionFile) {
|
|
1524
1543
|
const requestedId = params.id ?? params.runId;
|
|
1544
|
+
const resolutionDeps = omitUndefinedProperties({ state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
1525
1545
|
let resolved;
|
|
1526
1546
|
try {
|
|
1527
|
-
resolved = requestedId ? resolveSubagentRunId(requestedId,
|
|
1547
|
+
resolved = requestedId ? resolveSubagentRunId(requestedId, resolutionDeps) : undefined;
|
|
1528
1548
|
}
|
|
1529
1549
|
catch (error) {
|
|
1530
1550
|
const message = error instanceof Error ? error.message : "";
|
|
@@ -1540,11 +1560,18 @@ function resolveRequestedResumeTarget(params, deps, parentSessionFile) {
|
|
|
1540
1560
|
const externalJobTarget = resolveNestedExternalJobResumeTarget(resolved, params, deps);
|
|
1541
1561
|
if (externalJobTarget)
|
|
1542
1562
|
return externalJobTarget;
|
|
1543
|
-
const
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1563
|
+
const rootRunId = resolved.match.rootRunId;
|
|
1564
|
+
// The source must be a nested run the caller could address itself, in the same registry.
|
|
1565
|
+
const resolveSource = (id) => {
|
|
1566
|
+
try {
|
|
1567
|
+
const source = resolveSubagentRunId(id, resolutionDeps);
|
|
1568
|
+
return source?.kind === "nested" && source.id === id && source.match.rootRunId === rootRunId ? source.match.run : undefined;
|
|
1569
|
+
}
|
|
1570
|
+
catch {
|
|
1571
|
+
return undefined;
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
return resolveNestedResumeTarget(resolved, trustedSessionRoots(parentSessionFile, deps), resolveSource);
|
|
1548
1575
|
}
|
|
1549
1576
|
return resolveResumeTarget(params, deps.state, { asyncRequireSessionFile: false });
|
|
1550
1577
|
}
|
|
@@ -1882,6 +1909,13 @@ async function resumeAsyncRun(input) {
|
|
|
1882
1909
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1883
1910
|
const parentModel = input.parentModel;
|
|
1884
1911
|
const revivalAsyncDir = path.join(DIRS.async, runId);
|
|
1912
|
+
const revivalOutputBaseDir = resolveSingleRunOutputBaseDir(input.deps, artifactsDir, runId);
|
|
1913
|
+
const inheritedOutput = foregroundContract?.output ?? recoveryDescriptor?.outputPath;
|
|
1914
|
+
// The original run owns its saved output, so a resume without its own output writes next to it instead of over it.
|
|
1915
|
+
// Workflow resumes are routed by the workflow's output claims instead.
|
|
1916
|
+
const inheritedOutputPath = input.params.output === undefined && input.params.workflowParentRunId === undefined
|
|
1917
|
+
? (target.source === "foreground" ? target.savedOutputPath : undefined) ?? resolveSingleOutputPath(inheritedOutput, input.requestCwd, effectiveCwd, revivalOutputBaseDir)
|
|
1918
|
+
: undefined;
|
|
1885
1919
|
const result = await executeAsyncSingle(runId, compactOptional({
|
|
1886
1920
|
agent: target.agent,
|
|
1887
1921
|
task: buildRevivedAsyncTask(target, effectiveFollowUp),
|
|
@@ -1929,7 +1963,7 @@ async function resumeAsyncRun(input) {
|
|
|
1929
1963
|
thinkingCeiling: recoveryDescriptor?.thinkingCeiling ?? ("thinkingCeiling" in target ? target.thinkingCeiling : undefined),
|
|
1930
1964
|
extensionBindings: recoveryDescriptor?.extensionBindings ?? ("extensionBindings" in target ? target.extensionBindings : undefined),
|
|
1931
1965
|
requiredExtensions: recoveryDescriptor?.requiredExtensions ?? target.requiredExtensions,
|
|
1932
|
-
outputBaseDir:
|
|
1966
|
+
outputBaseDir: revivalOutputBaseDir,
|
|
1933
1967
|
maxSubagentDepth: recoveryDescriptor?.maxSubagentDepth ?? resolveCurrentMaxSubagentDepth(input.deps.config.maxSubagentDepth, input.deps.childRuntime),
|
|
1934
1968
|
waitToolEnabled: input.deps.waitToolEnabled,
|
|
1935
1969
|
waitToolDefaultTimeoutMs: input.deps.waitToolDefaultTimeoutMs,
|
|
@@ -1948,7 +1982,7 @@ async function resumeAsyncRun(input) {
|
|
|
1948
1982
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
1949
1983
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
1950
1984
|
availableModels,
|
|
1951
|
-
output: input.params.output !== undefined ? input.params.output :
|
|
1985
|
+
output: input.params.output !== undefined ? input.params.output : inheritedOutputPath ? suffixedOutputPath(inheritedOutputPath, runId.slice(0, 8)) : inheritedOutput,
|
|
1952
1986
|
outputMode: input.params.outputMode ?? foregroundContract?.outputMode ?? recoveryDescriptor?.outputMode,
|
|
1953
1987
|
outputClaimPath: input.params.workflowOutputClaimPath,
|
|
1954
1988
|
...(agentContract ? { agentContract } : {}),
|
|
@@ -3005,9 +3039,9 @@ function importWorkflowAwaitedChildResult(completed, options) {
|
|
|
3005
3039
|
};
|
|
3006
3040
|
}
|
|
3007
3041
|
// A replaced runtime leaves the child running so a relaunch of the workflow can re-attach to it.
|
|
3008
|
-
function stopAwaitedAsyncChildOnAbort(signal, state, runId, asyncDir, kill) {
|
|
3042
|
+
function stopAwaitedAsyncChildOnAbort(signal, state, runId, asyncDir, kill, reattachedFromOtherSession = false) {
|
|
3009
3043
|
const stopOnAbort = () => { if (!workflowStopCause(signal?.reason))
|
|
3010
|
-
stopAsyncRun(state, runId, kill, { asyncDir, resolvedId: runId }); };
|
|
3044
|
+
stopAsyncRun(state, runId, kill, { asyncDir, resolvedId: runId, ...(reattachedFromOtherSession ? { reattachedRunId: runId } : {}) }); };
|
|
3011
3045
|
if (signal?.aborted)
|
|
3012
3046
|
stopOnAbort();
|
|
3013
3047
|
else
|
|
@@ -3231,11 +3265,14 @@ export function sanitizeRunPathSegment(value, maxBytes = 120) {
|
|
|
3231
3265
|
function resolveSingleRunOutputBaseDir(deps, artifactsDir, runId) {
|
|
3232
3266
|
return resolveConfiguredSingleRunOutputBaseDir(deps) ?? path.join(artifactsDir, "outputs", sanitizeRunPathSegment(runId));
|
|
3233
3267
|
}
|
|
3268
|
+
/** `<dir>/<name>.<suffix><ext>` next to outputPath, with `.md` when it has no extension. */
|
|
3269
|
+
function suffixedOutputPath(outputPath, suffix) {
|
|
3270
|
+
const parsed = path.parse(outputPath);
|
|
3271
|
+
return path.join(parsed.dir, `${parsed.name}.${suffix}${parsed.ext || ".md"}`);
|
|
3272
|
+
}
|
|
3234
3273
|
function workflowChildDefaultOutput(aggregateOutputPath, artifactsDir, workflowRunId, workflowKey) {
|
|
3235
|
-
if (aggregateOutputPath)
|
|
3236
|
-
|
|
3237
|
-
return path.join(parsed.dir, `${parsed.name}.${workflowKey}${parsed.ext || ".md"}`);
|
|
3238
|
-
}
|
|
3274
|
+
if (aggregateOutputPath)
|
|
3275
|
+
return suffixedOutputPath(aggregateOutputPath, workflowKey);
|
|
3239
3276
|
return path.join(artifactsDir, "outputs", sanitizeRunPathSegment(workflowRunId), `${workflowKey}.md`);
|
|
3240
3277
|
}
|
|
3241
3278
|
function workflowHostCommandRunner(input) {
|
|
@@ -3328,9 +3365,8 @@ function resolveWorkflowChildOutputPath(input) {
|
|
|
3328
3365
|
const recoveryOutput = "recoveryDescriptor" in target ? target.recoveryDescriptor?.outputPath : undefined;
|
|
3329
3366
|
if (hasExplicitOutput)
|
|
3330
3367
|
return { path: recoveryOutput, inherited: false };
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
return { path: recoveryOutput, inherited: false, resumedOutput: recoveryOutput ?? (typeof foregroundOutput === "string" && path.isAbsolute(foregroundOutput) ? foregroundOutput : undefined) };
|
|
3368
|
+
const savedPath = recoveryOutput ?? (target.source === "foreground" ? target.savedOutputPath ?? resolveSingleOutputPath(target.resumeContract?.output, input.ctxCwd) : undefined);
|
|
3369
|
+
return { inherited: false, ...(savedPath ? { resumedSavedPath: savedPath } : {}) };
|
|
3334
3370
|
}
|
|
3335
3371
|
const childCwd = resolveWorkflowChildLocalCwd(input);
|
|
3336
3372
|
let agentOutput;
|
|
@@ -3370,10 +3406,12 @@ function workflowChildOutputClaims(input) {
|
|
|
3370
3406
|
}
|
|
3371
3407
|
const overrides = new Map();
|
|
3372
3408
|
for (const entry of resolvedEntries) {
|
|
3373
|
-
//
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3409
|
+
// The resumed run owns the report it saved, inside or outside this workflow, so an output-less resume writes its own.
|
|
3410
|
+
if (entry.resumedSavedPath || (entry.inherited && entry.path && (paths.get(resolveWorkflowHostOutputClaimPath(entry.path)) ?? 0) > 1)) {
|
|
3411
|
+
let output = workflowChildDefaultOutput(input.aggregateOutputPath, input.artifactsDir, input.workflowRunId, entry.key);
|
|
3412
|
+
// A rerun of the same workflow and key generates the very file the resumed run saved.
|
|
3413
|
+
if (entry.resumedSavedPath && resolveWorkflowHostOutputClaimPath(output) === resolveWorkflowHostOutputClaimPath(entry.resumedSavedPath))
|
|
3414
|
+
output = suffixedOutputPath(output, input.workflowRunId.slice(0, 8));
|
|
3377
3415
|
overrides.set(entry.key, output);
|
|
3378
3416
|
entry.path = output;
|
|
3379
3417
|
}
|
|
@@ -3390,16 +3428,6 @@ function workflowChildOutputClaims(input) {
|
|
|
3390
3428
|
claims.set(claimPath, key);
|
|
3391
3429
|
childClaims.set(key, claimPath);
|
|
3392
3430
|
}
|
|
3393
|
-
// Record a discovered output-less resume path for later admissions without adding same-batch duplicate errors.
|
|
3394
|
-
for (const { key, path: resolved, resumedOutput } of resolvedEntries) {
|
|
3395
|
-
if (resolved || !resumedOutput)
|
|
3396
|
-
continue;
|
|
3397
|
-
const claimPath = resolveWorkflowHostOutputClaimPath(resumedOutput);
|
|
3398
|
-
if (claims.has(claimPath))
|
|
3399
|
-
continue;
|
|
3400
|
-
claims.set(claimPath, key);
|
|
3401
|
-
childClaims.set(key, claimPath);
|
|
3402
|
-
}
|
|
3403
3431
|
return { claims, childClaims, overrides };
|
|
3404
3432
|
}
|
|
3405
3433
|
function applyWorkflowChildOutputClaims(target, claims) {
|
|
@@ -3622,7 +3650,6 @@ async function runSinglePath(data, deps) {
|
|
|
3622
3650
|
if (shouldForkAgent(contextPolicy, params.agent)) {
|
|
3623
3651
|
task = wrapForkTask(task);
|
|
3624
3652
|
}
|
|
3625
|
-
const cleanTask = task;
|
|
3626
3653
|
const outputPath = resolveSingleOutputPath(effectiveOutput, ctx.cwd, singleCwd, resolveSingleRunOutputBaseDir(deps, artifactsDir, runId));
|
|
3627
3654
|
const validationError = validateFileOnlyOutputMode(effectiveOutputMode, outputPath, `Single run (${params.agent})`);
|
|
3628
3655
|
if (validationError) {
|
|
@@ -3839,7 +3866,6 @@ async function runSinglePath(data, deps) {
|
|
|
3839
3866
|
}
|
|
3840
3867
|
}
|
|
3841
3868
|
}
|
|
3842
|
-
recordRun(params.agent, cleanTask, result.exitCode, result.progressSummary?.durationMs ?? 0, result);
|
|
3843
3869
|
},
|
|
3844
3870
|
timeoutMs: data.timeoutMs,
|
|
3845
3871
|
deadlineAt,
|
|
@@ -3880,9 +3906,6 @@ async function runSinglePath(data, deps) {
|
|
|
3880
3906
|
finishTrackedForegroundChild();
|
|
3881
3907
|
}
|
|
3882
3908
|
}
|
|
3883
|
-
if (!r.detached) {
|
|
3884
|
-
recordRun(params.agent, cleanTask, r.exitCode, r.progressSummary?.durationMs ?? 0, r);
|
|
3885
|
-
}
|
|
3886
3909
|
let worktreeHandoff;
|
|
3887
3910
|
if (worktreeSetup) {
|
|
3888
3911
|
worktreeHandoff = r.detached
|
|
@@ -4056,13 +4079,16 @@ export function bindMissionWorkflowChildAsyncLaunch(params, binding, asyncByDefa
|
|
|
4056
4079
|
}
|
|
4057
4080
|
function workflowChildResult(key, result, childParams = {}, resumeState, forcedTerminalOutcome) {
|
|
4058
4081
|
const running = missionWorkflowChildStatus(result) === "running";
|
|
4059
|
-
|
|
4082
|
+
// The receipt opens with the workflow-wide run fan-out line, which says nothing about this child.
|
|
4083
|
+
const fanoutPrefix = result.details.runFanoutBudget ? `${formatRunFanoutBudget(result.details.runFanoutBudget)}\n` : undefined;
|
|
4084
|
+
const fullReceipt = result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
|
|
4085
|
+
const receiptOutput = fanoutPrefix && fullReceipt.startsWith(fanoutPrefix) ? fullReceipt.slice(fanoutPrefix.length) : fullReceipt;
|
|
4060
4086
|
const output = running ? "" : result.details.results.length === 1 && result.details.results[0]?.finalOutput !== undefined
|
|
4061
4087
|
? result.details.results[0].finalOutput
|
|
4062
4088
|
: receiptOutput;
|
|
4063
4089
|
const childError = result.details.results.map((child) => child.error).find((error) => Boolean(error));
|
|
4064
4090
|
const stopped = result.details.results.some((child) => child.stopped);
|
|
4065
|
-
// A stopped child
|
|
4091
|
+
// A stopped child reports its structured stop reason alone, without the receipt's output block.
|
|
4066
4092
|
const failureErrorBase = stopped && childError
|
|
4067
4093
|
? childError
|
|
4068
4094
|
: childError && receiptOutput
|
|
@@ -4820,12 +4846,7 @@ export function createSubagentExecutor(deps) {
|
|
|
4820
4846
|
if (launchBlockingErrors.length > 0) {
|
|
4821
4847
|
return buildRequestedModeError(requestParams, `Workflow '${_id}' validation failed before child launch; no children launched. ${launchBlockingErrors.map((error) => error.message).join(" ")}`);
|
|
4822
4848
|
}
|
|
4823
|
-
//
|
|
4824
|
-
const structuredResource = workflowResource?.provenance.name === "chain" || workflowResource?.provenance.name === "tasks";
|
|
4825
|
-
for (const warning of workflowValidation.warnings ?? []) {
|
|
4826
|
-
if (!(structuredResource && warning.kind === "dynamic-spawn-count"))
|
|
4827
|
-
console.warn(`[pi-subagents] ${warning.message}`);
|
|
4828
|
-
}
|
|
4849
|
+
// Validation warnings belong to the validate action; a launch does not repeat them on every run.
|
|
4829
4850
|
const acceptanceErrors = validateAcceptanceInput(requestParams.acceptance);
|
|
4830
4851
|
if (acceptanceErrors.length > 0)
|
|
4831
4852
|
return buildRequestedModeError(requestParams, acceptanceErrors.join(" "));
|
|
@@ -4893,6 +4914,17 @@ export function createSubagentExecutor(deps) {
|
|
|
4893
4914
|
&& !inheritedNestedRoute(deps)
|
|
4894
4915
|
&& !requestParams.workflowParentRunId;
|
|
4895
4916
|
const workflowRunId = asyncWorkflow ? randomUUID() : undefined;
|
|
4917
|
+
if (requestParams.reuseFrom !== undefined && !topLevelAsyncWorkflow) {
|
|
4918
|
+
return { content: [{ type: "text", text: "options.reuseFrom requires an async top-level workflow." }], isError: true, details: { mode: "workflow", results: [] } };
|
|
4919
|
+
}
|
|
4920
|
+
let namedWorkflowReuseSource;
|
|
4921
|
+
try {
|
|
4922
|
+
if (requestParams.reuseFrom !== undefined)
|
|
4923
|
+
namedWorkflowReuseSource = readNamedWorkflowReuseSource(DIRS.async, requestParams.reuseFrom, workflowScriptDigest(requestParams.workflowScript), workflowCwd);
|
|
4924
|
+
}
|
|
4925
|
+
catch (error) {
|
|
4926
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "workflow", results: [] } };
|
|
4927
|
+
}
|
|
4896
4928
|
let workflowCapacity;
|
|
4897
4929
|
if (workflowRunId && topLevelAsyncWorkflow) {
|
|
4898
4930
|
const currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
@@ -4959,7 +4991,7 @@ export function createSubagentExecutor(deps) {
|
|
|
4959
4991
|
const toolCallId = _id;
|
|
4960
4992
|
const workflowSessionRoot = requestParams.sessionDir
|
|
4961
4993
|
? path.resolve(deps.expandTilde(requestParams.sessionDir))
|
|
4962
|
-
:
|
|
4994
|
+
: trustedSessionRoots(ctx.sessionManager.getSessionFile() ?? null, deps)[0];
|
|
4963
4995
|
const asyncDir = path.join(DIRS.async, workflowRunId);
|
|
4964
4996
|
const resultPath = resultFilePath(DIRS.results, workflowRunId);
|
|
4965
4997
|
const statusPath = path.join(asyncDir, "status.json");
|
|
@@ -4970,7 +5002,7 @@ export function createSubagentExecutor(deps) {
|
|
|
4970
5002
|
const completionOwnerId = deps.state.completionOwnerId ?? currentCompletionOwnerId();
|
|
4971
5003
|
deps.state.completionOwnerId = completionOwnerId;
|
|
4972
5004
|
const workflowScriptSourceDigest = workflowScriptDigest(requestParams.workflowScript);
|
|
4973
|
-
const workflowReuseSource = findWorkflowReuseSource(DIRS.async, currentSessionId, workflowScriptSourceDigest, workflowArgsDigest);
|
|
5005
|
+
const workflowReuseSource = namedWorkflowReuseSource ?? findWorkflowReuseSource(DIRS.async, currentSessionId, workflowScriptSourceDigest, workflowArgsDigest);
|
|
4974
5006
|
const workflowRunEvidence = { ...workflowArgsEvidence, scriptDigest: workflowScriptSourceDigest };
|
|
4975
5007
|
if (workflowReuseSource)
|
|
4976
5008
|
workflowRunEvidence.reusedFrom = workflowReuseSource.runId;
|
|
@@ -5495,6 +5527,9 @@ export function createSubagentExecutor(deps) {
|
|
|
5495
5527
|
if (entry.state === "reused" && existing) {
|
|
5496
5528
|
continue;
|
|
5497
5529
|
}
|
|
5530
|
+
// A runtime replacement does not stop awaited async children (stopAwaitedAsyncChildOnAbort): they keep running.
|
|
5531
|
+
if (entry.state === "stopped" && existing?.async === true && existing.runId && workflowStopCause(controller.signal.reason))
|
|
5532
|
+
continue;
|
|
5498
5533
|
const mapped = entry.state === "started" || entry.state === "reused"
|
|
5499
5534
|
? "running"
|
|
5500
5535
|
: entry.state === "completed"
|
|
@@ -5686,7 +5721,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5686
5721
|
const priorRunId = priorChild.runId;
|
|
5687
5722
|
const priorAsyncDir = path.join(DIRS.async, priorRunId);
|
|
5688
5723
|
appendWorkflowChildJournal(asyncDir, { type: "start", key, fingerprint: journalFingerprint, runId: priorRunId });
|
|
5689
|
-
const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps.state, priorRunId, priorAsyncDir, deps.kill);
|
|
5724
|
+
const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps.state, priorRunId, priorAsyncDir, deps.kill, requestParams.reuseFrom !== undefined);
|
|
5690
5725
|
const reattached = await awaitExistingAsyncRun(priorAsyncDir, priorRunId, workflowSignal).finally(stopListener.remove);
|
|
5691
5726
|
const claimedPath = reattached.status === "settled" ? claimWorkflowAwaitedResult(priorAsyncDir, workflowRunId, { ...reattached.result.importedPublication, runId: priorRunId }) : undefined;
|
|
5692
5727
|
if (reattached.status === "settled" && claimedPath) {
|
|
@@ -5883,7 +5918,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5883
5918
|
const errorPreview = status.error && status.error.length > 1_000 ? `${status.error.slice(0, 1_000)}… (truncated; full error: ${statusPath} (error))` : status.error;
|
|
5884
5919
|
const terminalSummary = `${status.state === "complete"
|
|
5885
5920
|
? "Workflow completed after detached child finished."
|
|
5886
|
-
: errorPreview ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.")}${stopCause ? ` ${
|
|
5921
|
+
: errorPreview ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.")}${stopCause ? ` ${workflowRuntimeReplacedRelaunchNotice(workflowRunId)}` : ""}${workflowOutputPathMappingSummary(partial.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
|
|
5887
5922
|
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, terminalSummary, producedChildOutputPaths);
|
|
5888
5923
|
const resultSummary = appendWorkflowOutputWarning(terminalSummary, outputWarning);
|
|
5889
5924
|
const receiptState = status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
|
|
@@ -5956,6 +5991,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5956
5991
|
const workflowHostSteps = new Map();
|
|
5957
5992
|
let liveWorkflow = { trace: [], emits: [], console: [], ...(workflowResource ? { resource: workflowResource.provenance } : {}) };
|
|
5958
5993
|
const childProgress = new Map();
|
|
5994
|
+
const childLaunches = new Map();
|
|
5959
5995
|
let activityTimer;
|
|
5960
5996
|
let lastProgressAt = 0;
|
|
5961
5997
|
let workflowProgressClosed = false;
|
|
@@ -5968,7 +6004,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5968
6004
|
clearTimeout(activityTimer);
|
|
5969
6005
|
activityTimer = undefined;
|
|
5970
6006
|
lastProgressAt = Date.now();
|
|
5971
|
-
const liveWorkflowChildren = workflowChildSummary({ parentToolCallId: _id, workflowRunId: foregroundWorkflowRunId, workflowState: "running", inventoryComplete: false, trace: liveWorkflow.trace, progress: childProgress });
|
|
6007
|
+
const liveWorkflowChildren = workflowChildSummary({ parentToolCallId: _id, workflowRunId: foregroundWorkflowRunId, workflowState: "running", inventoryComplete: false, trace: liveWorkflow.trace, progress: childProgress, launches: childLaunches });
|
|
5972
6008
|
onUpdate?.(workflowProgressUpdate(foregroundWorkflowRunId, chatProgress, liveWorkflow, liveWorkflowChildren, workflowPreflight));
|
|
5973
6009
|
};
|
|
5974
6010
|
try {
|
|
@@ -6056,11 +6092,21 @@ export function createSubagentExecutor(deps) {
|
|
|
6056
6092
|
throw new Error("Workflow child permit supports native Pi children only.");
|
|
6057
6093
|
workflowPermitContexts.set(childRequest, { child: { permit: delegatedWorkflowPermit, workflowRunId: foregroundWorkflowRunId, childKey: key } });
|
|
6058
6094
|
}
|
|
6059
|
-
workflowLaunchObservers.set(childRequest, (launch) =>
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6095
|
+
workflowLaunchObservers.set(childRequest, (launch) => {
|
|
6096
|
+
childLaunches.set(key, { agent: launch.agent, ...(launch.runId ? { runId: launch.runId } : {}) });
|
|
6097
|
+
// Telemetry must not decide the child's outcome, as with onTrace in scripted-workflow.
|
|
6098
|
+
try {
|
|
6099
|
+
sendWorkflowProgress();
|
|
6100
|
+
}
|
|
6101
|
+
catch (error) {
|
|
6102
|
+
console.error("Workflow progress update failed:", error);
|
|
6103
|
+
}
|
|
6104
|
+
recordMissionWorkflowChild(missionBinding, foregroundWorkflowRunId, key, {
|
|
6105
|
+
status: "running",
|
|
6106
|
+
agent: launch.agent,
|
|
6107
|
+
...(launch.sessionFile ? { sessionPath: launch.sessionFile } : {}),
|
|
6108
|
+
});
|
|
6109
|
+
});
|
|
6064
6110
|
return execute(randomUUID(), childRequest, workflowSignal, (update) => {
|
|
6065
6111
|
const progress = update.details.progress?.[0];
|
|
6066
6112
|
if (!progress)
|
|
@@ -6602,7 +6648,7 @@ export function createSubagentExecutor(deps) {
|
|
|
6602
6648
|
};
|
|
6603
6649
|
};
|
|
6604
6650
|
const nestedScope = nestedResolutionScopeForExecutor(deps);
|
|
6605
|
-
const sessionRoots =
|
|
6651
|
+
const sessionRoots = trustedSessionRoots(ctx.sessionManager.getSessionFile() ?? null, deps);
|
|
6606
6652
|
if (action === "debug.run") {
|
|
6607
6653
|
if (!targetRunId && !hasDirectoryTarget) {
|
|
6608
6654
|
return withBudget({ content: [{ type: "text", text: "action='debug.run' requires id, runId, or dir." }], isError: true, details: { mode: "management", results: [] } });
|
|
@@ -7044,12 +7090,20 @@ export function createSubagentExecutor(deps) {
|
|
|
7044
7090
|
// Forked children keep their requested thinking level. Signed Anthropic thinking
|
|
7045
7091
|
// blocks are stripped from the inherited transcript by the resolver (they are bound
|
|
7046
7092
|
// to the parent session), which is not a reason to disable the child's own reasoning.
|
|
7093
|
+
let sessionRunId;
|
|
7047
7094
|
try {
|
|
7048
7095
|
assertLaunchableAgentsAllowedBeforeFork();
|
|
7049
7096
|
const pruneSession = contextPolicy.usesFork && deps.config.forkContext?.mode === "pruned"
|
|
7050
7097
|
? await createPrunedForkSessionWriter(ctx, deps.config.forkContext, signal)
|
|
7051
7098
|
: undefined;
|
|
7052
|
-
const forkContextResolver = createForkContextResolver(ctx.sessionManager, contextPolicy.usesFork ? "fork" : undefined,
|
|
7099
|
+
const forkContextResolver = createForkContextResolver(ctx.sessionManager, contextPolicy.usesFork ? "fork" : undefined, {
|
|
7100
|
+
...(pruneSession ? { pruneSession } : {}),
|
|
7101
|
+
runDirName: () => {
|
|
7102
|
+
if (!sessionRunId)
|
|
7103
|
+
throw new Error("A fork session was requested before the launch's run id was assigned.");
|
|
7104
|
+
return sessionRunId;
|
|
7105
|
+
},
|
|
7106
|
+
});
|
|
7053
7107
|
prepareForkSessionForIndex = forkContextResolver.prepareSessionForIndex;
|
|
7054
7108
|
forkSessionFileForIndex = forkContextResolver.sessionFileForIndex;
|
|
7055
7109
|
}
|
|
@@ -7152,16 +7206,19 @@ export function createSubagentExecutor(deps) {
|
|
|
7152
7206
|
console.warn(`[pi-subagents] ${warning}`);
|
|
7153
7207
|
}
|
|
7154
7208
|
let sessionRoot;
|
|
7209
|
+
// Key the session directory by the id the run is recorded under: nested resume
|
|
7210
|
+
// accepts a session file only inside a directory named by that run's id.
|
|
7211
|
+
sessionRunId = effectiveAsync ? asyncRunId : runId;
|
|
7155
7212
|
if (effectiveParams.sessionDir) {
|
|
7156
7213
|
// An explicit sessionDir is a root keyed by this launch's run id so
|
|
7157
7214
|
// concurrent children resolve distinct per-child session files.
|
|
7158
|
-
sessionRoot = path.join(path.resolve(deps.expandTilde(effectiveParams.sessionDir)),
|
|
7215
|
+
sessionRoot = path.join(path.resolve(deps.expandTilde(effectiveParams.sessionDir)), sessionRunId);
|
|
7159
7216
|
}
|
|
7160
7217
|
else {
|
|
7161
7218
|
const baseSessionRoot = deps.config.defaultSessionDir
|
|
7162
7219
|
? path.resolve(deps.expandTilde(deps.config.defaultSessionDir))
|
|
7163
7220
|
: deps.getSubagentSessionRoot(parentSessionFile);
|
|
7164
|
-
sessionRoot = path.join(baseSessionRoot,
|
|
7221
|
+
sessionRoot = path.join(baseSessionRoot, sessionRunId);
|
|
7165
7222
|
}
|
|
7166
7223
|
try {
|
|
7167
7224
|
fs.mkdirSync(sessionRoot, { recursive: true });
|