pi-subagents 0.70.1 → 0.72.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 +87 -0
- package/README.md +4 -2
- package/agents/worker.md +2 -2
- package/docs/agents.md +1 -1
- package/docs/configuration.md +18 -2
- package/docs/extension-api.md +67 -3
- package/docs/models.md +1 -1
- package/docs/observability.md +17 -13
- package/docs/tool-reference.md +14 -10
- package/docs/workflows.md +3 -1
- package/package.json +11 -4
- package/prompts/council.md +6 -3
- package/skills/pi-subagents/references/constraints-and-recipes.md +5 -2
- package/skills/pi-subagents/references/execution-controls.md +3 -3
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/src/agents/agent-management.d.ts +2 -1
- package/src/agents/agent-management.d.ts.map +1 -1
- package/src/agents/agent-management.js +32 -29
- package/src/agents/agent-management.js.map +1 -1
- package/src/agents/agents.d.ts +7 -3
- package/src/agents/agents.d.ts.map +1 -1
- package/src/agents/agents.js +16 -15
- package/src/agents/agents.js.map +1 -1
- package/src/agents/global-npm-root.d.ts +7 -0
- package/src/agents/global-npm-root.d.ts.map +1 -0
- package/src/agents/global-npm-root.js +58 -0
- package/src/agents/global-npm-root.js.map +1 -0
- package/src/agents/proactive-skills.d.ts +1 -0
- package/src/agents/proactive-skills.d.ts.map +1 -1
- package/src/agents/proactive-skills.js +3 -1
- package/src/agents/proactive-skills.js.map +1 -1
- package/src/agents/skills.d.ts +2 -0
- package/src/agents/skills.d.ts.map +1 -1
- package/src/agents/skills.js +41 -8
- package/src/agents/skills.js.map +1 -1
- package/src/api/delegation.d.ts +14 -0
- package/src/api/delegation.d.ts.map +1 -1
- package/src/api/inspectors.d.ts +21 -0
- package/src/api/inspectors.d.ts.map +1 -0
- package/src/api/inspectors.js +12 -0
- package/src/api/inspectors.js.map +1 -0
- package/src/extension/fanout-child.d.ts.map +1 -1
- package/src/extension/fanout-child.js +9 -0
- package/src/extension/fanout-child.js.map +1 -1
- package/src/extension/index.d.ts.map +1 -1
- package/src/extension/index.js +76 -29
- package/src/extension/index.js.map +1 -1
- package/src/extension/rpc.d.ts +1 -1
- package/src/extension/rpc.d.ts.map +1 -1
- package/src/extension/rpc.js +11 -1
- package/src/extension/rpc.js.map +1 -1
- package/src/extension/schemas.js +5 -5
- package/src/extension/schemas.js.map +1 -1
- package/src/extension/subagent-guide.d.ts +1 -1
- package/src/extension/subagent-guide.d.ts.map +1 -1
- package/src/extension/subagent-guide.js +11 -4
- package/src/extension/subagent-guide.js.map +1 -1
- package/src/extension/tool-activation.d.ts +9 -0
- package/src/extension/tool-activation.d.ts.map +1 -0
- package/src/extension/tool-activation.js +182 -0
- package/src/extension/tool-activation.js.map +1 -0
- package/src/extension/tool-description.d.ts +4 -4
- package/src/extension/tool-description.d.ts.map +1 -1
- package/src/extension/tool-description.js +1 -1
- package/src/inspectors/plugins.d.ts +7 -2
- package/src/inspectors/plugins.d.ts.map +1 -1
- package/src/inspectors/plugins.js +78 -3
- package/src/inspectors/plugins.js.map +1 -1
- package/src/intercom/intercom-bridge.d.ts.map +1 -1
- package/src/intercom/intercom-bridge.js +2 -0
- package/src/intercom/intercom-bridge.js.map +1 -1
- package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
- package/src/intercom/native-supervisor-channel.js +3 -1
- package/src/intercom/native-supervisor-channel.js.map +1 -1
- package/src/runs/background/active-async-capacity.d.ts.map +1 -1
- package/src/runs/background/active-async-capacity.js +4 -33
- package/src/runs/background/active-async-capacity.js.map +1 -1
- package/src/runs/background/async-execution.d.ts.map +1 -1
- package/src/runs/background/async-execution.js +7 -33
- package/src/runs/background/async-execution.js.map +1 -1
- package/src/runs/background/async-job-tracker.d.ts.map +1 -1
- package/src/runs/background/async-job-tracker.js +26 -39
- package/src/runs/background/async-job-tracker.js.map +1 -1
- package/src/runs/background/async-resume.d.ts +1 -1
- package/src/runs/background/async-resume.d.ts.map +1 -1
- package/src/runs/background/async-resume.js +7 -2
- package/src/runs/background/async-resume.js.map +1 -1
- package/src/runs/background/async-status.d.ts +1 -0
- package/src/runs/background/async-status.d.ts.map +1 -1
- package/src/runs/background/async-status.js +1 -0
- package/src/runs/background/async-status.js.map +1 -1
- package/src/runs/background/binary-bootstrap.d.ts.map +1 -1
- package/src/runs/background/binary-bootstrap.js +34 -6
- package/src/runs/background/binary-bootstrap.js.map +1 -1
- package/src/runs/background/fleet-view.d.ts.map +1 -1
- package/src/runs/background/fleet-view.js +26 -7
- package/src/runs/background/fleet-view.js.map +1 -1
- package/src/runs/background/notify.d.ts +11 -0
- package/src/runs/background/notify.d.ts.map +1 -1
- package/src/runs/background/notify.js +73 -3
- package/src/runs/background/notify.js.map +1 -1
- package/src/runs/background/pid-namespace.d.ts +3 -0
- package/src/runs/background/pid-namespace.d.ts.map +1 -0
- package/src/runs/background/pid-namespace.js +20 -0
- package/src/runs/background/pid-namespace.js.map +1 -0
- package/src/runs/background/process-terminal-candidate.d.ts +18 -0
- package/src/runs/background/process-terminal-candidate.d.ts.map +1 -0
- package/src/runs/background/process-terminal-candidate.js +97 -0
- package/src/runs/background/process-terminal-candidate.js.map +1 -0
- package/src/runs/background/process-terminal.d.ts +3 -15
- package/src/runs/background/process-terminal.d.ts.map +1 -1
- package/src/runs/background/process-terminal.js +19 -96
- package/src/runs/background/process-terminal.js.map +1 -1
- package/src/runs/background/retained-children.d.ts.map +1 -1
- package/src/runs/background/retained-children.js +3 -2
- package/src/runs/background/retained-children.js.map +1 -1
- package/src/runs/background/run-child-session.d.ts +2 -0
- package/src/runs/background/run-child-session.d.ts.map +1 -1
- package/src/runs/background/run-child-session.js +2 -0
- 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 +5 -1
- 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 +2 -1
- package/src/runs/background/runner-aliases.js.map +1 -1
- package/src/runs/background/runner-startup-failure.d.ts +14 -0
- package/src/runs/background/runner-startup-failure.d.ts.map +1 -0
- package/src/runs/background/runner-startup-failure.js +47 -0
- package/src/runs/background/runner-startup-failure.js.map +1 -0
- package/src/runs/background/stale-run-reconciler.d.ts +1 -0
- package/src/runs/background/stale-run-reconciler.d.ts.map +1 -1
- package/src/runs/background/stale-run-reconciler.js +18 -3
- package/src/runs/background/stale-run-reconciler.js.map +1 -1
- package/src/runs/background/subagent-runner-bootstrap.d.ts +14 -0
- package/src/runs/background/subagent-runner-bootstrap.d.ts.map +1 -0
- package/src/runs/background/subagent-runner-bootstrap.js +277 -0
- package/src/runs/background/subagent-runner-bootstrap.js.map +1 -0
- package/src/runs/background/subagent-runner.d.ts +4 -2
- package/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/src/runs/background/subagent-runner.js +58 -180
- package/src/runs/background/subagent-runner.js.map +1 -1
- package/src/runs/background/workflow-terminal-proof.d.ts +18 -0
- package/src/runs/background/workflow-terminal-proof.d.ts.map +1 -0
- package/src/runs/background/workflow-terminal-proof.js +68 -0
- package/src/runs/background/workflow-terminal-proof.js.map +1 -0
- package/src/runs/foreground/execution.d.ts.map +1 -1
- package/src/runs/foreground/execution.js +43 -14
- package/src/runs/foreground/execution.js.map +1 -1
- package/src/runs/foreground/prompt-audit.d.ts.map +1 -1
- package/src/runs/foreground/prompt-audit.js +2 -6
- package/src/runs/foreground/prompt-audit.js.map +1 -1
- package/src/runs/foreground/subagent-executor.d.ts +2 -1
- package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/src/runs/foreground/subagent-executor.js +228 -24
- package/src/runs/foreground/subagent-executor.js.map +1 -1
- package/src/runs/shared/child-launch.d.ts.map +1 -1
- package/src/runs/shared/child-launch.js +3 -0
- package/src/runs/shared/child-launch.js.map +1 -1
- package/src/runs/shared/child-runtime-config.d.ts +4 -0
- package/src/runs/shared/child-runtime-config.d.ts.map +1 -1
- package/src/runs/shared/child-runtime-config.js.map +1 -1
- package/src/runs/shared/child-session.d.ts +1 -0
- package/src/runs/shared/child-session.d.ts.map +1 -1
- package/src/runs/shared/child-session.js +1 -0
- package/src/runs/shared/child-session.js.map +1 -1
- package/src/runs/shared/child-tool-plan.d.ts.map +1 -1
- package/src/runs/shared/child-tool-plan.js +4 -6
- package/src/runs/shared/child-tool-plan.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 -1
- package/src/runs/shared/external-cli-runner.js.map +1 -1
- package/src/runs/shared/external-job-bridge.d.ts +7 -0
- package/src/runs/shared/external-job-bridge.d.ts.map +1 -1
- package/src/runs/shared/external-job-bridge.js +63 -0
- package/src/runs/shared/external-job-bridge.js.map +1 -1
- package/src/runs/shared/git-environment.d.ts +3 -0
- package/src/runs/shared/git-environment.d.ts.map +1 -0
- package/src/runs/shared/git-environment.js +28 -0
- package/src/runs/shared/git-environment.js.map +1 -0
- package/src/runs/shared/mcp-config-sources.d.ts +3 -0
- package/src/runs/shared/mcp-config-sources.d.ts.map +1 -1
- package/src/runs/shared/mcp-config-sources.js.map +1 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.js +1 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.js.map +1 -1
- package/src/runs/shared/mcp-direct-tool-grant.d.ts +3 -1
- package/src/runs/shared/mcp-direct-tool-grant.d.ts.map +1 -1
- package/src/runs/shared/mcp-direct-tool-grant.js +19 -5
- package/src/runs/shared/mcp-direct-tool-grant.js.map +1 -1
- package/src/runs/shared/model-resolution.d.ts.map +1 -1
- package/src/runs/shared/model-resolution.js +7 -1
- package/src/runs/shared/model-resolution.js.map +1 -1
- package/src/runs/shared/pi-spawn.d.ts +10 -1
- package/src/runs/shared/pi-spawn.d.ts.map +1 -1
- package/src/runs/shared/pi-spawn.js +86 -7
- package/src/runs/shared/pi-spawn.js.map +1 -1
- package/src/runs/shared/single-output.js +1 -1
- package/src/runs/shared/single-output.js.map +1 -1
- package/src/runs/shared/structured-output.d.ts +7 -0
- package/src/runs/shared/structured-output.d.ts.map +1 -1
- package/src/runs/shared/structured-output.js +74 -0
- package/src/runs/shared/structured-output.js.map +1 -1
- package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
- package/src/runs/shared/subagent-prompt-runtime.js +23 -7
- package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
- package/src/runs/shared/tool-availability.js +2 -2
- package/src/runs/shared/tool-availability.js.map +1 -1
- package/src/runs/shared/worktree.d.ts.map +1 -1
- package/src/runs/shared/worktree.js +9 -3
- package/src/runs/shared/worktree.js.map +1 -1
- package/src/shared/child-session-name.d.ts.map +1 -1
- package/src/shared/child-session-name.js +4 -2
- package/src/shared/child-session-name.js.map +1 -1
- package/src/shared/fork-context.d.ts +4 -0
- package/src/shared/fork-context.d.ts.map +1 -1
- package/src/shared/fork-context.js +9 -4
- package/src/shared/fork-context.js.map +1 -1
- package/src/shared/pruned-fork.d.ts.map +1 -1
- package/src/shared/pruned-fork.js +68 -56
- package/src/shared/pruned-fork.js.map +1 -1
- package/src/shared/types.d.ts +31 -3
- package/src/shared/types.d.ts.map +1 -1
- package/src/shared/types.js +2 -0
- package/src/shared/types.js.map +1 -1
- package/src/slash/delegation-adapters.d.ts +7 -1
- package/src/slash/delegation-adapters.d.ts.map +1 -1
- package/src/slash/delegation-adapters.js +17 -0
- package/src/slash/delegation-adapters.js.map +1 -1
- package/src/slash/prompt-template-bridge.d.ts.map +1 -1
- package/src/slash/prompt-template-bridge.js +14 -1
- package/src/slash/prompt-template-bridge.js.map +1 -1
- package/src/slash/prompt-workflows.d.ts.map +1 -1
- package/src/slash/prompt-workflows.js +16 -2
- package/src/slash/prompt-workflows.js.map +1 -1
- package/src/slash/slash-commands.d.ts.map +1 -1
- package/src/slash/slash-commands.js +7 -253
- package/src/slash/slash-commands.js.map +1 -1
- package/src/slash/subagent-cost.d.ts +30 -0
- package/src/slash/subagent-cost.d.ts.map +1 -0
- package/src/slash/subagent-cost.js +307 -0
- package/src/slash/subagent-cost.js.map +1 -0
- package/src/tui/fleet-status.d.ts +2 -0
- package/src/tui/fleet-status.d.ts.map +1 -1
- package/src/tui/fleet-status.js +25 -2
- package/src/tui/fleet-status.js.map +1 -1
- package/src/tui/fleet.d.ts +1 -1
- package/src/tui/fleet.d.ts.map +1 -1
- package/src/tui/fleet.js +5 -1
- package/src/tui/fleet.js.map +1 -1
- package/src/tui/render.d.ts.map +1 -1
- package/src/tui/render.js +8 -4
- package/src/tui/render.js.map +1 -1
- package/src/watchdog/diff-tool.d.ts +2 -1
- package/src/watchdog/diff-tool.d.ts.map +1 -1
- package/src/watchdog/diff-tool.js +9 -3
- package/src/watchdog/diff-tool.js.map +1 -1
- package/src/watchdog/permission-arbiter.d.ts.map +1 -1
- package/src/watchdog/permission-arbiter.js +2 -7
- package/src/watchdog/permission-arbiter.js.map +1 -1
- package/src/watchdog/register-child.d.ts +3 -1
- package/src/watchdog/register-child.d.ts.map +1 -1
- package/src/watchdog/register-child.js +12 -3
- package/src/watchdog/register-child.js.map +1 -1
- package/src/watchdog/review.d.ts +1 -1
- package/src/watchdog/review.d.ts.map +1 -1
- package/src/watchdog/review.js +2 -7
- package/src/watchdog/review.js.map +1 -1
- package/src/watchdog/runtime.d.ts +1 -1
- package/src/watchdog/runtime.d.ts.map +1 -1
- package/src/watchdog/runtime.js +2 -1
- package/src/watchdog/runtime.js.map +1 -1
- package/src/watchdog/turn-delta.d.ts +5 -1
- package/src/watchdog/turn-delta.d.ts.map +1 -1
- package/src/watchdog/turn-delta.js +9 -5
- package/src/watchdog/turn-delta.js.map +1 -1
|
@@ -40,6 +40,7 @@ import { canPreferFork, createForkContextResolver, resolveSubagentLaunchContext
|
|
|
40
40
|
import { createPrunedForkSessionWriter } from "../../shared/pruned-fork.js";
|
|
41
41
|
import { resolveCurrentSessionId } from "../../shared/session-identity.js";
|
|
42
42
|
import { currentCompletionOwnerId } from "../../shared/completion-owner.js";
|
|
43
|
+
import { SUBAGENT_ASYNC_COMPLETE_EVENT } from "../../shared/types.js";
|
|
43
44
|
import { applyIntercomBridgeToAgent, INTERCOM_BRIDGE_MARKER, resolveIntercomBridge, resolveIntercomSessionTarget, resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.js";
|
|
44
45
|
import { formatControlIntercomMessage, formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "../shared/subagent-control.js";
|
|
45
46
|
import { formatSpawnBudget, getSpawnBudgetSnapshot, grantSpawnBudget, preflightSpawnBudget, preflightSpawnBudgetGrant, reserveSpawnBudget } from "../shared/spawn-budget.js";
|
|
@@ -47,13 +48,13 @@ import { claimRunFanoutBatch, claimRunFanoutBatchWithCommit, createRunFanoutBudg
|
|
|
47
48
|
import { retainLiveForegroundNestedRoute } from "../../integrations/pi-web-session-liveness.js";
|
|
48
49
|
import { validateToolBudgetConfig } from "../shared/tool-budget.js";
|
|
49
50
|
import { usageBudgetExceededMessage, usageBudgetState, validateUsageBudgetConfig } from "../shared/usage-budget.js";
|
|
50
|
-
import { intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling } from "../shared/capability-ceiling.js";
|
|
51
|
+
import { assertAgentAllowedByCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling } from "../shared/capability-ceiling.js";
|
|
51
52
|
import { isAgentContract } from "../shared/agent-contract.js";
|
|
52
53
|
import { normalizeExtensionBindings } from "../shared/extension-bindings.js";
|
|
53
54
|
import { resolveRequiredChildExtensions } from "../../shared/required-child-extensions.js";
|
|
54
55
|
import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, outputPathMappingFromTask, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.js";
|
|
55
56
|
import { assertJsonSchemaObject, cleanupStructuredOutputRuntime, createStructuredOutputRuntime } from "../shared/structured-output.js";
|
|
56
|
-
import { compactForegroundDetails, getSingleResultOutput, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.js";
|
|
57
|
+
import { compactForegroundDetails, getSingleResultOutput, PROMPT_REDACTED, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.js";
|
|
57
58
|
import { discardPreservedWorktrees, formatParallelHandoffError, formatParallelHandoffReference, formatStoredParallelHandoffCleanup, parallelHandoffPath, readParallelHandoffManifest, recordParallelHandoffMerge, recordParallelHandoffSupersession, writeParallelHandoffGroup, writeWorktreeSetupHandoff } from "../shared/parallel-handoff.js";
|
|
58
59
|
import { summarizeContextModes } from "../shared/context-mode.js";
|
|
59
60
|
import { attachNestedChildrenToResultChildren, buildSubagentResultIntercomPayload, deliverSubagentResultIntercomEvent, formatSubagentResultReceipt, resolveSubagentResultStatus, stripDetailsOutputsForIntercomReceipt, } from "../../intercom/result-intercom.js";
|
|
@@ -84,7 +85,7 @@ import { MissionNotFoundError, updateMission } from "../../missions/store.js";
|
|
|
84
85
|
import { createMissionWorkflowState } from "../../missions/workflow-state.js";
|
|
85
86
|
import { resolveAuthorityDecision } from "../../policy/authority.js";
|
|
86
87
|
import { handleInspectorAction, INSPECTOR_ACTIONS } from "../../inspectors/actions.js";
|
|
87
|
-
import {
|
|
88
|
+
import { getInspectorPlugins } from "../../inspectors/plugins.js";
|
|
88
89
|
import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.js";
|
|
89
90
|
import { previewSimpleWorkflowRun, runWorkflowScript, validateWorkflowScript, WorkflowScriptError } from "../../workflows/scripted-workflow.js";
|
|
90
91
|
import { formatIncrementalChildCompletion, incrementalChildCompletionTriggersTurn } from "../background/notify.js";
|
|
@@ -100,7 +101,7 @@ import { deepFreezeWorkflowArgs, normalizeWorkflowArgs, resolveWorkflowResource
|
|
|
100
101
|
import { stableJsonDigest } from "../../shared/launch-contract.js";
|
|
101
102
|
import { cleanupWorktrees, createWorktrees, preflightWorktreeSource, withWorktreeTransaction, diffWorktrees, formatWorktreeDiffSummary, } from "../shared/worktree.js";
|
|
102
103
|
import { createWorktreeCleanupPlan, formatWorktreeCleanupPlan } from "../shared/worktree-cleanup-plan.js";
|
|
103
|
-
import { DIRS, DEFAULT_ARTIFACT_CONFIG, DEFAULT_FORK_PREAMBLE, SUBAGENT_ACTIONS, SUBAGENT_CONTROL_EVENT, SUBAGENT_CONTROL_INTERCOM_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, checkSubagentDepth, resolveChildMaxSubagentDepth, resolveCurrentMaxSubagentDepth, resolveMaxSubagentSpawnsPerRun, wrapForkTask, } from "../../shared/types.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
105
|
import { deriveChildSessionName } from "../../shared/child-session-name.js";
|
|
105
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"]);
|
|
106
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"]);
|
|
@@ -1159,6 +1160,57 @@ function resolveNestedResumeTarget(match, trustedSessionRoots) {
|
|
|
1159
1160
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
1160
1161
|
});
|
|
1161
1162
|
}
|
|
1163
|
+
function resolveNestedExternalJobResumeTarget(match, params, deps) {
|
|
1164
|
+
const run = match.match.run;
|
|
1165
|
+
if (run.state === "stopped")
|
|
1166
|
+
return undefined;
|
|
1167
|
+
const asyncDir = resolveNestedAsyncDir(match.match.rootRunId, run);
|
|
1168
|
+
if (!asyncDir)
|
|
1169
|
+
return undefined;
|
|
1170
|
+
const status = readNestedRunStatus(asyncDir, run);
|
|
1171
|
+
const steps = status?.steps ?? [];
|
|
1172
|
+
const step = steps[params.index ?? 0];
|
|
1173
|
+
if (!step) {
|
|
1174
|
+
// An index outside an external-job run gets the async resolver's index error instead of a Pi revive.
|
|
1175
|
+
if (params.index === undefined || !steps.some((candidate) => candidate.runner?.type === "external-job"))
|
|
1176
|
+
return undefined;
|
|
1177
|
+
}
|
|
1178
|
+
else if (!step.runner) {
|
|
1179
|
+
// Pi steps record no runner, and neither does a launch status before the runner starts.
|
|
1180
|
+
// A session file means a Pi run; otherwise the agent definition says what the step runs.
|
|
1181
|
+
if (nestedRunSessionFile(run))
|
|
1182
|
+
return undefined;
|
|
1183
|
+
const agent = deps.discoverAgents(status?.cwd ?? deps.state.baseCwd, resolveExecutionAgentScope(params.agentScope)).agents.find((candidate) => candidate.name === step.agent);
|
|
1184
|
+
if (agent?.runner?.type === "external-job")
|
|
1185
|
+
throw new Error(externalJobWithoutMetadataMessage(run.id));
|
|
1186
|
+
return undefined;
|
|
1187
|
+
}
|
|
1188
|
+
else if (step.runner.type !== "external-job") {
|
|
1189
|
+
return undefined;
|
|
1190
|
+
}
|
|
1191
|
+
// External-job runs have no Pi session, so resume them as a provider follow-up from their own run directory.
|
|
1192
|
+
const target = resolveAsyncResumeTarget(compactOptional({ dir: asyncDir, index: params.index }), nestedRunScope(match.match.rootRunId), { requireSessionFile: false });
|
|
1193
|
+
if (target.kind === "live")
|
|
1194
|
+
throw new Error(externalJobStillRunningMessage(target.runId));
|
|
1195
|
+
return { source: "async", ...target };
|
|
1196
|
+
}
|
|
1197
|
+
function readNestedRunStatus(asyncDir, run) {
|
|
1198
|
+
try {
|
|
1199
|
+
return readStatus(asyncDir);
|
|
1200
|
+
}
|
|
1201
|
+
catch (error) {
|
|
1202
|
+
// A nested Pi run revives from its session file, so its unreadable status file must not block it.
|
|
1203
|
+
if (nestedRunSessionFile(run))
|
|
1204
|
+
return null;
|
|
1205
|
+
throw error;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function externalJobStillRunningMessage(runId) {
|
|
1209
|
+
return `External-job run '${runId}' is still running. Wait for completion, then use subagent({ action: "resume", id: "${runId}", message: "..." }).`;
|
|
1210
|
+
}
|
|
1211
|
+
function externalJobWithoutMetadataMessage(runId) {
|
|
1212
|
+
return `External-job run '${runId}' has no persisted provider metadata. Cannot follow up without the parent provider job id.`;
|
|
1213
|
+
}
|
|
1162
1214
|
async function waitForNestedControlResult(target, requestId, ignoredFiles, timeoutMs = 1_000) {
|
|
1163
1215
|
const deadline = Date.now() + timeoutMs;
|
|
1164
1216
|
while (Date.now() < deadline) {
|
|
@@ -1319,14 +1371,14 @@ function externalRunnerControlError(asyncDir, action) {
|
|
|
1319
1371
|
}
|
|
1320
1372
|
async function resumeExternalJobFollowUp(input) {
|
|
1321
1373
|
if (input.target.kind === "live" || input.target.state === "running" || input.target.state === "queued") {
|
|
1322
|
-
return { content: [{ type: "text", text:
|
|
1374
|
+
return { content: [{ type: "text", text: externalJobStillRunningMessage(input.target.runId) }], isError: true, details: { mode: "management", results: [] } };
|
|
1323
1375
|
}
|
|
1324
1376
|
const runner = input.target.runner;
|
|
1325
1377
|
const externalJob = input.target.externalJob;
|
|
1326
1378
|
if (runner?.type !== "external-job")
|
|
1327
1379
|
return { content: [{ type: "text", text: "Internal error: external-job follow-up was requested for a non-external-job runner." }], isError: true, details: { mode: "management", results: [] } };
|
|
1328
1380
|
if (!externalJob)
|
|
1329
|
-
return { content: [{ type: "text", text:
|
|
1381
|
+
return { content: [{ type: "text", text: externalJobWithoutMetadataMessage(input.target.runId) }], isError: true, details: { mode: "management", results: [] } };
|
|
1330
1382
|
if (externalJob.provider !== runner.provider)
|
|
1331
1383
|
return { content: [{ type: "text", text: `External-job run '${input.target.runId}' has mismatched provider metadata. Refusing to follow up.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1332
1384
|
if (!externalJobOptionsEqual(externalJob.options, runner.options))
|
|
@@ -1342,11 +1394,14 @@ async function resumeExternalJobFollowUp(input) {
|
|
|
1342
1394
|
const requestDigest = externalJobFollowUpRequestDigest({ provider: runner.provider, parentProviderJobId: externalJob.providerJobId, promptDigest, options: runner.options });
|
|
1343
1395
|
const requestId = externalJobFollowUpRequestId(requestDigest);
|
|
1344
1396
|
const runId = externalJobFollowUpRunId(requestDigest);
|
|
1345
|
-
|
|
1397
|
+
// A child launches the follow-up under its nested route, so look for an earlier one where it would be.
|
|
1398
|
+
const nestedRoute = inheritedNestedRoute(input.deps);
|
|
1399
|
+
const runRoots = nestedRoute ? nestedRunScope(nestedRoute.rootRunId) : { asyncDirRoot: DIRS.async, resultsDir: DIRS.results };
|
|
1400
|
+
const asyncDir = path.join(runRoots.asyncDirRoot, runId);
|
|
1346
1401
|
const currentSessionId = input.deps.state.currentSessionId;
|
|
1347
1402
|
if (!currentSessionId)
|
|
1348
1403
|
return { content: [{ type: "text", text: "External-job follow-up requires an active parent session." }], isError: true, details: { mode: "management", results: [] } };
|
|
1349
|
-
if (fs.existsSync(asyncDir) || fs.existsSync(resultFilePath(
|
|
1404
|
+
if (fs.existsSync(asyncDir) || fs.existsSync(resultFilePath(runRoots.resultsDir, runId))) {
|
|
1350
1405
|
return externalJobFollowUpStarted({ sourceRunId: input.target.runId, runId, asyncDir, duplicate: true, interactive: input.ctx.hasUI });
|
|
1351
1406
|
}
|
|
1352
1407
|
const depthState = checkSubagentDepth(input.deps.config.maxSubagentDepth, input.deps.childRuntime);
|
|
@@ -1442,6 +1497,9 @@ function resolveRequestedResumeTarget(params, deps, parentSessionFile) {
|
|
|
1442
1497
|
throw new Error("Attaching a running subagent as a chain root is currently available for top-level async runs only.");
|
|
1443
1498
|
if (resolved.match.run.state === "running" || resolved.match.run.state === "queued")
|
|
1444
1499
|
return { kind: "live-nested", target: resolved };
|
|
1500
|
+
const externalJobTarget = resolveNestedExternalJobResumeTarget(resolved, params, deps);
|
|
1501
|
+
if (externalJobTarget)
|
|
1502
|
+
return externalJobTarget;
|
|
1445
1503
|
const trustedSessionRoots = [
|
|
1446
1504
|
...(deps.config.defaultSessionDir ? [path.resolve(deps.expandTilde(deps.config.defaultSessionDir))] : []),
|
|
1447
1505
|
...(parentSessionFile ? [deps.getSubagentSessionRoot(parentSessionFile)] : []),
|
|
@@ -1516,7 +1574,7 @@ async function resumeAsyncRun(input) {
|
|
|
1516
1574
|
const discoveredAgents = discovered.agents;
|
|
1517
1575
|
const unknownAgentDiagnosticContext = diagnosticContextFromDiscovery(discovered, effectiveCwd, scope);
|
|
1518
1576
|
const modelScope = discovered.modelScope;
|
|
1519
|
-
const sessionName = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
|
|
1577
|
+
const sessionName = resolveIntercomSessionTarget(input.deps.childRuntime?.intercomSessionName ?? input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
|
|
1520
1578
|
const recoveryDescriptor = "recoveryDescriptor" in target ? target.recoveryDescriptor : undefined;
|
|
1521
1579
|
const recoveryContext = recoveryDescriptor?.context ?? (input.params.context === "profile" ? undefined : input.params.context);
|
|
1522
1580
|
const intercomBridge = resolveIntercomBridge({
|
|
@@ -1558,7 +1616,7 @@ async function resumeAsyncRun(input) {
|
|
|
1558
1616
|
if (target.source === "async" && target.runner?.type === "external-job") {
|
|
1559
1617
|
if (attachChain)
|
|
1560
1618
|
return { content: [{ type: "text", text: "External-job follow-up does not support chain attachment. Use action='resume' with message instead." }], isError: true, details: { mode: "management", results: [] } };
|
|
1561
|
-
|
|
1619
|
+
const resumed = await resumeExternalJobFollowUp({
|
|
1562
1620
|
target,
|
|
1563
1621
|
followUp,
|
|
1564
1622
|
baseAgentConfig,
|
|
@@ -1572,6 +1630,10 @@ async function resumeAsyncRun(input) {
|
|
|
1572
1630
|
parentSessionFile,
|
|
1573
1631
|
absoluteDeadlineAt: input.absoluteDeadlineAt,
|
|
1574
1632
|
});
|
|
1633
|
+
const resumedRunId = resumed.details.runId ?? resumed.details.asyncId;
|
|
1634
|
+
if (!resumed.isError && resumedRunId)
|
|
1635
|
+
input.onLaunch?.({ agent: target.agent, async: true, runId: resumedRunId });
|
|
1636
|
+
return resumed;
|
|
1575
1637
|
}
|
|
1576
1638
|
if (attachChain) {
|
|
1577
1639
|
if (target.source !== "async") {
|
|
@@ -1679,6 +1741,7 @@ async function resumeAsyncRun(input) {
|
|
|
1679
1741
|
return result;
|
|
1680
1742
|
}
|
|
1681
1743
|
const attachedId = result.details.asyncId ?? runId;
|
|
1744
|
+
input.onLaunch?.({ agent: target.agent, ...(target.sessionFile ? { sessionFile: target.sessionFile } : {}), async: true, runId: attachedId });
|
|
1682
1745
|
const lines = [
|
|
1683
1746
|
`Attached async subagent ${target.runId} as the first step of a new chain.`,
|
|
1684
1747
|
`Chain run: ${attachedId}`,
|
|
@@ -1695,11 +1758,14 @@ async function resumeAsyncRun(input) {
|
|
|
1695
1758
|
if (!revivalSessionFile) {
|
|
1696
1759
|
return { content: [{ type: "text", text: `Async run '${target.runId}' child ${target.index} does not have a persisted session file to resume from.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1697
1760
|
}
|
|
1761
|
+
if (input.params.baseRef !== undefined && "managedWorktree" in target && target.managedWorktree === true) {
|
|
1762
|
+
return { content: [{ type: "text", text: "Cannot resume with baseRef: retained managed-worktree children continue in their existing worktree. Start a new worktree run from that base ref instead." }], isError: true, details: { mode: "management", results: [] } };
|
|
1763
|
+
}
|
|
1698
1764
|
if (target.source === "async" && asyncReviveRequiresRecoveryDescriptor(target)) {
|
|
1699
1765
|
return { content: [{ type: "text", text: `Async child '${target.runId}' is missing its required run fan-out recovery identity. Start a new run instead.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1700
1766
|
}
|
|
1701
|
-
if (
|
|
1702
|
-
return { content: [{ type: "text", text:
|
|
1767
|
+
if (target.source === "nested" && !target.recoveryDescriptor) {
|
|
1768
|
+
return { content: [{ type: "text", text: `Nested child '${target.runId}' is missing its required recovery identity. Start a new run instead.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1703
1769
|
}
|
|
1704
1770
|
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(baseAgentConfig, recoveryDescriptor) : baseAgentConfig;
|
|
1705
1771
|
const agentConfig = intercomBridge.active ? applyIntercomBridgeToAgent(recoveryAgentConfig, intercomBridge) : recoveryAgentConfig;
|
|
@@ -1821,15 +1887,19 @@ async function resumeAsyncRun(input) {
|
|
|
1821
1887
|
...(input.params.timeoutMs !== undefined ? { timeoutMs: input.params.timeoutMs } : {}),
|
|
1822
1888
|
...(input.absoluteDeadlineAt !== undefined ? { absoluteDeadlineAt: input.absoluteDeadlineAt } : {}),
|
|
1823
1889
|
...(input.params.toolBudget !== undefined ? { toolBudget: input.params.toolBudget } : {}),
|
|
1824
|
-
|
|
1890
|
+
// Recovery descriptors, remembered foreground runs, and current workflow roots
|
|
1891
|
+
// preserve parent authority before the selected agent's descendant ceiling.
|
|
1892
|
+
capabilityCeiling: intersectSubagentCapabilityCeilings(recoveryDescriptor?.capabilityCeiling ?? (target.source === "foreground" || (target.source === "async" && target.mode === "workflow") ? target.capabilityCeiling : undefined), resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
|
|
1825
1893
|
runFanoutBudget: input.params.runFanoutBudget ?? recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
1826
1894
|
parentWorkflowRunId: input.params.workflowParentRunId,
|
|
1827
1895
|
workflowKey: input.params.workflowKey,
|
|
1828
1896
|
activeAsyncCapacity,
|
|
1829
1897
|
}));
|
|
1898
|
+
const notifyLaunch = () => input.onLaunch?.({ agent: target.agent, sessionFile: revivalSessionFile, async: true, runId });
|
|
1830
1899
|
if (result.isError) {
|
|
1831
1900
|
const startedStatus = readStatus(revivalAsyncDir);
|
|
1832
1901
|
if (input.params.workflowParentRunId !== undefined && startedStatus?.runId === runId && startedStatus.processTerminal?.runnerProcessInstanceId) {
|
|
1902
|
+
notifyLaunch();
|
|
1833
1903
|
return {
|
|
1834
1904
|
...result,
|
|
1835
1905
|
details: {
|
|
@@ -1844,6 +1914,7 @@ async function resumeAsyncRun(input) {
|
|
|
1844
1914
|
activeAsyncCapacity?.rollback();
|
|
1845
1915
|
return result;
|
|
1846
1916
|
}
|
|
1917
|
+
notifyLaunch();
|
|
1847
1918
|
for (const brief of queuedBriefs)
|
|
1848
1919
|
fs.rmSync(brief.path, { force: true });
|
|
1849
1920
|
if (queuedBriefs.length > 0 && sourceAsyncDir) {
|
|
@@ -1872,6 +1943,7 @@ async function resumeAsyncRun(input) {
|
|
|
1872
1943
|
}
|
|
1873
1944
|
if (completed.importedPublication)
|
|
1874
1945
|
removeWorkflowAwaitedResult(asyncDir, resultPath, revivedId, completed.importedPublication);
|
|
1946
|
+
emitWorkflowAwaitedChildComplete(input.deps.pi, input.deps.state, revivedId, asyncDir, input.params.workflowParentRunId, completed);
|
|
1875
1947
|
const usage = importedAsyncRootUsage(completed);
|
|
1876
1948
|
const childResult = {
|
|
1877
1949
|
index: 0,
|
|
@@ -2147,11 +2219,15 @@ function projectEffectiveAcceptanceSchemas(params, agents) {
|
|
|
2147
2219
|
}
|
|
2148
2220
|
function validateExecutionInput(params, agents, hasChain, hasTasks, hasSingle, allowClarifyTaskPrompt, context) {
|
|
2149
2221
|
if (Number(hasChain) + Number(hasTasks) + Number(hasSingle) !== 1) {
|
|
2222
|
+
const agentList = agents.map((a) => a.name).join(", ") || "none";
|
|
2223
|
+
const noMode = !hasChain && !hasTasks && !hasSingle;
|
|
2150
2224
|
return {
|
|
2151
2225
|
content: [
|
|
2152
2226
|
{
|
|
2153
2227
|
type: "text",
|
|
2154
|
-
text:
|
|
2228
|
+
text: noMode && typeof params.workflowKey === "string"
|
|
2229
|
+
? `Workflow child '${params.workflowKey}' has no agent. Pass { key, agent, task }. Agents: ${agentList}`
|
|
2230
|
+
: `Provide exactly one mode. Agents: ${agentList}`,
|
|
2155
2231
|
},
|
|
2156
2232
|
],
|
|
2157
2233
|
isError: true,
|
|
@@ -2787,6 +2863,30 @@ function removeWorkflowAwaitedResult(asyncDir, resultPath, runId, publication) {
|
|
|
2787
2863
|
}
|
|
2788
2864
|
removeResultIndex(asyncDir, publication.sessionId, runId, publication.toolCallId);
|
|
2789
2865
|
}
|
|
2866
|
+
function emitWorkflowAwaitedChildComplete(pi, state, runId, asyncDir, parentWorkflowRunId, completed) {
|
|
2867
|
+
let status;
|
|
2868
|
+
try {
|
|
2869
|
+
status = readStatus(asyncDir);
|
|
2870
|
+
}
|
|
2871
|
+
catch (error) {
|
|
2872
|
+
console.error(`Failed to read awaited workflow child status for ${runId}; emitting completion with fallback metadata:`, error);
|
|
2873
|
+
}
|
|
2874
|
+
pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
|
|
2875
|
+
id: runId,
|
|
2876
|
+
runId,
|
|
2877
|
+
sessionId: status?.sessionId ?? completed.importedPublication?.sessionId ?? state.currentSessionId,
|
|
2878
|
+
completionOwnerId: status?.completionOwnerId ?? state.completionOwnerId ?? currentCompletionOwnerId(),
|
|
2879
|
+
asyncDir,
|
|
2880
|
+
agent: completed.agent,
|
|
2881
|
+
mode: "single",
|
|
2882
|
+
state: completed.stopped ? "stopped" : completed.success ? "complete" : "failed",
|
|
2883
|
+
success: completed.success,
|
|
2884
|
+
timestamp: Date.now(),
|
|
2885
|
+
triggerTurn: false,
|
|
2886
|
+
awaitedByWorkflow: true,
|
|
2887
|
+
parentWorkflowRunId,
|
|
2888
|
+
});
|
|
2889
|
+
}
|
|
2790
2890
|
async function waitForWorkflowAsyncSingleResult(params, launchResult, options) {
|
|
2791
2891
|
if (params.workflowAwaitAsync !== true || !launchResult.details.asyncDir)
|
|
2792
2892
|
return launchResult;
|
|
@@ -2809,6 +2909,7 @@ async function waitForWorkflowAsyncSingleResult(params, launchResult, options) {
|
|
|
2809
2909
|
}
|
|
2810
2910
|
if (completed.importedPublication)
|
|
2811
2911
|
removeWorkflowAwaitedResult(asyncDir, resultPath, options.runId, completed.importedPublication);
|
|
2912
|
+
emitWorkflowAwaitedChildComplete(options.pi, options.state, options.runId, asyncDir, params.workflowParentRunId, completed);
|
|
2812
2913
|
const usage = importedAsyncRootUsage(completed);
|
|
2813
2914
|
const childResult = omitUndefinedProperties({
|
|
2814
2915
|
index: 0,
|
|
@@ -2983,7 +3084,7 @@ async function runAsyncPath(data, deps) {
|
|
|
2983
3084
|
lane: params.lane,
|
|
2984
3085
|
workflowAwaitAsync: params.workflowAwaitAsync,
|
|
2985
3086
|
}));
|
|
2986
|
-
return waitForWorkflowAsyncSingleResult(params, asyncResult, { runId: id, task: params.task ?? "", signal: data.signal, state: deps.state, kill: deps.kill });
|
|
3087
|
+
return waitForWorkflowAsyncSingleResult(params, asyncResult, { runId: id, task: params.task ?? "", signal: data.signal, state: deps.state, pi: deps.pi, kill: deps.kill });
|
|
2987
3088
|
}
|
|
2988
3089
|
return null;
|
|
2989
3090
|
}
|
|
@@ -4662,6 +4763,7 @@ export function createSubagentExecutor(deps) {
|
|
|
4662
4763
|
...(workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {}),
|
|
4663
4764
|
...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}),
|
|
4664
4765
|
pid: process.pid,
|
|
4766
|
+
...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}),
|
|
4665
4767
|
steps: [],
|
|
4666
4768
|
...(workflowPreflight ? { preflight: workflowPreflight } : {}),
|
|
4667
4769
|
workflow: { trace: [], emits: [], console: [], ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}) },
|
|
@@ -4730,11 +4832,15 @@ export function createSubagentExecutor(deps) {
|
|
|
4730
4832
|
deps.refreshResultDelivery?.();
|
|
4731
4833
|
return false;
|
|
4732
4834
|
};
|
|
4835
|
+
const pendingWorkflowChildAnnouncements = new Map();
|
|
4836
|
+
let announcePersistedWorkflowChildren = () => { };
|
|
4733
4837
|
const runPersistence = createCapacityResilientJsonWriter({
|
|
4734
4838
|
keepAlive: true,
|
|
4735
4839
|
onSuccess: (filePath, payload) => {
|
|
4736
|
-
if (filePath === statusPath)
|
|
4840
|
+
if (filePath === statusPath) {
|
|
4841
|
+
announcePersistedWorkflowChildren();
|
|
4737
4842
|
queueActiveRunIndex(payload);
|
|
4843
|
+
}
|
|
4738
4844
|
if (filePath === resultPath)
|
|
4739
4845
|
settleResultPublication?.(true);
|
|
4740
4846
|
},
|
|
@@ -4775,7 +4881,8 @@ export function createSubagentExecutor(deps) {
|
|
|
4775
4881
|
else if (options.tolerateStatusWriteFailure) {
|
|
4776
4882
|
try {
|
|
4777
4883
|
runPersistence.write(statusPath, { ...status });
|
|
4778
|
-
|
|
4884
|
+
if (runPersistence.pendingCount() === 0)
|
|
4885
|
+
statusPersistenceDegraded = false;
|
|
4779
4886
|
}
|
|
4780
4887
|
catch (error) {
|
|
4781
4888
|
const message = `Failed to persist async workflow state ${statusPath}: ${error instanceof Error ? error.message : String(error)}`;
|
|
@@ -4871,6 +4978,25 @@ export function createSubagentExecutor(deps) {
|
|
|
4871
4978
|
return { content: [{ type: "text", text: `Failed to create async workflow storage: ${error instanceof Error ? error.message : String(error)}` }], isError: true, details: { mode: "workflow", results: [] } };
|
|
4872
4979
|
}
|
|
4873
4980
|
appendWorkflowEvent({ type: "subagent.workflow.started", ...(workflowArgsDigest ? { argsDigest: workflowArgsDigest } : {}) });
|
|
4981
|
+
try {
|
|
4982
|
+
deps.pi.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
|
|
4983
|
+
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
4984
|
+
id: workflowRunId,
|
|
4985
|
+
asyncDir,
|
|
4986
|
+
cwd: workflowCwd,
|
|
4987
|
+
...(workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {}),
|
|
4988
|
+
pid: process.pid,
|
|
4989
|
+
sessionId: currentSessionId ?? undefined,
|
|
4990
|
+
completionOwnerId,
|
|
4991
|
+
mode: "workflow",
|
|
4992
|
+
agent: "workflow",
|
|
4993
|
+
goal: derivedObjective.trim() ? PROMPT_REDACTED : undefined,
|
|
4994
|
+
...(timeout !== undefined ? { timeoutMs: timeout, deadlineAt: startedAt + timeout } : {}),
|
|
4995
|
+
});
|
|
4996
|
+
}
|
|
4997
|
+
catch (error) {
|
|
4998
|
+
console.error("Failed to emit async workflow start event:", error);
|
|
4999
|
+
}
|
|
4874
5000
|
// The runner does not execute workflow scripts: this active owner must consume its own
|
|
4875
5001
|
// durable steer inbox, deliver through in-process child controls, and persist receipts.
|
|
4876
5002
|
const emitWorkflowSteerEvent = (type, requestId, index, extra = {}) => {
|
|
@@ -5039,6 +5165,44 @@ export function createSubagentExecutor(deps) {
|
|
|
5039
5165
|
const childOutputClaimPaths = new Map();
|
|
5040
5166
|
const producedChildOutputPaths = new Set();
|
|
5041
5167
|
const workflowSteps = new Map();
|
|
5168
|
+
const announcedWorkflowChildren = new Set();
|
|
5169
|
+
const announceWorkflowChild = (key, step) => {
|
|
5170
|
+
if (announcedWorkflowChildren.has(key))
|
|
5171
|
+
return;
|
|
5172
|
+
announcedWorkflowChildren.add(key);
|
|
5173
|
+
const stepIndex = status.steps?.indexOf(step);
|
|
5174
|
+
const childEvent = {
|
|
5175
|
+
type: "subagent.child-status",
|
|
5176
|
+
version: 1,
|
|
5177
|
+
runId: workflowRunId,
|
|
5178
|
+
childId: key,
|
|
5179
|
+
status: "started",
|
|
5180
|
+
ts: Date.now(),
|
|
5181
|
+
source: "async",
|
|
5182
|
+
asyncDir,
|
|
5183
|
+
...(stepIndex !== undefined ? { stepIndex } : {}),
|
|
5184
|
+
agent: step.agent,
|
|
5185
|
+
...(step.runId ? { childRunId: step.runId } : {}),
|
|
5186
|
+
workflowKey: key,
|
|
5187
|
+
...(step.phase ? { phase: step.phase } : {}),
|
|
5188
|
+
...(step.label ? { label: step.label } : {}),
|
|
5189
|
+
};
|
|
5190
|
+
appendWorkflowEvent({ ...childEvent });
|
|
5191
|
+
try {
|
|
5192
|
+
deps.pi.events.emit(SUBAGENT_CHILD_STATUS_EVENT, childEvent);
|
|
5193
|
+
}
|
|
5194
|
+
catch (error) {
|
|
5195
|
+
console.error("Failed to emit workflow child status event:", error);
|
|
5196
|
+
}
|
|
5197
|
+
};
|
|
5198
|
+
announcePersistedWorkflowChildren = () => {
|
|
5199
|
+
for (const [key, step] of pendingWorkflowChildAnnouncements) {
|
|
5200
|
+
if (!step.runId)
|
|
5201
|
+
continue;
|
|
5202
|
+
announceWorkflowChild(key, step);
|
|
5203
|
+
pendingWorkflowChildAnnouncements.delete(key);
|
|
5204
|
+
}
|
|
5205
|
+
};
|
|
5042
5206
|
const runHostCommand = workflowHostCommandRunner({
|
|
5043
5207
|
workflowCwd,
|
|
5044
5208
|
artifactsDir: workflowArtifactsDir,
|
|
@@ -5280,6 +5444,8 @@ export function createSubagentExecutor(deps) {
|
|
|
5280
5444
|
step.runId = launch.runId;
|
|
5281
5445
|
if (childRequest.lane)
|
|
5282
5446
|
step.lane = childRequest.lane;
|
|
5447
|
+
if (step.runId)
|
|
5448
|
+
pendingWorkflowChildAnnouncements.set(key, step);
|
|
5283
5449
|
persist({ tolerateStatusWriteFailure: true });
|
|
5284
5450
|
}
|
|
5285
5451
|
recordMissionWorkflowChild(missionBinding, workflowRunId, key, { status: "running", agent: launch.agent, ...(launch.sessionFile ? { sessionPath: launch.sessionFile } : {}) });
|
|
@@ -5376,7 +5542,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5376
5542
|
catch (receiptError) {
|
|
5377
5543
|
appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
|
|
5378
5544
|
}
|
|
5379
|
-
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, workflowChildren, results: workflowResultChildren(workflow.children, status, false), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
|
|
5545
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, workflowChildren, results: workflowResultChildren(workflow.children, status, false), workflow: status.workflow, ...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}), ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
|
|
5380
5546
|
return;
|
|
5381
5547
|
if (pendingResultPublication && !await pendingResultPublication)
|
|
5382
5548
|
return;
|
|
@@ -5433,7 +5599,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5433
5599
|
catch (receiptError) {
|
|
5434
5600
|
appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
|
|
5435
5601
|
}
|
|
5436
|
-
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: workflowResultChildren(partial.children, status, true), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
|
|
5602
|
+
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: workflowResultChildren(partial.children, status, true), workflow: status.workflow, ...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}), ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
|
|
5437
5603
|
return;
|
|
5438
5604
|
if (pendingResultPublication && !await pendingResultPublication)
|
|
5439
5605
|
return;
|
|
@@ -5880,7 +6046,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5880
6046
|
cwd: requestCwd,
|
|
5881
6047
|
...(deps.config.missions ? { missions: deps.config.missions } : {}),
|
|
5882
6048
|
...(deps.config.authorityPolicy ? { authorityPolicy: deps.config.authorityPolicy } : {}),
|
|
5883
|
-
plugins:
|
|
6049
|
+
plugins: getInspectorPlugins(deps.pi),
|
|
5884
6050
|
signal,
|
|
5885
6051
|
});
|
|
5886
6052
|
}
|
|
@@ -6035,7 +6201,7 @@ export function createSubagentExecutor(deps) {
|
|
|
6035
6201
|
}
|
|
6036
6202
|
let orchestratorTarget;
|
|
6037
6203
|
try {
|
|
6038
|
-
orchestratorTarget = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
6204
|
+
orchestratorTarget = resolveIntercomSessionTarget(deps.childRuntime?.intercomSessionName ?? deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
6039
6205
|
}
|
|
6040
6206
|
catch (error) {
|
|
6041
6207
|
if (!sessionError)
|
|
@@ -6117,7 +6283,18 @@ export function createSubagentExecutor(deps) {
|
|
|
6117
6283
|
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots, abandonedSlotReleaseAfterMs: resolveAbandonedSlotReleaseAfterMs(deps.config.capacity?.abandonedSlotReleaseAfterMs) })));
|
|
6118
6284
|
}
|
|
6119
6285
|
if (action === "resume") {
|
|
6120
|
-
return resumeAsyncRun(omitUndefinedProperties({
|
|
6286
|
+
return resumeAsyncRun(omitUndefinedProperties({
|
|
6287
|
+
params: paramsWithResolvedCwd,
|
|
6288
|
+
requestCwd,
|
|
6289
|
+
ctx,
|
|
6290
|
+
deps,
|
|
6291
|
+
parentModel: requestParentModel,
|
|
6292
|
+
signal,
|
|
6293
|
+
...(workflowLaunchObserver ? { onLaunch: (launch) => {
|
|
6294
|
+
workflowLaunchObservers.delete(params);
|
|
6295
|
+
workflowLaunchObserver(launch);
|
|
6296
|
+
} } : {}),
|
|
6297
|
+
}));
|
|
6121
6298
|
}
|
|
6122
6299
|
if (action === "steer") {
|
|
6123
6300
|
if (paramsWithResolvedCwd.mode !== undefined && resolveSteerDeliveryMode(paramsWithResolvedCwd.mode) === undefined) {
|
|
@@ -6401,6 +6578,7 @@ export function createSubagentExecutor(deps) {
|
|
|
6401
6578
|
cwd: requestCwd,
|
|
6402
6579
|
config: deps.config,
|
|
6403
6580
|
currentSessionId: deps.state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined,
|
|
6581
|
+
discoverAgentsAll: deps.discoverAgentsAll,
|
|
6404
6582
|
runtimeAgentOwner: deps.pi,
|
|
6405
6583
|
onAgentsChanged: deps.onAgentsChanged,
|
|
6406
6584
|
});
|
|
@@ -6468,7 +6646,7 @@ export function createSubagentExecutor(deps) {
|
|
|
6468
6646
|
return buildRequestedModeError(effectiveParams, contextPolicyResult.error);
|
|
6469
6647
|
const contextPolicy = contextPolicyResult;
|
|
6470
6648
|
effectiveParams = contextPolicy.params;
|
|
6471
|
-
const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
6649
|
+
const sessionName = resolveIntercomSessionTarget(deps.childRuntime?.intercomSessionName ?? deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
6472
6650
|
const intercomBridge = resolveIntercomBridge({
|
|
6473
6651
|
config: deps.config.intercomBridge,
|
|
6474
6652
|
override: effectiveParams.intercomBridge,
|
|
@@ -6498,10 +6676,29 @@ export function createSubagentExecutor(deps) {
|
|
|
6498
6676
|
return spawnBudgetErrorResult(spawnPreflight.error, foregroundMode);
|
|
6499
6677
|
let forkSessionFileForIndex = () => undefined;
|
|
6500
6678
|
let prepareForkSessionForIndex = async () => { };
|
|
6679
|
+
// Check before pruner/session preparation, then recheck immediately before each fork
|
|
6680
|
+
// because the session capability ceiling can tighten while preparation awaits.
|
|
6681
|
+
const launchCapabilityCeiling = () => intersectSubagentCapabilityCeilings(intersectSubagentCapabilityCeilings(effectiveParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(requestSessionId)), deps.childRuntime?.capabilityCeiling);
|
|
6682
|
+
const assertLaunchableAgentsAllowedBeforeFork = () => {
|
|
6683
|
+
if (!contextPolicy.usesFork)
|
|
6684
|
+
return;
|
|
6685
|
+
const ceiling = launchCapabilityCeiling();
|
|
6686
|
+
const launchable = hasSingle
|
|
6687
|
+
? [effectiveParams.agent]
|
|
6688
|
+
: hasTasks
|
|
6689
|
+
? (effectiveParams.tasks ?? []).map((task) => task.agent)
|
|
6690
|
+
: (effectiveParams.chain ?? []).flatMap((step) => isDynamicParallelStep(step)
|
|
6691
|
+
&& (step.expand.maxItems ?? deps.config.chain?.dynamicFanout?.maxItems ?? 0) === 0
|
|
6692
|
+
? []
|
|
6693
|
+
: getStepAgents(step));
|
|
6694
|
+
for (const agent of launchable)
|
|
6695
|
+
assertAgentAllowedByCapabilityCeiling(agent, ceiling);
|
|
6696
|
+
};
|
|
6501
6697
|
// Forked children keep their requested thinking level. Signed Anthropic thinking
|
|
6502
6698
|
// blocks are stripped from the inherited transcript by the resolver (they are bound
|
|
6503
6699
|
// to the parent session), which is not a reason to disable the child's own reasoning.
|
|
6504
6700
|
try {
|
|
6701
|
+
assertLaunchableAgentsAllowedBeforeFork();
|
|
6505
6702
|
const pruneSession = contextPolicy.usesFork && deps.config.forkContext?.mode === "pruned"
|
|
6506
6703
|
? await createPrunedForkSessionWriter(ctx, deps.config.forkContext, signal)
|
|
6507
6704
|
: undefined;
|
|
@@ -6630,8 +6827,15 @@ export function createSubagentExecutor(deps) {
|
|
|
6630
6827
|
const childSessionFileForTask = (agentName, idx, modelOverride, modelOverrideFromParent, modelOrigin) => forkSessionFileForTask(agentName, idx, modelOverride, modelOverrideFromParent, modelOrigin) ?? path.join(sessionDirForIndex(idx), "session.jsonl");
|
|
6631
6828
|
const childSessionFileForIndex = (idx) => path.join(sessionDirForIndex(idx), "session.jsonl");
|
|
6632
6829
|
try {
|
|
6830
|
+
// The ceiling can change while the pruned writer is built; clarify skips preflight but
|
|
6831
|
+
// still branches the parent session at launch.
|
|
6832
|
+
assertLaunchableAgentsAllowedBeforeFork();
|
|
6633
6833
|
if (!(effectiveParams.clarify === true && ctx.hasUI) || deps.config.forkContext?.mode === "pruned") {
|
|
6634
|
-
|
|
6834
|
+
const prepareAllowedForkSession = async (agent, ...rest) => {
|
|
6835
|
+
assertAgentAllowedByCapabilityCeiling(agent, launchCapabilityCeiling());
|
|
6836
|
+
await prepareForkSessionForTask(agent, ...rest);
|
|
6837
|
+
};
|
|
6838
|
+
await preflightForkSessionsForStaticTasks(effectiveParams, contextPolicy, prepareAllowedForkSession, deps.config.chain?.dynamicFanout?.maxItems);
|
|
6635
6839
|
}
|
|
6636
6840
|
}
|
|
6637
6841
|
catch (error) {
|