pi-subagents 0.76.1 → 0.78.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 +115 -0
- package/README.md +1 -1
- package/agents/evidence-auditor.md +1 -0
- package/agents/oracle.md +9 -19
- package/agents/researcher.md +0 -3
- package/agents/reviewer.md +18 -61
- package/agents/scout.md +1 -4
- package/agents/worker.md +8 -25
- package/docs/agents.md +71 -4
- package/docs/configuration.md +75 -10
- package/docs/extension-api.md +38 -9
- package/docs/missions.md +24 -17
- package/docs/models.md +1 -1
- package/docs/observability.md +12 -5
- package/docs/tool-reference.md +103 -85
- package/docs/watchdog.md +8 -6
- package/docs/workflows.md +17 -8
- package/package.json +1 -1
- package/prompts/council.md +1 -1
- package/skills/pi-subagents/SKILL.md +2 -2
- package/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/skills/pi-subagents/references/execution-controls.md +16 -16
- package/skills/pi-subagents/references/management-authoring-rpc.md +16 -12
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +3 -3
- package/src/agents/advertised-agent-prompt.d.ts +5 -1
- package/src/agents/advertised-agent-prompt.d.ts.map +1 -1
- package/src/agents/advertised-agent-prompt.js +8 -2
- package/src/agents/advertised-agent-prompt.js.map +1 -1
- package/src/agents/agent-management.d.ts.map +1 -1
- package/src/agents/agent-management.js +5 -0
- package/src/agents/agent-management.js.map +1 -1
- package/src/agents/agent-scope.d.ts +1 -0
- package/src/agents/agent-scope.d.ts.map +1 -1
- package/src/agents/agent-scope.js +3 -0
- package/src/agents/agent-scope.js.map +1 -1
- package/src/agents/agent-serializer.d.ts.map +1 -1
- package/src/agents/agent-serializer.js +3 -0
- package/src/agents/agent-serializer.js.map +1 -1
- package/src/agents/agents.d.ts +14 -2
- package/src/agents/agents.d.ts.map +1 -1
- package/src/agents/agents.js +94 -36
- package/src/agents/agents.js.map +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.d.ts +2 -0
- package/src/api/preflight.d.ts.map +1 -1
- package/src/api/preflight.js +7 -3
- 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 +29 -2
- package/src/extension/config.js.map +1 -1
- package/src/extension/control-notices.d.ts +0 -2
- package/src/extension/control-notices.d.ts.map +1 -1
- package/src/extension/control-notices.js +1 -7
- package/src/extension/control-notices.js.map +1 -1
- package/src/extension/declaration-pinning.d.ts +19 -0
- package/src/extension/declaration-pinning.d.ts.map +1 -0
- package/src/extension/declaration-pinning.js +154 -0
- package/src/extension/declaration-pinning.js.map +1 -0
- package/src/extension/fanout-child.d.ts.map +1 -1
- package/src/extension/fanout-child.js +6 -8
- package/src/extension/fanout-child.js.map +1 -1
- package/src/extension/index.d.ts +1 -2
- package/src/extension/index.d.ts.map +1 -1
- package/src/extension/index.js +104 -121
- package/src/extension/index.js.map +1 -1
- package/src/extension/rpc.d.ts.map +1 -1
- package/src/extension/rpc.js +12 -6
- package/src/extension/rpc.js.map +1 -1
- package/src/extension/schemas.d.ts +137 -1
- package/src/extension/schemas.d.ts.map +1 -1
- package/src/extension/schemas.js +22 -22
- package/src/extension/schemas.js.map +1 -1
- package/src/extension/subagent-guide.d.ts +1 -0
- package/src/extension/subagent-guide.d.ts.map +1 -1
- package/src/extension/subagent-guide.js +80 -6
- package/src/extension/subagent-guide.js.map +1 -1
- package/src/extension/subagent-options.d.ts +8 -0
- package/src/extension/subagent-options.d.ts.map +1 -0
- package/src/extension/subagent-options.js +52 -0
- package/src/extension/subagent-options.js.map +1 -0
- package/src/extension/tool-activation.d.ts.map +1 -1
- package/src/extension/tool-activation.js +7 -4
- package/src/extension/tool-activation.js.map +1 -1
- package/src/extension/tool-description.d.ts +4 -7
- package/src/extension/tool-description.d.ts.map +1 -1
- package/src/extension/tool-description.js +45 -59
- package/src/extension/tool-description.js.map +1 -1
- package/src/inspectors/actions.d.ts +2 -0
- package/src/inspectors/actions.d.ts.map +1 -1
- package/src/inspectors/actions.js +41 -13
- package/src/inspectors/actions.js.map +1 -1
- package/src/inspectors/plugins.d.ts.map +1 -1
- package/src/inspectors/plugins.js +3 -2
- package/src/inspectors/plugins.js.map +1 -1
- package/src/inspectors/tmux/actions.d.ts +26 -0
- package/src/inspectors/tmux/actions.d.ts.map +1 -0
- package/src/inspectors/tmux/actions.js +182 -0
- package/src/inspectors/tmux/actions.js.map +1 -0
- package/src/inspectors/tmux/client.d.ts +28 -0
- package/src/inspectors/tmux/client.d.ts.map +1 -0
- package/src/inspectors/tmux/client.js +65 -0
- package/src/inspectors/tmux/client.js.map +1 -0
- package/src/inspectors/tmux/plugin.d.ts +8 -0
- package/src/inspectors/tmux/plugin.d.ts.map +1 -0
- package/src/inspectors/tmux/plugin.js +15 -0
- package/src/inspectors/tmux/plugin.js.map +1 -0
- package/src/integrations/program-status.d.ts +31 -0
- package/src/integrations/program-status.d.ts.map +1 -0
- package/src/integrations/program-status.js +189 -0
- package/src/integrations/program-status.js.map +1 -0
- package/src/intercom/native-supervisor-channel.d.ts +16 -1
- package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
- package/src/intercom/native-supervisor-channel.js +101 -8
- package/src/intercom/native-supervisor-channel.js.map +1 -1
- package/src/intercom/result-intercom.js +1 -1
- package/src/intercom/result-intercom.js.map +1 -1
- package/src/intercom/supervisor-ui.d.ts +2 -12
- package/src/intercom/supervisor-ui.d.ts.map +1 -1
- package/src/intercom/supervisor-ui.js +2 -154
- package/src/intercom/supervisor-ui.js.map +1 -1
- package/src/missions/store.d.ts.map +1 -1
- package/src/missions/store.js +27 -5
- package/src/missions/store.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.d.ts +9 -1
- package/src/runs/background/async-execution.d.ts.map +1 -1
- package/src/runs/background/async-execution.js +253 -144
- package/src/runs/background/async-execution.js.map +1 -1
- package/src/runs/background/async-job-tracker.d.ts +4 -1
- package/src/runs/background/async-job-tracker.d.ts.map +1 -1
- package/src/runs/background/async-job-tracker.js +3 -2
- package/src/runs/background/async-job-tracker.js.map +1 -1
- package/src/runs/background/async-resume.d.ts.map +1 -1
- package/src/runs/background/async-resume.js +9 -3
- package/src/runs/background/async-resume.js.map +1 -1
- package/src/runs/background/await-async-run.d.ts +8 -4
- package/src/runs/background/await-async-run.d.ts.map +1 -1
- package/src/runs/background/await-async-run.js +14 -8
- package/src/runs/background/await-async-run.js.map +1 -1
- package/src/runs/background/binary-bootstrap.d.ts.map +1 -1
- package/src/runs/background/binary-bootstrap.js +2 -1
- package/src/runs/background/binary-bootstrap.js.map +1 -1
- package/src/runs/background/chain-root-attachment.d.ts +2 -0
- package/src/runs/background/chain-root-attachment.d.ts.map +1 -1
- package/src/runs/background/chain-root-attachment.js +9 -6
- 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/fleet-view.js +5 -5
- package/src/runs/background/fleet-view.js.map +1 -1
- package/src/runs/background/notify.d.ts +6 -1
- package/src/runs/background/notify.d.ts.map +1 -1
- package/src/runs/background/notify.js +130 -14
- package/src/runs/background/notify.js.map +1 -1
- package/src/runs/background/result-files.d.ts +27 -0
- package/src/runs/background/result-files.d.ts.map +1 -1
- package/src/runs/background/result-files.js +100 -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 +60 -64
- package/src/runs/background/result-watcher.js.map +1 -1
- package/src/runs/background/resume-guidance.js +2 -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 +9 -15
- package/src/runs/background/run-child-session.js.map +1 -1
- package/src/runs/background/run-id-resolver.d.ts.map +1 -1
- package/src/runs/background/run-id-resolver.js +9 -6
- package/src/runs/background/run-id-resolver.js.map +1 -1
- package/src/runs/background/run-status.d.ts.map +1 -1
- package/src/runs/background/run-status.js +19 -15
- 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/runner-child-launch.d.ts.map +1 -1
- package/src/runs/background/runner-child-launch.js +1 -0
- package/src/runs/background/runner-child-launch.js.map +1 -1
- package/src/runs/background/runner-http-dispatcher.d.ts +3 -0
- package/src/runs/background/runner-http-dispatcher.d.ts.map +1 -1
- package/src/runs/background/runner-http-dispatcher.js +2 -0
- package/src/runs/background/runner-http-dispatcher.js.map +1 -1
- package/src/runs/background/scheduled-runs.d.ts +9 -0
- package/src/runs/background/scheduled-runs.d.ts.map +1 -1
- package/src/runs/background/scheduled-runs.js +124 -36
- package/src/runs/background/scheduled-runs.js.map +1 -1
- package/src/runs/background/subagent-runner-bootstrap.d.ts.map +1 -1
- package/src/runs/background/subagent-runner-bootstrap.js +5 -1
- package/src/runs/background/subagent-runner-bootstrap.js.map +1 -1
- package/src/runs/background/subagent-runner.d.ts +3 -1
- package/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/src/runs/background/subagent-runner.js +211 -283
- package/src/runs/background/subagent-runner.js.map +1 -1
- package/src/runs/background/subagent-wait.d.ts +2 -0
- package/src/runs/background/subagent-wait.d.ts.map +1 -1
- package/src/runs/background/subagent-wait.js +34 -20
- package/src/runs/background/subagent-wait.js.map +1 -1
- package/src/runs/background/terminal-run-index.d.ts +1 -0
- package/src/runs/background/terminal-run-index.d.ts.map +1 -1
- package/src/runs/background/terminal-run-index.js +47 -1
- package/src/runs/background/terminal-run-index.js.map +1 -1
- package/src/runs/background/wait-tool.d.ts.map +1 -1
- package/src/runs/background/wait-tool.js +36 -23
- package/src/runs/background/wait-tool.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-stop-action.d.ts +7 -1
- package/src/runs/foreground/async-stop-action.d.ts.map +1 -1
- package/src/runs/foreground/async-stop-action.js +27 -23
- package/src/runs/foreground/async-stop-action.js.map +1 -1
- package/src/runs/foreground/execution.d.ts.map +1 -1
- package/src/runs/foreground/execution.js +91 -69
- package/src/runs/foreground/execution.js.map +1 -1
- package/src/runs/foreground/subagent-executor.d.ts +4 -1
- package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/src/runs/foreground/subagent-executor.js +174 -79
- package/src/runs/foreground/subagent-executor.js.map +1 -1
- package/src/runs/shared/child-hooks.js +6 -5
- package/src/runs/shared/child-hooks.js.map +1 -1
- package/src/runs/shared/child-launch.d.ts +2 -0
- package/src/runs/shared/child-launch.d.ts.map +1 -1
- package/src/runs/shared/child-launch.js +1 -0
- package/src/runs/shared/child-launch.js.map +1 -1
- package/src/runs/shared/child-session.d.ts +4 -0
- package/src/runs/shared/child-session.d.ts.map +1 -1
- package/src/runs/shared/child-session.js +28 -23
- 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 +11 -10
- package/src/runs/shared/child-tool-plan.js.map +1 -1
- package/src/runs/shared/dynamic-fanout.js +1 -1
- package/src/runs/shared/dynamic-fanout.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/herdr-placed-run.d.ts +1 -0
- package/src/runs/shared/herdr-placed-run.d.ts.map +1 -1
- package/src/runs/shared/herdr-placed-run.js +10 -6
- package/src/runs/shared/herdr-placed-run.js.map +1 -1
- package/src/runs/shared/model-resolution-diagnostic.d.ts +17 -5
- package/src/runs/shared/model-resolution-diagnostic.d.ts.map +1 -1
- package/src/runs/shared/model-resolution-diagnostic.js +37 -10
- package/src/runs/shared/model-resolution-diagnostic.js.map +1 -1
- package/src/runs/shared/model-resolution.d.ts.map +1 -1
- package/src/runs/shared/model-resolution.js +29 -1
- package/src/runs/shared/model-resolution.js.map +1 -1
- package/src/runs/shared/nested-events.d.ts +2 -0
- package/src/runs/shared/nested-events.d.ts.map +1 -1
- package/src/runs/shared/nested-events.js +4 -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/parallel-handoff.js +2 -2
- package/src/runs/shared/parallel-handoff.js.map +1 -1
- package/src/runs/shared/parallel-utils.d.ts +2 -0
- package/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/src/runs/shared/parallel-utils.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/runner-launcher.d.ts +12 -0
- package/src/runs/shared/runner-launcher.d.ts.map +1 -0
- package/src/runs/shared/runner-launcher.js +25 -0
- package/src/runs/shared/runner-launcher.js.map +1 -0
- package/src/runs/shared/single-output.d.ts +31 -1
- package/src/runs/shared/single-output.d.ts.map +1 -1
- package/src/runs/shared/single-output.js +100 -21
- 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 +26 -8
- package/src/runs/shared/structured-output.js.map +1 -1
- package/src/runs/shared/subagent-control.js +3 -3
- package/src/runs/shared/subagent-control.js.map +1 -1
- package/src/runs/shared/subagent-prompt-runtime.d.ts +37 -2
- package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
- package/src/runs/shared/subagent-prompt-runtime.js +127 -20
- 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/runs/shared/workflow-async-child-guidance.js +1 -1
- package/src/runs/shared/workflow-async-child-guidance.js.map +1 -1
- package/src/runs/shared/worktree-cleanup-plan.js +1 -1
- package/src/runs/shared/worktree-cleanup-plan.js.map +1 -1
- package/src/shared/atomic-json.d.ts +4 -3
- package/src/shared/atomic-json.d.ts.map +1 -1
- package/src/shared/atomic-json.js +3 -1
- package/src/shared/atomic-json.js.map +1 -1
- package/src/shared/child-transcript.js +1 -1
- package/src/shared/child-transcript.js.map +1 -1
- package/src/shared/edit-distance.d.ts +5 -0
- package/src/shared/edit-distance.d.ts.map +1 -0
- package/src/shared/edit-distance.js +33 -0
- package/src/shared/edit-distance.js.map +1 -0
- 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/formatters.d.ts.map +1 -1
- package/src/shared/formatters.js +1 -6
- package/src/shared/formatters.js.map +1 -1
- package/src/shared/model-info.d.ts +8 -0
- package/src/shared/model-info.d.ts.map +1 -1
- package/src/shared/model-info.js +22 -0
- package/src/shared/model-info.js.map +1 -1
- package/src/shared/parent-wake.d.ts +7 -1
- package/src/shared/parent-wake.d.ts.map +1 -1
- package/src/shared/parent-wake.js +36 -12
- package/src/shared/parent-wake.js.map +1 -1
- package/src/shared/pruned-fork.d.ts +1 -1
- package/src/shared/pruned-fork.d.ts.map +1 -1
- package/src/shared/pruned-fork.js +6 -0
- package/src/shared/pruned-fork.js.map +1 -1
- package/src/shared/runtime-module-path.d.ts +11 -0
- package/src/shared/runtime-module-path.d.ts.map +1 -0
- package/src/shared/runtime-module-path.js +17 -0
- package/src/shared/runtime-module-path.js.map +1 -0
- package/src/shared/types.d.ts +33 -10
- 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 +2 -0
- package/src/shared/utils.d.ts.map +1 -1
- package/src/shared/utils.js +10 -7
- package/src/shared/utils.js.map +1 -1
- package/src/slash/slash-commands.d.ts.map +1 -1
- package/src/slash/slash-commands.js +21 -10
- 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 -1
- 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-transcript.d.ts +2 -0
- package/src/tui/fleet-transcript.d.ts.map +1 -1
- package/src/tui/fleet-transcript.js +7 -2
- package/src/tui/fleet-transcript.js.map +1 -1
- package/src/tui/fleet.d.ts.map +1 -1
- package/src/tui/fleet.js +11 -6
- package/src/tui/fleet.js.map +1 -1
- package/src/tui/render.d.ts +2 -2
- package/src/tui/render.d.ts.map +1 -1
- package/src/tui/render.js +19 -17
- package/src/tui/render.js.map +1 -1
- package/src/tui/subagent-messages.d.ts +23 -0
- package/src/tui/subagent-messages.d.ts.map +1 -0
- package/src/tui/subagent-messages.js +270 -0
- package/src/tui/subagent-messages.js.map +1 -0
- 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.d.ts.map +1 -1
- package/src/watchdog/register-main.js +1 -19
- package/src/watchdog/register-main.js.map +1 -1
- package/src/watchdog/render.d.ts +2 -10
- package/src/watchdog/render.d.ts.map +1 -1
- package/src/watchdog/render.js +1 -19
- package/src/watchdog/render.js.map +1 -1
- package/src/watchdog/tool-actions.js +2 -2
- package/src/watchdog/tool-actions.js.map +1 -1
- package/src/workflows/scripted-workflow.d.ts.map +1 -1
- package/src/workflows/scripted-workflow.js +33 -10
- package/src/workflows/scripted-workflow.js.map +1 -1
- package/src/workflows/workflow-resources.d.ts.map +1 -1
- package/src/workflows/workflow-resources.js +12 -0
- package/src/workflows/workflow-resources.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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { discoverAgents, findBlockingAgentDiagnostic, formatUnknownAgentError, resolveAgentName, unknownAgentDiagnosticContext } from "../../agents/agents.js";
|
|
4
|
+
import { discoverAgents, findBlockingAgentDiagnostic, formatAvailableAgentLines, formatUnknownAgentError, resolveAgentName, suggestAgentName, unknownAgentDiagnosticContext } from "../../agents/agents.js";
|
|
5
5
|
import { getArtifactsDir, getProjectArtifactPackagingWarning, getProjectSubagentsDir } from "../../shared/artifacts.js";
|
|
6
6
|
import { writeAtomicJson } from "../../shared/atomic-json.js";
|
|
7
7
|
import { createCapacityResilientJsonWriter } from "../../shared/capacity-resilient-json.js";
|
|
@@ -10,7 +10,7 @@ import { resolveEffectiveThinking, toModelInfo } from "../../shared/model-info.j
|
|
|
10
10
|
import { beginForegroundChild, finishForegroundChild, foregroundSchedulingSettled, settleForegroundSchedulingOwner, updateForegroundChild, } from "./foreground-control.js";
|
|
11
11
|
import { getLivePromptAudit, rewritePromptWithGuidance, updateLiveEffectivePrompt } from "./prompt-audit.js";
|
|
12
12
|
import { persistForegroundRunHistory, MAX_REMEMBERED_FOREGROUND_RUNS } from "./foreground-history.js";
|
|
13
|
-
import { resolveExecutionAgentScope } from "../../agents/agent-scope.js";
|
|
13
|
+
import { projectScopeRequiresTrustMessage, resolveExecutionAgentScope } from "../../agents/agent-scope.js";
|
|
14
14
|
import { handleManagementAction } from "../../agents/agent-management.js";
|
|
15
15
|
import { handleRefinementAction } from "../../agents/agent-refinements.js";
|
|
16
16
|
import { buildDoctorReport } from "../../extension/doctor.js";
|
|
@@ -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";
|
|
@@ -56,7 +55,7 @@ import { assertAgentAllowedByCapabilityCeiling, intersectSubagentCapabilityCeili
|
|
|
56
55
|
import { isAgentContract } from "../shared/agent-contract.js";
|
|
57
56
|
import { normalizeExtensionBindings } from "../shared/extension-bindings.js";
|
|
58
57
|
import { assertRequiredChildExtensionsAdmitted, hasMandatoryRequiredChildExtensions, readRetainedRequiredChildExtensions, resolveRequiredChildExtensions } from "../../shared/required-child-extensions.js";
|
|
59
|
-
import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, outputPathMappingFromTask, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.js";
|
|
58
|
+
import { capInlineOutput, finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, outputPathMappingFromTask, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.js";
|
|
60
59
|
import { assertJsonSchemaObject, cleanupStructuredOutputRuntime, createStructuredOutputRuntime } from "../shared/structured-output.js";
|
|
61
60
|
import { compactForegroundDetails, getSingleResultOutput, PROMPT_REDACTED, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.js";
|
|
62
61
|
import { discardPreservedWorktrees, formatParallelHandoffError, formatParallelHandoffReference, protectRetainedWorktreeForResume, formatStoredParallelHandoffCleanup, parallelHandoffPath, readParallelHandoffManifest, recordParallelHandoffMerge, recordParallelHandoffSupersession, writeParallelHandoffGroup, writeWorktreeSetupHandoff } from "../shared/parallel-handoff.js";
|
|
@@ -73,8 +72,8 @@ import { promotePausedWorkflowIfSettled, reconcileDetachedWorkflowChildCompletio
|
|
|
73
72
|
import { reconcileAsyncRun } from "../background/stale-run-reconciler.js";
|
|
74
73
|
import { resolveAsyncRootResultPath, waitForImportedAsyncRoot } from "../background/chain-root-attachment.js";
|
|
75
74
|
import { awaitExistingAsyncRun, claimWorkflowAwaitedResult } from "../background/await-async-run.js";
|
|
76
|
-
import { fallbackResultPayloadPathForSessionRun,
|
|
77
|
-
import { attachRootChildrenToSteps, createNestedRoute, findNestedControlResult, inheritedNestedParentAddressOf, inheritedNestedRouteOf, nestedRunScope, resolveNestedAsyncDir, retainNestedLookupRoute, snapshotNestedEventFiles, updateForegroundNestedProjection, writeNestedControlRequest, writeNestedEvent } from "../shared/nested-events.js";
|
|
75
|
+
import { fallbackResultPayloadPathForSessionRun, resultFilePath, retireResultSnapshot, writeAsyncResultFile } from "../background/result-files.js";
|
|
76
|
+
import { attachRootChildrenToSteps, createNestedRoute, findNestedControlResult, inheritedNestedParentAddressOf, inheritedNestedRouteOf, nestedRunNotActiveMessage, nestedRunScope, resolveNestedAsyncDir, retainNestedLookupRoute, snapshotNestedEventFiles, updateForegroundNestedProjection, writeNestedControlRequest, writeNestedEvent } from "../shared/nested-events.js";
|
|
78
77
|
import { resolveSubagentRunId } from "../background/run-id-resolver.js";
|
|
79
78
|
import { formatNestedRunStatusLines } from "../shared/nested-render.js";
|
|
80
79
|
import { isStoppableAsyncStatusStep, resolveAsyncStatusChild } from "../shared/child-identity.js";
|
|
@@ -83,6 +82,7 @@ import { getExternalJobProvider } from "../../api/external-job-provider.js";
|
|
|
83
82
|
import { externalJobFollowUpRequestDigest, externalJobFollowUpRequestId, externalJobFollowUpRunId, externalJobPromptDigest, externalJobStableJson } from "../shared/external-job-runner.js";
|
|
84
83
|
import { externalCliReceiptMetadata, normalizeExternalCliRunnerStatus } from "../shared/external-cli-contract.js";
|
|
85
84
|
import { formatHerdrMachineRunnerUnsupported, resolveHerdrMachinePlacement } from "../shared/herdr-machine.js";
|
|
85
|
+
import { lookupRunnerLauncher, resolveAgentRunnerLauncher } from "../shared/runner-launcher.js";
|
|
86
86
|
import { applyForceTopLevelAsyncOverride } from "../background/top-level-async.js";
|
|
87
87
|
import { handleMissionAction, MISSION_ACTIONS } from "../../missions/actions.js";
|
|
88
88
|
import { attachMissionToLaunchResult, prepareMissionLaunch, writeMissionAsyncBinding } from "../../missions/lifecycle.js";
|
|
@@ -111,35 +111,12 @@ import { applyReviewedCleanupPlan, formatCleanupReceipt, loadReviewedCleanupPlan
|
|
|
111
111
|
import { createWorktreeCleanupPlan, formatWorktreeCleanupPlan } from "../shared/worktree-cleanup-plan.js";
|
|
112
112
|
import { DIRS, DEFAULT_ARTIFACT_CONFIG, DEFAULT_MAX_OUTPUT, DEFAULT_FORK_PREAMBLE, SUBAGENT_ACTIONS, SUBAGENT_ASYNC_STARTED_EVENT, SUBAGENT_CHILD_STATUS_EVENT, SUBAGENT_CONTROL_EVENT, SUBAGENT_CONTROL_INTERCOM_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, checkSubagentDepth, resolveChildMaxSubagentDepth, resolveCurrentMaxSubagentDepth, resolveMaxSubagentSpawnsPerRun, truncateOutput, wrapForkTask, } from "../../shared/types.js";
|
|
113
113
|
import { deriveChildSessionName } from "../../shared/child-session-name.js";
|
|
114
|
+
import { editDistance, hasSingleAdjacentTransposition } from "../../shared/edit-distance.js";
|
|
114
115
|
const MUTATING_MANAGEMENT_ACTIONS = new Set(["command.yield", "command.cancel", "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"]);
|
|
115
116
|
const DESTRUCTIVE_MANAGEMENT_ACTIONS = new Set(["command.cancel", "delete", "eject", "disable", "reset", "mission.close", "worktree.discard", "refine.rollback", "inspector.close", "project.close", "stop", "interrupt", "schedule.delete"]);
|
|
116
117
|
function resolveSteerDeliveryMode(mode) {
|
|
117
118
|
return mode === "steer" || mode === "follow_up" || mode === "auto" ? mode : undefined;
|
|
118
119
|
}
|
|
119
|
-
function editDistance(left, right) {
|
|
120
|
-
const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
121
|
-
for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
|
|
122
|
-
let diagonal = previous[0];
|
|
123
|
-
previous[0] = leftIndex;
|
|
124
|
-
for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
|
|
125
|
-
const above = previous[rightIndex];
|
|
126
|
-
previous[rightIndex] = left[leftIndex - 1] === right[rightIndex - 1]
|
|
127
|
-
? diagonal
|
|
128
|
-
: Math.min(diagonal, above, previous[rightIndex - 1]) + 1;
|
|
129
|
-
diagonal = above;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return previous[right.length];
|
|
133
|
-
}
|
|
134
|
-
function hasSingleAdjacentTransposition(left, right) {
|
|
135
|
-
if (left.length !== right.length)
|
|
136
|
-
return false;
|
|
137
|
-
const mismatch = [...left].findIndex((character, index) => character !== right[index]);
|
|
138
|
-
return mismatch >= 0
|
|
139
|
-
&& left[mismatch] === right[mismatch + 1]
|
|
140
|
-
&& left[mismatch + 1] === right[mismatch]
|
|
141
|
-
&& left.slice(mismatch + 2) === right.slice(mismatch + 2);
|
|
142
|
-
}
|
|
143
120
|
export function unknownSubagentActionMessage(action, disabled) {
|
|
144
121
|
const requested = action.toLowerCase();
|
|
145
122
|
const enabledActions = SUBAGENT_ACTIONS.filter((candidate) => !disabled?.actions.has(candidate));
|
|
@@ -304,6 +281,21 @@ function trustedSessionRootsForStatus(ctx, deps) {
|
|
|
304
281
|
function sessionProjectTrust(ctx) {
|
|
305
282
|
return typeof ctx.isProjectTrusted === "function" ? ctx.isProjectTrusted() : undefined;
|
|
306
283
|
}
|
|
284
|
+
/** Agent and settings discovery follows the launching session's trust, like the child itself. */
|
|
285
|
+
function withSessionProjectTrust(deps, ctx) {
|
|
286
|
+
if (sessionProjectTrust(ctx) !== false)
|
|
287
|
+
return deps;
|
|
288
|
+
return { ...deps, discoverAgents: (cwd, scope, preferredModelProvider) => deps.discoverAgents(cwd, scope, preferredModelProvider, { projectTrusted: false }) };
|
|
289
|
+
}
|
|
290
|
+
function projectScopeTrustError(params, ctx) {
|
|
291
|
+
if (sessionProjectTrust(ctx) !== false || resolveExecutionAgentScope(params.agentScope) !== "project")
|
|
292
|
+
return undefined;
|
|
293
|
+
const action = typeof params.action === "string" ? params.action.trim() : undefined;
|
|
294
|
+
// These actions resolve agents in the requested scope; management actions are left to their own handlers.
|
|
295
|
+
if (action !== undefined && action !== "resume" && action !== "validate" && action !== "append-step")
|
|
296
|
+
return undefined;
|
|
297
|
+
return buildRequestedModeError(params, projectScopeRequiresTrustMessage(resolveRequestedCwd(ctx.cwd, params.cwd)));
|
|
298
|
+
}
|
|
307
299
|
function spawnBudgetErrorResult(message, mode) {
|
|
308
300
|
return {
|
|
309
301
|
content: [{ type: "text", text: message }],
|
|
@@ -644,6 +636,7 @@ function resolveForegroundResumeTarget(params, state, options = {}) {
|
|
|
644
636
|
...(child.thinking ? { thinking: child.thinking } : {}),
|
|
645
637
|
...(child.launchContractDigest ? { launchContractDigest: child.launchContractDigest } : {}),
|
|
646
638
|
...(child.resumeContract ? { resumeContract: child.resumeContract } : {}),
|
|
639
|
+
...(child.savedOutputPath ? { savedOutputPath: child.savedOutputPath } : {}),
|
|
647
640
|
...(child.extensionBindings ? { extensionBindings: normalizeExtensionBindings(child.extensionBindings).value } : {}),
|
|
648
641
|
...(child.requiredExtensions ? { requiredExtensions: child.requiredExtensions } : {}),
|
|
649
642
|
...(child.capabilityCeiling ? { capabilityCeiling: child.capabilityCeiling } : {}),
|
|
@@ -824,7 +817,7 @@ function emitControlNotification(input) {
|
|
|
824
817
|
}
|
|
825
818
|
}
|
|
826
819
|
function interruptAsyncRun(state, runId, kill, location) {
|
|
827
|
-
const target = getAsyncInterruptTarget(state, runId, location);
|
|
820
|
+
const target = getAsyncInterruptTarget(state, runId, location, { fallbackToNewest: runId === undefined });
|
|
828
821
|
if (!target)
|
|
829
822
|
return null;
|
|
830
823
|
const status = reconcileAsyncRun(target.asyncDir, omitUndefinedProperties({ kill })).status;
|
|
@@ -1016,6 +1009,7 @@ function appendStepToAsyncChain(input) {
|
|
|
1016
1009
|
cwd: input.ctx.cwd,
|
|
1017
1010
|
currentSessionId: resolveCurrentSessionId(input.ctx.sessionManager),
|
|
1018
1011
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1012
|
+
parentSessionFile: input.ctx.sessionManager.getSessionFile() ?? undefined,
|
|
1019
1013
|
currentModelProvider: parentModel?.provider,
|
|
1020
1014
|
currentModel: parentModel,
|
|
1021
1015
|
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
@@ -1025,6 +1019,17 @@ function appendStepToAsyncChain(input) {
|
|
|
1025
1019
|
permissions: input.deps.config.permissions,
|
|
1026
1020
|
childRuntime: input.deps.childRuntime,
|
|
1027
1021
|
});
|
|
1022
|
+
// Appended steps run inside the already-running runner, so they must use its launcher (or none).
|
|
1023
|
+
// Checked before building, which can write progress files. A mix is refused by the builder.
|
|
1024
|
+
const appendedLaunchers = new Set(chain.flatMap(getStepAgents).map((name) => agents.find((agent) => agent.name === name)?.launcher));
|
|
1025
|
+
const appendedLauncher = [...appendedLaunchers][0];
|
|
1026
|
+
if (appendedLaunchers.size === 1 && appendedLauncher !== status.launcher?.name) {
|
|
1027
|
+
return {
|
|
1028
|
+
content: [{ type: "text", text: `Cannot append step to run '${resolved.id}': its runner uses ${status.launcher ? `launcher '${status.launcher.name}'` : "no launcher"}, but the appended agents use ${appendedLauncher ? `launcher '${appendedLauncher}'` : "no launcher"}.` }],
|
|
1029
|
+
isError: true,
|
|
1030
|
+
details: { mode: "management", results: [] },
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1028
1033
|
const built = buildAsyncRunnerSteps(resolved.id, compactOptional({
|
|
1029
1034
|
chain: wrapChainTasksForFork(chain, contextPolicy),
|
|
1030
1035
|
task: input.params.task,
|
|
@@ -1332,11 +1337,18 @@ async function interruptNestedRun(target) {
|
|
|
1332
1337
|
if (run.state === "paused")
|
|
1333
1338
|
return { content: [{ type: "text", text: `Nested run ${run.id} is already paused.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1334
1339
|
const result = await sendNestedControlRequest(target, "interrupt");
|
|
1335
|
-
|
|
1340
|
+
// The owner's foreground map cannot address a detached async child. Only
|
|
1341
|
+
// that missing-route response may use the existing authorized async inbox;
|
|
1342
|
+
// other owner refusals must remain authoritative.
|
|
1343
|
+
const missingForegroundRoute = result?.ok === false && result.message === nestedRunNotActiveMessage(run.id);
|
|
1344
|
+
if (result && !missingForegroundRoute)
|
|
1336
1345
|
return { content: [{ type: "text", text: result.message }], ...(result.ok ? {} : { isError: true }), details: { mode: "management", results: [] } };
|
|
1337
1346
|
const direct = directNestedAsyncInterrupt(target);
|
|
1338
1347
|
if (direct)
|
|
1339
1348
|
return direct;
|
|
1349
|
+
// No async inbox either: the owner's own answer is the accurate one.
|
|
1350
|
+
if (result)
|
|
1351
|
+
return { content: [{ type: "text", text: result.message }], isError: true, details: { mode: "management", results: [] } };
|
|
1340
1352
|
return { content: [{ type: "text", text: `Nested run ${run.id} owner is not reachable and no safe direct async interrupt fallback is available.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1341
1353
|
}
|
|
1342
1354
|
async function resumeLiveNestedRun(input) {
|
|
@@ -1467,6 +1479,7 @@ async function resumeExternalJobFollowUp(input) {
|
|
|
1467
1479
|
cwd: input.requestCwd,
|
|
1468
1480
|
currentSessionId,
|
|
1469
1481
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1482
|
+
parentSessionFile: input.ctx.sessionManager.getSessionFile() ?? undefined,
|
|
1470
1483
|
currentModelProvider: parentModel?.provider,
|
|
1471
1484
|
currentModel: parentModel,
|
|
1472
1485
|
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
@@ -1587,7 +1600,7 @@ async function resumeAsyncRun(input) {
|
|
|
1587
1600
|
type: "text",
|
|
1588
1601
|
text: [
|
|
1589
1602
|
`Async child '${target.runId}' index ${target.index} is still running. action='resume' only revives paused, completed, or failed children.`,
|
|
1590
|
-
`Send live input with subagent({ action: "steer", id: "${target.runId}", index: ${target.index}
|
|
1603
|
+
`Send live input with subagent({ action: "steer", id: "${target.runId}", message: "...", options: { index: ${target.index} } }).`,
|
|
1591
1604
|
].join("\n"),
|
|
1592
1605
|
}],
|
|
1593
1606
|
isError: true,
|
|
@@ -1727,7 +1740,7 @@ async function resumeAsyncRun(input) {
|
|
|
1727
1740
|
const chain = wrapChainTasksForFork(attachChain, contextPolicy);
|
|
1728
1741
|
const normalized = normalizeSkillInput(input.params.skill);
|
|
1729
1742
|
const parentModel = input.parentModel;
|
|
1730
|
-
const result = executeAsyncChain(runId, compactOptional({
|
|
1743
|
+
const result = await executeAsyncChain(runId, compactOptional({
|
|
1731
1744
|
chain,
|
|
1732
1745
|
task: workflowTask,
|
|
1733
1746
|
goal,
|
|
@@ -1746,11 +1759,13 @@ async function resumeAsyncRun(input) {
|
|
|
1746
1759
|
cwd: input.requestCwd,
|
|
1747
1760
|
currentSessionId: input.deps.state.currentSessionId,
|
|
1748
1761
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1762
|
+
parentSessionFile: input.ctx.sessionManager.getSessionFile() ?? undefined,
|
|
1749
1763
|
currentModelProvider: parentModel?.provider,
|
|
1750
1764
|
currentModel: parentModel,
|
|
1751
1765
|
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
1752
1766
|
modelScope,
|
|
1753
1767
|
modelResponseAliases: input.deps.config.modelResponseAliases,
|
|
1768
|
+
runnerLaunchers: input.deps.config.runnerLaunchers,
|
|
1754
1769
|
interactive: input.ctx.hasUI,
|
|
1755
1770
|
permissions: input.deps.config.permissions,
|
|
1756
1771
|
childRuntime: input.deps.childRuntime,
|
|
@@ -1814,7 +1829,8 @@ async function resumeAsyncRun(input) {
|
|
|
1814
1829
|
if (target.source === "nested" && !target.recoveryDescriptor) {
|
|
1815
1830
|
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: [] } };
|
|
1816
1831
|
}
|
|
1817
|
-
|
|
1832
|
+
// Runs without a recovery descriptor were never wrapped; a launcher added to the agent file later does not apply.
|
|
1833
|
+
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(baseAgentConfig, recoveryDescriptor) : { ...baseAgentConfig, launcher: undefined };
|
|
1818
1834
|
const agentConfig = intercomBridge.active ? applyIntercomBridgeToAgent(recoveryAgentConfig, intercomBridge) : recoveryAgentConfig;
|
|
1819
1835
|
const foregroundContract = target.source === "foreground" ? target.resumeContract : undefined;
|
|
1820
1836
|
const outputSchema = Object.hasOwn(input.params, "outputSchema")
|
|
@@ -1831,6 +1847,10 @@ async function resumeAsyncRun(input) {
|
|
|
1831
1847
|
if (acceptanceErrors.length > 0) {
|
|
1832
1848
|
return { content: [{ type: "text", text: `Cannot resume: ${acceptanceErrors.join(" ")}` }], isError: true, details: { mode: "management", results: [] } };
|
|
1833
1849
|
}
|
|
1850
|
+
// Refuse before capacity moves so the retained run stays resumable once the config is fixed.
|
|
1851
|
+
if (agentConfig.launcher !== undefined && !lookupRunnerLauncher(input.deps.config.runnerLaunchers, agentConfig.launcher)) {
|
|
1852
|
+
return { content: [{ type: "text", text: `Cannot resume: run '${target.runId}' was launched with launcher '${agentConfig.launcher}', which is no longer defined in runnerLaunchers in the user subagent config.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1853
|
+
}
|
|
1834
1854
|
const runId = randomUUID();
|
|
1835
1855
|
const topLevelResume = depth === 0 && !inheritedNestedRoute(input.deps) && !input.params.workflowParentRunId;
|
|
1836
1856
|
let activeAsyncCapacity;
|
|
@@ -1862,6 +1882,13 @@ async function resumeAsyncRun(input) {
|
|
|
1862
1882
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1863
1883
|
const parentModel = input.parentModel;
|
|
1864
1884
|
const revivalAsyncDir = path.join(DIRS.async, runId);
|
|
1885
|
+
const revivalOutputBaseDir = resolveSingleRunOutputBaseDir(input.deps, artifactsDir, runId);
|
|
1886
|
+
const inheritedOutput = foregroundContract?.output ?? recoveryDescriptor?.outputPath;
|
|
1887
|
+
// The original run owns its saved output, so a resume without its own output writes next to it instead of over it.
|
|
1888
|
+
// Workflow resumes are routed by the workflow's output claims instead.
|
|
1889
|
+
const inheritedOutputPath = input.params.output === undefined && input.params.workflowParentRunId === undefined
|
|
1890
|
+
? (target.source === "foreground" ? target.savedOutputPath : undefined) ?? resolveSingleOutputPath(inheritedOutput, input.requestCwd, effectiveCwd, revivalOutputBaseDir)
|
|
1891
|
+
: undefined;
|
|
1865
1892
|
const result = await executeAsyncSingle(runId, compactOptional({
|
|
1866
1893
|
agent: target.agent,
|
|
1867
1894
|
task: buildRevivedAsyncTask(target, effectiveFollowUp),
|
|
@@ -1873,12 +1900,14 @@ async function resumeAsyncRun(input) {
|
|
|
1873
1900
|
cwd: input.requestCwd,
|
|
1874
1901
|
currentSessionId: input.deps.state.currentSessionId,
|
|
1875
1902
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1903
|
+
parentSessionFile: input.ctx.sessionManager.getSessionFile() ?? undefined,
|
|
1876
1904
|
currentModelProvider: parentModel?.provider,
|
|
1877
1905
|
currentModel: parentModel,
|
|
1878
1906
|
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
1879
1907
|
modelScope,
|
|
1880
1908
|
// Absence in the retained contract is meaningful; never acquire current aliases.
|
|
1881
1909
|
modelResponseAliases: recoveryDescriptor ? recoveryDescriptor.modelResponseAliases : foregroundContract?.modelResponseAliases,
|
|
1910
|
+
runnerLaunchers: input.deps.config.runnerLaunchers,
|
|
1882
1911
|
interactive: input.ctx.hasUI,
|
|
1883
1912
|
permissions: input.deps.config.permissions,
|
|
1884
1913
|
childRuntime: input.deps.childRuntime,
|
|
@@ -1907,7 +1936,7 @@ async function resumeAsyncRun(input) {
|
|
|
1907
1936
|
thinkingCeiling: recoveryDescriptor?.thinkingCeiling ?? ("thinkingCeiling" in target ? target.thinkingCeiling : undefined),
|
|
1908
1937
|
extensionBindings: recoveryDescriptor?.extensionBindings ?? ("extensionBindings" in target ? target.extensionBindings : undefined),
|
|
1909
1938
|
requiredExtensions: recoveryDescriptor?.requiredExtensions ?? target.requiredExtensions,
|
|
1910
|
-
outputBaseDir:
|
|
1939
|
+
outputBaseDir: revivalOutputBaseDir,
|
|
1911
1940
|
maxSubagentDepth: recoveryDescriptor?.maxSubagentDepth ?? resolveCurrentMaxSubagentDepth(input.deps.config.maxSubagentDepth, input.deps.childRuntime),
|
|
1912
1941
|
waitToolEnabled: input.deps.waitToolEnabled,
|
|
1913
1942
|
waitToolDefaultTimeoutMs: input.deps.waitToolDefaultTimeoutMs,
|
|
@@ -1926,7 +1955,7 @@ async function resumeAsyncRun(input) {
|
|
|
1926
1955
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
1927
1956
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
1928
1957
|
availableModels,
|
|
1929
|
-
output: input.params.output !== undefined ? input.params.output :
|
|
1958
|
+
output: input.params.output !== undefined ? input.params.output : inheritedOutputPath ? suffixedOutputPath(inheritedOutputPath, runId.slice(0, 8)) : inheritedOutput,
|
|
1930
1959
|
outputMode: input.params.outputMode ?? foregroundContract?.outputMode ?? recoveryDescriptor?.outputMode,
|
|
1931
1960
|
outputClaimPath: input.params.workflowOutputClaimPath,
|
|
1932
1961
|
...(agentContract ? { agentContract } : {}),
|
|
@@ -2028,10 +2057,12 @@ function formatFailedSingleRunOutput(result, displayOutput) {
|
|
|
2028
2057
|
const error = result.error || "Failed";
|
|
2029
2058
|
const output = displayOutput.trim();
|
|
2030
2059
|
const lines = [error];
|
|
2060
|
+
let cappedOutput = output;
|
|
2031
2061
|
if (output && output !== error.trim()) {
|
|
2032
|
-
|
|
2062
|
+
cappedOutput = capInlineOutput(output, { artifactPath: result.artifactPaths?.outputPath, savedPath: result.savedOutputPath });
|
|
2063
|
+
lines.push("", "Output:", cappedOutput);
|
|
2033
2064
|
}
|
|
2034
|
-
if (result.artifactPaths?.outputPath && fs.existsSync(result.artifactPaths.outputPath)) {
|
|
2065
|
+
if (cappedOutput === output && result.artifactPaths?.outputPath && fs.existsSync(result.artifactPaths.outputPath)) {
|
|
2035
2066
|
lines.push("", `Output artifact: ${result.artifactPaths.outputPath}`);
|
|
2036
2067
|
}
|
|
2037
2068
|
return lines.join("\n");
|
|
@@ -2156,6 +2187,8 @@ function workflowValidationOptions(deps, params, runtimeCwd, parentModelProvider
|
|
|
2156
2187
|
const cwd = resolveRequestedCwd(runtimeCwd, params.cwd);
|
|
2157
2188
|
const scope = resolveExecutionAgentScope(params.agentScope);
|
|
2158
2189
|
let discovered;
|
|
2190
|
+
// Validation reports every bad agent name; only the first one carries the agent list.
|
|
2191
|
+
let listedAgents = false;
|
|
2159
2192
|
return {
|
|
2160
2193
|
maxSubagentSpawnsPerRun: params.maxSubagentSpawnsPerRun ?? resolveMaxSubagentSpawnsPerRun(deps.config.maxSubagentSpawnsPerRun),
|
|
2161
2194
|
agentNameError: (name) => {
|
|
@@ -2164,12 +2197,13 @@ function workflowValidationOptions(deps, params, runtimeCwd, parentModelProvider
|
|
|
2164
2197
|
const resolved = resolveAgentName(name, agents);
|
|
2165
2198
|
if (resolved.agent || resolved.error)
|
|
2166
2199
|
return canonicalizeAgentName(name, agents, discovered.agentDiagnostics, diagnosticContextFromDiscovery(discovered, cwd, scope)).error;
|
|
2167
|
-
const
|
|
2168
|
-
const suggestion =
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2200
|
+
const disabled = discovered.disabledAgents?.includes(name.trim()) === true;
|
|
2201
|
+
const suggestion = disabled ? undefined : suggestAgentName(name, agents);
|
|
2202
|
+
const problem = disabled ? `Agent '${name}' is disabled by a settings override.` : `Unknown agent '${name}'.${suggestion ? ` Did you mean '${suggestion}'?` : ""}`;
|
|
2203
|
+
if (listedAgents)
|
|
2204
|
+
return problem;
|
|
2205
|
+
listedAgents = true;
|
|
2206
|
+
return [`${problem} Available agents:`, ...formatAvailableAgentLines(agents)].join("\n");
|
|
2173
2207
|
},
|
|
2174
2208
|
};
|
|
2175
2209
|
}
|
|
@@ -2904,12 +2938,12 @@ function importedAsyncRootUsage(completed) {
|
|
|
2904
2938
|
}
|
|
2905
2939
|
function removeWorkflowAwaitedResult(asyncDir, resultPath, runId, publication) {
|
|
2906
2940
|
try {
|
|
2907
|
-
|
|
2941
|
+
retireResultSnapshot(workflowAwaitedAsyncResultPath(asyncDir), { ...publication, runId }, resultPath);
|
|
2908
2942
|
}
|
|
2909
|
-
catch {
|
|
2910
|
-
//
|
|
2943
|
+
catch (error) {
|
|
2944
|
+
// Cleanup must not replace an already imported delivery.
|
|
2945
|
+
console.error(`Failed to remove imported workflow child result '${resultPath}'; leaving it in place:`, error);
|
|
2911
2946
|
}
|
|
2912
|
-
removeResultIndex(asyncDir, publication.sessionId, runId, publication.toolCallId);
|
|
2913
2947
|
}
|
|
2914
2948
|
function emitWorkflowAwaitedChildComplete(pi, state, runId, asyncDir, parentWorkflowRunId, completed) {
|
|
2915
2949
|
let status;
|
|
@@ -3037,11 +3071,13 @@ async function runAsyncPath(data, deps) {
|
|
|
3037
3071
|
cwd: ctx.cwd,
|
|
3038
3072
|
currentSessionId: data.parentSessionId,
|
|
3039
3073
|
parentSessionId: data.parentPiSessionId,
|
|
3074
|
+
parentSessionFile: ctx.sessionManager.getSessionFile() ?? undefined,
|
|
3040
3075
|
currentModelProvider: parentModel?.provider,
|
|
3041
3076
|
currentModel: parentModel,
|
|
3042
3077
|
scopedModelIds: data.scopedModelIds,
|
|
3043
3078
|
modelScope: data.modelScope,
|
|
3044
3079
|
modelResponseAliases: deps.config.modelResponseAliases,
|
|
3080
|
+
runnerLaunchers: deps.config.runnerLaunchers,
|
|
3045
3081
|
interactive: ctx.hasUI,
|
|
3046
3082
|
permissions: deps.config.permissions,
|
|
3047
3083
|
childRuntime: deps.childRuntime,
|
|
@@ -3091,6 +3127,7 @@ async function runAsyncPath(data, deps) {
|
|
|
3091
3127
|
if (launchRuleError)
|
|
3092
3128
|
return toExecutionErrorResult(params, new Error(launchRuleError), data.contextPolicy.contextSummary);
|
|
3093
3129
|
const asyncResult = await executeAsyncSingle(id, compactOptional({
|
|
3130
|
+
toolCallId: data.toolCallId,
|
|
3094
3131
|
agent: params.agent,
|
|
3095
3132
|
task: shouldForkAgent(contextPolicy, params.agent) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
3096
3133
|
goal: params.task ?? "",
|
|
@@ -3201,11 +3238,14 @@ export function sanitizeRunPathSegment(value, maxBytes = 120) {
|
|
|
3201
3238
|
function resolveSingleRunOutputBaseDir(deps, artifactsDir, runId) {
|
|
3202
3239
|
return resolveConfiguredSingleRunOutputBaseDir(deps) ?? path.join(artifactsDir, "outputs", sanitizeRunPathSegment(runId));
|
|
3203
3240
|
}
|
|
3241
|
+
/** `<dir>/<name>.<suffix><ext>` next to outputPath, with `.md` when it has no extension. */
|
|
3242
|
+
function suffixedOutputPath(outputPath, suffix) {
|
|
3243
|
+
const parsed = path.parse(outputPath);
|
|
3244
|
+
return path.join(parsed.dir, `${parsed.name}.${suffix}${parsed.ext || ".md"}`);
|
|
3245
|
+
}
|
|
3204
3246
|
function workflowChildDefaultOutput(aggregateOutputPath, artifactsDir, workflowRunId, workflowKey) {
|
|
3205
|
-
if (aggregateOutputPath)
|
|
3206
|
-
|
|
3207
|
-
return path.join(parsed.dir, `${parsed.name}.${workflowKey}${parsed.ext || ".md"}`);
|
|
3208
|
-
}
|
|
3247
|
+
if (aggregateOutputPath)
|
|
3248
|
+
return suffixedOutputPath(aggregateOutputPath, workflowKey);
|
|
3209
3249
|
return path.join(artifactsDir, "outputs", sanitizeRunPathSegment(workflowRunId), `${workflowKey}.md`);
|
|
3210
3250
|
}
|
|
3211
3251
|
function workflowHostCommandRunner(input) {
|
|
@@ -3295,7 +3335,11 @@ function resolveWorkflowChildOutputPath(input) {
|
|
|
3295
3335
|
id: input.params.resume.trim(),
|
|
3296
3336
|
...(typeof index === "number" && Number.isInteger(index) ? { index } : {}),
|
|
3297
3337
|
}, input.state);
|
|
3298
|
-
|
|
3338
|
+
const recoveryOutput = "recoveryDescriptor" in target ? target.recoveryDescriptor?.outputPath : undefined;
|
|
3339
|
+
if (hasExplicitOutput)
|
|
3340
|
+
return { path: recoveryOutput, inherited: false };
|
|
3341
|
+
const savedPath = recoveryOutput ?? (target.source === "foreground" ? target.savedOutputPath ?? resolveSingleOutputPath(target.resumeContract?.output, input.ctxCwd) : undefined);
|
|
3342
|
+
return { inherited: false, ...(savedPath ? { resumedSavedPath: savedPath } : {}) };
|
|
3299
3343
|
}
|
|
3300
3344
|
const childCwd = resolveWorkflowChildLocalCwd(input);
|
|
3301
3345
|
let agentOutput;
|
|
@@ -3335,8 +3379,12 @@ function workflowChildOutputClaims(input) {
|
|
|
3335
3379
|
}
|
|
3336
3380
|
const overrides = new Map();
|
|
3337
3381
|
for (const entry of resolvedEntries) {
|
|
3338
|
-
|
|
3339
|
-
|
|
3382
|
+
// The resumed run owns the report it saved, inside or outside this workflow, so an output-less resume writes its own.
|
|
3383
|
+
if (entry.resumedSavedPath || (entry.inherited && entry.path && (paths.get(resolveWorkflowHostOutputClaimPath(entry.path)) ?? 0) > 1)) {
|
|
3384
|
+
let output = workflowChildDefaultOutput(input.aggregateOutputPath, input.artifactsDir, input.workflowRunId, entry.key);
|
|
3385
|
+
// A rerun of the same workflow and key generates the very file the resumed run saved.
|
|
3386
|
+
if (entry.resumedSavedPath && resolveWorkflowHostOutputClaimPath(output) === resolveWorkflowHostOutputClaimPath(entry.resumedSavedPath))
|
|
3387
|
+
output = suffixedOutputPath(output, input.workflowRunId.slice(0, 8));
|
|
3340
3388
|
overrides.set(entry.key, output);
|
|
3341
3389
|
entry.path = output;
|
|
3342
3390
|
}
|
|
@@ -3363,7 +3411,7 @@ function applyWorkflowChildOutputClaims(target, claims) {
|
|
|
3363
3411
|
function prepareWorkflowChildLaunchParams(input) {
|
|
3364
3412
|
let childParams = input.childParams;
|
|
3365
3413
|
const usesDefaultOutput = input.childParams.output === undefined && input.childParams.resume === undefined;
|
|
3366
|
-
if (
|
|
3414
|
+
if (input.childParams.output === undefined && input.outputOverride !== undefined) {
|
|
3367
3415
|
childParams = { ...input.childParams, output: input.outputOverride };
|
|
3368
3416
|
}
|
|
3369
3417
|
else if (usesDefaultOutput && input.aggregateOutputPath !== undefined) {
|
|
@@ -3380,7 +3428,7 @@ function prepareWorkflowChildLaunchParams(input) {
|
|
|
3380
3428
|
const agent = typeof childParams.agent === "string"
|
|
3381
3429
|
? resolveAgentName(childParams.agent, discoveredAgents).agent ?? resolveAgentName(childParams.agent, input.agents).agent
|
|
3382
3430
|
: undefined;
|
|
3383
|
-
const externalAsyncRequired = agent?.runner?.type === "external-cli" || agent?.runner?.type === "external-job";
|
|
3431
|
+
const externalAsyncRequired = agent?.runner?.type === "external-cli" || agent?.runner?.type === "external-job" || agent?.launcher !== undefined;
|
|
3384
3432
|
return prepareWorkflowLaunchParams(input.workflowDefaults, childParams, input.parentWorkflowRunId, input.workflowKey, { ...input.options, externalAsyncRequired, outputClaimPath: input.outputClaimPath });
|
|
3385
3433
|
}
|
|
3386
3434
|
async function finalizeSingleWorktreeHandoff(input) {
|
|
@@ -3575,7 +3623,6 @@ async function runSinglePath(data, deps) {
|
|
|
3575
3623
|
if (shouldForkAgent(contextPolicy, params.agent)) {
|
|
3576
3624
|
task = wrapForkTask(task);
|
|
3577
3625
|
}
|
|
3578
|
-
const cleanTask = task;
|
|
3579
3626
|
const outputPath = resolveSingleOutputPath(effectiveOutput, ctx.cwd, singleCwd, resolveSingleRunOutputBaseDir(deps, artifactsDir, runId));
|
|
3580
3627
|
const validationError = validateFileOnlyOutputMode(effectiveOutputMode, outputPath, `Single run (${params.agent})`);
|
|
3581
3628
|
if (validationError) {
|
|
@@ -3604,6 +3651,7 @@ async function runSinglePath(data, deps) {
|
|
|
3604
3651
|
const interruptController = new AbortController();
|
|
3605
3652
|
let detachForeground;
|
|
3606
3653
|
let childSessionControls;
|
|
3654
|
+
let pendingRuntimeStop;
|
|
3607
3655
|
const foregroundControl = deps.state.foregroundControls.get(runId);
|
|
3608
3656
|
const syncHerdrForegroundChild = () => {
|
|
3609
3657
|
if (!foregroundControl?.parentWorkflowRunId)
|
|
@@ -3679,6 +3727,7 @@ async function runSinglePath(data, deps) {
|
|
|
3679
3727
|
? new Promise((resolve) => { resolveDetachedWorkflowChild = resolve; })
|
|
3680
3728
|
: undefined;
|
|
3681
3729
|
try {
|
|
3730
|
+
const childSessionFile = sessionFileForTask(params.agent, 0, modelOverride, modelOverrideFromParent, modelOrigin);
|
|
3682
3731
|
const launched = await runSync(ctx.cwd, agents, params.agent, task, compactOptional({
|
|
3683
3732
|
machine: foregroundMachine,
|
|
3684
3733
|
parentProviderRegistry: ctx.modelRegistry,
|
|
@@ -3687,9 +3736,14 @@ async function runSinglePath(data, deps) {
|
|
|
3687
3736
|
permissions: deps.config.permissions,
|
|
3688
3737
|
runtimeSnapshotHost: deps.pi,
|
|
3689
3738
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
3739
|
+
parentSessionFile: ctx.sessionManager.getSessionFile() ?? undefined,
|
|
3690
3740
|
requiredExtensions,
|
|
3691
3741
|
childRuntime: deps.childRuntime,
|
|
3692
|
-
onChildSession: (controls) => {
|
|
3742
|
+
onChildSession: (controls) => {
|
|
3743
|
+
childSessionControls = controls;
|
|
3744
|
+
if (pendingRuntimeStop)
|
|
3745
|
+
controls.stop(pendingRuntimeStop);
|
|
3746
|
+
},
|
|
3693
3747
|
context: data.contextPolicy.contextForAgent(params.agent),
|
|
3694
3748
|
unknownAgentDiagnosticContext: data.unknownAgentDiagnosticContext,
|
|
3695
3749
|
runFanoutBudget: params.runFanoutAdmitted ? data.runFanoutBudget : { ...data.runFanoutBudget, parentPath: `${data.runFanoutBudget.parentPath ? `${data.runFanoutBudget.parentPath}/` : ""}single` },
|
|
@@ -3702,7 +3756,7 @@ async function runSinglePath(data, deps) {
|
|
|
3702
3756
|
intercomEvents: deps.pi.events,
|
|
3703
3757
|
runId,
|
|
3704
3758
|
sessionDir: sessionDirForIndex(0),
|
|
3705
|
-
sessionFile:
|
|
3759
|
+
sessionFile: childSessionFile,
|
|
3706
3760
|
share: shareEnabled,
|
|
3707
3761
|
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
3708
3762
|
artifactConfig,
|
|
@@ -3743,6 +3797,8 @@ async function runSinglePath(data, deps) {
|
|
|
3743
3797
|
detachForeground = detach;
|
|
3744
3798
|
},
|
|
3745
3799
|
onDetachedExit: async (result) => {
|
|
3800
|
+
if (foregroundControl)
|
|
3801
|
+
foregroundControl.stopForRuntimeReplacement = undefined;
|
|
3746
3802
|
if (resolveDetachedWorkflowChild) {
|
|
3747
3803
|
resolveDetachedWorkflowChild(result);
|
|
3748
3804
|
return;
|
|
@@ -3783,7 +3839,6 @@ async function runSinglePath(data, deps) {
|
|
|
3783
3839
|
}
|
|
3784
3840
|
}
|
|
3785
3841
|
}
|
|
3786
|
-
recordRun(params.agent, cleanTask, result.exitCode, result.progressSummary?.durationMs ?? 0, result);
|
|
3787
3842
|
},
|
|
3788
3843
|
timeoutMs: data.timeoutMs,
|
|
3789
3844
|
deadlineAt,
|
|
@@ -3794,6 +3849,20 @@ async function runSinglePath(data, deps) {
|
|
|
3794
3849
|
capabilityCeiling: data.capabilityCeiling,
|
|
3795
3850
|
allowZeroToolBudget: data.allowZeroToolBudget && effectiveToolBudget.toolBudget === data.toolBudget,
|
|
3796
3851
|
}));
|
|
3852
|
+
if (launched.detached && foregroundControl) {
|
|
3853
|
+
// Record the stop before aborting so the next runtime's history restore finds it.
|
|
3854
|
+
foregroundControl.stopForRuntimeReplacement = () => {
|
|
3855
|
+
// The detach receipt predates the session file that resume needs.
|
|
3856
|
+
const sessionFile = childSessionFile && fs.existsSync(childSessionFile) ? childSessionFile : undefined;
|
|
3857
|
+
const stopped = { ...launched, detached: undefined, stopped: true, exitCode: 1, error: RUNTIME_REPLACED_STOP_ERROR, finalOutput: RUNTIME_REPLACED_STOP_ERROR, sessionFile };
|
|
3858
|
+
rememberForegroundRun(deps.state, { modelResponseAliases, runId, mode: "single", cwd: singleCwd, sessionId: data.parentSessionId, results: [stopped], params, effectiveOutput, effectiveOutputMode, extensionBindings: params.extensionBindings, requiredExtensions });
|
|
3859
|
+
// A child detached during creation has no controls yet; stop it as soon as they arrive.
|
|
3860
|
+
if (childSessionControls)
|
|
3861
|
+
childSessionControls.stop(RUNTIME_REPLACED_STOP_ERROR);
|
|
3862
|
+
else
|
|
3863
|
+
pendingRuntimeStop = RUNTIME_REPLACED_STOP_ERROR;
|
|
3864
|
+
};
|
|
3865
|
+
}
|
|
3797
3866
|
r = launched.detached && detachedWorkflowChild ? await detachedWorkflowChild : launched;
|
|
3798
3867
|
}
|
|
3799
3868
|
catch (error) {
|
|
@@ -3810,9 +3879,6 @@ async function runSinglePath(data, deps) {
|
|
|
3810
3879
|
finishTrackedForegroundChild();
|
|
3811
3880
|
}
|
|
3812
3881
|
}
|
|
3813
|
-
if (!r.detached) {
|
|
3814
|
-
recordRun(params.agent, cleanTask, r.exitCode, r.progressSummary?.durationMs ?? 0, r);
|
|
3815
|
-
}
|
|
3816
3882
|
let worktreeHandoff;
|
|
3817
3883
|
if (worktreeSetup) {
|
|
3818
3884
|
worktreeHandoff = r.detached
|
|
@@ -3904,7 +3970,7 @@ async function runSinglePath(data, deps) {
|
|
|
3904
3970
|
isError: true,
|
|
3905
3971
|
};
|
|
3906
3972
|
return {
|
|
3907
|
-
content: [{ type: "text", text: `${finalizedOutput.displayOutput || "(no output)"}${worktreeSuffix}` }],
|
|
3973
|
+
content: [{ type: "text", text: `${capInlineOutput(finalizedOutput.displayOutput, { artifactPath: r.artifactPaths?.outputPath, savedPath: finalizedOutput.savedPath }) || "(no output)"}${worktreeSuffix}` }],
|
|
3908
3974
|
details,
|
|
3909
3975
|
};
|
|
3910
3976
|
}
|
|
@@ -4107,7 +4173,7 @@ function workflowRunningChildrenSummary(children) {
|
|
|
4107
4173
|
function workflowResultChildren(children, status, includeFailureFields) {
|
|
4108
4174
|
return withWorkflowRevivals(DIRS.async, status.runId, children).map((child) => {
|
|
4109
4175
|
const sessionName = status.steps?.find((step) => step.workflowKey === child.key)?.sessionName;
|
|
4110
|
-
return { workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), ...(child.revival ? { revival: formatWorkflowKeyRevival(child.revival) } : {}), ...(sessionName ? { sessionName } : {}), ...workflowChildAccountingFields(child), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, ...(child.state === "running" ? { state: "running" } : { success: child.ok }), ...(child.asyncDir ? { asyncDir: child.asyncDir } : {}), ...(child.outputReference ? { outputReference: child.outputReference } : {}), ...(includeFailureFields && child.terminalOutcome ? { terminalOutcome: child.terminalOutcome } : {}), ...(child.outputPathMapping ? { outputPathMapping: child.outputPathMapping } : {}), ...(child.stopped ? { stopped: true } : {}), ...(child.interrupted ? { interrupted: true } : {}), ...(includeFailureFields && child.detached && status.state !== "complete" ? { detached: true } : {}), ...(child.outputArtifactPath || child.outputReference ? { artifactPaths: { outputPath: child.outputArtifactPath ?? child.outputReference } } : {}) };
|
|
4176
|
+
return { workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), ...(child.revival ? { revival: formatWorkflowKeyRevival(child.revival) } : {}), ...(sessionName ? { sessionName } : {}), ...workflowChildAccountingFields(child), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, ...(child.state === "running" ? { state: "running" } : { success: child.ok }), ...(!child.ok && child.error ? { error: child.error } : {}), ...(child.asyncDir ? { asyncDir: child.asyncDir } : {}), ...(child.outputReference ? { outputReference: child.outputReference } : {}), ...(includeFailureFields && child.terminalOutcome ? { terminalOutcome: child.terminalOutcome } : {}), ...(child.outputPathMapping ? { outputPathMapping: child.outputPathMapping } : {}), ...(child.stopped ? { stopped: true } : {}), ...(child.interrupted ? { interrupted: true } : {}), ...(includeFailureFields && child.detached && status.state !== "complete" ? { detached: true } : {}), ...(child.outputArtifactPath || child.outputReference ? { artifactPaths: { outputPath: child.outputArtifactPath ?? child.outputReference } } : {}) };
|
|
4111
4177
|
});
|
|
4112
4178
|
}
|
|
4113
4179
|
function workflowOutputPathMappingSummary(children) {
|
|
@@ -4141,6 +4207,7 @@ function workflowSteerReceipt(key, result) {
|
|
|
4141
4207
|
};
|
|
4142
4208
|
}
|
|
4143
4209
|
const CHILD_SESSION_NOT_RUNNING_YET = "Child session is not running yet.";
|
|
4210
|
+
const RUNTIME_REPLACED_STOP_ERROR = "Subagent stopped because the pi-subagents runtime that ran it was replaced (reload or session switch).";
|
|
4144
4211
|
const MAX_WORKFLOW_RESUME_HINT_BYTES = 1024;
|
|
4145
4212
|
const MAX_WORKFLOW_CHILD_RUN_ID_BYTES = 256;
|
|
4146
4213
|
const WORKFLOW_RESUME_HINT_PARENT_STATES = new Set(["complete", "failed", "partial"]);
|
|
@@ -4634,6 +4701,7 @@ function createScheduledOwnerState(source, ownerSessionId, ctx) {
|
|
|
4634
4701
|
};
|
|
4635
4702
|
}
|
|
4636
4703
|
export function createSubagentExecutor(deps) {
|
|
4704
|
+
const executorDeps = deps;
|
|
4637
4705
|
const delegatedThinkingOverrides = new WeakMap();
|
|
4638
4706
|
const delegatedZeroToolBudgets = new WeakSet();
|
|
4639
4707
|
const delegatedExecutions = new WeakSet();
|
|
@@ -4657,6 +4725,10 @@ export function createSubagentExecutor(deps) {
|
|
|
4657
4725
|
}
|
|
4658
4726
|
};
|
|
4659
4727
|
const execute = async (_id, params, signal, onUpdate, ctx, preserveActiveSession = false, parentModelOverride) => {
|
|
4728
|
+
const projectScopeError = projectScopeTrustError(params, ctx);
|
|
4729
|
+
if (projectScopeError)
|
|
4730
|
+
return projectScopeError;
|
|
4731
|
+
const deps = withSessionProjectTrust(executorDeps, ctx);
|
|
4660
4732
|
const workflowLaunchObserver = workflowLaunchObservers.get(params);
|
|
4661
4733
|
const inheritedUsageBudget = workflowOwnedUsageBudgets.get(params);
|
|
4662
4734
|
const retainedRequiredExtensions = workflowRetainedRequiredExtensions.get(params);
|
|
@@ -4744,12 +4816,7 @@ export function createSubagentExecutor(deps) {
|
|
|
4744
4816
|
if (launchBlockingErrors.length > 0) {
|
|
4745
4817
|
return buildRequestedModeError(requestParams, `Workflow '${_id}' validation failed before child launch; no children launched. ${launchBlockingErrors.map((error) => error.message).join(" ")}`);
|
|
4746
4818
|
}
|
|
4747
|
-
//
|
|
4748
|
-
const structuredResource = workflowResource?.provenance.name === "chain" || workflowResource?.provenance.name === "tasks";
|
|
4749
|
-
for (const warning of workflowValidation.warnings ?? []) {
|
|
4750
|
-
if (!(structuredResource && warning.kind === "dynamic-spawn-count"))
|
|
4751
|
-
console.warn(`[pi-subagents] ${warning.message}`);
|
|
4752
|
-
}
|
|
4819
|
+
// Validation warnings belong to the validate action; a launch does not repeat them on every run.
|
|
4753
4820
|
const acceptanceErrors = validateAcceptanceInput(requestParams.acceptance);
|
|
4754
4821
|
if (acceptanceErrors.length > 0)
|
|
4755
4822
|
return buildRequestedModeError(requestParams, acceptanceErrors.join(" "));
|
|
@@ -5529,6 +5596,16 @@ export function createSubagentExecutor(deps) {
|
|
|
5529
5596
|
const journalFingerprint = workflowJournalFingerprints.get(notification.childKey);
|
|
5530
5597
|
if (journalFingerprint)
|
|
5531
5598
|
appendWorkflowChildJournal(asyncDir, { type: "settle", key: notification.childKey, fingerprint: journalFingerprint, result: notification.result });
|
|
5599
|
+
// Fresh, journal-reused and re-attached children all settle here, so their rows take usage from the same result.
|
|
5600
|
+
const settledResults = notification.result.results ?? [];
|
|
5601
|
+
const settledStep = settledResults.length ? status.steps?.find((candidate) => candidate.workflowKey === notification.childKey) : undefined;
|
|
5602
|
+
if (settledStep) {
|
|
5603
|
+
const usage = sumResultsUsage(settledResults);
|
|
5604
|
+
settledStep.tokens = { input: usage.input, output: usage.output, total: usage.input + usage.output };
|
|
5605
|
+
if (usage.turns > 0)
|
|
5606
|
+
settledStep.turnCount = usage.turns;
|
|
5607
|
+
persist({ tolerateStatusWriteFailure: true });
|
|
5608
|
+
}
|
|
5532
5609
|
appendWorkflowEvent({
|
|
5533
5610
|
type: "subagent.workflow.child_settled",
|
|
5534
5611
|
childKey: notification.childKey,
|
|
@@ -5541,6 +5618,8 @@ export function createSubagentExecutor(deps) {
|
|
|
5541
5618
|
customType: "subagent-incremental-child-notify",
|
|
5542
5619
|
content: formatIncrementalChildCompletion(notification),
|
|
5543
5620
|
display: notification.outcome !== "completed",
|
|
5621
|
+
// Render-only: Pi does not send details to the model.
|
|
5622
|
+
details: { childKey: notification.childKey, outcome: notification.outcome },
|
|
5544
5623
|
}, { triggerTurn: incrementalChildCompletionTriggersTurn(notification, requestParams.scheduleOrigin) });
|
|
5545
5624
|
}
|
|
5546
5625
|
catch (sendError) {
|
|
@@ -5600,7 +5679,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5600
5679
|
appendWorkflowChildJournal(asyncDir, { type: "start", key, fingerprint: journalFingerprint, runId: priorRunId });
|
|
5601
5680
|
const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps.state, priorRunId, priorAsyncDir, deps.kill);
|
|
5602
5681
|
const reattached = await awaitExistingAsyncRun(priorAsyncDir, priorRunId, workflowSignal).finally(stopListener.remove);
|
|
5603
|
-
const claimedPath = reattached.status === "settled" ? claimWorkflowAwaitedResult(priorAsyncDir, workflowRunId) : undefined;
|
|
5682
|
+
const claimedPath = reattached.status === "settled" ? claimWorkflowAwaitedResult(priorAsyncDir, workflowRunId, { ...reattached.result.importedPublication, runId: priorRunId }) : undefined;
|
|
5604
5683
|
if (reattached.status === "settled" && claimedPath) {
|
|
5605
5684
|
const imported = importWorkflowAwaitedChildResult(reattached.result, { runId: priorRunId, asyncDir: priorAsyncDir, resultPath: claimedPath, task: typeof childParams.task === "string" ? childParams.task : "", parentWorkflowRunId: workflowReuseSource?.runId, details: { mode: "single", asyncId: priorRunId, asyncDir: priorAsyncDir, results: [] }, state: deps.state, pi: deps.pi });
|
|
5606
5685
|
const reattachedResult = workflowChildResult(key, imported, childParams, deps.state);
|
|
@@ -6408,7 +6487,10 @@ export function createSubagentExecutor(deps) {
|
|
|
6408
6487
|
if (action === "guide") {
|
|
6409
6488
|
try {
|
|
6410
6489
|
const guide = readSubagentGuide(paramsWithResolvedCwd.topic);
|
|
6411
|
-
const
|
|
6490
|
+
const [topic, section] = paramsWithResolvedCwd.topic?.split("/") ?? [];
|
|
6491
|
+
const fullNotice = topic === "tool-reference" ? disabledFeatureNotice(disabledFeatures) : undefined;
|
|
6492
|
+
// Sections are capped at 8,000 chars, so they get a one-line pointer instead of the full list.
|
|
6493
|
+
const notice = fullNotice && section !== undefined ? "Some options and actions documented here are disabled by config in this session; guide topic tool-reference lists them." : fullNotice;
|
|
6412
6494
|
return {
|
|
6413
6495
|
content: [{ type: "text", text: notice ? `${notice}\n\n${guide}` : guide }],
|
|
6414
6496
|
details: { mode: "management", results: [] },
|
|
@@ -6970,16 +7052,28 @@ export function createSubagentExecutor(deps) {
|
|
|
6970
7052
|
: hasTasks
|
|
6971
7053
|
? (effectiveParams.tasks ?? []).map((task) => task.agent)
|
|
6972
7054
|
: (effectiveParams.chain ?? []).flatMap((step) => getStepAgents(step));
|
|
6973
|
-
const
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
7055
|
+
const selectedAgents = selectedAgentNames.map((name) => agents.find((agent) => agent.name === name));
|
|
7056
|
+
const externalAgent = selectedAgents.find((agent) => agent?.runner?.type === "external-cli" || agent?.runner?.type === "external-job");
|
|
7057
|
+
const launcherAgent = selectedAgents.find((agent) => agent?.launcher !== undefined);
|
|
7058
|
+
// A launcher agent goes to the background whenever the caller omitted async, even if the agent file defaults to foreground.
|
|
7059
|
+
const externalAsyncRequired = effectiveParams.foregroundOnly !== true && ((Boolean(externalAgent) && effectiveParams.async === undefined && effectiveParams.clarify !== true)
|
|
7060
|
+
|| (Boolean(launcherAgent) && normalizedParams.async === undefined && normalizedParams.clarify !== true));
|
|
6977
7061
|
const requestedAsync = externalAsyncRequired ? true : effectiveParams.async ?? deps.asyncByDefault;
|
|
6978
7062
|
const backgroundRequestedWhileClarifying = (hasChain || hasTasks) && requestedAsync && effectiveParams.clarify === true;
|
|
6979
7063
|
const effectiveAsync = requestedAsync && effectiveParams.clarify !== true;
|
|
6980
7064
|
if (externalAgent && (!effectiveAsync || effectiveParams.foregroundOnly === true)) {
|
|
6981
7065
|
return buildRequestedModeError(effectiveParams, `Agent '${externalAgent.name}' uses runner.type='${externalAgent.runner?.type}', which currently supports async/background execution only. Omit async or pass async:true; clarify and foregroundOnly are unsupported.`);
|
|
6982
7066
|
}
|
|
7067
|
+
// forceTopLevelAsync rewrites async:false and clarify, so check what the caller asked for.
|
|
7068
|
+
if (launcherAgent && (!effectiveAsync || normalizedParams.async === false || normalizedParams.clarify === true || effectiveParams.foregroundOnly === true)) {
|
|
7069
|
+
return buildRequestedModeError(effectiveParams, `Agent '${launcherAgent.name}' uses launcher '${launcherAgent.launcher}', which wraps the background runner only. Foreground children run inside the parent process, so a launcher cannot wrap them. Omit async or pass async:true; clarify and foregroundOnly are unsupported.`);
|
|
7070
|
+
}
|
|
7071
|
+
// Refuse a launcher launch that cannot start before fan-out admission or a session directory exists.
|
|
7072
|
+
for (const agent of selectedAgents) {
|
|
7073
|
+
const launcherError = agent ? resolveAgentRunnerLauncher(agent, deps.config.runnerLaunchers, effectiveParams.machine ?? agent.machine).error : undefined;
|
|
7074
|
+
if (launcherError)
|
|
7075
|
+
return buildRequestedModeError(effectiveParams, launcherError);
|
|
7076
|
+
}
|
|
6983
7077
|
if (effectiveAsync && hasSingle && effectiveParams.resume === undefined && effectiveParams.worktree === true) {
|
|
6984
7078
|
try {
|
|
6985
7079
|
await preflightWorktreeSource(effectiveCwd, { signal });
|
|
@@ -7173,6 +7267,7 @@ export function createSubagentExecutor(deps) {
|
|
|
7173
7267
|
backgroundRequestedWhileClarifying,
|
|
7174
7268
|
effectiveAsync,
|
|
7175
7269
|
asyncRunId,
|
|
7270
|
+
toolCallId: _id,
|
|
7176
7271
|
controlConfig,
|
|
7177
7272
|
...(delegatedExecution ? { suppressUnchangedDelegationUpdates: true } : {}),
|
|
7178
7273
|
intercomBridge,
|