@selesai/code 0.6.3 → 0.8.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 +22 -1
- package/README.md +5 -3
- package/dist/bun/cli.d.ts +0 -1
- package/dist/bun/cli.js +0 -1
- package/dist/bun/register-bedrock.d.ts +0 -1
- package/dist/bun/register-bedrock.js +0 -1
- package/dist/bun/restore-sandbox-env.d.ts +0 -1
- package/dist/bun/restore-sandbox-env.js +0 -1
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.js +0 -1
- package/dist/cli/config-selector.d.ts +0 -1
- package/dist/cli/config-selector.js +0 -1
- package/dist/cli/credential-print.d.ts +0 -1
- package/dist/cli/credential-print.js +0 -1
- package/dist/cli/file-processor.d.ts +0 -1
- package/dist/cli/file-processor.js +0 -1
- package/dist/cli/initial-message.d.ts +0 -1
- package/dist/cli/initial-message.js +0 -1
- package/dist/cli/list-models.d.ts +0 -1
- package/dist/cli/list-models.js +0 -1
- package/dist/cli/project-trust.d.ts +0 -1
- package/dist/cli/project-trust.js +0 -1
- package/dist/cli/session-picker.d.ts +0 -1
- package/dist/cli/session-picker.js +0 -1
- package/dist/cli/startup-ui.d.ts +0 -1
- package/dist/cli/startup-ui.js +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/core/agent-session-auto-handoff.test.d.ts +0 -1
- package/dist/core/agent-session-auto-handoff.test.js +0 -1
- package/dist/core/agent-session-runtime.d.ts +0 -1
- package/dist/core/agent-session-runtime.js +0 -1
- package/dist/core/agent-session-services.d.ts +0 -1
- package/dist/core/agent-session-services.js +0 -1
- package/dist/core/agent-session-skill-block.test.d.ts +0 -1
- package/dist/core/agent-session-skill-block.test.js +0 -1
- package/dist/core/agent-session.d.ts +0 -1
- package/dist/core/agent-session.js +0 -1
- package/dist/core/agents.d.ts +0 -1
- package/dist/core/agents.js +0 -1
- package/dist/core/auth-guidance.d.ts +0 -1
- package/dist/core/auth-guidance.js +0 -1
- package/dist/core/auth-storage.d.ts +0 -1
- package/dist/core/auth-storage.js +0 -1
- package/dist/core/bash-executor.d.ts +0 -1
- package/dist/core/bash-executor.js +0 -1
- package/dist/core/built-in-extensions.d.ts +0 -1
- package/dist/core/built-in-extensions.js +0 -1
- package/dist/core/cache-stats.d.ts +0 -1
- package/dist/core/cache-stats.js +0 -1
- package/dist/core/compaction/branch-summarization.d.ts +0 -1
- package/dist/core/compaction/branch-summarization.js +0 -1
- package/dist/core/compaction/compaction.d.ts +0 -1
- package/dist/core/compaction/compaction.js +0 -1
- package/dist/core/compaction/index.d.ts +0 -1
- package/dist/core/compaction/index.js +0 -1
- package/dist/core/compaction/utils.d.ts +0 -1
- package/dist/core/compaction/utils.js +0 -1
- package/dist/core/defaults.d.ts +0 -1
- package/dist/core/defaults.js +0 -1
- package/dist/core/diagnostics.d.ts +0 -1
- package/dist/core/diagnostics.js +0 -1
- package/dist/core/event-bus.d.ts +0 -1
- package/dist/core/event-bus.js +0 -1
- package/dist/core/exec.d.ts +0 -1
- package/dist/core/exec.js +0 -1
- package/dist/core/experimental.d.ts +0 -1
- package/dist/core/experimental.js +0 -1
- package/dist/core/export-html/ansi-to-html.d.ts +0 -1
- package/dist/core/export-html/ansi-to-html.js +0 -1
- package/dist/core/export-html/index.d.ts +0 -1
- package/dist/core/export-html/index.js +0 -1
- package/dist/core/export-html/tool-renderer.d.ts +0 -1
- package/dist/core/export-html/tool-renderer.js +0 -1
- package/dist/core/extensions/index.d.ts +0 -1
- package/dist/core/extensions/index.js +0 -1
- package/dist/core/extensions/loader.d.ts +0 -1
- package/dist/core/extensions/loader.js +0 -1
- package/dist/core/extensions/runner.d.ts +0 -1
- package/dist/core/extensions/runner.js +0 -1
- package/dist/core/extensions/types.d.ts +0 -1
- package/dist/core/extensions/types.js +0 -1
- package/dist/core/extensions/wrapper.d.ts +0 -1
- package/dist/core/extensions/wrapper.js +0 -1
- package/dist/core/footer-data-provider.d.ts +0 -1
- package/dist/core/footer-data-provider.js +0 -1
- package/dist/core/git-command.d.ts +0 -1
- package/dist/core/git-command.js +0 -1
- package/dist/core/http-dispatcher.d.ts +0 -1
- package/dist/core/http-dispatcher.js +0 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +0 -1
- package/dist/core/keybindings.d.ts +0 -1
- package/dist/core/keybindings.js +0 -1
- package/dist/core/llama/client.d.ts +0 -1
- package/dist/core/llama/client.js +0 -1
- package/dist/core/llama/huggingface.d.ts +0 -1
- package/dist/core/llama/huggingface.js +0 -1
- package/dist/core/llama/index.d.ts +0 -1
- package/dist/core/llama/index.js +0 -1
- package/dist/core/llama/provider.d.ts +0 -1
- package/dist/core/llama/provider.js +0 -1
- package/dist/core/llama/ui.d.ts +0 -1
- package/dist/core/llama/ui.js +0 -1
- package/dist/core/messages.d.ts +0 -1
- package/dist/core/messages.js +0 -1
- package/dist/core/model-config.d.ts +0 -1
- package/dist/core/model-config.js +0 -1
- package/dist/core/model-registry.d.ts +0 -1
- package/dist/core/model-registry.js +0 -1
- package/dist/core/model-resolver.d.ts +0 -1
- package/dist/core/model-resolver.js +0 -1
- package/dist/core/model-runtime.d.ts +0 -1
- package/dist/core/model-runtime.js +0 -1
- package/dist/core/models-store.d.ts +0 -1
- package/dist/core/models-store.js +0 -1
- package/dist/core/output-guard.d.ts +0 -1
- package/dist/core/output-guard.js +0 -1
- package/dist/core/package-manager.d.ts +0 -1
- package/dist/core/package-manager.js +0 -1
- package/dist/core/package-manager.test.d.ts +0 -1
- package/dist/core/package-manager.test.js +0 -1
- package/dist/core/project-trust.d.ts +0 -1
- package/dist/core/project-trust.js +0 -1
- package/dist/core/prompt-templates.d.ts +0 -1
- package/dist/core/prompt-templates.js +0 -1
- package/dist/core/provider-attribution.d.ts +0 -1
- package/dist/core/provider-attribution.js +0 -1
- package/dist/core/provider-composer.d.ts +0 -1
- package/dist/core/provider-composer.js +0 -1
- package/dist/core/radius.d.ts +0 -1
- package/dist/core/radius.js +0 -1
- package/dist/core/remote-catalog-provider.d.ts +0 -1
- package/dist/core/remote-catalog-provider.js +0 -1
- package/dist/core/resolve-config-value.d.ts +0 -1
- package/dist/core/resolve-config-value.js +0 -1
- package/dist/core/resource-loader.d.ts +0 -1
- package/dist/core/resource-loader.js +0 -1
- package/dist/core/runtime-credentials.d.ts +0 -1
- package/dist/core/runtime-credentials.js +0 -1
- package/dist/core/sdk.d.ts +0 -1
- package/dist/core/sdk.js +0 -1
- package/dist/core/session-cwd.d.ts +0 -1
- package/dist/core/session-cwd.js +0 -1
- package/dist/core/session-manager.d.ts +0 -1
- package/dist/core/session-manager.js +0 -1
- package/dist/core/settings-manager-auto-handoff.test.d.ts +0 -1
- package/dist/core/settings-manager-auto-handoff.test.js +0 -1
- package/dist/core/settings-manager.d.ts +0 -4
- package/dist/core/settings-manager.js +0 -12
- package/dist/core/skills.d.ts +0 -1
- package/dist/core/skills.js +0 -1
- package/dist/core/slash-commands.d.ts +0 -1
- package/dist/core/slash-commands.js +0 -1
- package/dist/core/source-info.d.ts +0 -1
- package/dist/core/source-info.js +0 -1
- package/dist/core/system-prompt.d.ts +0 -1
- package/dist/core/system-prompt.js +0 -1
- package/dist/core/system-prompt.test.d.ts +0 -1
- package/dist/core/system-prompt.test.js +0 -1
- package/dist/core/telemetry.d.ts +0 -1
- package/dist/core/telemetry.js +0 -1
- package/dist/core/timings.d.ts +0 -1
- package/dist/core/timings.js +0 -1
- package/dist/core/tools/bash.d.ts +0 -1
- package/dist/core/tools/bash.js +0 -1
- package/dist/core/tools/edit-diff.d.ts +0 -1
- package/dist/core/tools/edit-diff.js +0 -1
- package/dist/core/tools/edit.d.ts +0 -1
- package/dist/core/tools/edit.js +0 -1
- package/dist/core/tools/file-mutation-queue.d.ts +0 -1
- package/dist/core/tools/file-mutation-queue.js +0 -1
- package/dist/core/tools/find.d.ts +0 -1
- package/dist/core/tools/find.js +0 -1
- package/dist/core/tools/grep.d.ts +0 -1
- package/dist/core/tools/grep.js +0 -1
- package/dist/core/tools/index.d.ts +0 -1
- package/dist/core/tools/index.js +0 -1
- package/dist/core/tools/ls.d.ts +0 -1
- package/dist/core/tools/ls.js +0 -1
- package/dist/core/tools/output-accumulator.d.ts +0 -1
- package/dist/core/tools/output-accumulator.js +0 -1
- package/dist/core/tools/path-utils.d.ts +0 -1
- package/dist/core/tools/path-utils.js +0 -1
- package/dist/core/tools/read.d.ts +0 -1
- package/dist/core/tools/read.js +0 -1
- package/dist/core/tools/render-utils.d.ts +0 -1
- package/dist/core/tools/render-utils.js +0 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +0 -1
- package/dist/core/tools/tool-definition-wrapper.js +0 -1
- package/dist/core/tools/truncate.d.ts +0 -1
- package/dist/core/tools/truncate.js +0 -1
- package/dist/core/tools/write.d.ts +0 -1
- package/dist/core/tools/write.js +0 -1
- package/dist/core/trust-manager.d.ts +0 -1
- package/dist/core/trust-manager.js +0 -1
- package/dist/core/usage-totals.d.ts +0 -1
- package/dist/core/usage-totals.js +0 -1
- package/dist/defaults/models.json +8 -0
- package/dist/defaults/settings.json +6 -7
- package/dist/extensions/agent-browser.test.ts +195 -0
- package/dist/extensions/agent-browser.ts +158 -0
- package/dist/extensions/inline-skills.test.ts +27 -13
- package/dist/extensions/inline-skills.ts +18 -11
- package/dist/extensions/package.json +2 -1
- package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +27 -0
- package/dist/extensions/pi-powerline-footer/CHANGELOG.md +153 -0
- package/dist/extensions/pi-powerline-footer/CONTRIBUTING.md +16 -0
- package/dist/extensions/pi-powerline-footer/README.md +192 -44
- package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +19 -4
- package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +80 -25
- package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +81 -29
- package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +1 -1
- package/dist/extensions/pi-powerline-footer/cd-command.ts +190 -0
- package/dist/extensions/pi-powerline-footer/colors.ts +2 -1
- package/dist/extensions/pi-powerline-footer/context-usage.ts +121 -6
- package/dist/extensions/pi-powerline-footer/currency-rates.ts +142 -0
- package/dist/extensions/pi-powerline-footer/editor-composition.ts +32 -0
- package/dist/extensions/pi-powerline-footer/git-status.ts +108 -6
- package/dist/extensions/pi-powerline-footer/icons.ts +11 -2
- package/dist/extensions/pi-powerline-footer/index.ts +1056 -324
- package/dist/extensions/pi-powerline-footer/lifecycle.ts +10 -0
- package/dist/extensions/pi-powerline-footer/package.json +10 -6
- package/dist/extensions/pi-powerline-footer/paths.ts +22 -0
- package/dist/extensions/pi-powerline-footer/powerline-config.ts +297 -15
- package/dist/extensions/pi-powerline-footer/presets.ts +6 -25
- package/dist/extensions/pi-powerline-footer/queue/store.ts +361 -0
- package/dist/extensions/pi-powerline-footer/queue/types.ts +54 -0
- package/dist/extensions/pi-powerline-footer/render-scheduler.ts +12 -7
- package/dist/extensions/pi-powerline-footer/segments.ts +114 -107
- package/dist/extensions/pi-powerline-footer/session-usage.ts +1 -1
- package/dist/extensions/pi-powerline-footer/shortcuts.ts +17 -3
- package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +189 -17
- package/dist/extensions/pi-powerline-footer/tests/cd-command.test.ts +144 -0
- package/dist/extensions/pi-powerline-footer/tests/context-usage.test.ts +120 -2
- package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +245 -22
- package/dist/extensions/pi-powerline-footer/tests/editor-composition.test.ts +48 -0
- package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +34 -0
- package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +39 -0
- package/dist/extensions/pi-powerline-footer/tests/git-status.test.ts +92 -0
- package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +4 -1
- package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +33 -197
- package/dist/extensions/pi-powerline-footer/tests/mode-aware-trigger.test.ts +79 -0
- package/dist/extensions/pi-powerline-footer/tests/paths.test.ts +63 -0
- package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +195 -0
- package/dist/extensions/pi-powerline-footer/tests/quit-cursor.test.ts +14 -0
- package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +167 -0
- package/dist/extensions/pi-powerline-footer/tests/stash-shortcut.test.ts +23 -18
- package/dist/extensions/pi-powerline-footer/tests/thinking-segment.test.ts +16 -1
- package/dist/extensions/pi-powerline-footer/tests/token-stats.test.ts +249 -0
- package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +237 -0
- package/dist/extensions/pi-powerline-footer/tests/welcome.test.ts +199 -0
- package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +191 -100
- package/dist/extensions/pi-powerline-footer/theme.ts +32 -18
- package/dist/extensions/pi-powerline-footer/token-stats.ts +304 -0
- package/dist/extensions/pi-powerline-footer/tsconfig.json +13 -0
- package/dist/extensions/pi-powerline-footer/types.ts +74 -29
- package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +34 -0
- package/dist/extensions/pi-powerline-footer/welcome.ts +65 -10
- package/dist/extensions/pi-powerline-footer/working-vibes.ts +44 -11
- package/dist/extensions/pi-subagents/CHANGELOG.md +89 -12
- package/dist/extensions/pi-subagents/README.md +339 -604
- package/dist/extensions/pi-subagents/package-lock.json +190 -2079
- package/dist/extensions/pi-subagents/package.json +13 -5
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +1 -1
- package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +10 -10
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +32 -43
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +106 -105
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +3 -3
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +28 -35
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +167 -124
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +163 -75
- package/dist/extensions/pi-subagents/src/agents/chain-serializer.ts +10 -7
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +5 -3
- package/dist/extensions/pi-subagents/src/agents/identity.ts +1 -1
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +14 -11
- package/dist/extensions/pi-subagents/src/agents/skills.ts +23 -6
- package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +8 -1
- package/dist/extensions/pi-subagents/src/api/control-channel.ts +4 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +26 -194
- package/dist/extensions/pi-subagents/src/api/external-runs.ts +129 -0
- package/dist/extensions/pi-subagents/src/api/intercom-bridge.ts +3 -0
- package/dist/extensions/pi-subagents/src/api/pi-args.ts +5 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +4 -4
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +19 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +10 -0
- package/dist/extensions/pi-subagents/src/extension/control-notices.ts +5 -39
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +10 -9
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +7 -4
- package/dist/extensions/pi-subagents/src/extension/index.ts +243 -77
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +18 -6
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +50 -39
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +36 -103
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +229 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/client.ts +130 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +141 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +154 -0
- package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +330 -0
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +3 -2
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +5 -1
- package/dist/extensions/pi-subagents/src/missions/actions.ts +372 -0
- package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +314 -0
- package/dist/extensions/pi-subagents/src/missions/store.ts +442 -0
- package/dist/extensions/pi-subagents/src/missions/types.ts +135 -0
- package/dist/extensions/pi-subagents/src/policy/authority.ts +46 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +103 -72
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +10 -2
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +6 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +29 -1
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +3 -2
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +9 -7
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +3 -4
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +3 -28
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +5 -5
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +18 -68
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +35 -8
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +602 -375
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +612 -464
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +50 -9
- package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +253 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +12 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +8 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +74 -102
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +21 -22
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1050 -396
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +44 -18
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +0 -1
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +302 -22
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +130 -0
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +42 -1
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +59 -5
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -4
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +86 -2
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +11 -2
- package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +95 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +11 -1
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +15 -6
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +9 -63
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +37 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +2 -23
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +6 -6
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +124 -13
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +29 -7
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +18 -1
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +3 -2
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +1 -0
- package/dist/extensions/pi-subagents/src/shared/settings.ts +10 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +158 -55
- package/dist/extensions/pi-subagents/src/shared/utils.ts +16 -66
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +33 -199
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +43 -126
- package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +136 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +158 -205
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +22 -58
- package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +14 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +44 -642
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +18 -14
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +156 -21
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +110 -5
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +60 -24
- package/dist/extensions/pi-subagents/src/tui/render.ts +296 -140
- package/dist/extensions/pi-subagents/src/types/pi-runtime-compat.d.ts +14 -0
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +13 -7
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +2 -2
- package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +145 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -1
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +3 -2
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +140 -0
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +415 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +41 -144
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +16 -16
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +415 -298
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +149 -82
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +40 -40
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +193 -133
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +1 -49
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +56 -58
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +81 -68
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +20 -25
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +425 -317
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +73 -73
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +123 -98
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +653 -240
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +20 -1661
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +8 -5
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +6 -6
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +4 -20
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +280 -295
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +47 -207
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +26 -26
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +89 -89
- package/dist/extensions/pi-subagents/test/unit/agent-selection.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +33 -9
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +24 -2
- package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +11 -9
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +40 -40
- package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +5 -39
- package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +19 -19
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/chain-serializer.test.ts +20 -20
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +99 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +41 -0
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +35 -5
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +16 -82
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +162 -620
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +25 -25
- package/dist/extensions/pi-subagents/test/unit/ensure-accessible-dir.test.ts +125 -0
- package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +66 -0
- package/dist/extensions/pi-subagents/test/unit/extra-agent-dirs.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +242 -52
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +197 -36
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +245 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +494 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +261 -31
- package/dist/extensions/pi-subagents/test/unit/inline-subagents.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +6 -6
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +217 -0
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +182 -0
- package/dist/extensions/pi-subagents/test/unit/mock-pi.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +10 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +47 -5
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +49 -55
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +20 -3
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +37 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +10 -10
- package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +46 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +31 -10
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +40 -16
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +42 -44
- package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +13 -13
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +75 -9
- package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +20 -84
- package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +15 -16
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +28 -28
- package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +19 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +37 -21
- package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +50 -50
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +396 -433
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +76 -153
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +411 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +1 -91
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +139 -0
- package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +29 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +13 -13
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +35 -35
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +53 -18
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +13 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +44 -11
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +2 -26
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +24 -148
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +11 -9
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +13 -13
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +8 -8
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +45 -9
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +197 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-graph.test.ts +8 -8
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +142 -12
- package/dist/extensions/pi-subagents/tsconfig.json +15 -0
- package/dist/extensions/ponytail/index.js +1 -31
- package/dist/extensions/ponytail/test/extension.test.js +5 -22
- package/dist/extensions/rtk.test.ts +141 -0
- package/dist/extensions/rtk.ts +78 -36
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.d.ts +0 -1
- package/dist/main.js +0 -1
- package/dist/migrations.d.ts +0 -1
- package/dist/migrations.js +0 -1
- package/dist/modes/index.d.ts +0 -1
- package/dist/modes/index.js +0 -1
- package/dist/modes/interactive/components/armin.d.ts +0 -1
- package/dist/modes/interactive/components/armin.js +0 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +0 -1
- package/dist/modes/interactive/components/assistant-message.js +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
- package/dist/modes/interactive/components/bash-execution.js +0 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +0 -1
- package/dist/modes/interactive/components/bordered-loader.js +0 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -1
- package/dist/modes/interactive/components/branch-summary-message.js +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +0 -1
- package/dist/modes/interactive/components/config-selector.d.ts +0 -1
- package/dist/modes/interactive/components/config-selector.js +0 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts +0 -1
- package/dist/modes/interactive/components/countdown-timer.js +0 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +0 -1
- package/dist/modes/interactive/components/custom-editor.js +0 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +0 -1
- package/dist/modes/interactive/components/custom-entry.js +0 -1
- package/dist/modes/interactive/components/custom-message.d.ts +0 -1
- package/dist/modes/interactive/components/custom-message.js +0 -1
- package/dist/modes/interactive/components/daxnuts.d.ts +0 -1
- package/dist/modes/interactive/components/daxnuts.js +0 -1
- package/dist/modes/interactive/components/diff.d.ts +0 -1
- package/dist/modes/interactive/components/diff.js +0 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts +0 -1
- package/dist/modes/interactive/components/dynamic-border.js +0 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -1
- package/dist/modes/interactive/components/earendil-announcement.js +0 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +0 -1
- package/dist/modes/interactive/components/extension-editor.js +0 -1
- package/dist/modes/interactive/components/extension-input.d.ts +0 -1
- package/dist/modes/interactive/components/extension-input.js +0 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +0 -1
- package/dist/modes/interactive/components/extension-selector.js +0 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +0 -1
- package/dist/modes/interactive/components/first-time-setup.js +0 -1
- package/dist/modes/interactive/components/footer.d.ts +0 -1
- package/dist/modes/interactive/components/footer.js +0 -1
- package/dist/modes/interactive/components/index.d.ts +0 -1
- package/dist/modes/interactive/components/index.js +0 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -1
- package/dist/modes/interactive/components/keybinding-hints.js +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
- package/dist/modes/interactive/components/login-dialog.js +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts +0 -1
- package/dist/modes/interactive/components/model-selector.js +0 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +0 -1
- package/dist/modes/interactive/components/oauth-selector.js +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +0 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +0 -1
- package/dist/modes/interactive/components/session-selector-search.js +0 -1
- package/dist/modes/interactive/components/session-selector.d.ts +0 -1
- package/dist/modes/interactive/components/session-selector.js +0 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +0 -3
- package/dist/modes/interactive/components/settings-selector.js +1 -14
- package/dist/modes/interactive/components/show-images-selector.d.ts +0 -1
- package/dist/modes/interactive/components/show-images-selector.js +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +0 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +0 -1
- package/dist/modes/interactive/components/status-indicator.js +0 -1
- package/dist/modes/interactive/components/theme-selector.d.ts +0 -1
- package/dist/modes/interactive/components/theme-selector.js +0 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts +0 -1
- package/dist/modes/interactive/components/thinking-selector.js +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/dist/modes/interactive/components/tool-execution.js +0 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +0 -1
- package/dist/modes/interactive/components/tree-selector.js +0 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +0 -1
- package/dist/modes/interactive/components/trust-selector.js +0 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts +0 -1
- package/dist/modes/interactive/components/user-message-selector.js +0 -1
- package/dist/modes/interactive/components/user-message.d.ts +0 -1
- package/dist/modes/interactive/components/user-message.js +0 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +0 -1
- package/dist/modes/interactive/components/visual-truncate.js +0 -1
- package/dist/modes/interactive/external-editor.d.ts +0 -1
- package/dist/modes/interactive/external-editor.js +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -2
- package/dist/modes/interactive/interactive-mode.js +1 -22
- package/dist/modes/interactive/model-search.d.ts +0 -1
- package/dist/modes/interactive/model-search.js +0 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +0 -1
- package/dist/modes/interactive/theme/theme-controller.js +0 -1
- package/dist/modes/interactive/theme/theme.d.ts +0 -1
- package/dist/modes/interactive/theme/theme.js +0 -1
- package/dist/modes/print-mode.d.ts +0 -1
- package/dist/modes/print-mode.js +0 -1
- package/dist/modes/rpc/jsonl.d.ts +0 -1
- package/dist/modes/rpc/jsonl.js +0 -1
- package/dist/modes/rpc/rpc-client.d.ts +1 -2
- package/dist/modes/rpc/rpc-client.js +1 -2
- package/dist/modes/rpc/rpc-mode.d.ts +0 -1
- package/dist/modes/rpc/rpc-mode.js +0 -9
- package/dist/modes/rpc/rpc-types.d.ts +0 -1
- package/dist/modes/rpc/rpc-types.js +0 -1
- package/dist/package-manager-cli.d.ts +0 -1
- package/dist/package-manager-cli.js +0 -1
- package/dist/rpc-entry.d.ts +0 -1
- package/dist/rpc-entry.js +0 -1
- package/dist/utils/ansi.d.ts +0 -1
- package/dist/utils/ansi.js +0 -1
- package/dist/utils/changelog.d.ts +0 -1
- package/dist/utils/changelog.js +0 -1
- package/dist/utils/child-process.d.ts +0 -1
- package/dist/utils/child-process.js +0 -1
- package/dist/utils/clipboard-image.d.ts +0 -1
- package/dist/utils/clipboard-image.js +0 -1
- package/dist/utils/clipboard-native.d.ts +0 -1
- package/dist/utils/clipboard-native.js +0 -1
- package/dist/utils/clipboard.d.ts +0 -1
- package/dist/utils/clipboard.js +0 -1
- package/dist/utils/deprecation.d.ts +0 -1
- package/dist/utils/deprecation.js +0 -1
- package/dist/utils/exif-orientation.d.ts +0 -1
- package/dist/utils/exif-orientation.js +0 -1
- package/dist/utils/frontmatter.d.ts +0 -1
- package/dist/utils/frontmatter.js +0 -1
- package/dist/utils/fs-watch.d.ts +0 -1
- package/dist/utils/fs-watch.js +0 -1
- package/dist/utils/git.d.ts +0 -1
- package/dist/utils/git.js +0 -1
- package/dist/utils/html.d.ts +0 -1
- package/dist/utils/html.js +0 -1
- package/dist/utils/image-convert.d.ts +0 -1
- package/dist/utils/image-convert.js +0 -1
- package/dist/utils/image-process.d.ts +0 -1
- package/dist/utils/image-process.js +0 -1
- package/dist/utils/image-resize-core.d.ts +0 -1
- package/dist/utils/image-resize-core.js +0 -1
- package/dist/utils/image-resize-worker.d.ts +0 -1
- package/dist/utils/image-resize-worker.js +0 -1
- package/dist/utils/image-resize.d.ts +0 -1
- package/dist/utils/image-resize.js +0 -1
- package/dist/utils/json.d.ts +0 -1
- package/dist/utils/json.js +0 -1
- package/dist/utils/mime.d.ts +0 -1
- package/dist/utils/mime.js +0 -1
- package/dist/utils/open-browser.d.ts +0 -1
- package/dist/utils/open-browser.js +0 -1
- package/dist/utils/paths.d.ts +0 -1
- package/dist/utils/paths.js +0 -1
- package/dist/utils/photon.d.ts +0 -1
- package/dist/utils/photon.js +0 -1
- package/dist/utils/pi-user-agent.d.ts +0 -1
- package/dist/utils/pi-user-agent.js +0 -1
- package/dist/utils/shell.d.ts +0 -1
- package/dist/utils/shell.js +0 -1
- package/dist/utils/sleep.d.ts +0 -1
- package/dist/utils/sleep.js +0 -1
- package/dist/utils/syntax-highlight.d.ts +0 -1
- package/dist/utils/syntax-highlight.js +0 -1
- package/dist/utils/thinking-tags.d.ts +0 -1
- package/dist/utils/thinking-tags.js +0 -1
- package/dist/utils/tools-manager.d.ts +3 -3
- package/dist/utils/tools-manager.js +125 -42
- package/dist/utils/version-check.d.ts +0 -1
- package/dist/utils/version-check.js +0 -1
- package/dist/utils/windows-self-update.d.ts +0 -1
- package/dist/utils/windows-self-update.js +0 -1
- package/docs/rpc.md +1 -2
- package/docs/settings.md +0 -1
- package/docs/skills.md +10 -18
- package/package.json +3 -2
- package/dist/bun/cli.d.ts.map +0 -1
- package/dist/bun/cli.js.map +0 -1
- package/dist/bun/register-bedrock.d.ts.map +0 -1
- package/dist/bun/register-bedrock.js.map +0 -1
- package/dist/bun/restore-sandbox-env.d.ts.map +0 -1
- package/dist/bun/restore-sandbox-env.js.map +0 -1
- package/dist/cli/args.d.ts.map +0 -1
- package/dist/cli/args.js.map +0 -1
- package/dist/cli/config-selector.d.ts.map +0 -1
- package/dist/cli/config-selector.js.map +0 -1
- package/dist/cli/credential-print.d.ts.map +0 -1
- package/dist/cli/credential-print.js.map +0 -1
- package/dist/cli/file-processor.d.ts.map +0 -1
- package/dist/cli/file-processor.js.map +0 -1
- package/dist/cli/initial-message.d.ts.map +0 -1
- package/dist/cli/initial-message.js.map +0 -1
- package/dist/cli/list-models.d.ts.map +0 -1
- package/dist/cli/list-models.js.map +0 -1
- package/dist/cli/project-trust.d.ts.map +0 -1
- package/dist/cli/project-trust.js.map +0 -1
- package/dist/cli/session-picker.d.ts.map +0 -1
- package/dist/cli/session-picker.js.map +0 -1
- package/dist/cli/startup-ui.d.ts.map +0 -1
- package/dist/cli/startup-ui.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/core/agent-session-auto-handoff.test.d.ts.map +0 -1
- package/dist/core/agent-session-auto-handoff.test.js.map +0 -1
- package/dist/core/agent-session-runtime.d.ts.map +0 -1
- package/dist/core/agent-session-runtime.js.map +0 -1
- package/dist/core/agent-session-services.d.ts.map +0 -1
- package/dist/core/agent-session-services.js.map +0 -1
- package/dist/core/agent-session-skill-block.test.d.ts.map +0 -1
- package/dist/core/agent-session-skill-block.test.js.map +0 -1
- package/dist/core/agent-session.d.ts.map +0 -1
- package/dist/core/agent-session.js.map +0 -1
- package/dist/core/agents.d.ts.map +0 -1
- package/dist/core/agents.js.map +0 -1
- package/dist/core/auth-guidance.d.ts.map +0 -1
- package/dist/core/auth-guidance.js.map +0 -1
- package/dist/core/auth-storage.d.ts.map +0 -1
- package/dist/core/auth-storage.js.map +0 -1
- package/dist/core/bash-executor.d.ts.map +0 -1
- package/dist/core/bash-executor.js.map +0 -1
- package/dist/core/built-in-extensions.d.ts.map +0 -1
- package/dist/core/built-in-extensions.js.map +0 -1
- package/dist/core/cache-stats.d.ts.map +0 -1
- package/dist/core/cache-stats.js.map +0 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
- package/dist/core/compaction/branch-summarization.js.map +0 -1
- package/dist/core/compaction/compaction.d.ts.map +0 -1
- package/dist/core/compaction/compaction.js.map +0 -1
- package/dist/core/compaction/index.d.ts.map +0 -1
- package/dist/core/compaction/index.js.map +0 -1
- package/dist/core/compaction/utils.d.ts.map +0 -1
- package/dist/core/compaction/utils.js.map +0 -1
- package/dist/core/defaults.d.ts.map +0 -1
- package/dist/core/defaults.js.map +0 -1
- package/dist/core/diagnostics.d.ts.map +0 -1
- package/dist/core/diagnostics.js.map +0 -1
- package/dist/core/event-bus.d.ts.map +0 -1
- package/dist/core/event-bus.js.map +0 -1
- package/dist/core/exec.d.ts.map +0 -1
- package/dist/core/exec.js.map +0 -1
- package/dist/core/experimental.d.ts.map +0 -1
- package/dist/core/experimental.js.map +0 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
- package/dist/core/export-html/ansi-to-html.js.map +0 -1
- package/dist/core/export-html/index.d.ts.map +0 -1
- package/dist/core/export-html/index.js.map +0 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
- package/dist/core/export-html/tool-renderer.js.map +0 -1
- package/dist/core/extensions/index.d.ts.map +0 -1
- package/dist/core/extensions/index.js.map +0 -1
- package/dist/core/extensions/loader.d.ts.map +0 -1
- package/dist/core/extensions/loader.js.map +0 -1
- package/dist/core/extensions/runner.d.ts.map +0 -1
- package/dist/core/extensions/runner.js.map +0 -1
- package/dist/core/extensions/types.d.ts.map +0 -1
- package/dist/core/extensions/types.js.map +0 -1
- package/dist/core/extensions/wrapper.d.ts.map +0 -1
- package/dist/core/extensions/wrapper.js.map +0 -1
- package/dist/core/footer-data-provider.d.ts.map +0 -1
- package/dist/core/footer-data-provider.js.map +0 -1
- package/dist/core/git-command.d.ts.map +0 -1
- package/dist/core/git-command.js.map +0 -1
- package/dist/core/http-dispatcher.d.ts.map +0 -1
- package/dist/core/http-dispatcher.js.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -1
- package/dist/core/keybindings.d.ts.map +0 -1
- package/dist/core/keybindings.js.map +0 -1
- package/dist/core/llama/client.d.ts.map +0 -1
- package/dist/core/llama/client.js.map +0 -1
- package/dist/core/llama/huggingface.d.ts.map +0 -1
- package/dist/core/llama/huggingface.js.map +0 -1
- package/dist/core/llama/index.d.ts.map +0 -1
- package/dist/core/llama/index.js.map +0 -1
- package/dist/core/llama/provider.d.ts.map +0 -1
- package/dist/core/llama/provider.js.map +0 -1
- package/dist/core/llama/ui.d.ts.map +0 -1
- package/dist/core/llama/ui.js.map +0 -1
- package/dist/core/messages.d.ts.map +0 -1
- package/dist/core/messages.js.map +0 -1
- package/dist/core/model-config.d.ts.map +0 -1
- package/dist/core/model-config.js.map +0 -1
- package/dist/core/model-registry.d.ts.map +0 -1
- package/dist/core/model-registry.js.map +0 -1
- package/dist/core/model-resolver.d.ts.map +0 -1
- package/dist/core/model-resolver.js.map +0 -1
- package/dist/core/model-runtime.d.ts.map +0 -1
- package/dist/core/model-runtime.js.map +0 -1
- package/dist/core/models-store.d.ts.map +0 -1
- package/dist/core/models-store.js.map +0 -1
- package/dist/core/output-guard.d.ts.map +0 -1
- package/dist/core/output-guard.js.map +0 -1
- package/dist/core/package-manager.d.ts.map +0 -1
- package/dist/core/package-manager.js.map +0 -1
- package/dist/core/package-manager.test.d.ts.map +0 -1
- package/dist/core/package-manager.test.js.map +0 -1
- package/dist/core/project-trust.d.ts.map +0 -1
- package/dist/core/project-trust.js.map +0 -1
- package/dist/core/prompt-templates.d.ts.map +0 -1
- package/dist/core/prompt-templates.js.map +0 -1
- package/dist/core/provider-attribution.d.ts.map +0 -1
- package/dist/core/provider-attribution.js.map +0 -1
- package/dist/core/provider-composer.d.ts.map +0 -1
- package/dist/core/provider-composer.js.map +0 -1
- package/dist/core/radius.d.ts.map +0 -1
- package/dist/core/radius.js.map +0 -1
- package/dist/core/remote-catalog-provider.d.ts.map +0 -1
- package/dist/core/remote-catalog-provider.js.map +0 -1
- package/dist/core/resolve-config-value.d.ts.map +0 -1
- package/dist/core/resolve-config-value.js.map +0 -1
- package/dist/core/resource-loader.d.ts.map +0 -1
- package/dist/core/resource-loader.js.map +0 -1
- package/dist/core/runtime-credentials.d.ts.map +0 -1
- package/dist/core/runtime-credentials.js.map +0 -1
- package/dist/core/sdk.d.ts.map +0 -1
- package/dist/core/sdk.js.map +0 -1
- package/dist/core/session-cwd.d.ts.map +0 -1
- package/dist/core/session-cwd.js.map +0 -1
- package/dist/core/session-manager.d.ts.map +0 -1
- package/dist/core/session-manager.js.map +0 -1
- package/dist/core/settings-manager-auto-handoff.test.d.ts.map +0 -1
- package/dist/core/settings-manager-auto-handoff.test.js.map +0 -1
- package/dist/core/settings-manager.d.ts.map +0 -1
- package/dist/core/settings-manager.js.map +0 -1
- package/dist/core/skills.d.ts.map +0 -1
- package/dist/core/skills.js.map +0 -1
- package/dist/core/slash-commands.d.ts.map +0 -1
- package/dist/core/slash-commands.js.map +0 -1
- package/dist/core/source-info.d.ts.map +0 -1
- package/dist/core/source-info.js.map +0 -1
- package/dist/core/system-prompt.d.ts.map +0 -1
- package/dist/core/system-prompt.js.map +0 -1
- package/dist/core/system-prompt.test.d.ts.map +0 -1
- package/dist/core/system-prompt.test.js.map +0 -1
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js.map +0 -1
- package/dist/core/timings.d.ts.map +0 -1
- package/dist/core/timings.js.map +0 -1
- package/dist/core/tools/bash.d.ts.map +0 -1
- package/dist/core/tools/bash.js.map +0 -1
- package/dist/core/tools/edit-diff.d.ts.map +0 -1
- package/dist/core/tools/edit-diff.js.map +0 -1
- package/dist/core/tools/edit.d.ts.map +0 -1
- package/dist/core/tools/edit.js.map +0 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
- package/dist/core/tools/file-mutation-queue.js.map +0 -1
- package/dist/core/tools/find.d.ts.map +0 -1
- package/dist/core/tools/find.js.map +0 -1
- package/dist/core/tools/grep.d.ts.map +0 -1
- package/dist/core/tools/grep.js.map +0 -1
- package/dist/core/tools/index.d.ts.map +0 -1
- package/dist/core/tools/index.js.map +0 -1
- package/dist/core/tools/ls.d.ts.map +0 -1
- package/dist/core/tools/ls.js.map +0 -1
- package/dist/core/tools/output-accumulator.d.ts.map +0 -1
- package/dist/core/tools/output-accumulator.js.map +0 -1
- package/dist/core/tools/path-utils.d.ts.map +0 -1
- package/dist/core/tools/path-utils.js.map +0 -1
- package/dist/core/tools/read.d.ts.map +0 -1
- package/dist/core/tools/read.js.map +0 -1
- package/dist/core/tools/render-utils.d.ts.map +0 -1
- package/dist/core/tools/render-utils.js.map +0 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
- package/dist/core/tools/truncate.d.ts.map +0 -1
- package/dist/core/tools/truncate.js.map +0 -1
- package/dist/core/tools/write.d.ts.map +0 -1
- package/dist/core/tools/write.js.map +0 -1
- package/dist/core/trust-manager.d.ts.map +0 -1
- package/dist/core/trust-manager.js.map +0 -1
- package/dist/core/usage-totals.d.ts.map +0 -1
- package/dist/core/usage-totals.js.map +0 -1
- package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/dist/extensions/pi-subagents/test/unit/slash-chain-groups.test.ts +0 -464
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/migrations.d.ts.map +0 -1
- package/dist/migrations.js.map +0 -1
- package/dist/modes/index.d.ts.map +0 -1
- package/dist/modes/index.js.map +0 -1
- package/dist/modes/interactive/components/armin.d.ts.map +0 -1
- package/dist/modes/interactive/components/armin.js.map +0 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/assistant-message.js.map +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
- package/dist/modes/interactive/components/bash-execution.js.map +0 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/config-selector.js.map +0 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
- package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-editor.js.map +0 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-entry.js.map +0 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-message.js.map +0 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
- package/dist/modes/interactive/components/daxnuts.js.map +0 -1
- package/dist/modes/interactive/components/diff.d.ts.map +0 -1
- package/dist/modes/interactive/components/diff.js.map +0 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-editor.js.map +0 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-input.js.map +0 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-selector.js.map +0 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +0 -1
- package/dist/modes/interactive/components/first-time-setup.js.map +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +0 -1
- package/dist/modes/interactive/components/footer.js.map +0 -1
- package/dist/modes/interactive/components/index.d.ts.map +0 -1
- package/dist/modes/interactive/components/index.js.map +0 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
- package/dist/modes/interactive/components/login-dialog.js.map +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/model-selector.js.map +0 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/session-selector.js.map +0 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/settings-selector.js.map +0 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +0 -1
- package/dist/modes/interactive/components/status-indicator.js.map +0 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/theme-selector.js.map +0 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-execution.js.map +0 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/tree-selector.js.map +0 -1
- package/dist/modes/interactive/components/trust-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/trust-selector.js.map +0 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/user-message.js.map +0 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
- package/dist/modes/interactive/external-editor.d.ts.map +0 -1
- package/dist/modes/interactive/external-editor.js.map +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
- package/dist/modes/interactive/interactive-mode.js.map +0 -1
- package/dist/modes/interactive/model-search.d.ts.map +0 -1
- package/dist/modes/interactive/model-search.js.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme.js.map +0 -1
- package/dist/modes/print-mode.d.ts.map +0 -1
- package/dist/modes/print-mode.js.map +0 -1
- package/dist/modes/rpc/jsonl.d.ts.map +0 -1
- package/dist/modes/rpc/jsonl.js.map +0 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-client.js.map +0 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-mode.js.map +0 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-types.js.map +0 -1
- package/dist/package-manager-cli.d.ts.map +0 -1
- package/dist/package-manager-cli.js.map +0 -1
- package/dist/rpc-entry.d.ts.map +0 -1
- package/dist/rpc-entry.js.map +0 -1
- package/dist/utils/ansi.d.ts.map +0 -1
- package/dist/utils/ansi.js.map +0 -1
- package/dist/utils/changelog.d.ts.map +0 -1
- package/dist/utils/changelog.js.map +0 -1
- package/dist/utils/child-process.d.ts.map +0 -1
- package/dist/utils/child-process.js.map +0 -1
- package/dist/utils/clipboard-image.d.ts.map +0 -1
- package/dist/utils/clipboard-image.js.map +0 -1
- package/dist/utils/clipboard-native.d.ts.map +0 -1
- package/dist/utils/clipboard-native.js.map +0 -1
- package/dist/utils/clipboard.d.ts.map +0 -1
- package/dist/utils/clipboard.js.map +0 -1
- package/dist/utils/deprecation.d.ts.map +0 -1
- package/dist/utils/deprecation.js.map +0 -1
- package/dist/utils/exif-orientation.d.ts.map +0 -1
- package/dist/utils/exif-orientation.js.map +0 -1
- package/dist/utils/frontmatter.d.ts.map +0 -1
- package/dist/utils/frontmatter.js.map +0 -1
- package/dist/utils/fs-watch.d.ts.map +0 -1
- package/dist/utils/fs-watch.js.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/html.d.ts.map +0 -1
- package/dist/utils/html.js.map +0 -1
- package/dist/utils/image-convert.d.ts.map +0 -1
- package/dist/utils/image-convert.js.map +0 -1
- package/dist/utils/image-process.d.ts.map +0 -1
- package/dist/utils/image-process.js.map +0 -1
- package/dist/utils/image-resize-core.d.ts.map +0 -1
- package/dist/utils/image-resize-core.js.map +0 -1
- package/dist/utils/image-resize-worker.d.ts.map +0 -1
- package/dist/utils/image-resize-worker.js.map +0 -1
- package/dist/utils/image-resize.d.ts.map +0 -1
- package/dist/utils/image-resize.js.map +0 -1
- package/dist/utils/json.d.ts.map +0 -1
- package/dist/utils/json.js.map +0 -1
- package/dist/utils/mime.d.ts.map +0 -1
- package/dist/utils/mime.js.map +0 -1
- package/dist/utils/open-browser.d.ts.map +0 -1
- package/dist/utils/open-browser.js.map +0 -1
- package/dist/utils/paths.d.ts.map +0 -1
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/photon.d.ts.map +0 -1
- package/dist/utils/photon.js.map +0 -1
- package/dist/utils/pi-user-agent.d.ts.map +0 -1
- package/dist/utils/pi-user-agent.js.map +0 -1
- package/dist/utils/shell.d.ts.map +0 -1
- package/dist/utils/shell.js.map +0 -1
- package/dist/utils/sleep.d.ts.map +0 -1
- package/dist/utils/sleep.js.map +0 -1
- package/dist/utils/syntax-highlight.d.ts.map +0 -1
- package/dist/utils/syntax-highlight.js.map +0 -1
- package/dist/utils/thinking-tags.d.ts.map +0 -1
- package/dist/utils/thinking-tags.js.map +0 -1
- package/dist/utils/tools-manager.d.ts.map +0 -1
- package/dist/utils/tools-manager.js.map +0 -1
- package/dist/utils/version-check.d.ts.map +0 -1
- package/dist/utils/version-check.js.map +0 -1
- package/dist/utils/windows-self-update.d.ts.map +0 -1
- package/dist/utils/windows-self-update.js.map +0 -1
|
@@ -4,7 +4,8 @@ import * as path from "node:path";
|
|
|
4
4
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
5
5
|
import type { ExtensionAPI, ExtensionContext } from "@selesai/code";
|
|
6
6
|
import { resolveAgentName, type AgentConfig, type AgentScope } from "../../agents/agents.ts";
|
|
7
|
-
import { getArtifactsDir,
|
|
7
|
+
import { getArtifactsDir, getChainRunsDir } from "../../shared/artifacts.ts";
|
|
8
|
+
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
8
9
|
import { ChainClarifyComponent, type ChainClarifyResult } from "./chain-clarify.ts";
|
|
9
10
|
import { resolveEffectiveThinking, toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
10
11
|
import { executeChain } from "./chain-execution.ts";
|
|
@@ -19,12 +20,12 @@ import {
|
|
|
19
20
|
import { resolveExecutionAgentScope } from "../../agents/agent-scope.ts";
|
|
20
21
|
import { handleManagementAction } from "../../agents/agent-management.ts";
|
|
21
22
|
import { buildDoctorReport } from "../../extension/doctor.ts";
|
|
22
|
-
import { clearPendingForegroundControlNotices } from "../../extension/control-notices.ts";
|
|
23
23
|
import { runSync } from "./execution.ts";
|
|
24
24
|
import { handleWatchdogToolAction, WATCHDOG_TOOL_ACTIONS } from "../../watchdog/tool-actions.ts";
|
|
25
25
|
import type { MainWatchdogRuntime } from "../../watchdog/runtime.ts";
|
|
26
26
|
import { buildModelCandidates, normalizeParentModel, resolveEffectiveSubagentModel, resolveModelCandidate, type ParentModel } from "../shared/model-fallback.ts";
|
|
27
27
|
import type { ModelScopeConfig } from "../shared/model-scope.ts";
|
|
28
|
+
import { aggregateParallelOutputs } from "../shared/parallel-utils.ts";
|
|
28
29
|
import { recordRun } from "../shared/run-history.ts";
|
|
29
30
|
import {
|
|
30
31
|
buildChainInstructions,
|
|
@@ -36,6 +37,9 @@ import {
|
|
|
36
37
|
suppressProgressForReadOnlyTask,
|
|
37
38
|
taskDisallowsFileUpdates,
|
|
38
39
|
type ChainStep,
|
|
40
|
+
type DynamicParallelStep,
|
|
41
|
+
type ParallelStep,
|
|
42
|
+
type ParallelTaskItem,
|
|
39
43
|
type ResolvedStepBehavior,
|
|
40
44
|
type SequentialStep,
|
|
41
45
|
type StepOverrides,
|
|
@@ -56,11 +60,11 @@ import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
|
56
60
|
import { usageBudgetExceededMessage, usageBudgetState, validateUsageBudgetConfig } from "../shared/usage-budget.ts";
|
|
57
61
|
import { intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
58
62
|
import { isAgentContractV1 } from "../shared/agent-contract.ts";
|
|
59
|
-
import { finalizeSingleOutput,
|
|
63
|
+
import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
60
64
|
import { cleanupStructuredOutputRuntime, createStructuredOutputRuntime } from "../shared/structured-output.ts";
|
|
61
65
|
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage } from "../../shared/utils.ts";
|
|
62
66
|
import { DEFAULT_GLOBAL_CONCURRENCY_LIMIT, Semaphore } from "../shared/parallel-utils.ts";
|
|
63
|
-
import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup } from "../shared/parallel-handoff.ts";
|
|
67
|
+
import { discardPreservedWorktrees, formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup, writePendingParallelHandoff } from "../shared/parallel-handoff.ts";
|
|
64
68
|
import { summarizeContextModes, type ContextMode, type ContextSummary } from "../shared/context-mode.ts";
|
|
65
69
|
import {
|
|
66
70
|
attachNestedChildrenToResultChildren,
|
|
@@ -82,6 +86,13 @@ import { resolveSubagentRunId, type ResolvedSubagentRunId } from "../background/
|
|
|
82
86
|
import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
|
|
83
87
|
import { inspectSubagentStatus } from "../background/run-status.ts";
|
|
84
88
|
import { applyForceTopLevelAsyncOverride } from "../background/top-level-async.ts";
|
|
89
|
+
import { handleMissionAction, MISSION_ACTIONS } from "../../missions/actions.ts";
|
|
90
|
+
import { attachMissionToLaunchResult, prepareMissionLaunch, type MissionLaunchBinding } from "../../missions/lifecycle.ts";
|
|
91
|
+
import { resolveAuthorityDecision } from "../../policy/authority.ts";
|
|
92
|
+
import { handleHerdrInspectorAction, HERDR_INSPECTOR_ACTIONS } from "../../inspectors/herdr/actions.ts";
|
|
93
|
+
import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.ts";
|
|
94
|
+
import { runWorkflowScript, WorkflowScriptError, type WorkflowScriptChildResult } from "../../workflows/scripted-workflow.ts";
|
|
95
|
+
import { resolveWorkflowChatProgress, type WorkflowChatProgressProjection } from "../../workflows/chat-progress.ts";
|
|
85
96
|
import {
|
|
86
97
|
cleanupWorktrees,
|
|
87
98
|
createWorktrees,
|
|
@@ -93,6 +104,7 @@ import {
|
|
|
93
104
|
} from "../shared/worktree.ts";
|
|
94
105
|
import {
|
|
95
106
|
type AgentProgress,
|
|
107
|
+
type AsyncJobState,
|
|
96
108
|
type AsyncStatus,
|
|
97
109
|
type AcceptanceInput,
|
|
98
110
|
type AgentContract,
|
|
@@ -117,10 +129,9 @@ import {
|
|
|
117
129
|
type UsageBudgetConfig,
|
|
118
130
|
type SubagentRunMode,
|
|
119
131
|
type SubagentState,
|
|
120
|
-
|
|
132
|
+
DIRS,
|
|
121
133
|
DEFAULT_ARTIFACT_CONFIG,
|
|
122
134
|
DEFAULT_FORK_PREAMBLE,
|
|
123
|
-
RESULTS_DIR,
|
|
124
135
|
SUBAGENT_ACTIONS,
|
|
125
136
|
SUBAGENT_CONTROL_EVENT,
|
|
126
137
|
SUBAGENT_CONTROL_INTERCOM_EVENT,
|
|
@@ -133,7 +144,39 @@ import {
|
|
|
133
144
|
wrapForkTask,
|
|
134
145
|
} from "../../shared/types.ts";
|
|
135
146
|
|
|
136
|
-
const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure"]);
|
|
147
|
+
const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure", "mission.create", "mission.update", "mission.attach-run", "mission.close", "inspector.open", "inspector.close", "project.open", "project.close", "worktree.discard", "schedule.create", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"]);
|
|
148
|
+
|
|
149
|
+
type UndefinedOmitted<T extends object> = {
|
|
150
|
+
[K in keyof T as undefined extends T[K] ? never : K]: T[K];
|
|
151
|
+
} & {
|
|
152
|
+
[K in keyof T as undefined extends T[K] ? K : never]?: Exclude<T[K], undefined>;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// These helpers mutate their argument, so keep calls scoped to fresh object literals or shallow copies.
|
|
156
|
+
function omitUndefinedProperties<T extends object>(value: T): UndefinedOmitted<T> {
|
|
157
|
+
for (const key of Object.keys(value) as Array<keyof T>) {
|
|
158
|
+
if (value[key] === undefined) delete value[key];
|
|
159
|
+
}
|
|
160
|
+
return value as UndefinedOmitted<T>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
type WithUndefinedOptionals<T extends object> = {
|
|
164
|
+
[K in keyof T]: {} extends Pick<T, K> ? T[K] | undefined : T[K];
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
type RequiredKeysAllowingUndefined<T extends object> = {
|
|
168
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? never : undefined extends T[K] ? K : never;
|
|
169
|
+
}[keyof T];
|
|
170
|
+
|
|
171
|
+
function compactOptional<T extends object>(
|
|
172
|
+
value: WithUndefinedOptionals<T> & (RequiredKeysAllowingUndefined<T> extends never ? unknown : never),
|
|
173
|
+
): T {
|
|
174
|
+
for (const key of Object.keys(value) as Array<keyof T>) {
|
|
175
|
+
if (value[key] === undefined) delete value[key];
|
|
176
|
+
}
|
|
177
|
+
return value as T;
|
|
178
|
+
}
|
|
179
|
+
|
|
137
180
|
interface TaskParam {
|
|
138
181
|
agent: string;
|
|
139
182
|
task: string;
|
|
@@ -156,13 +199,26 @@ export interface SubagentParamsLike {
|
|
|
156
199
|
id?: string;
|
|
157
200
|
runId?: string;
|
|
158
201
|
dir?: string;
|
|
202
|
+
handoffPath?: string;
|
|
159
203
|
index?: number;
|
|
160
204
|
view?: "fleet" | "transcript";
|
|
161
205
|
lines?: number;
|
|
206
|
+
chainName?: string;
|
|
207
|
+
config?: unknown;
|
|
208
|
+
name?: string;
|
|
209
|
+
type?: string;
|
|
162
210
|
agent?: string;
|
|
163
211
|
task?: string;
|
|
164
212
|
message?: string;
|
|
165
213
|
steeringRecovery?: boolean;
|
|
214
|
+
workflowScript?: string;
|
|
215
|
+
chatProgress?: "auto" | "off" | "terminal" | "milestones" | "live-card";
|
|
216
|
+
step?: ChainStep;
|
|
217
|
+
/** Internal workflow ownership metadata; not part of the public schema. */
|
|
218
|
+
workflowParentRunId?: string;
|
|
219
|
+
workflowKey?: string;
|
|
220
|
+
suppressRoutineResultIntercom?: boolean;
|
|
221
|
+
/** Internal durable-run compatibility fields. Public callers must use workflowScript. */
|
|
166
222
|
chain?: ChainStep[];
|
|
167
223
|
tasks?: TaskParam[];
|
|
168
224
|
concurrency?: number;
|
|
@@ -189,6 +245,7 @@ export interface SubagentParamsLike {
|
|
|
189
245
|
thinking?: string | false;
|
|
190
246
|
scope?: string;
|
|
191
247
|
target?: string;
|
|
248
|
+
focus?: boolean;
|
|
192
249
|
skill?: string | string[] | boolean;
|
|
193
250
|
output?: string | boolean;
|
|
194
251
|
outputMode?: "inline" | "file-only";
|
|
@@ -199,11 +256,25 @@ export interface SubagentParamsLike {
|
|
|
199
256
|
agentContract?: AgentContract;
|
|
200
257
|
schedule?: string;
|
|
201
258
|
scheduleName?: string;
|
|
259
|
+
at?: string;
|
|
260
|
+
every?: string;
|
|
261
|
+
on?: string | number;
|
|
262
|
+
timezone?: string;
|
|
263
|
+
overlap?: "skip";
|
|
264
|
+
catchUp?: "none" | "latest";
|
|
202
265
|
additional?: number;
|
|
266
|
+
missionId?: string;
|
|
267
|
+
mission?: unknown;
|
|
268
|
+
missionUpdate?: unknown;
|
|
269
|
+
missionStatus?: string;
|
|
270
|
+
missionScope?: string;
|
|
271
|
+
runMode?: string;
|
|
272
|
+
runStatus?: string;
|
|
273
|
+
summary?: string;
|
|
203
274
|
}
|
|
204
275
|
|
|
205
276
|
function rememberParentModel(state: { currentSessionId?: string | null; lastParentModel?: ParentModel }, sessionId: string | null, model: unknown): ParentModel | undefined {
|
|
206
|
-
if (state.currentSessionId !== sessionId) state.lastParentModel
|
|
277
|
+
if (state.currentSessionId !== sessionId) delete state.lastParentModel;
|
|
207
278
|
state.currentSessionId = sessionId;
|
|
208
279
|
const parentModel = normalizeParentModel(model);
|
|
209
280
|
if (!sessionId) return parentModel;
|
|
@@ -262,6 +333,7 @@ interface ExecutionContextData {
|
|
|
262
333
|
modelScope?: ModelScopeConfig;
|
|
263
334
|
parentModel?: ParentModel;
|
|
264
335
|
parentSessionId: string | null;
|
|
336
|
+
parentPiSessionId?: string;
|
|
265
337
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
266
338
|
}
|
|
267
339
|
|
|
@@ -272,7 +344,6 @@ function resolveRequestedCwd(runtimeCwd: string, requestedCwd: string | undefine
|
|
|
272
344
|
function removeForegroundControlIfIdle(state: SubagentState, runId: string): boolean {
|
|
273
345
|
const control = state.foregroundControls.get(runId);
|
|
274
346
|
if (control && (!foregroundSchedulingSettled(control) || (control.activeChildren?.size ?? 0) > 0)) return false;
|
|
275
|
-
clearPendingForegroundControlNotices(state, runId);
|
|
276
347
|
state.foregroundControls.delete(runId);
|
|
277
348
|
if (state.lastForegroundControlId === runId) state.lastForegroundControlId = null;
|
|
278
349
|
return true;
|
|
@@ -428,7 +499,7 @@ function rememberForegroundRun(state: SubagentState, input: { runId: string; mod
|
|
|
428
499
|
agent: result.agent,
|
|
429
500
|
index,
|
|
430
501
|
...(result.context ? { context: result.context } : {}),
|
|
431
|
-
status: resolveSubagentResultStatus({
|
|
502
|
+
status: resolveSubagentResultStatus(omitUndefinedProperties({
|
|
432
503
|
exitCode: result.exitCode,
|
|
433
504
|
interrupted: result.interrupted,
|
|
434
505
|
detached: result.detached,
|
|
@@ -436,7 +507,7 @@ function rememberForegroundRun(state: SubagentState, input: { runId: string; mod
|
|
|
436
507
|
timedOut: result.timedOut,
|
|
437
508
|
stopped: result.stopped,
|
|
438
509
|
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
439
|
-
}),
|
|
510
|
+
})),
|
|
440
511
|
...foregroundChildActivityFromProgress(result.progress),
|
|
441
512
|
updatedAt,
|
|
442
513
|
...(result.exitCode !== undefined ? { exitCode: result.exitCode } : {}),
|
|
@@ -490,7 +561,7 @@ function applyControlEventToRememberedForegroundRun(state: SubagentState, event:
|
|
|
490
561
|
};
|
|
491
562
|
}
|
|
492
563
|
|
|
493
|
-
function updateRememberedForegroundChild(state: SubagentState, input: { runId: string; mode: "single" | "parallel" | "chain"; cwd: string; sessionId: string | null; index: number; result: SingleResult; events: IntercomEventBus }): void {
|
|
564
|
+
function updateRememberedForegroundChild(state: SubagentState, input: { runId: string; mode: "single" | "parallel" | "chain"; cwd: string; sessionId: string | null; index: number; result: SingleResult; events: IntercomEventBus; notify?: boolean }): void {
|
|
494
565
|
state.foregroundRuns ??= new Map();
|
|
495
566
|
const updatedAt = Date.now();
|
|
496
567
|
let run = state.foregroundRuns.get(input.runId);
|
|
@@ -499,7 +570,7 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
499
570
|
state.foregroundRuns.set(input.runId, run);
|
|
500
571
|
}
|
|
501
572
|
run.updatedAt = updatedAt;
|
|
502
|
-
const terminalStatus = resolveSubagentResultStatus({
|
|
573
|
+
const terminalStatus = resolveSubagentResultStatus(omitUndefinedProperties({
|
|
503
574
|
exitCode: input.result.exitCode,
|
|
504
575
|
...(input.result.acceptance?.status === "rejected" ? { success: false } : {}),
|
|
505
576
|
interrupted: input.result.interrupted,
|
|
@@ -508,9 +579,9 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
508
579
|
timedOut: input.result.timedOut,
|
|
509
580
|
stopped: input.result.stopped,
|
|
510
581
|
turnBudgetExceeded: input.result.turnBudgetExceeded,
|
|
511
|
-
});
|
|
582
|
+
}));
|
|
512
583
|
const child = run.children[input.index] ?? { agent: input.result.agent, index: input.index, status: "detached" as const };
|
|
513
|
-
run.children[input.index] = {
|
|
584
|
+
run.children[input.index] = omitUndefinedProperties({
|
|
514
585
|
...child,
|
|
515
586
|
agent: input.result.agent,
|
|
516
587
|
index: input.index,
|
|
@@ -520,12 +591,7 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
520
591
|
updatedAt,
|
|
521
592
|
...(input.result.exitCode !== undefined ? { exitCode: input.result.exitCode } : {}),
|
|
522
593
|
...(input.result.error ? { error: input.result.error } : {}),
|
|
523
|
-
|
|
524
|
-
// exists, do not retain the full final output in memory; status/transcript
|
|
525
|
-
// views recover it from `savedOutputPath` via `rememberedForegroundChildOutput`
|
|
526
|
-
// (runs/background/run-status.ts) and the TUI via `resultOutputForUi`
|
|
527
|
-
// (tui/render.ts).
|
|
528
|
-
...(input.result.finalOutput && !input.result.savedOutputPath ? { finalOutput: input.result.finalOutput } : {}),
|
|
594
|
+
...(input.result.finalOutput ? { finalOutput: input.result.finalOutput } : {}),
|
|
529
595
|
outputState: input.result.outputState,
|
|
530
596
|
outputMode: input.result.outputMode,
|
|
531
597
|
savedOutputPath: input.result.savedOutputPath,
|
|
@@ -543,17 +609,16 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
543
609
|
...(input.result.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: input.result.runtimeAcknowledgedExtensions } : {}),
|
|
544
610
|
...(input.result.capabilityCeiling ? { capabilityCeiling: input.result.capabilityCeiling } : {}),
|
|
545
611
|
...(input.result.capabilityAudit ? { capabilityAudit: input.result.capabilityAudit } : {}),
|
|
546
|
-
};
|
|
612
|
+
});
|
|
547
613
|
trimRememberedForegroundRuns(state);
|
|
548
|
-
const
|
|
549
|
-
const output = reference ?? getSingleResultOutput(input.result).trim();
|
|
614
|
+
const output = getSingleResultOutput(input.result).trim();
|
|
550
615
|
const success = terminalStatus === "completed";
|
|
551
616
|
const summary = !success && input.result.error
|
|
552
|
-
? `${input.result.error}${output ? `\n\n${output}` : ""}`
|
|
617
|
+
? `${input.result.error}${output ? `\n\nOutput:\n${output}` : ""}`
|
|
553
618
|
: output || input.result.error || "Detached child exited without final output.";
|
|
554
619
|
// A detached callback may outlive its extension runtime. Stale sessions are
|
|
555
620
|
// intentionally dropped rather than routed through a replacement runtime.
|
|
556
|
-
if (!input.sessionId || input.sessionId !== state.currentSessionId) return;
|
|
621
|
+
if (input.notify === false || !input.sessionId || input.sessionId !== state.currentSessionId) return;
|
|
557
622
|
input.events.emit(SUBAGENT_FOREGROUND_COMPLETE_EVENT, {
|
|
558
623
|
id: `${input.runId}:${input.index}`,
|
|
559
624
|
runId: input.runId,
|
|
@@ -577,7 +642,7 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
577
642
|
});
|
|
578
643
|
}
|
|
579
644
|
|
|
580
|
-
function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState): { runId: string; mode:
|
|
645
|
+
function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState): { runId: string; mode: SubagentRunMode; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
|
|
581
646
|
const requested = (params.id ?? params.runId)?.trim();
|
|
582
647
|
if (!requested || !state.foregroundRuns?.size || !state.currentSessionId) return undefined;
|
|
583
648
|
const sessionRuns = [...state.foregroundRuns.values()].filter((run) => run.sessionId === state.currentSessionId);
|
|
@@ -622,6 +687,9 @@ type NestedResumeSourceTarget = {
|
|
|
622
687
|
index: number;
|
|
623
688
|
cwd?: string;
|
|
624
689
|
sessionFile: string;
|
|
690
|
+
model?: string;
|
|
691
|
+
thinking?: AgentConfig["thinking"];
|
|
692
|
+
launchContractDigest?: string;
|
|
625
693
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
626
694
|
};
|
|
627
695
|
type ResumeSourceTarget = AsyncResumeSourceTarget | ForegroundResumeSourceTarget | NestedResumeSourceTarget;
|
|
@@ -663,10 +731,10 @@ function resolveResumeTarget(params: SubagentParamsLike, state: SubagentState, o
|
|
|
663
731
|
try {
|
|
664
732
|
asyncTarget = {
|
|
665
733
|
source: "async",
|
|
666
|
-
...resolveAsyncResumeTarget(params, {}, {
|
|
734
|
+
...resolveAsyncResumeTarget(params, {}, compactOptional<NonNullable<Parameters<typeof resolveAsyncResumeTarget>[2]>>({
|
|
667
735
|
requireSessionFile: options.asyncRequireSessionFile,
|
|
668
736
|
sessionId: state.currentSessionId ?? undefined,
|
|
669
|
-
}),
|
|
737
|
+
})),
|
|
670
738
|
};
|
|
671
739
|
} catch (error) {
|
|
672
740
|
asyncError = error;
|
|
@@ -758,7 +826,7 @@ function interruptAsyncRun(
|
|
|
758
826
|
): AgentToolResult<Details> | null {
|
|
759
827
|
const target = getAsyncInterruptTarget(state, runId, location);
|
|
760
828
|
if (!target) return null;
|
|
761
|
-
const status = reconcileAsyncRun(target.asyncDir, { kill }).status;
|
|
829
|
+
const status = reconcileAsyncRun(target.asyncDir, omitUndefinedProperties({ kill })).status;
|
|
762
830
|
if (!status || status.state !== "running" || typeof status.pid !== "number") {
|
|
763
831
|
return {
|
|
764
832
|
content: [{ type: "text", text: `No running async run with an interrupt-capable pid was found for '${runId ?? "current"}'.` }],
|
|
@@ -766,11 +834,19 @@ function interruptAsyncRun(
|
|
|
766
834
|
details: { mode: "management", results: [] },
|
|
767
835
|
};
|
|
768
836
|
}
|
|
837
|
+
const activeSteps = status.steps?.filter((step) => step.status === "running") ?? [];
|
|
838
|
+
if (activeSteps.length > 0 && activeSteps.every((step) => step.runner?.type === "external-cli")) {
|
|
839
|
+
return {
|
|
840
|
+
content: [{ type: "text", text: `Interrupt is unsupported for one-shot external CLI async run ${target.asyncId}; use stop instead.` }],
|
|
841
|
+
isError: true,
|
|
842
|
+
details: { mode: "management", results: [] },
|
|
843
|
+
};
|
|
844
|
+
}
|
|
769
845
|
try {
|
|
770
|
-
deliverInterruptRequest({ asyncDir: target.asyncDir, pid: status.pid, kill, source: "interrupt-action" });
|
|
846
|
+
deliverInterruptRequest(omitUndefinedProperties({ asyncDir: target.asyncDir, pid: status.pid, kill, source: "interrupt-action" }));
|
|
771
847
|
const tracked = state.asyncJobs.get(target.asyncId);
|
|
772
848
|
if (tracked) {
|
|
773
|
-
tracked.activityState
|
|
849
|
+
delete tracked.activityState;
|
|
774
850
|
tracked.updatedAt = Date.now();
|
|
775
851
|
}
|
|
776
852
|
return {
|
|
@@ -812,14 +888,15 @@ function appendStepToAsyncChain(input: {
|
|
|
812
888
|
details: { mode: "management", results: [] },
|
|
813
889
|
};
|
|
814
890
|
}
|
|
815
|
-
if (!input.params.
|
|
891
|
+
if (!input.params.step) {
|
|
816
892
|
return {
|
|
817
|
-
content: [{ type: "text", text: "action='append-step' requires
|
|
893
|
+
content: [{ type: "text", text: "action='append-step' requires step." }],
|
|
818
894
|
isError: true,
|
|
819
895
|
details: { mode: "management", results: [] },
|
|
820
896
|
};
|
|
821
897
|
}
|
|
822
|
-
const
|
|
898
|
+
const chain = [input.params.step];
|
|
899
|
+
const acceptanceErrors = validateExecutionAcceptance({ ...input.params, chain } as Parameters<typeof validateExecutionAcceptance>[0]);
|
|
823
900
|
if (acceptanceErrors.length > 0) {
|
|
824
901
|
return {
|
|
825
902
|
content: [{ type: "text", text: `Cannot append step: ${acceptanceErrors.join(" ")}` }],
|
|
@@ -830,7 +907,7 @@ function appendStepToAsyncChain(input: {
|
|
|
830
907
|
|
|
831
908
|
let resolved: ResolvedSubagentRunId | undefined;
|
|
832
909
|
try {
|
|
833
|
-
resolved = resolveSubagentRunId(targetRunId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) });
|
|
910
|
+
resolved = resolveSubagentRunId(targetRunId, omitUndefinedProperties({ state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }));
|
|
834
911
|
} catch (error) {
|
|
835
912
|
const message = error instanceof Error ? error.message : String(error);
|
|
836
913
|
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
@@ -888,7 +965,7 @@ function appendStepToAsyncChain(input: {
|
|
|
888
965
|
...pendingAppendRequests.flatMap((request) => runnerStepOutputNames(request.steps)),
|
|
889
966
|
]);
|
|
890
967
|
try {
|
|
891
|
-
validateChainOutputBindingsWithContext(
|
|
968
|
+
validateChainOutputBindingsWithContext(chain, omitUndefinedProperties({ maxItems: input.deps.config.chain?.dynamicFanout?.maxItems }), {
|
|
892
969
|
priorOutputNames: reservedOutputNames,
|
|
893
970
|
startStepIndex: status.chainStepCount ?? status.steps?.length ?? 0,
|
|
894
971
|
});
|
|
@@ -908,7 +985,7 @@ function appendStepToAsyncChain(input: {
|
|
|
908
985
|
const chainSkillInput = normalizeSkillInput(input.params.skill);
|
|
909
986
|
const chainSkills = chainSkillInput === false ? [] : (chainSkillInput ?? []);
|
|
910
987
|
const parentModel = input.parentModel;
|
|
911
|
-
const asyncCtx = {
|
|
988
|
+
const asyncCtx = compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
912
989
|
pi: input.deps.pi,
|
|
913
990
|
cwd: input.ctx.cwd,
|
|
914
991
|
currentSessionId: resolveCurrentSessionId(input.ctx.sessionManager),
|
|
@@ -917,9 +994,10 @@ function appendStepToAsyncChain(input: {
|
|
|
917
994
|
currentModel: parentModel,
|
|
918
995
|
modelScope: discoveredForAppend.modelScope,
|
|
919
996
|
interactive: input.ctx.hasUI,
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
997
|
+
permissions: input.deps.config.permissions,
|
|
998
|
+
});
|
|
999
|
+
const built = buildAsyncRunnerSteps(resolved.id, compactOptional<Parameters<typeof buildAsyncRunnerSteps>[1]>({
|
|
1000
|
+
chain: wrapChainTasksForFork(chain, contextPolicy),
|
|
923
1001
|
task: input.params.task,
|
|
924
1002
|
resultMode: "chain",
|
|
925
1003
|
agents,
|
|
@@ -934,7 +1012,7 @@ function appendStepToAsyncChain(input: {
|
|
|
934
1012
|
asyncDir: resolved.location.asyncDir,
|
|
935
1013
|
validateOutputBindings: false,
|
|
936
1014
|
capabilityCeiling: intersectSubagentCapabilityCeilings(status.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(asyncCtx.currentSessionId)),
|
|
937
|
-
});
|
|
1015
|
+
}));
|
|
938
1016
|
if ("error" in built) {
|
|
939
1017
|
return {
|
|
940
1018
|
content: [{ type: "text", text: built.error }],
|
|
@@ -1029,7 +1107,7 @@ function resolveNestedResumeTarget(match: ResolvedSubagentRunId & { kind: "neste
|
|
|
1029
1107
|
if (!agent) throw new Error(`Could not determine child agent for nested run '${run.id}'.`);
|
|
1030
1108
|
const state = run.state === "complete" || run.state === "failed" || run.state === "paused" ? run.state : "failed";
|
|
1031
1109
|
const asyncDir = resolveNestedAsyncDir(match.match.rootRunId, run);
|
|
1032
|
-
return {
|
|
1110
|
+
return compactOptional<NestedResumeSourceTarget>({
|
|
1033
1111
|
kind: "revive",
|
|
1034
1112
|
source: "nested",
|
|
1035
1113
|
runId: run.id,
|
|
@@ -1039,7 +1117,7 @@ function resolveNestedResumeTarget(match: ResolvedSubagentRunId & { kind: "neste
|
|
|
1039
1117
|
cwd: asyncDir ? path.dirname(asyncDir) : undefined,
|
|
1040
1118
|
sessionFile: validateNestedSessionFile(run, trustedSessionRoots),
|
|
1041
1119
|
...(run.capabilityCeiling ? { capabilityCeiling: run.capabilityCeiling } : {}),
|
|
1042
|
-
};
|
|
1120
|
+
});
|
|
1043
1121
|
}
|
|
1044
1122
|
|
|
1045
1123
|
async function waitForNestedControlResult(target: ResolvedSubagentRunId & { kind: "nested" }, requestId: string, ignoredFiles: ReadonlySet<string>, timeoutMs = 1_000) {
|
|
@@ -1070,7 +1148,7 @@ function directNestedAsyncInterrupt(target: ResolvedSubagentRunId & { kind: "nes
|
|
|
1070
1148
|
const run = target.match.run;
|
|
1071
1149
|
const asyncDir = resolveNestedAsyncDir(target.match.rootRunId, run);
|
|
1072
1150
|
if (!asyncDir) return undefined;
|
|
1073
|
-
const status = reconcileAsyncRun(asyncDir, { resultsDir: path.join(
|
|
1151
|
+
const status = reconcileAsyncRun(asyncDir, { resultsDir: path.join(DIRS.results, "nested", target.match.rootRunId) }).status;
|
|
1074
1152
|
const pid = typeof status?.pid === "number" && status.pid > 0 ? status.pid : run.pid;
|
|
1075
1153
|
if (!status || status.state !== "running" || typeof pid !== "number" || pid <= 0) return undefined;
|
|
1076
1154
|
try {
|
|
@@ -1086,7 +1164,7 @@ async function directNestedAsyncSteer(input: { target: ResolvedSubagentRunId & {
|
|
|
1086
1164
|
const run = input.target.match.run;
|
|
1087
1165
|
const asyncDir = resolveNestedAsyncDir(input.target.match.rootRunId, run);
|
|
1088
1166
|
if (!asyncDir) return undefined;
|
|
1089
|
-
const status = reconcileAsyncRun(asyncDir, { resultsDir: path.join(
|
|
1167
|
+
const status = reconcileAsyncRun(asyncDir, { resultsDir: path.join(DIRS.results, "nested", input.target.match.rootRunId) }).status;
|
|
1090
1168
|
if (!status || (status.state !== "running" && status.state !== "queued")) return undefined;
|
|
1091
1169
|
const steps = status.steps ?? [];
|
|
1092
1170
|
if (input.index !== undefined) {
|
|
@@ -1116,7 +1194,7 @@ async function directNestedAsyncSteer(input: { target: ResolvedSubagentRunId & {
|
|
|
1116
1194
|
const scheduled = { requestId, state: "scheduled" as const, sourceRunId: run.id, targets };
|
|
1117
1195
|
return { content: [{ type: "text", text: `Steering scheduled for nested async run ${run.id} (request ${requestId}).` }], details: { mode: "management", results: [], steering: scheduled } };
|
|
1118
1196
|
}
|
|
1119
|
-
const waited = await waitForSteeringAction({ asyncDir, sourceRunId: run.id, requestId, timeoutMs: 3_000, signal: input.signal });
|
|
1197
|
+
const waited = await waitForSteeringAction(omitUndefinedProperties({ asyncDir, sourceRunId: run.id, requestId, timeoutMs: 3_000, signal: input.signal }));
|
|
1120
1198
|
const result = waited ?? { requestId, state: "pending" as const, sourceRunId: run.id, targets };
|
|
1121
1199
|
const stateText = result.state === "delivered" ? "delivered" : result.state === "failed" ? "failed" : result.state === "partial" ? "partial" : "pending";
|
|
1122
1200
|
return { content: [{ type: "text", text: `Steering ${stateText} for nested async run ${run.id} (request ${requestId}).` }], ...(result.state === "failed" || result.state === "partial" ? { isError: true } : {}), details: { mode: "management", results: [], steering: result } };
|
|
@@ -1128,7 +1206,7 @@ async function interruptNestedRun(target: ResolvedSubagentRunId & { kind: "neste
|
|
|
1128
1206
|
if (run.state === "failed") return { content: [{ type: "text", text: `Nested run ${run.id} has failed and cannot be interrupted.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1129
1207
|
if (run.state === "paused") return { content: [{ type: "text", text: `Nested run ${run.id} is already paused.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1130
1208
|
const result = await sendNestedControlRequest(target, "interrupt");
|
|
1131
|
-
if (result) return { content: [{ type: "text", text: result.message }],
|
|
1209
|
+
if (result) return { content: [{ type: "text", text: result.message }], ...(result.ok ? {} : { isError: true }), details: { mode: "management", results: [] } };
|
|
1132
1210
|
const direct = directNestedAsyncInterrupt(target);
|
|
1133
1211
|
if (direct) return direct;
|
|
1134
1212
|
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: [] } };
|
|
@@ -1137,7 +1215,7 @@ async function interruptNestedRun(target: ResolvedSubagentRunId & { kind: "neste
|
|
|
1137
1215
|
async function resumeLiveNestedRun(input: { target: ResolvedSubagentRunId & { kind: "nested" }; message: string }): Promise<AgentToolResult<Details>> {
|
|
1138
1216
|
const run = input.target.match.run;
|
|
1139
1217
|
const result = await sendNestedControlRequest(input.target, "resume", input.message);
|
|
1140
|
-
if (result) return { content: [{ type: "text", text: result.message }],
|
|
1218
|
+
if (result) return { content: [{ type: "text", text: result.message }], ...(result.ok ? {} : { isError: true }), details: { mode: "management", results: [] } };
|
|
1141
1219
|
return { content: [{ type: "text", text: `Nested run ${run.id} appears live but its owner route is not reachable. Wait for completion, then retry action='resume'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1142
1220
|
}
|
|
1143
1221
|
|
|
@@ -1149,6 +1227,15 @@ async function steerNestedRun(input: { target: ResolvedSubagentRunId & { kind: "
|
|
|
1149
1227
|
return { content: [{ type: "text", text: `Nested run ${run.id} is not a live async Pi child session with a steering inbox. action='steer' cannot target foreground nested runs.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1150
1228
|
}
|
|
1151
1229
|
|
|
1230
|
+
function externalRunnerControlError(asyncDir: string, action: "steer" | "resume"): AgentToolResult<Details> | undefined {
|
|
1231
|
+
const status = readStatus(asyncDir);
|
|
1232
|
+
if (!status?.steps?.length || !status.steps.every((step) => step.runner?.type === "external-cli")) return undefined;
|
|
1233
|
+
const message = action === "steer"
|
|
1234
|
+
? "One-shot external CLI runners do not accept live steer messages."
|
|
1235
|
+
: "One-shot external CLI runners do not persist sessions and cannot be resumed.";
|
|
1236
|
+
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1152
1239
|
async function resumeAsyncRun(input: {
|
|
1153
1240
|
params: SubagentParamsLike;
|
|
1154
1241
|
requestCwd: string;
|
|
@@ -1173,7 +1260,7 @@ async function resumeAsyncRun(input: {
|
|
|
1173
1260
|
details: { mode: "management", results: [] },
|
|
1174
1261
|
};
|
|
1175
1262
|
}
|
|
1176
|
-
const acceptanceErrors = validateExecutionAcceptance(input.params);
|
|
1263
|
+
const acceptanceErrors = validateExecutionAcceptance(input.params as Parameters<typeof validateExecutionAcceptance>[0]);
|
|
1177
1264
|
if (acceptanceErrors.length > 0) {
|
|
1178
1265
|
return {
|
|
1179
1266
|
content: [{ type: "text", text: `Cannot resume: ${acceptanceErrors.join(" ")}` }],
|
|
@@ -1189,7 +1276,7 @@ async function resumeAsyncRun(input: {
|
|
|
1189
1276
|
const requestedId = input.params.id ?? input.params.runId;
|
|
1190
1277
|
let resolved: ResolvedSubagentRunId | undefined;
|
|
1191
1278
|
try {
|
|
1192
|
-
resolved = requestedId ? resolveSubagentRunId(requestedId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }) : undefined;
|
|
1279
|
+
resolved = requestedId ? resolveSubagentRunId(requestedId, omitUndefinedProperties({ state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) })) : undefined;
|
|
1193
1280
|
} catch (error) {
|
|
1194
1281
|
const message = error instanceof Error ? error.message : "";
|
|
1195
1282
|
const asyncMatches = message.match(/async:/g)?.length ?? 0;
|
|
@@ -1212,6 +1299,10 @@ async function resumeAsyncRun(input: {
|
|
|
1212
1299
|
];
|
|
1213
1300
|
target = resolveNestedResumeTarget(resolved, trustedSessionRoots);
|
|
1214
1301
|
} else {
|
|
1302
|
+
if (resolved?.kind === "async" && resolved.location.asyncDir) {
|
|
1303
|
+
const unsupported = externalRunnerControlError(resolved.location.asyncDir, "resume");
|
|
1304
|
+
if (unsupported) return unsupported;
|
|
1305
|
+
}
|
|
1215
1306
|
target = resolveResumeTarget(input.params, input.deps.state, { asyncRequireSessionFile: !attachChain });
|
|
1216
1307
|
}
|
|
1217
1308
|
} catch (error) {
|
|
@@ -1293,7 +1384,7 @@ async function resumeAsyncRun(input: {
|
|
|
1293
1384
|
};
|
|
1294
1385
|
}
|
|
1295
1386
|
const runId = randomUUID().slice(0, 8);
|
|
1296
|
-
const artifactConfig: ArtifactConfig = { ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts
|
|
1387
|
+
const artifactConfig: ArtifactConfig = omitUndefinedProperties({ ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false, dir: input.deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir });
|
|
1297
1388
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1298
1389
|
const contextPolicy = resolveExplicitContextPolicy(input.params);
|
|
1299
1390
|
const workflowTask = (input.params.task ?? followUp) || undefined;
|
|
@@ -1301,20 +1392,20 @@ async function resumeAsyncRun(input: {
|
|
|
1301
1392
|
const chain = wrapChainTasksForFork(attachChain, contextPolicy);
|
|
1302
1393
|
const normalized = normalizeSkillInput(input.params.skill);
|
|
1303
1394
|
const parentModel = input.parentModel;
|
|
1304
|
-
const result = executeAsyncChain(runId, {
|
|
1395
|
+
const result = executeAsyncChain(runId, compactOptional<Parameters<typeof executeAsyncChain>[1]>({
|
|
1305
1396
|
chain,
|
|
1306
1397
|
task: workflowTask,
|
|
1307
1398
|
goal,
|
|
1308
1399
|
attachRoot: {
|
|
1309
1400
|
runId: target.runId,
|
|
1310
|
-
asyncDir: target.asyncDir ?? path.join(
|
|
1311
|
-
resultPath: resolveAsyncRootResultPath(
|
|
1401
|
+
asyncDir: target.asyncDir ?? path.join(DIRS.async, target.runId),
|
|
1402
|
+
resultPath: resolveAsyncRootResultPath(DIRS.results, target.runId),
|
|
1312
1403
|
index: target.index,
|
|
1313
1404
|
agent: target.agent,
|
|
1314
1405
|
label: `Attached ${target.runId}`,
|
|
1315
1406
|
},
|
|
1316
1407
|
agents,
|
|
1317
|
-
ctx: {
|
|
1408
|
+
ctx: compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
1318
1409
|
pi: input.deps.pi,
|
|
1319
1410
|
cwd: input.requestCwd,
|
|
1320
1411
|
currentSessionId: input.deps.state.currentSessionId,
|
|
@@ -1323,7 +1414,8 @@ async function resumeAsyncRun(input: {
|
|
|
1323
1414
|
currentModel: parentModel,
|
|
1324
1415
|
modelScope,
|
|
1325
1416
|
interactive: input.ctx.hasUI,
|
|
1326
|
-
|
|
1417
|
+
permissions: input.deps.config.permissions,
|
|
1418
|
+
}),
|
|
1327
1419
|
availableModels,
|
|
1328
1420
|
cwd: effectiveCwd,
|
|
1329
1421
|
maxOutput: input.params.maxOutput,
|
|
@@ -1344,7 +1436,7 @@ async function resumeAsyncRun(input: {
|
|
|
1344
1436
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
1345
1437
|
globalConcurrencyLimit: input.deps.config.globalConcurrencyLimit,
|
|
1346
1438
|
capabilityCeiling: intersectSubagentCapabilityCeilings("capabilityCeiling" in target ? target.capabilityCeiling : undefined, resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
|
|
1347
|
-
});
|
|
1439
|
+
}));
|
|
1348
1440
|
if (result.isError) return result;
|
|
1349
1441
|
const attachedId = result.details.asyncId ?? runId;
|
|
1350
1442
|
const lines = [
|
|
@@ -1357,18 +1449,22 @@ async function resumeAsyncRun(input: {
|
|
|
1357
1449
|
return { content: [{ type: "text", text: formatAsyncStartedMessage(lines.join("\n"), input.ctx.hasUI) }], details: result.details };
|
|
1358
1450
|
}
|
|
1359
1451
|
|
|
1452
|
+
const revivalSessionFile = target.sessionFile;
|
|
1453
|
+
if (!revivalSessionFile) {
|
|
1454
|
+
return { content: [{ type: "text", text: `Async child '${target.runId}' has no persisted session file to resume.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1455
|
+
}
|
|
1360
1456
|
const runId = randomUUID().slice(0, 8);
|
|
1361
1457
|
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(agentConfig, recoveryDescriptor) : agentConfig;
|
|
1362
|
-
const artifactConfig: ArtifactConfig = recoveryDescriptor?.artifactConfig ?? { ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts
|
|
1458
|
+
const artifactConfig: ArtifactConfig = recoveryDescriptor?.artifactConfig ?? omitUndefinedProperties({ ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false, dir: input.deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir });
|
|
1363
1459
|
const artifactsDir = recoveryDescriptor?.artifactsDir ?? getArtifactsDir(parentSessionFile, effectiveCwd, artifactConfig.dir);
|
|
1364
1460
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1365
1461
|
const parentModel = input.parentModel;
|
|
1366
|
-
const result = executeAsyncSingle(runId, {
|
|
1462
|
+
const result = executeAsyncSingle(runId, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
1367
1463
|
agent: target.agent,
|
|
1368
|
-
task: buildRevivedAsyncTask(target, followUp),
|
|
1464
|
+
task: buildRevivedAsyncTask(target as Parameters<typeof buildRevivedAsyncTask>[0], followUp),
|
|
1369
1465
|
goal: followUp,
|
|
1370
1466
|
agentConfig: recoveryAgentConfig,
|
|
1371
|
-
ctx: {
|
|
1467
|
+
ctx: compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
1372
1468
|
pi: input.deps.pi,
|
|
1373
1469
|
cwd: input.requestCwd,
|
|
1374
1470
|
currentSessionId: input.deps.state.currentSessionId,
|
|
@@ -1377,17 +1473,18 @@ async function resumeAsyncRun(input: {
|
|
|
1377
1473
|
currentModel: parentModel,
|
|
1378
1474
|
modelScope,
|
|
1379
1475
|
interactive: input.ctx.hasUI,
|
|
1380
|
-
|
|
1476
|
+
permissions: input.deps.config.permissions,
|
|
1477
|
+
}),
|
|
1381
1478
|
cwd: effectiveCwd,
|
|
1382
1479
|
maxOutput: input.params.maxOutput ?? recoveryDescriptor?.maxOutput,
|
|
1383
1480
|
artifactsDir,
|
|
1384
1481
|
artifactConfig,
|
|
1385
1482
|
shareEnabled: recoveryDescriptor?.share ?? input.params.share === true,
|
|
1386
|
-
sessionRoot: input.deps.getSubagentSessionRoot(parentSessionFile),
|
|
1483
|
+
sessionRoot: input.deps.getSubagentSessionRoot(parentSessionFile ?? revivalSessionFile),
|
|
1387
1484
|
...(recoveryDescriptor?.sessionDir ? { sessionDir: recoveryDescriptor.sessionDir } : {}),
|
|
1388
|
-
sessionFile:
|
|
1485
|
+
sessionFile: revivalSessionFile,
|
|
1389
1486
|
revivalLease: {
|
|
1390
|
-
sessionFile:
|
|
1487
|
+
sessionFile: revivalSessionFile,
|
|
1391
1488
|
runId,
|
|
1392
1489
|
sourceRunId: target.runId,
|
|
1393
1490
|
...(input.deps.state.currentSessionId ? { parentSessionId: input.deps.state.currentSessionId } : {}),
|
|
@@ -1415,7 +1512,7 @@ async function resumeAsyncRun(input: {
|
|
|
1415
1512
|
...(input.params.turnBudget !== undefined ? { turnBudget: input.params.turnBudget } : {}),
|
|
1416
1513
|
...(input.params.toolBudget !== undefined ? { toolBudget: input.params.toolBudget } : {}),
|
|
1417
1514
|
capabilityCeiling: intersectSubagentCapabilityCeilings("capabilityCeiling" in target ? target.capabilityCeiling : undefined, recoveryDescriptor?.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
|
|
1418
|
-
});
|
|
1515
|
+
}));
|
|
1419
1516
|
if (result.isError) return result;
|
|
1420
1517
|
|
|
1421
1518
|
const revivedId = result.details.asyncId ?? runId;
|
|
@@ -1440,82 +1537,14 @@ async function resumeAsyncRun(input: {
|
|
|
1440
1537
|
}
|
|
1441
1538
|
|
|
1442
1539
|
function resultSummaryForIntercom(result: SingleResult): string {
|
|
1443
|
-
const
|
|
1444
|
-
if (
|
|
1445
|
-
return
|
|
1540
|
+
const output = getSingleResultOutput(result);
|
|
1541
|
+
if (result.exitCode !== 0 && result.error) {
|
|
1542
|
+
return output ? `${result.error}\n\nOutput:\n${output}` : result.error;
|
|
1446
1543
|
}
|
|
1447
|
-
|
|
1448
|
-
try {
|
|
1449
|
-
const ref = formatSavedOutputReference(result.savedOutputPath, fs.readFileSync(result.savedOutputPath, "utf-8"));
|
|
1450
|
-
return result.exitCode !== 0 && result.error ? `${result.error}\n\n${ref.message}` : ref.message;
|
|
1451
|
-
} catch (error) {
|
|
1452
|
-
const fallback = formatBoundedPersistenceFallback({
|
|
1453
|
-
error: `Failed to read saved output: ${error instanceof Error ? error.message : String(error)}`,
|
|
1454
|
-
outputPath: result.savedOutputPath,
|
|
1455
|
-
fullOutput: getSingleResultOutput(result),
|
|
1456
|
-
exitCode: result.exitCode,
|
|
1457
|
-
processError: result.error,
|
|
1458
|
-
});
|
|
1459
|
-
return result.exitCode !== 0 && result.error ? `${result.error}\n\n${fallback}` : fallback;
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
if (result.outputSaveError) {
|
|
1463
|
-
return formatBoundedPersistenceFallback({
|
|
1464
|
-
error: result.outputSaveError,
|
|
1465
|
-
outputPath: result.savedOutputPath,
|
|
1466
|
-
fullOutput: getSingleResultOutput(result),
|
|
1467
|
-
exitCode: result.exitCode,
|
|
1468
|
-
processError: result.error,
|
|
1469
|
-
});
|
|
1470
|
-
}
|
|
1471
|
-
// Legacy / `output: false` child without a durable saved path: bounded fallback
|
|
1472
|
-
// only, never the raw full output.
|
|
1473
|
-
return formatBoundedPersistenceFallback({
|
|
1474
|
-
error: "No saved output path is available for this child.",
|
|
1475
|
-
fullOutput: getSingleResultOutput(result),
|
|
1476
|
-
exitCode: result.exitCode,
|
|
1477
|
-
processError: result.error,
|
|
1478
|
-
});
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
/**
|
|
1482
|
-
* Compact terminal per-child line for bridge-off foreground parallel content:
|
|
1483
|
-
* status plus either the saved-output reference (default/file-only), the legacy
|
|
1484
|
-
* inline full output when explicitly requested, or the bounded fallback.
|
|
1485
|
-
*/
|
|
1486
|
-
function formatParallelChildResult(result: SingleResult, index: number): string {
|
|
1487
|
-
const status = resolveSubagentResultStatus({
|
|
1488
|
-
exitCode: result.exitCode,
|
|
1489
|
-
interrupted: result.interrupted,
|
|
1490
|
-
detached: result.detached,
|
|
1491
|
-
processSignal: result.processSignal,
|
|
1492
|
-
timedOut: result.timedOut,
|
|
1493
|
-
stopped: result.stopped,
|
|
1494
|
-
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
1495
|
-
});
|
|
1496
|
-
const header = `=== Task ${index + 1}: ${result.agent} [${status}] ===`;
|
|
1497
|
-
if (result.outputMode === "inline") {
|
|
1498
|
-
const output = getSingleResultOutput(result).trim();
|
|
1499
|
-
return `${header}\n${output || "(no output)"}`;
|
|
1500
|
-
}
|
|
1501
|
-
const reference = result.outputReference?.message;
|
|
1502
|
-
if (reference) {
|
|
1503
|
-
const body = result.exitCode !== 0 && result.error ? `${result.error}\n${reference}` : reference;
|
|
1504
|
-
return `${header}\n${body}`;
|
|
1505
|
-
}
|
|
1506
|
-
return `${header}\n${formatBoundedPersistenceFallback({
|
|
1507
|
-
error: result.outputSaveError ?? "No saved output path is available for this child.",
|
|
1508
|
-
outputPath: result.savedOutputPath,
|
|
1509
|
-
fullOutput: getSingleResultOutput(result),
|
|
1510
|
-
exitCode: result.exitCode,
|
|
1511
|
-
processError: result.error,
|
|
1512
|
-
})}`;
|
|
1544
|
+
return output || result.error || "(no output)";
|
|
1513
1545
|
}
|
|
1514
1546
|
|
|
1515
1547
|
function formatFailedSingleRunOutput(result: SingleResult, displayOutput: string): string {
|
|
1516
|
-
// Reference-first and persistence-failure fallbacks already carry error/status
|
|
1517
|
-
// and must not be re-wrapped as raw "Output:" text.
|
|
1518
|
-
if (result.savedOutputPath || result.outputSaveError) return displayOutput;
|
|
1519
1548
|
const error = result.error || "Failed";
|
|
1520
1549
|
const output = displayOutput.trim();
|
|
1521
1550
|
const lines = [error];
|
|
@@ -1540,6 +1569,25 @@ function createForegroundControlNotifier(data: Pick<ExecutionContextData, "contr
|
|
|
1540
1569
|
};
|
|
1541
1570
|
}
|
|
1542
1571
|
|
|
1572
|
+
export function foregroundResultIntercomStatus(result: SingleResult): ReturnType<typeof resolveSubagentResultStatus> {
|
|
1573
|
+
return resolveSubagentResultStatus(omitUndefinedProperties({
|
|
1574
|
+
exitCode: result.exitCode,
|
|
1575
|
+
...(result.acceptance?.status === "rejected" ? { success: false } : {}),
|
|
1576
|
+
interrupted: result.interrupted,
|
|
1577
|
+
detached: result.detached,
|
|
1578
|
+
processSignal: result.processSignal,
|
|
1579
|
+
timedOut: result.timedOut,
|
|
1580
|
+
stopped: result.stopped,
|
|
1581
|
+
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
1582
|
+
}));
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
export function shouldSuppressRoutineResultIntercom(input: { suppressRoutineResultIntercom?: boolean; results: SingleResult[] }): boolean {
|
|
1586
|
+
return input.suppressRoutineResultIntercom === true
|
|
1587
|
+
&& input.results.length > 0
|
|
1588
|
+
&& input.results.every((result) => foregroundResultIntercomStatus(result) === "completed");
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1543
1591
|
async function emitForegroundResultIntercom(input: {
|
|
1544
1592
|
pi: ExtensionAPI;
|
|
1545
1593
|
intercomBridge: IntercomBridgeState;
|
|
@@ -1551,24 +1599,16 @@ async function emitForegroundResultIntercom(input: {
|
|
|
1551
1599
|
parallelHandoff?: Details["parallelHandoff"];
|
|
1552
1600
|
}): Promise<ReturnType<typeof buildSubagentResultIntercomPayload> | null> {
|
|
1553
1601
|
if (!input.intercomBridge.active || !input.intercomBridge.resultDelivery || !input.intercomBridge.orchestratorTarget) return null;
|
|
1554
|
-
const children = input.results.flatMap((result, index) => result.detached ? [] : [{
|
|
1602
|
+
const children = input.results.flatMap((result, index) => result.detached ? [] : [omitUndefinedProperties({
|
|
1555
1603
|
agent: result.agent,
|
|
1556
|
-
status:
|
|
1557
|
-
exitCode: result.exitCode,
|
|
1558
|
-
interrupted: result.interrupted,
|
|
1559
|
-
detached: result.detached,
|
|
1560
|
-
processSignal: result.processSignal,
|
|
1561
|
-
timedOut: result.timedOut,
|
|
1562
|
-
stopped: result.stopped,
|
|
1563
|
-
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
1564
|
-
}),
|
|
1604
|
+
status: foregroundResultIntercomStatus(result),
|
|
1565
1605
|
outputState: result.outputState ?? "unknown",
|
|
1566
1606
|
summary: resultSummaryForIntercom(result),
|
|
1567
1607
|
index,
|
|
1568
1608
|
artifactPath: result.artifactPaths?.outputPath,
|
|
1569
1609
|
sessionPath: result.sessionFile,
|
|
1570
1610
|
intercomTarget: resolveSubagentIntercomTarget(input.runId, result.agent, index),
|
|
1571
|
-
}]);
|
|
1611
|
+
})]);
|
|
1572
1612
|
if (children.length === 0) return null;
|
|
1573
1613
|
const payload = buildSubagentResultIntercomPayload({
|
|
1574
1614
|
to: input.intercomBridge.orchestratorTarget,
|
|
@@ -1624,7 +1664,7 @@ function canonicalizeExecutionParams(params: SubagentParamsLike, agents: AgentCo
|
|
|
1624
1664
|
if (params.agent) {
|
|
1625
1665
|
const result = resolve(params.agent);
|
|
1626
1666
|
if (result.error) return { error: result.error };
|
|
1627
|
-
params = { ...params, agent: result.name };
|
|
1667
|
+
params = omitUndefinedProperties({ ...params, agent: result.name });
|
|
1628
1668
|
}
|
|
1629
1669
|
if (params.tasks) {
|
|
1630
1670
|
const tasks: TaskParam[] = [];
|
|
@@ -1641,7 +1681,7 @@ function canonicalizeExecutionParams(params: SubagentParamsLike, agents: AgentCo
|
|
|
1641
1681
|
for (let index = 0; index < params.chain.length; index++) {
|
|
1642
1682
|
const step = params.chain[index]!;
|
|
1643
1683
|
if (isParallelStep(step)) {
|
|
1644
|
-
const parallel:
|
|
1684
|
+
const parallel: ParallelTaskItem[] = [];
|
|
1645
1685
|
for (let taskIndex = 0; taskIndex < step.parallel.length; taskIndex++) {
|
|
1646
1686
|
const task = step.parallel[taskIndex]!;
|
|
1647
1687
|
const result = resolve(task.agent, `step ${index + 1}, task ${taskIndex + 1}`);
|
|
@@ -1691,7 +1731,7 @@ function validateExecutionInput(
|
|
|
1691
1731
|
};
|
|
1692
1732
|
}
|
|
1693
1733
|
|
|
1694
|
-
const acceptanceErrors = validateExecutionAcceptance(params);
|
|
1734
|
+
const acceptanceErrors = validateExecutionAcceptance(params as Parameters<typeof validateExecutionAcceptance>[0]);
|
|
1695
1735
|
if (acceptanceErrors.length > 0) {
|
|
1696
1736
|
return {
|
|
1697
1737
|
content: [{ type: "text", text: acceptanceErrors.join(" ") }],
|
|
@@ -1780,7 +1820,7 @@ function validateExecutionInput(
|
|
|
1780
1820
|
function validateExecutionChainBindings(params: SubagentParamsLike, dynamicFanoutMaxItems?: number): AgentToolResult<Details> | null {
|
|
1781
1821
|
if ((params.chain?.length ?? 0) === 0) return null;
|
|
1782
1822
|
try {
|
|
1783
|
-
validateChainOutputBindingsWithContext(params.chain as ChainStep[], { maxItems: dynamicFanoutMaxItems });
|
|
1823
|
+
validateChainOutputBindingsWithContext(params.chain as ChainStep[], dynamicFanoutMaxItems === undefined ? {} : { maxItems: dynamicFanoutMaxItems });
|
|
1784
1824
|
} catch (error) {
|
|
1785
1825
|
if (error instanceof ChainOutputValidationError) {
|
|
1786
1826
|
return {
|
|
@@ -1795,6 +1835,7 @@ function validateExecutionChainBindings(params: SubagentParamsLike, dynamicFanou
|
|
|
1795
1835
|
}
|
|
1796
1836
|
|
|
1797
1837
|
function getRequestedModeLabel(params: SubagentParamsLike): Details["mode"] {
|
|
1838
|
+
if (params.workflowScript !== undefined) return "workflow";
|
|
1798
1839
|
if ((params.chain?.length ?? 0) > 0) return "chain";
|
|
1799
1840
|
if ((params.tasks?.length ?? 0) > 0) return "parallel";
|
|
1800
1841
|
if (params.agent) return "single";
|
|
@@ -1818,12 +1859,12 @@ function resolveAgentDefaultContextPolicy(params: SubagentParamsLike, agents: Ag
|
|
|
1818
1859
|
const requestedAgentNames = collectRequestedAgentNames(params);
|
|
1819
1860
|
const contextSummary = summarizeContextModes(requestedAgentNames.map((name) => contextForAgent(name)));
|
|
1820
1861
|
const usesFork = contextSummary === "fork" || contextSummary === "mixed";
|
|
1821
|
-
return {
|
|
1862
|
+
return omitUndefinedProperties({
|
|
1822
1863
|
params,
|
|
1823
1864
|
contextForAgent,
|
|
1824
1865
|
contextSummary,
|
|
1825
1866
|
usesFork,
|
|
1826
|
-
};
|
|
1867
|
+
});
|
|
1827
1868
|
}
|
|
1828
1869
|
|
|
1829
1870
|
function resolveExplicitContextPolicy(params: SubagentParamsLike): AgentDefaultContextPolicy {
|
|
@@ -1899,7 +1940,8 @@ function resolveForegroundTimeout(params: SubagentParamsLike, defaultTimeoutMs?:
|
|
|
1899
1940
|
if (rawTimeout !== undefined && rawMaxRuntime !== undefined && rawTimeout !== rawMaxRuntime) {
|
|
1900
1941
|
return { error: "timeoutMs and maxRuntimeMs are aliases; provide only one value or use the same value for both." };
|
|
1901
1942
|
}
|
|
1902
|
-
|
|
1943
|
+
const timeoutMs = rawTimeout ?? rawMaxRuntime;
|
|
1944
|
+
return timeoutMs === undefined ? {} : { timeoutMs };
|
|
1903
1945
|
}
|
|
1904
1946
|
|
|
1905
1947
|
function resolveToolBudget(
|
|
@@ -1908,7 +1950,7 @@ function resolveToolBudget(
|
|
|
1908
1950
|
options?: { minimumHard?: 0 | 1 },
|
|
1909
1951
|
): { toolBudget?: ResolvedToolBudget; error?: string } {
|
|
1910
1952
|
const resolved = validateToolBudgetConfig(raw, label, options);
|
|
1911
|
-
return { toolBudget: resolved.budget, error: resolved.error };
|
|
1953
|
+
return { ...(resolved.budget === undefined ? {} : { toolBudget: resolved.budget }), ...(resolved.error === undefined ? {} : { error: resolved.error }) };
|
|
1912
1954
|
}
|
|
1913
1955
|
|
|
1914
1956
|
function resolveEffectiveToolBudget(input: { stepBudget?: ToolBudgetConfig; runBudget?: ResolvedToolBudget; agentBudget?: ToolBudgetConfig; configBudget?: ToolBudgetConfig }): { toolBudget?: ResolvedToolBudget; error?: string } {
|
|
@@ -1942,7 +1984,7 @@ function expandChainParallelCounts(chain: ChainStep[]): { chain?: ChainStep[]; e
|
|
|
1942
1984
|
expandedChain.push(step);
|
|
1943
1985
|
continue;
|
|
1944
1986
|
}
|
|
1945
|
-
const expandedParallel = [];
|
|
1987
|
+
const expandedParallel: ParallelTaskItem[] = [];
|
|
1946
1988
|
for (let taskIndex = 0; taskIndex < step.parallel.length; taskIndex++) {
|
|
1947
1989
|
const task = step.parallel[taskIndex]!;
|
|
1948
1990
|
const rawCount = (task as typeof task & { count?: unknown }).count;
|
|
@@ -1965,14 +2007,14 @@ function normalizeRepeatedParallelCounts(params: SubagentParamsLike): { params?:
|
|
|
1965
2007
|
if (expandedTasks.error) {
|
|
1966
2008
|
return { error: buildRequestedModeError(params, expandedTasks.error) };
|
|
1967
2009
|
}
|
|
1968
|
-
return { params: { ...params, tasks: expandedTasks.tasks } };
|
|
2010
|
+
return { params: { ...params, ...(expandedTasks.tasks === undefined ? {} : { tasks: expandedTasks.tasks }) } };
|
|
1969
2011
|
}
|
|
1970
2012
|
if (params.chain) {
|
|
1971
2013
|
const expandedChain = expandChainParallelCounts(params.chain);
|
|
1972
2014
|
if (expandedChain.error) {
|
|
1973
2015
|
return { error: buildRequestedModeError(params, expandedChain.error) };
|
|
1974
2016
|
}
|
|
1975
|
-
return { params: { ...params, chain: expandedChain.chain } };
|
|
2017
|
+
return { params: { ...params, ...(expandedChain.chain === undefined ? {} : { chain: expandedChain.chain }) } };
|
|
1976
2018
|
}
|
|
1977
2019
|
return { params };
|
|
1978
2020
|
}
|
|
@@ -2078,6 +2120,87 @@ function collectChainThinkingOverrides(
|
|
|
2078
2120
|
return thinkingOverrides;
|
|
2079
2121
|
}
|
|
2080
2122
|
|
|
2123
|
+
type StaticLaunchSummary = { agent: string; model?: string; thinking?: string };
|
|
2124
|
+
|
|
2125
|
+
function resolveStaticLaunchSummary(input: {
|
|
2126
|
+
agent: string;
|
|
2127
|
+
index: number;
|
|
2128
|
+
explicitModel?: string;
|
|
2129
|
+
agents: AgentConfig[];
|
|
2130
|
+
parentModel?: ParentModel;
|
|
2131
|
+
availableModels: ModelInfo[];
|
|
2132
|
+
currentProvider?: string;
|
|
2133
|
+
modelScope?: ModelScopeConfig;
|
|
2134
|
+
thinkingOverrideForTask: ForkThinkingOverrideForTask;
|
|
2135
|
+
}): StaticLaunchSummary {
|
|
2136
|
+
const agentConfig = input.agents.find((agent) => agent.name === input.agent);
|
|
2137
|
+
const model = resolveEffectiveSubagentModel(
|
|
2138
|
+
input.explicitModel,
|
|
2139
|
+
agentConfig?.model,
|
|
2140
|
+
input.parentModel,
|
|
2141
|
+
input.availableModels,
|
|
2142
|
+
input.currentProvider,
|
|
2143
|
+
input.modelScope === undefined ? {} : { scope: input.modelScope },
|
|
2144
|
+
);
|
|
2145
|
+
const thinkingOverride = input.thinkingOverrideForTask(input.agent, input.index, model);
|
|
2146
|
+
const thinking = resolveEffectiveThinking(model, thinkingOverride ?? agentConfig?.thinking);
|
|
2147
|
+
return {
|
|
2148
|
+
agent: input.agent,
|
|
2149
|
+
...(model ? { model } : {}),
|
|
2150
|
+
...(thinking ? { thinking } : {}),
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
function collectStaticLaunchSummaries(input: {
|
|
2155
|
+
params: SubagentParamsLike;
|
|
2156
|
+
agents: AgentConfig[];
|
|
2157
|
+
parentModel?: ParentModel;
|
|
2158
|
+
availableModels: ModelInfo[];
|
|
2159
|
+
currentProvider?: string;
|
|
2160
|
+
modelScope?: ModelScopeConfig;
|
|
2161
|
+
thinkingOverrideForTask: ForkThinkingOverrideForTask;
|
|
2162
|
+
dynamicFanoutMaxItems?: number;
|
|
2163
|
+
}): StaticLaunchSummary[] {
|
|
2164
|
+
const summary = (agent: string, index: number, explicitModel?: string) => resolveStaticLaunchSummary({
|
|
2165
|
+
agent,
|
|
2166
|
+
index,
|
|
2167
|
+
explicitModel,
|
|
2168
|
+
agents: input.agents,
|
|
2169
|
+
parentModel: input.parentModel,
|
|
2170
|
+
availableModels: input.availableModels,
|
|
2171
|
+
currentProvider: input.currentProvider,
|
|
2172
|
+
modelScope: input.modelScope,
|
|
2173
|
+
thinkingOverrideForTask: input.thinkingOverrideForTask,
|
|
2174
|
+
});
|
|
2175
|
+
if (input.params.tasks) return input.params.tasks.map((task, index) => summary(task.agent, index, task.model));
|
|
2176
|
+
if (input.params.chain?.length) {
|
|
2177
|
+
const launches: StaticLaunchSummary[] = [];
|
|
2178
|
+
let flatIndex = 0;
|
|
2179
|
+
for (const step of input.params.chain) {
|
|
2180
|
+
if (isParallelStep(step)) {
|
|
2181
|
+
for (const task of step.parallel) {
|
|
2182
|
+
launches.push(summary(task.agent, flatIndex, task.model));
|
|
2183
|
+
flatIndex++;
|
|
2184
|
+
}
|
|
2185
|
+
continue;
|
|
2186
|
+
}
|
|
2187
|
+
if (isDynamicParallelStep(step)) {
|
|
2188
|
+
const maxItems = step.expand.maxItems ?? input.dynamicFanoutMaxItems ?? 0;
|
|
2189
|
+
for (let itemIndex = 0; itemIndex < maxItems; itemIndex++) {
|
|
2190
|
+
launches.push(summary(step.parallel.agent, flatIndex, step.parallel.model));
|
|
2191
|
+
flatIndex++;
|
|
2192
|
+
}
|
|
2193
|
+
continue;
|
|
2194
|
+
}
|
|
2195
|
+
const sequential = step as SequentialStep;
|
|
2196
|
+
launches.push(summary(sequential.agent, flatIndex, sequential.model));
|
|
2197
|
+
flatIndex++;
|
|
2198
|
+
}
|
|
2199
|
+
return launches;
|
|
2200
|
+
}
|
|
2201
|
+
return input.params.agent ? [summary(input.params.agent, 0, input.params.model as string | undefined)] : [];
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2081
2204
|
function firstChainAgent(chain: ChainStep[]): string | undefined {
|
|
2082
2205
|
const first = chain[0];
|
|
2083
2206
|
if (!first) return undefined;
|
|
@@ -2105,34 +2228,34 @@ function resolveAsyncEventGoal(workflowTask: string | undefined, rawChain: Chain
|
|
|
2105
2228
|
function wrapChainTasksForFork(chain: ChainStep[], contextPolicy: AgentDefaultContextPolicy): ChainStep[] {
|
|
2106
2229
|
return chain.map((step, stepIndex) => {
|
|
2107
2230
|
if (isParallelStep(step)) {
|
|
2108
|
-
return {
|
|
2231
|
+
return compactOptional<ParallelStep>({
|
|
2109
2232
|
...step,
|
|
2110
|
-
parallel: step.parallel.map((task) => ({
|
|
2233
|
+
parallel: step.parallel.map((task) => compactOptional<ParallelTaskItem>({
|
|
2111
2234
|
...task,
|
|
2112
2235
|
task: shouldForkAgent(contextPolicy, task.agent)
|
|
2113
2236
|
? wrapForkTask(task.task ?? "{previous}")
|
|
2114
2237
|
: task.task,
|
|
2115
2238
|
})),
|
|
2116
|
-
};
|
|
2239
|
+
});
|
|
2117
2240
|
}
|
|
2118
2241
|
if (isDynamicParallelStep(step)) {
|
|
2119
|
-
return {
|
|
2242
|
+
return compactOptional<DynamicParallelStep>({
|
|
2120
2243
|
...step,
|
|
2121
|
-
parallel: {
|
|
2244
|
+
parallel: compactOptional<DynamicParallelStep["parallel"]>({
|
|
2122
2245
|
...step.parallel,
|
|
2123
2246
|
task: shouldForkAgent(contextPolicy, step.parallel.agent)
|
|
2124
2247
|
? wrapForkTask(step.parallel.task ?? "{previous}")
|
|
2125
2248
|
: step.parallel.task,
|
|
2126
|
-
},
|
|
2127
|
-
};
|
|
2249
|
+
}),
|
|
2250
|
+
});
|
|
2128
2251
|
}
|
|
2129
2252
|
const sequential = step as SequentialStep;
|
|
2130
|
-
return {
|
|
2253
|
+
return compactOptional<SequentialStep>({
|
|
2131
2254
|
...sequential,
|
|
2132
2255
|
task: shouldForkAgent(contextPolicy, sequential.agent)
|
|
2133
2256
|
? wrapForkTask(sequential.task ?? (stepIndex === 0 ? "{task}" : "{previous}"))
|
|
2134
2257
|
: sequential.task,
|
|
2135
|
-
};
|
|
2258
|
+
});
|
|
2136
2259
|
});
|
|
2137
2260
|
}
|
|
2138
2261
|
|
|
@@ -2232,16 +2355,17 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2232
2355
|
}
|
|
2233
2356
|
const id = randomUUID();
|
|
2234
2357
|
const parentModel = data.parentModel;
|
|
2235
|
-
const asyncCtx = {
|
|
2358
|
+
const asyncCtx = compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
2236
2359
|
pi: deps.pi,
|
|
2237
2360
|
cwd: ctx.cwd,
|
|
2238
|
-
currentSessionId:
|
|
2239
|
-
parentSessionId:
|
|
2361
|
+
currentSessionId: data.parentSessionId!,
|
|
2362
|
+
parentSessionId: data.parentPiSessionId,
|
|
2240
2363
|
currentModelProvider: parentModel?.provider,
|
|
2241
2364
|
currentModel: parentModel,
|
|
2242
2365
|
modelScope: data.modelScope,
|
|
2243
2366
|
interactive: ctx.hasUI,
|
|
2244
|
-
|
|
2367
|
+
permissions: deps.config.permissions,
|
|
2368
|
+
});
|
|
2245
2369
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
2246
2370
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
2247
2371
|
const currentProvider = parentModel?.provider;
|
|
@@ -2250,7 +2374,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2250
2374
|
|
|
2251
2375
|
if (hasTasks && params.tasks) {
|
|
2252
2376
|
const skillOverrides = params.tasks.map((task) => normalizeSkillInput(task.skill));
|
|
2253
|
-
const parallelTasks = params.tasks.map((task, index) => ({
|
|
2377
|
+
const parallelTasks = params.tasks.map((task, index) => compactOptional<ParallelTaskItem>({
|
|
2254
2378
|
agent: task.agent,
|
|
2255
2379
|
task: shouldForkAgent(contextPolicy, task.agent) ? wrapForkTask(task.task) : task.task,
|
|
2256
2380
|
cwd: task.cwd,
|
|
@@ -2265,12 +2389,12 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2265
2389
|
...(task.agentContract !== undefined ? { agentContract: task.agentContract } : {}),
|
|
2266
2390
|
...(task.acceptance !== undefined ? { acceptance: task.acceptance } : {}),
|
|
2267
2391
|
}));
|
|
2268
|
-
return executeAsyncChain(id, {
|
|
2269
|
-
chain: [{
|
|
2392
|
+
return executeAsyncChain(id, compactOptional<Parameters<typeof executeAsyncChain>[1]>({
|
|
2393
|
+
chain: [compactOptional<ParallelStep>({
|
|
2270
2394
|
parallel: parallelTasks,
|
|
2271
2395
|
concurrency: resolveTopLevelParallelConcurrency(params.concurrency, deps.config.parallel?.concurrency),
|
|
2272
2396
|
worktree: params.worktree,
|
|
2273
|
-
}],
|
|
2397
|
+
})],
|
|
2274
2398
|
resultMode: "parallel",
|
|
2275
2399
|
goal: params.tasks[0]?.task ?? "",
|
|
2276
2400
|
agents,
|
|
@@ -2303,7 +2427,9 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2303
2427
|
configToolBudget: data.configToolBudget,
|
|
2304
2428
|
capabilityCeiling: data.capabilityCeiling,
|
|
2305
2429
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
2306
|
-
|
|
2430
|
+
parentWorkflowRunId: params.workflowParentRunId,
|
|
2431
|
+
workflowKey: params.workflowKey,
|
|
2432
|
+
}));
|
|
2307
2433
|
}
|
|
2308
2434
|
|
|
2309
2435
|
if (hasChain && params.chain) {
|
|
@@ -2311,7 +2437,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2311
2437
|
const chainSkills = normalized === false ? [] : (normalized ?? []);
|
|
2312
2438
|
const rawChain = params.chain as ChainStep[];
|
|
2313
2439
|
const chain = wrapChainTasksForFork(rawChain, contextPolicy);
|
|
2314
|
-
return executeAsyncChain(id, {
|
|
2440
|
+
return executeAsyncChain(id, compactOptional<Parameters<typeof executeAsyncChain>[1]>({
|
|
2315
2441
|
chain,
|
|
2316
2442
|
task: params.task,
|
|
2317
2443
|
goal: resolveAsyncEventGoal(params.task, rawChain),
|
|
@@ -2346,7 +2472,9 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2346
2472
|
configToolBudget: data.configToolBudget,
|
|
2347
2473
|
capabilityCeiling: data.capabilityCeiling,
|
|
2348
2474
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
2349
|
-
|
|
2475
|
+
parentWorkflowRunId: params.workflowParentRunId,
|
|
2476
|
+
workflowKey: params.workflowKey,
|
|
2477
|
+
}));
|
|
2350
2478
|
}
|
|
2351
2479
|
|
|
2352
2480
|
if (hasSingle) {
|
|
@@ -2360,11 +2488,12 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2360
2488
|
}
|
|
2361
2489
|
const rawOutput = params.output !== undefined ? params.output : a.output;
|
|
2362
2490
|
const effectiveOutput = normalizeSingleOutputOverride(rawOutput, a.output);
|
|
2491
|
+
const effectiveOutputMode = params.outputMode ?? "inline";
|
|
2363
2492
|
const normalizedSkills = normalizeSkillInput(params.skill);
|
|
2364
2493
|
const skills = normalizedSkills === false ? [] : normalizedSkills;
|
|
2365
2494
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, a.maxSubagentDepth);
|
|
2366
|
-
const modelOverride = resolveEffectiveSubagentModel(params.model as string | undefined, a.model, parentModel, availableModels, currentProvider, { scope: data.modelScope });
|
|
2367
|
-
return executeAsyncSingle(id, {
|
|
2495
|
+
const modelOverride = resolveEffectiveSubagentModel(params.model as string | undefined, a.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope });
|
|
2496
|
+
return executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
2368
2497
|
agent: params.agent!,
|
|
2369
2498
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
2370
2499
|
goal: params.task ?? "",
|
|
@@ -2381,7 +2510,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2381
2510
|
context: contextPolicy.contextForAgent(params.agent!),
|
|
2382
2511
|
skills,
|
|
2383
2512
|
output: effectiveOutput,
|
|
2384
|
-
outputMode:
|
|
2513
|
+
outputMode: effectiveOutputMode,
|
|
2385
2514
|
outputBaseDir: resolveSingleRunOutputBaseDir(deps, artifactsDir, id),
|
|
2386
2515
|
modelOverride,
|
|
2387
2516
|
thinkingOverride: thinkingOverrideForTask(params.agent!, 0, modelOverride),
|
|
@@ -2403,7 +2532,9 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2403
2532
|
usageBudget: data.usageBudget,
|
|
2404
2533
|
configToolBudget: data.configToolBudget,
|
|
2405
2534
|
capabilityCeiling: data.capabilityCeiling,
|
|
2406
|
-
|
|
2535
|
+
parentWorkflowRunId: params.workflowParentRunId,
|
|
2536
|
+
workflowKey: params.workflowKey,
|
|
2537
|
+
}));
|
|
2407
2538
|
}
|
|
2408
2539
|
|
|
2409
2540
|
return null;
|
|
@@ -2436,8 +2567,8 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2436
2567
|
const chainSkills = normalized === false ? [] : (normalized ?? []);
|
|
2437
2568
|
const chain = wrapChainTasksForFork(params.chain as ChainStep[], contextPolicy);
|
|
2438
2569
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
2439
|
-
const chainCtx = normalizeParentModel(ctx.model) || !data.parentModel ? ctx : { ...ctx, model: data.parentModel };
|
|
2440
|
-
const chainResult = await executeChain({
|
|
2570
|
+
const chainCtx = normalizeParentModel(ctx.model) || !data.parentModel ? ctx : ({ ...ctx, model: data.parentModel } as ExtensionContext);
|
|
2571
|
+
const chainResult = await executeChain(compactOptional<Parameters<typeof executeChain>[0]>({
|
|
2441
2572
|
chain,
|
|
2442
2573
|
task: params.task,
|
|
2443
2574
|
agents,
|
|
@@ -2466,7 +2597,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2466
2597
|
foregroundControl,
|
|
2467
2598
|
nestedRoute: foregroundControl?.nestedRoute,
|
|
2468
2599
|
chainSkills,
|
|
2469
|
-
chainDir: params.chainDir ??
|
|
2600
|
+
chainDir: params.chainDir ?? getChainRunsDir(effectiveCwd, artifactConfig.dir),
|
|
2470
2601
|
dynamicFanoutMaxItems: deps.config.chain?.dynamicFanout?.maxItems,
|
|
2471
2602
|
maxSubagentDepth: currentMaxSubagentDepth,
|
|
2472
2603
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
@@ -2488,9 +2619,10 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2488
2619
|
toolBudget: data.toolBudget,
|
|
2489
2620
|
usageBudget: data.usageBudget,
|
|
2490
2621
|
configToolBudget: data.configToolBudget,
|
|
2622
|
+
permissions: deps.config.permissions,
|
|
2491
2623
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
2492
2624
|
capabilityCeiling: data.capabilityCeiling,
|
|
2493
|
-
});
|
|
2625
|
+
}));
|
|
2494
2626
|
|
|
2495
2627
|
if (chainResult.requestedAsync) {
|
|
2496
2628
|
if (!isAsyncAvailable()) {
|
|
@@ -2502,20 +2634,21 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2502
2634
|
}
|
|
2503
2635
|
const id = randomUUID();
|
|
2504
2636
|
const parentModel = data.parentModel;
|
|
2505
|
-
const asyncCtx = {
|
|
2637
|
+
const asyncCtx = compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
2506
2638
|
pi: deps.pi,
|
|
2507
2639
|
cwd: ctx.cwd,
|
|
2508
|
-
currentSessionId:
|
|
2509
|
-
parentSessionId:
|
|
2640
|
+
currentSessionId: data.parentSessionId!,
|
|
2641
|
+
parentSessionId: data.parentPiSessionId,
|
|
2510
2642
|
currentModelProvider: parentModel?.provider,
|
|
2511
2643
|
currentModel: parentModel,
|
|
2512
2644
|
modelScope: data.modelScope,
|
|
2513
2645
|
interactive: ctx.hasUI,
|
|
2514
|
-
|
|
2646
|
+
permissions: deps.config.permissions,
|
|
2647
|
+
});
|
|
2515
2648
|
const rawAsyncChain = chainResult.requestedAsync.chain;
|
|
2516
2649
|
const asyncChain = wrapChainTasksForFork(rawAsyncChain, contextPolicy);
|
|
2517
2650
|
const firstAgent = firstChainAgent(rawAsyncChain);
|
|
2518
|
-
return executeAsyncChain(id, {
|
|
2651
|
+
return executeAsyncChain(id, compactOptional<Parameters<typeof executeAsyncChain>[1]>({
|
|
2519
2652
|
chain: asyncChain,
|
|
2520
2653
|
task: params.task,
|
|
2521
2654
|
goal: resolveAsyncEventGoal(params.task, rawAsyncChain, firstAgent ? shouldForkAgent(contextPolicy, firstAgent) : false),
|
|
@@ -2550,15 +2683,17 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2550
2683
|
configToolBudget: data.configToolBudget,
|
|
2551
2684
|
capabilityCeiling: data.capabilityCeiling,
|
|
2552
2685
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
2553
|
-
});
|
|
2686
|
+
}));
|
|
2554
2687
|
}
|
|
2555
2688
|
|
|
2556
|
-
const rawChainDetails = chainResult.details ? { ...chainResult.details, runId, timeoutMs: data.timeoutMs } : undefined;
|
|
2689
|
+
const rawChainDetails = chainResult.details ? compactOptional<Details>({ ...chainResult.details, runId, timeoutMs: data.timeoutMs }) : undefined;
|
|
2557
2690
|
if (foregroundControl && rawChainDetails) {
|
|
2558
2691
|
updateForegroundNestedProjection(foregroundControl);
|
|
2559
2692
|
attachRootChildrenToSteps(runId, rawChainDetails.results, foregroundControl.nestedChildren);
|
|
2560
2693
|
rawChainDetails.totalCost = sumResultsCost(rawChainDetails.results);
|
|
2561
|
-
|
|
2694
|
+
const usageBudget = usageBudgetState(data.usageBudget, rawChainDetails.totalCost);
|
|
2695
|
+
if (usageBudget === undefined) delete rawChainDetails.usageBudget;
|
|
2696
|
+
else rawChainDetails.usageBudget = usageBudget;
|
|
2562
2697
|
}
|
|
2563
2698
|
const chainDetails = rawChainDetails ? compactForegroundDetails(rawChainDetails) : undefined;
|
|
2564
2699
|
if (chainDetails) rememberForegroundRun(deps.state, { runId, mode: "chain", cwd: effectiveCwd, sessionId: data.parentSessionId, results: chainDetails.results, checkpoint: chainDetails.checkpoint });
|
|
@@ -2632,6 +2767,7 @@ interface ForegroundParallelRunInput {
|
|
|
2632
2767
|
usageBudget?: UsageBudgetConfig;
|
|
2633
2768
|
toolBudgets: (ResolvedToolBudget | undefined)[];
|
|
2634
2769
|
agentContract?: AgentContract;
|
|
2770
|
+
permissions?: ExtensionConfig["permissions"];
|
|
2635
2771
|
}
|
|
2636
2772
|
function buildParallelModeError(message: string): AgentToolResult<Details> {
|
|
2637
2773
|
return {
|
|
@@ -2653,13 +2789,13 @@ function createParallelWorktreeSetup(
|
|
|
2653
2789
|
if (!enabled) return {};
|
|
2654
2790
|
try {
|
|
2655
2791
|
return {
|
|
2656
|
-
setup: createWorktrees(cwd, runId, tasks.length, {
|
|
2792
|
+
setup: createWorktrees(cwd, runId, tasks.length, omitUndefinedProperties({
|
|
2657
2793
|
agents: tasks.map((task) => task.agent),
|
|
2658
2794
|
setupHook: setupHook
|
|
2659
|
-
? { hookPath: setupHook, timeoutMs: setupHookTimeoutMs }
|
|
2795
|
+
? { hookPath: setupHook, ...(setupHookTimeoutMs === undefined ? {} : { timeoutMs: setupHookTimeoutMs }) }
|
|
2660
2796
|
: undefined,
|
|
2661
2797
|
baseDir,
|
|
2662
|
-
}),
|
|
2798
|
+
})),
|
|
2663
2799
|
};
|
|
2664
2800
|
} catch (error) {
|
|
2665
2801
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -2682,19 +2818,6 @@ function resolveSingleRunOutputBaseDir(deps: ExecutorDeps, artifactsDir: string,
|
|
|
2682
2818
|
: path.join(artifactsDir, "outputs", runId);
|
|
2683
2819
|
}
|
|
2684
2820
|
|
|
2685
|
-
/**
|
|
2686
|
-
* Generated per-run durable output path for foreground single runs when the
|
|
2687
|
-
* caller omits `output` (and does not set `output: false`):
|
|
2688
|
-
* `<singleRunOutputBaseDir>/<runId>/result.md`. The base is the configured
|
|
2689
|
-
* `singleRunOutputBaseDir` when present, otherwise `{artifactsDir}/outputs`.
|
|
2690
|
-
*/
|
|
2691
|
-
function resolveGeneratedSingleOutputPath(deps: ExecutorDeps, artifactsDir: string, runId: string): string {
|
|
2692
|
-
const base = deps.config.singleRunOutputBaseDir
|
|
2693
|
-
? path.resolve(deps.expandTilde(deps.config.singleRunOutputBaseDir))
|
|
2694
|
-
: path.join(artifactsDir, "outputs");
|
|
2695
|
-
return path.join(base, runId, "result.md");
|
|
2696
|
-
}
|
|
2697
|
-
|
|
2698
2821
|
function buildChainWorktreeTaskCwdError(chain: ChainStep[], sharedCwd: string): string | undefined {
|
|
2699
2822
|
for (let stepIndex = 0; stepIndex < chain.length; stepIndex++) {
|
|
2700
2823
|
const step = chain[stepIndex]!;
|
|
@@ -2728,39 +2851,41 @@ function finalizeParallelWorktreeHandoff(input: {
|
|
|
2728
2851
|
}): { suffix: string; reference?: NonNullable<Details["parallelHandoff"]> } {
|
|
2729
2852
|
const diffsDir = path.join(input.artifactsDir, "worktree-diffs", input.runId);
|
|
2730
2853
|
const diffs = diffWorktrees(input.worktreeSetup, input.tasks.map((task) => task.agent), diffsDir);
|
|
2731
|
-
const cleanup = cleanupWorktrees(input.worktreeSetup);
|
|
2732
2854
|
const diffSummary = formatWorktreeDiffSummary(diffs);
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
2756
|
-
}),
|
|
2757
|
-
summary: resultSummaryForIntercom(result),
|
|
2758
|
-
...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
|
|
2759
|
-
...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
|
|
2760
|
-
...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
|
|
2761
|
-
...(result.sessionFile ? { sessionPath: result.sessionFile } : {}),
|
|
2855
|
+
const manifestPath = parallelHandoffPath(input.artifactsDir, input.runId);
|
|
2856
|
+
const handoff = {
|
|
2857
|
+
manifestPath,
|
|
2858
|
+
runId: input.runId,
|
|
2859
|
+
mode: "parallel" as const,
|
|
2860
|
+
source: "foreground" as const,
|
|
2861
|
+
cwd: input.cwd,
|
|
2862
|
+
stepIndex: 0,
|
|
2863
|
+
flatStartIndex: 0,
|
|
2864
|
+
setup: input.worktreeSetup,
|
|
2865
|
+
diffs,
|
|
2866
|
+
results: input.results.map((result) => ({
|
|
2867
|
+
agent: result.agent,
|
|
2868
|
+
status: resolveSubagentResultStatus(omitUndefinedProperties({
|
|
2869
|
+
exitCode: result.exitCode,
|
|
2870
|
+
interrupted: result.interrupted,
|
|
2871
|
+
detached: result.detached,
|
|
2872
|
+
state: result.stopped ? "stopped" : undefined,
|
|
2873
|
+
processSignal: result.processSignal,
|
|
2874
|
+
timedOut: result.timedOut,
|
|
2875
|
+
stopped: result.stopped,
|
|
2876
|
+
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
2762
2877
|
})),
|
|
2763
|
-
|
|
2878
|
+
summary: resultSummaryForIntercom(result),
|
|
2879
|
+
...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
|
|
2880
|
+
...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
|
|
2881
|
+
...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
|
|
2882
|
+
...(result.sessionFile ? { sessionPath: result.sessionFile } : {}),
|
|
2883
|
+
})),
|
|
2884
|
+
};
|
|
2885
|
+
try {
|
|
2886
|
+
writeParallelHandoffGroup(handoff);
|
|
2887
|
+
const cleanup = cleanupWorktrees(input.worktreeSetup, { kind: "preserve", capturedDiffs: diffs, handoffManifestPath: manifestPath });
|
|
2888
|
+
const reference = writeParallelHandoffGroup({ ...handoff, cleanup });
|
|
2764
2889
|
return {
|
|
2765
2890
|
suffix: [diffSummary, formatParallelHandoffReference(reference)].filter(Boolean).join("\n\n"),
|
|
2766
2891
|
reference,
|
|
@@ -2840,7 +2965,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2840
2965
|
beginForegroundChild(input.foregroundControl, {
|
|
2841
2966
|
index,
|
|
2842
2967
|
agent: task.agent,
|
|
2843
|
-
description: input.taskDescriptions[index],
|
|
2968
|
+
...(input.taskDescriptions[index] === undefined ? {} : { description: input.taskDescriptions[index] }),
|
|
2844
2969
|
...(model ? { model } : {}),
|
|
2845
2970
|
...(thinking ? { thinking } : {}),
|
|
2846
2971
|
interrupt: () => {
|
|
@@ -2854,7 +2979,8 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2854
2979
|
? createStructuredOutputRuntime(task.outputSchema, path.join(input.artifactsDir, "structured-output", input.runId))
|
|
2855
2980
|
: undefined;
|
|
2856
2981
|
let detachedReceipt = false;
|
|
2857
|
-
const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskText, {
|
|
2982
|
+
const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskText, compactOptional<Parameters<typeof runSync>[4]>({
|
|
2983
|
+
permissions: input.permissions,
|
|
2858
2984
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
2859
2985
|
context: input.contextPolicy.contextForAgent(task.agent),
|
|
2860
2986
|
cwd: taskCwd,
|
|
@@ -2918,17 +3044,17 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2918
3044
|
const mergedProgress = input.liveProgress.filter((progress): progress is AgentProgress => progress !== undefined);
|
|
2919
3045
|
input.onUpdate?.({
|
|
2920
3046
|
content: progressUpdate.content,
|
|
2921
|
-
details: {
|
|
3047
|
+
details: compactOptional<Details>({
|
|
2922
3048
|
mode: "parallel",
|
|
2923
3049
|
results: mergedResults,
|
|
2924
3050
|
progress: mergedProgress,
|
|
2925
3051
|
controlEvents: progressUpdate.details?.controlEvents,
|
|
2926
3052
|
totalSteps: input.tasks.length,
|
|
2927
|
-
},
|
|
3053
|
+
}),
|
|
2928
3054
|
});
|
|
2929
3055
|
}
|
|
2930
3056
|
: undefined,
|
|
2931
|
-
}).then((result) => {
|
|
3057
|
+
})).then((result) => {
|
|
2932
3058
|
detachedReceipt = result.detached === true;
|
|
2933
3059
|
return result;
|
|
2934
3060
|
}).finally(() => {
|
|
@@ -3003,7 +3129,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3003
3129
|
);
|
|
3004
3130
|
const toolBudgets: (ResolvedToolBudget | undefined)[] = [];
|
|
3005
3131
|
for (let index = 0; index < tasks.length; index++) {
|
|
3006
|
-
const resolved = resolveEffectiveToolBudget({ stepBudget: tasks[index]?.toolBudget, runBudget: data.toolBudget, agentBudget: agentConfigs[index]?.toolBudget, configBudget: data.configToolBudget });
|
|
3132
|
+
const resolved = resolveEffectiveToolBudget(omitUndefinedProperties({ stepBudget: tasks[index]?.toolBudget, runBudget: data.toolBudget, agentBudget: agentConfigs[index]?.toolBudget, configBudget: data.configToolBudget }));
|
|
3007
3133
|
if (resolved.error) return buildParallelModeError(resolved.error);
|
|
3008
3134
|
toolBudgets.push(resolved.toolBudget);
|
|
3009
3135
|
}
|
|
@@ -3029,7 +3155,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3029
3155
|
...(task.model !== undefined ? { model: task.model } : {}),
|
|
3030
3156
|
}));
|
|
3031
3157
|
const modelOverrides: (string | undefined)[] = tasks.map((_, i) =>
|
|
3032
|
-
resolveEffectiveSubagentModel(behaviorOverrides[i]?.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, { scope: data.modelScope }),
|
|
3158
|
+
resolveEffectiveSubagentModel(behaviorOverrides[i]?.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope }),
|
|
3033
3159
|
);
|
|
3034
3160
|
|
|
3035
3161
|
if (params.clarify === true && ctx.hasUI) {
|
|
@@ -3064,7 +3190,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3064
3190
|
for (let i = 0; i < result.behaviorOverrides.length; i++) {
|
|
3065
3191
|
const override = result.behaviorOverrides[i];
|
|
3066
3192
|
if (override?.model !== undefined) {
|
|
3067
|
-
modelOverrides[i] = resolveEffectiveSubagentModel(override.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, { scope: data.modelScope });
|
|
3193
|
+
modelOverrides[i] = resolveEffectiveSubagentModel(override.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope });
|
|
3068
3194
|
behaviorOverrides[i]!.model = override.model;
|
|
3069
3195
|
}
|
|
3070
3196
|
if (override?.output !== undefined) behaviorOverrides[i]!.output = override.output;
|
|
@@ -3085,20 +3211,21 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3085
3211
|
};
|
|
3086
3212
|
}
|
|
3087
3213
|
const id = randomUUID();
|
|
3088
|
-
const asyncCtx = {
|
|
3214
|
+
const asyncCtx = compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
3089
3215
|
pi: deps.pi,
|
|
3090
3216
|
cwd: ctx.cwd,
|
|
3091
|
-
currentSessionId:
|
|
3092
|
-
parentSessionId:
|
|
3217
|
+
currentSessionId: data.parentSessionId!,
|
|
3218
|
+
parentSessionId: data.parentPiSessionId,
|
|
3093
3219
|
currentModelProvider: parentModel?.provider,
|
|
3094
3220
|
currentModel: parentModel,
|
|
3095
3221
|
modelScope: data.modelScope,
|
|
3096
3222
|
interactive: ctx.hasUI,
|
|
3097
|
-
|
|
3223
|
+
permissions: deps.config.permissions,
|
|
3224
|
+
});
|
|
3098
3225
|
const parallelTasks = tasks.map((t, i) => {
|
|
3099
3226
|
const taskText = shouldForkAgent(contextPolicy, t.agent) ? wrapForkTask(taskTexts[i]!) : taskTexts[i]!;
|
|
3100
3227
|
const progress = taskDisallowsFileUpdates(taskText) ? false : behaviorOverrides[i]?.progress;
|
|
3101
|
-
return {
|
|
3228
|
+
return compactOptional<ParallelTaskItem>({
|
|
3102
3229
|
agent: t.agent,
|
|
3103
3230
|
task: taskText,
|
|
3104
3231
|
cwd: t.cwd,
|
|
@@ -3112,10 +3239,10 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3112
3239
|
...(t.outputSchema !== undefined ? { outputSchema: t.outputSchema } : {}),
|
|
3113
3240
|
...(t.acceptance !== undefined ? { acceptance: t.acceptance } : {}),
|
|
3114
3241
|
...(t.agentContract !== undefined ? { agentContract: t.agentContract } : {}),
|
|
3115
|
-
};
|
|
3242
|
+
});
|
|
3116
3243
|
});
|
|
3117
|
-
return executeAsyncChain(id, {
|
|
3118
|
-
chain: [{ parallel: parallelTasks, concurrency: parallelConcurrency, worktree: params.worktree }],
|
|
3244
|
+
return executeAsyncChain(id, compactOptional<Parameters<typeof executeAsyncChain>[1]>({
|
|
3245
|
+
chain: [compactOptional<ParallelStep>({ parallel: parallelTasks, concurrency: parallelConcurrency, worktree: params.worktree })],
|
|
3119
3246
|
resultMode: "parallel",
|
|
3120
3247
|
goal: taskTexts[0] ?? "",
|
|
3121
3248
|
agents,
|
|
@@ -3147,25 +3274,14 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3147
3274
|
toolBudget: data.toolBudget,
|
|
3148
3275
|
configToolBudget: data.configToolBudget,
|
|
3149
3276
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
3150
|
-
});
|
|
3277
|
+
}));
|
|
3151
3278
|
}
|
|
3152
3279
|
}
|
|
3153
3280
|
|
|
3154
3281
|
const behaviors = tasks.map((task, index) => {
|
|
3155
3282
|
let behavior = suppressProgressForReadOnlyTask(resolveStepBehavior(agentConfigs[index]!, behaviorOverrides[index]!), taskTexts[index]);
|
|
3156
|
-
if (behaviorOverrides[index]?.output === undefined) {
|
|
3157
|
-
|
|
3158
|
-
behavior = { ...behavior, output: path.join("parallel-0", `${index}-${task.agent}`, behavior.output) };
|
|
3159
|
-
} else if (behavior.output === false && behaviorOverrides[index]?.output !== false && behaviorOverrides[index]?.output !== "false") {
|
|
3160
|
-
// Omitted output: generate a collision-safe per-task durable path in the
|
|
3161
|
-
// existing per-task namespace (parallel-0/<index>-<agent>/result.md).
|
|
3162
|
-
behavior = { ...behavior, output: path.join("parallel-0", `${index}-${task.agent}`, "result.md") };
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
// Omitted outputMode resolves to file-only whenever an output path is active;
|
|
3166
|
-
// explicit `outputMode: "inline"` is preserved exactly.
|
|
3167
|
-
if (behaviorOverrides[index]?.outputMode === undefined && typeof behavior.output === "string") {
|
|
3168
|
-
behavior = { ...behavior, outputMode: "file-only" };
|
|
3283
|
+
if (behaviorOverrides[index]?.output === undefined && typeof behavior.output === "string" && !path.isAbsolute(behavior.output)) {
|
|
3284
|
+
behavior = { ...behavior, output: path.join("parallel-0", `${index}-${task.agent}`, behavior.output) };
|
|
3169
3285
|
}
|
|
3170
3286
|
return behavior;
|
|
3171
3287
|
});
|
|
@@ -3186,15 +3302,27 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3186
3302
|
|
|
3187
3303
|
let worktreeFinalized = false;
|
|
3188
3304
|
try {
|
|
3305
|
+
if (worktreeSetup) {
|
|
3306
|
+
writePendingParallelHandoff({
|
|
3307
|
+
manifestPath: parallelHandoffPath(artifactsDir, runId),
|
|
3308
|
+
runId,
|
|
3309
|
+
mode: "parallel",
|
|
3310
|
+
source: "foreground",
|
|
3311
|
+
cwd: effectiveCwd,
|
|
3312
|
+
stepIndex: 0,
|
|
3313
|
+
flatStartIndex: 0,
|
|
3314
|
+
setup: worktreeSetup,
|
|
3315
|
+
});
|
|
3316
|
+
}
|
|
3189
3317
|
const outputBaseDir = path.join(artifactsDir, "outputs", runId);
|
|
3190
|
-
const duplicateOutputError = findDuplicateParallelOutputPath({
|
|
3318
|
+
const duplicateOutputError = findDuplicateParallelOutputPath(omitUndefinedProperties({
|
|
3191
3319
|
tasks,
|
|
3192
3320
|
behaviors,
|
|
3193
3321
|
paramsCwd: effectiveCwd,
|
|
3194
3322
|
ctxCwd: ctx.cwd,
|
|
3195
3323
|
outputBaseDir,
|
|
3196
3324
|
worktreeSetup,
|
|
3197
|
-
});
|
|
3325
|
+
}));
|
|
3198
3326
|
if (duplicateOutputError) return buildParallelModeError(duplicateOutputError);
|
|
3199
3327
|
for (let index = 0; index < tasks.length; index++) {
|
|
3200
3328
|
const taskCwd = resolveParallelTaskCwd(tasks[index]!, effectiveCwd, worktreeSetup, index);
|
|
@@ -3213,8 +3341,9 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3213
3341
|
}
|
|
3214
3342
|
|
|
3215
3343
|
const deadlineAt = data.deadlineAt ?? (data.timeoutMs !== undefined ? Date.now() + data.timeoutMs : undefined);
|
|
3216
|
-
const results = await runForegroundParallelTasks({
|
|
3344
|
+
const results = await runForegroundParallelTasks(compactOptional<ForegroundParallelRunInput>({
|
|
3217
3345
|
tasks,
|
|
3346
|
+
permissions: deps.config.permissions,
|
|
3218
3347
|
taskTexts,
|
|
3219
3348
|
taskDescriptions,
|
|
3220
3349
|
agents,
|
|
@@ -3262,7 +3391,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3262
3391
|
usageBudget: data.usageBudget,
|
|
3263
3392
|
toolBudgets,
|
|
3264
3393
|
agentContract: params.agentContract,
|
|
3265
|
-
});
|
|
3394
|
+
}));
|
|
3266
3395
|
for (let i = 0; i < results.length; i++) {
|
|
3267
3396
|
const run = results[i]!;
|
|
3268
3397
|
recordRun(run.agent, taskTexts[i]!, run.exitCode, run.progressSummary?.durationMs ?? 0);
|
|
@@ -3284,7 +3413,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3284
3413
|
}
|
|
3285
3414
|
const interrupted = results.find((result) => result.interrupted);
|
|
3286
3415
|
const totalCost = sumResultsCost(results);
|
|
3287
|
-
const details = compactForegroundDetails({
|
|
3416
|
+
const details = compactForegroundDetails(compactOptional<Details>({
|
|
3288
3417
|
mode: "parallel",
|
|
3289
3418
|
runId,
|
|
3290
3419
|
timeoutMs: data.timeoutMs,
|
|
@@ -3295,7 +3424,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3295
3424
|
totalCost,
|
|
3296
3425
|
usageBudget: usageBudgetState(data.usageBudget, totalCost),
|
|
3297
3426
|
...(handoff?.reference ? { parallelHandoff: handoff.reference } : {}),
|
|
3298
|
-
});
|
|
3427
|
+
}));
|
|
3299
3428
|
rememberForegroundRun(deps.state, { runId, mode: "parallel", cwd: effectiveCwd, sessionId: data.parentSessionId, results: details.results });
|
|
3300
3429
|
if (interrupted) {
|
|
3301
3430
|
return {
|
|
@@ -3312,31 +3441,43 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3312
3441
|
};
|
|
3313
3442
|
}
|
|
3314
3443
|
|
|
3444
|
+
const suppressRoutineResultIntercom = shouldSuppressRoutineResultIntercom({ suppressRoutineResultIntercom: params.suppressRoutineResultIntercom, results });
|
|
3315
3445
|
if (foregroundControl) updateForegroundNestedProjection(foregroundControl);
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3446
|
+
if (!suppressRoutineResultIntercom) {
|
|
3447
|
+
const intercomReceipt = await maybeBuildForegroundIntercomReceipt({
|
|
3448
|
+
pi: deps.pi,
|
|
3449
|
+
intercomBridge: data.intercomBridge,
|
|
3450
|
+
runId,
|
|
3451
|
+
mode: "parallel",
|
|
3452
|
+
details,
|
|
3453
|
+
...(foregroundControl?.nestedChildren?.length ? { nestedChildren: foregroundControl.nestedChildren } : {}),
|
|
3454
|
+
});
|
|
3455
|
+
if (intercomReceipt) {
|
|
3456
|
+
return {
|
|
3457
|
+
content: [{ type: "text", text: intercomReceipt.text }],
|
|
3458
|
+
details: intercomReceipt.details,
|
|
3459
|
+
};
|
|
3460
|
+
}
|
|
3329
3461
|
}
|
|
3330
3462
|
|
|
3331
3463
|
const worktreeSuffix = handoff?.suffix ?? "";
|
|
3332
3464
|
const ok = results.filter((result) => result.exitCode === 0).length;
|
|
3333
3465
|
const downgradeNote = backgroundRequestedWhileClarifying ? " (background requested, but clarify kept this run foreground)" : "";
|
|
3334
|
-
const
|
|
3466
|
+
const aggregatedOutput = aggregateParallelOutputs(
|
|
3467
|
+
results.map((result) => ({
|
|
3468
|
+
agent: result.agent,
|
|
3469
|
+
output: result.truncation?.text || getSingleResultOutput(result),
|
|
3470
|
+
exitCode: result.exitCode,
|
|
3471
|
+
...(result.error === undefined ? {} : { error: result.error }),
|
|
3472
|
+
...(result.timedOut === undefined ? {} : { timedOut: result.timedOut }),
|
|
3473
|
+
})),
|
|
3474
|
+
(i, agent) => `=== Task ${i + 1}: ${agent} ===`,
|
|
3475
|
+
);
|
|
3335
3476
|
|
|
3336
3477
|
const summary = `${ok}/${results.length} succeeded${downgradeNote}`;
|
|
3337
3478
|
const fullContent = worktreeSuffix
|
|
3338
|
-
? `${summary}\n\n${
|
|
3339
|
-
: `${summary}\n\n${
|
|
3479
|
+
? `${summary}\n\n${aggregatedOutput}\n\n${worktreeSuffix}`
|
|
3480
|
+
: `${summary}\n\n${aggregatedOutput}`;
|
|
3340
3481
|
|
|
3341
3482
|
return {
|
|
3342
3483
|
content: [{ type: "text", text: fullContent }],
|
|
@@ -3378,7 +3519,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3378
3519
|
details: { mode: "single", results: [] },
|
|
3379
3520
|
};
|
|
3380
3521
|
}
|
|
3381
|
-
const effectiveToolBudget = resolveEffectiveToolBudget({ runBudget: data.toolBudget, agentBudget: agentConfig.toolBudget, configBudget: data.configToolBudget });
|
|
3522
|
+
const effectiveToolBudget = resolveEffectiveToolBudget(omitUndefinedProperties({ runBudget: data.toolBudget, agentBudget: agentConfig.toolBudget, configBudget: data.configToolBudget }));
|
|
3382
3523
|
if (effectiveToolBudget.error) return toExecutionErrorResult(params, new Error(effectiveToolBudget.error), data.contextPolicy.contextSummary);
|
|
3383
3524
|
|
|
3384
3525
|
const parentModel = data.parentModel;
|
|
@@ -3391,16 +3532,17 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3391
3532
|
parentModel,
|
|
3392
3533
|
availableModels,
|
|
3393
3534
|
currentProvider,
|
|
3394
|
-
{ scope: data.modelScope },
|
|
3535
|
+
data.modelScope === undefined ? {} : { scope: data.modelScope },
|
|
3395
3536
|
);
|
|
3396
3537
|
let skillOverride: string[] | false | undefined = normalizeSkillInput(params.skill);
|
|
3397
3538
|
const rawOutput = params.output !== undefined ? params.output : agentConfig.output;
|
|
3398
3539
|
let effectiveOutput = normalizeSingleOutputOverride(rawOutput, agentConfig.output);
|
|
3540
|
+
const effectiveOutputMode = params.outputMode ?? "inline";
|
|
3399
3541
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
3400
3542
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, agentConfig.maxSubagentDepth);
|
|
3401
3543
|
|
|
3402
3544
|
if (params.clarify === true && ctx.hasUI) {
|
|
3403
|
-
const behavior = resolveStepBehavior(agentConfig, { output: effectiveOutput, skills: skillOverride });
|
|
3545
|
+
const behavior = resolveStepBehavior(agentConfig, omitUndefinedProperties({ output: effectiveOutput, skills: skillOverride }));
|
|
3404
3546
|
const availableSkills = discoverAvailableSkills(effectiveCwd);
|
|
3405
3547
|
|
|
3406
3548
|
const result = await ctx.ui.custom<ChainClarifyResult>(
|
|
@@ -3427,7 +3569,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3427
3569
|
|
|
3428
3570
|
task = result.templates[0]!;
|
|
3429
3571
|
const override = result.behaviorOverrides[0];
|
|
3430
|
-
if (override?.model !== undefined) modelOverride = resolveEffectiveSubagentModel(override.model, agentConfig.model, parentModel, availableModels, currentProvider, { scope: data.modelScope });
|
|
3572
|
+
if (override?.model !== undefined) modelOverride = resolveEffectiveSubagentModel(override.model, agentConfig.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope });
|
|
3431
3573
|
if (override?.output !== undefined) effectiveOutput = normalizeSingleOutputOverride(override.output, agentConfig.output);
|
|
3432
3574
|
if (override?.skills !== undefined) skillOverride = override.skills;
|
|
3433
3575
|
|
|
@@ -3440,17 +3582,18 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3440
3582
|
};
|
|
3441
3583
|
}
|
|
3442
3584
|
const id = randomUUID();
|
|
3443
|
-
const asyncCtx = {
|
|
3585
|
+
const asyncCtx = compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
3444
3586
|
pi: deps.pi,
|
|
3445
3587
|
cwd: ctx.cwd,
|
|
3446
|
-
currentSessionId:
|
|
3447
|
-
parentSessionId:
|
|
3588
|
+
currentSessionId: data.parentSessionId!,
|
|
3589
|
+
parentSessionId: data.parentPiSessionId,
|
|
3448
3590
|
currentModelProvider: parentModel?.provider,
|
|
3449
3591
|
currentModel: parentModel,
|
|
3450
3592
|
modelScope: data.modelScope,
|
|
3451
3593
|
interactive: ctx.hasUI,
|
|
3452
|
-
|
|
3453
|
-
|
|
3594
|
+
permissions: deps.config.permissions,
|
|
3595
|
+
});
|
|
3596
|
+
return executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
3454
3597
|
agent: params.agent!,
|
|
3455
3598
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(task) : task,
|
|
3456
3599
|
goal: task,
|
|
@@ -3467,7 +3610,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3467
3610
|
context: contextPolicy.contextForAgent(params.agent!),
|
|
3468
3611
|
skills: skillOverride === false ? [] : skillOverride,
|
|
3469
3612
|
output: effectiveOutput,
|
|
3470
|
-
outputMode:
|
|
3613
|
+
outputMode: effectiveOutputMode,
|
|
3471
3614
|
outputBaseDir: resolveSingleRunOutputBaseDir(deps, artifactsDir, id),
|
|
3472
3615
|
modelOverride,
|
|
3473
3616
|
thinkingOverride: thinkingOverrideForTask(params.agent!, 0, modelOverride),
|
|
@@ -3488,7 +3631,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3488
3631
|
toolBudget: effectiveToolBudget.toolBudget,
|
|
3489
3632
|
usageBudget: data.usageBudget,
|
|
3490
3633
|
allowZeroToolBudget: data.allowZeroToolBudget && effectiveToolBudget.toolBudget === data.toolBudget,
|
|
3491
|
-
});
|
|
3634
|
+
}));
|
|
3492
3635
|
}
|
|
3493
3636
|
}
|
|
3494
3637
|
|
|
@@ -3496,16 +3639,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3496
3639
|
task = wrapForkTask(task);
|
|
3497
3640
|
}
|
|
3498
3641
|
const cleanTask = task;
|
|
3499
|
-
|
|
3500
|
-
// (`<singleRunOutputBaseDir>/<runId>/result.md`); omitted outputMode resolves to
|
|
3501
|
-
// file-only whenever an output path is active. Explicit paths, `output: false`,
|
|
3502
|
-
// and explicit `outputMode: "inline"` are preserved exactly.
|
|
3503
|
-
const outputPath = typeof effectiveOutput === "string"
|
|
3504
|
-
? resolveSingleOutputPath(effectiveOutput, ctx.cwd, effectiveCwd, resolveSingleRunOutputBaseDir(deps, artifactsDir, runId))
|
|
3505
|
-
: effectiveOutput === false
|
|
3506
|
-
? undefined
|
|
3507
|
-
: resolveGeneratedSingleOutputPath(deps, artifactsDir, runId);
|
|
3508
|
-
const effectiveOutputMode = params.outputMode ?? (outputPath ? "file-only" : "inline");
|
|
3642
|
+
const outputPath = resolveSingleOutputPath(effectiveOutput, ctx.cwd, effectiveCwd, resolveSingleRunOutputBaseDir(deps, artifactsDir, runId));
|
|
3509
3643
|
const validationError = validateFileOnlyOutputMode(effectiveOutputMode, outputPath, `Single run (${params.agent})`);
|
|
3510
3644
|
if (validationError) {
|
|
3511
3645
|
return { content: [{ type: "text", text: validationError }], isError: true, details: { mode: "single", results: [] } };
|
|
@@ -3526,7 +3660,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3526
3660
|
const foregroundControl = deps.state.foregroundControls.get(runId);
|
|
3527
3661
|
if (foregroundControl) {
|
|
3528
3662
|
const thinking = resolveEffectiveThinking(modelOverride, thinkingOverrideForTask(params.agent!, 0, modelOverride));
|
|
3529
|
-
beginForegroundChild(foregroundControl, {
|
|
3663
|
+
beginForegroundChild(foregroundControl, omitUndefinedProperties({
|
|
3530
3664
|
index: 0,
|
|
3531
3665
|
agent: params.agent!,
|
|
3532
3666
|
description: foregroundControl.description,
|
|
@@ -3538,7 +3672,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3538
3672
|
return true;
|
|
3539
3673
|
},
|
|
3540
3674
|
detach: () => detachForeground?.("user request") === true,
|
|
3541
|
-
});
|
|
3675
|
+
}));
|
|
3542
3676
|
}
|
|
3543
3677
|
|
|
3544
3678
|
const forwardSingleUpdate = onUpdate
|
|
@@ -3549,9 +3683,10 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3549
3683
|
: undefined;
|
|
3550
3684
|
|
|
3551
3685
|
const deadlineAt = data.deadlineAt ?? (data.timeoutMs !== undefined ? Date.now() + data.timeoutMs : undefined);
|
|
3552
|
-
let r: Awaited<ReturnType<typeof runSync
|
|
3686
|
+
let r: Awaited<ReturnType<typeof runSync>> | undefined;
|
|
3553
3687
|
try {
|
|
3554
|
-
r = await runSync(ctx.cwd, agents, params.agent!, task, {
|
|
3688
|
+
r = await runSync(ctx.cwd, agents, params.agent!, task, compactOptional<Parameters<typeof runSync>[4]>({
|
|
3689
|
+
permissions: deps.config.permissions,
|
|
3555
3690
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
3556
3691
|
context: data.contextPolicy.contextForAgent(params.agent!),
|
|
3557
3692
|
cwd: effectiveCwd,
|
|
@@ -3593,7 +3728,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3593
3728
|
onDetachedExit: (result) => {
|
|
3594
3729
|
try {
|
|
3595
3730
|
try {
|
|
3596
|
-
updateRememberedForegroundChild(deps.state, { runId, mode: "single", cwd: effectiveCwd, sessionId: data.parentSessionId, index: 0, result, events: deps.pi.events });
|
|
3731
|
+
updateRememberedForegroundChild(deps.state, { runId, mode: "single", cwd: effectiveCwd, sessionId: data.parentSessionId, index: 0, result, events: deps.pi.events, notify: params.workflowParentRunId === undefined });
|
|
3597
3732
|
} catch {
|
|
3598
3733
|
// Remembered foreground state is best-effort; run history and cleanup must still complete.
|
|
3599
3734
|
}
|
|
@@ -3617,7 +3752,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3617
3752
|
toolBudget: effectiveToolBudget.toolBudget,
|
|
3618
3753
|
capabilityCeiling: data.capabilityCeiling,
|
|
3619
3754
|
allowZeroToolBudget: data.allowZeroToolBudget && effectiveToolBudget.toolBudget === data.toolBudget,
|
|
3620
|
-
});
|
|
3755
|
+
}));
|
|
3621
3756
|
} finally {
|
|
3622
3757
|
// An attached runSync rejection still owns its child and structured runtime.
|
|
3623
3758
|
// A successful detached receipt transfers both to onDetachedExit while the
|
|
@@ -3635,7 +3770,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3635
3770
|
if (r.artifactPaths) allArtifactPaths.push(r.artifactPaths);
|
|
3636
3771
|
|
|
3637
3772
|
const fullOutput = getSingleResultOutput(r);
|
|
3638
|
-
const finalizedOutput = finalizeSingleOutput({
|
|
3773
|
+
const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
|
|
3639
3774
|
fullOutput,
|
|
3640
3775
|
truncatedOutput: r.truncation?.text,
|
|
3641
3776
|
outputPath,
|
|
@@ -3644,14 +3779,13 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3644
3779
|
savedPath: r.savedOutputPath,
|
|
3645
3780
|
outputReference: r.outputReference,
|
|
3646
3781
|
saveError: r.outputSaveError,
|
|
3647
|
-
|
|
3648
|
-
});
|
|
3782
|
+
}));
|
|
3649
3783
|
if (foregroundControl) {
|
|
3650
3784
|
updateForegroundNestedProjection(foregroundControl);
|
|
3651
3785
|
attachRootChildrenToSteps(runId, [r], foregroundControl.nestedChildren);
|
|
3652
3786
|
}
|
|
3653
3787
|
const totalCost = sumResultsCost([r]);
|
|
3654
|
-
const details = compactForegroundDetails({
|
|
3788
|
+
const details = compactForegroundDetails(compactOptional<Details>({
|
|
3655
3789
|
mode: "single",
|
|
3656
3790
|
runId,
|
|
3657
3791
|
timeoutMs: data.timeoutMs,
|
|
@@ -3664,10 +3798,11 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3664
3798
|
totalChildUsage: sumResultsUsage([r]),
|
|
3665
3799
|
totalCost,
|
|
3666
3800
|
usageBudget: usageBudgetState(data.usageBudget, totalCost),
|
|
3667
|
-
});
|
|
3801
|
+
}));
|
|
3668
3802
|
rememberForegroundRun(deps.state, { runId, mode: "single", cwd: effectiveCwd, sessionId: data.parentSessionId, results: details.results });
|
|
3669
3803
|
|
|
3670
|
-
|
|
3804
|
+
const suppressRoutineResultIntercom = shouldSuppressRoutineResultIntercom({ suppressRoutineResultIntercom: params.suppressRoutineResultIntercom, results: [r] });
|
|
3805
|
+
if (!r.detached && !r.interrupted && !suppressRoutineResultIntercom) {
|
|
3671
3806
|
if (foregroundControl) updateForegroundNestedProjection(foregroundControl);
|
|
3672
3807
|
const intercomReceipt = await maybeBuildForegroundIntercomReceipt({
|
|
3673
3808
|
pi: deps.pi,
|
|
@@ -3712,7 +3847,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3712
3847
|
};
|
|
3713
3848
|
}
|
|
3714
3849
|
|
|
3715
|
-
function inferExecutionMode(params: SubagentParamsLike):
|
|
3850
|
+
function inferExecutionMode(params: SubagentParamsLike): Details["mode"] {
|
|
3851
|
+
if (params.workflowScript !== undefined) return "workflow";
|
|
3716
3852
|
if ((params.chain?.length ?? 0) > 0) return "chain";
|
|
3717
3853
|
if ((params.tasks?.length ?? 0) > 0) return "parallel";
|
|
3718
3854
|
return "single";
|
|
@@ -3729,6 +3865,84 @@ function duplicateSubagentCallResult(params: SubagentParamsLike): AgentToolResul
|
|
|
3729
3865
|
};
|
|
3730
3866
|
}
|
|
3731
3867
|
|
|
3868
|
+
function workflowChildResult(key: string, result: AgentToolResult<Details>): WorkflowScriptChildResult {
|
|
3869
|
+
const output = result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
|
|
3870
|
+
const artifactPaths = new Set<string>();
|
|
3871
|
+
if (result.details.asyncDir) artifactPaths.add(result.details.asyncDir);
|
|
3872
|
+
if (result.details.parallelHandoff?.path) artifactPaths.add(result.details.parallelHandoff.path);
|
|
3873
|
+
for (const child of result.details.results) {
|
|
3874
|
+
if (child.savedOutputPath) artifactPaths.add(child.savedOutputPath);
|
|
3875
|
+
if (child.outputReference?.path) artifactPaths.add(child.outputReference.path);
|
|
3876
|
+
if (child.sessionFile) artifactPaths.add(child.sessionFile);
|
|
3877
|
+
}
|
|
3878
|
+
const structured = result.details.results.map((child) => child.structuredOutput).filter((value) => value !== undefined);
|
|
3879
|
+
return {
|
|
3880
|
+
key,
|
|
3881
|
+
ok: result.isError !== true,
|
|
3882
|
+
...(result.details.runId || result.details.asyncId ? { runId: result.details.runId ?? result.details.asyncId } : {}),
|
|
3883
|
+
output,
|
|
3884
|
+
...(result.isError === true ? { error: output || "Child run failed." } : {}),
|
|
3885
|
+
...(structured.length === 1 ? { structuredOutput: structured[0] } : structured.length > 1 ? { structuredOutput: structured } : {}),
|
|
3886
|
+
artifactPaths: [...artifactPaths],
|
|
3887
|
+
results: result.details.results,
|
|
3888
|
+
};
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
function prepareWorkflowChildParams(params: SubagentParamsLike): SubagentParamsLike {
|
|
3892
|
+
if (params.worktree !== true || !params.agent) return params;
|
|
3893
|
+
const {
|
|
3894
|
+
agent,
|
|
3895
|
+
task = "",
|
|
3896
|
+
model,
|
|
3897
|
+
skill,
|
|
3898
|
+
output,
|
|
3899
|
+
outputMode,
|
|
3900
|
+
outputSchema,
|
|
3901
|
+
acceptance,
|
|
3902
|
+
agentContract,
|
|
3903
|
+
toolBudget,
|
|
3904
|
+
...runParams
|
|
3905
|
+
} = params;
|
|
3906
|
+
return {
|
|
3907
|
+
...runParams,
|
|
3908
|
+
worktree: true,
|
|
3909
|
+
tasks: [{
|
|
3910
|
+
agent,
|
|
3911
|
+
task,
|
|
3912
|
+
...(model !== undefined ? { model } : {}),
|
|
3913
|
+
...(skill !== undefined ? { skill } : {}),
|
|
3914
|
+
...(output !== undefined ? { output } : {}),
|
|
3915
|
+
...(outputMode !== undefined ? { outputMode } : {}),
|
|
3916
|
+
...(outputSchema !== undefined ? { outputSchema } : {}),
|
|
3917
|
+
...(acceptance !== undefined ? { acceptance } : {}),
|
|
3918
|
+
...(agentContract !== undefined ? { agentContract } : {}),
|
|
3919
|
+
...(toolBudget !== undefined ? { toolBudget } : {}),
|
|
3920
|
+
}],
|
|
3921
|
+
};
|
|
3922
|
+
}
|
|
3923
|
+
|
|
3924
|
+
function formatWorkflowValue(value: unknown): string {
|
|
3925
|
+
if (value === undefined) return "(undefined)";
|
|
3926
|
+
if (typeof value === "string") return value;
|
|
3927
|
+
try {
|
|
3928
|
+
return JSON.stringify(value, null, 2);
|
|
3929
|
+
} catch {
|
|
3930
|
+
return String(value);
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
function workflowChatProgressUpdate(
|
|
3935
|
+
runId: string,
|
|
3936
|
+
chatProgress: WorkflowChatProgressProjection,
|
|
3937
|
+
workflow: NonNullable<Details["workflow"]>,
|
|
3938
|
+
): AgentToolResult<Details> | undefined {
|
|
3939
|
+
if (chatProgress.mode !== "live-card") return undefined;
|
|
3940
|
+
return {
|
|
3941
|
+
content: [{ type: "text", text: "Workflow running." }],
|
|
3942
|
+
details: { mode: "workflow", runId, results: [], workflow, chatProgress },
|
|
3943
|
+
};
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3732
3946
|
function omitExecutionModeActionAlias(params: SubagentParamsLike): SubagentParamsLike {
|
|
3733
3947
|
const action = params.action?.toLowerCase();
|
|
3734
3948
|
if (action === "single" && (params.agent !== undefined || params.task !== undefined)) {
|
|
@@ -3744,6 +3958,36 @@ function omitExecutionModeActionAlias(params: SubagentParamsLike): SubagentParam
|
|
|
3744
3958
|
return params;
|
|
3745
3959
|
}
|
|
3746
3960
|
|
|
3961
|
+
function createScheduledOwnerState(source: SubagentState, ownerSessionId: string, ctx: ExtensionContext): SubagentState {
|
|
3962
|
+
const ownerSpawns = source.subagentSpawns?.sessionId === ownerSessionId
|
|
3963
|
+
? {
|
|
3964
|
+
...source.subagentSpawns,
|
|
3965
|
+
grantHistory: [...(source.subagentSpawns.grantHistory ?? [])],
|
|
3966
|
+
}
|
|
3967
|
+
: undefined;
|
|
3968
|
+
return {
|
|
3969
|
+
...source,
|
|
3970
|
+
baseCwd: ctx.cwd,
|
|
3971
|
+
currentSessionId: ownerSessionId,
|
|
3972
|
+
parentSessionFile: ctx.sessionManager.getSessionFile() ?? null,
|
|
3973
|
+
subagentInProgress: false,
|
|
3974
|
+
...(ownerSpawns ? { subagentSpawns: ownerSpawns } : { subagentSpawns: undefined }),
|
|
3975
|
+
asyncJobs: new Map(),
|
|
3976
|
+
fleetJobs: new Map(),
|
|
3977
|
+
foregroundRuns: new Map(),
|
|
3978
|
+
foregroundControls: new Map(),
|
|
3979
|
+
lastForegroundControlId: null,
|
|
3980
|
+
cleanupTimers: new Map(),
|
|
3981
|
+
lastUiContext: null,
|
|
3982
|
+
poller: null,
|
|
3983
|
+
completionSeen: new Map(),
|
|
3984
|
+
watcher: null,
|
|
3985
|
+
watcherRestartTimer: null,
|
|
3986
|
+
waitSubscriptions: new Map(),
|
|
3987
|
+
workflowControllers: new Map(),
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
|
|
3747
3991
|
export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
3748
3992
|
execute: (
|
|
3749
3993
|
id: string,
|
|
@@ -3764,34 +4008,319 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3764
4008
|
onUpdate: ((r: AgentToolResult<Details>) => void) | undefined,
|
|
3765
4009
|
ctx: ExtensionContext,
|
|
3766
4010
|
) => Promise<AgentToolResult<Details>>;
|
|
4011
|
+
/** Scheduled launches retain their owning context without replacing the live active session. */
|
|
4012
|
+
executeScheduled: (
|
|
4013
|
+
id: string,
|
|
4014
|
+
params: SubagentParamsLike,
|
|
4015
|
+
signal: AbortSignal,
|
|
4016
|
+
ctx: ExtensionContext,
|
|
4017
|
+
) => Promise<AgentToolResult<Details>>;
|
|
3767
4018
|
} {
|
|
3768
4019
|
const delegatedThinkingOverrides = new WeakMap<object, AgentConfig["thinking"]>();
|
|
3769
4020
|
const delegatedZeroToolBudgets = new WeakSet<object>();
|
|
4021
|
+
const scheduledOwnerExecutors = new Map<string, ReturnType<typeof createSubagentExecutor>>();
|
|
3770
4022
|
const execute = async (
|
|
3771
4023
|
_id: string,
|
|
3772
4024
|
params: SubagentParamsLike,
|
|
3773
4025
|
signal: AbortSignal,
|
|
3774
4026
|
onUpdate: ((r: AgentToolResult<Details>) => void) | undefined,
|
|
3775
4027
|
ctx: ExtensionContext,
|
|
4028
|
+
preserveActiveSession = false,
|
|
3776
4029
|
): Promise<AgentToolResult<Details>> => {
|
|
3777
4030
|
const delegatedThinkingOverride = delegatedThinkingOverrides.get(params);
|
|
3778
4031
|
const allowZeroToolBudget = delegatedZeroToolBudgets.has(params);
|
|
3779
|
-
deps.state.baseCwd = ctx.cwd;
|
|
4032
|
+
if (!preserveActiveSession) deps.state.baseCwd = ctx.cwd;
|
|
3780
4033
|
deps.state.foregroundRuns ??= new Map();
|
|
3781
4034
|
deps.state.foregroundControls ??= new Map();
|
|
3782
4035
|
deps.state.lastForegroundControlId ??= null;
|
|
3783
4036
|
const requestParams = omitExecutionModeActionAlias(params);
|
|
3784
|
-
|
|
3785
|
-
|
|
4037
|
+
if (requestParams.workflowScript !== undefined) {
|
|
4038
|
+
const invalidMode = requestParams.action !== undefined || requestParams.agent !== undefined || requestParams.step !== undefined || requestParams.tasks !== undefined || requestParams.chain !== undefined;
|
|
4039
|
+
if (invalidMode) {
|
|
4040
|
+
return { content: [{ type: "text", text: "workflowScript is its own execution mode; do not combine it with action, agent, step, tasks, or chain." }], isError: true, details: { mode: "workflow", results: [] } };
|
|
4041
|
+
}
|
|
4042
|
+
if (requestParams.clarify === true) {
|
|
4043
|
+
return { content: [{ type: "text", text: "workflowScript does not support clarify UI." }], isError: true, details: { mode: "workflow", results: [] } };
|
|
4044
|
+
}
|
|
4045
|
+
const timeout = requestParams.timeoutMs ?? requestParams.maxRuntimeMs ?? DEFAULT_FOREGROUND_TIMEOUT_MS;
|
|
4046
|
+
const workflowUsageBudget = validateUsageBudgetConfig(requestParams.usageBudget ?? deps.config.usageBudget, requestParams.usageBudget ? "usageBudget" : "config.usageBudget");
|
|
4047
|
+
if (workflowUsageBudget.error) return buildRequestedModeError(requestParams, workflowUsageBudget.error);
|
|
4048
|
+
const workflowCwd = resolveRequestedCwd(ctx.cwd, requestParams.cwd);
|
|
4049
|
+
const chatProgressResult = resolveWorkflowChatProgress({ requested: requestParams.chatProgress, parentCwd: ctx.cwd, workflowCwd, background: requestParams.async !== false });
|
|
4050
|
+
if (chatProgressResult.error) return { content: [{ type: "text", text: chatProgressResult.error }], isError: true, details: { mode: "workflow", results: [] } };
|
|
4051
|
+
const chatProgress = chatProgressResult.projection!;
|
|
4052
|
+
if (requestParams.async !== false) {
|
|
4053
|
+
const workflowRunId = _id;
|
|
4054
|
+
const asyncDir = path.join(DIRS.async, workflowRunId);
|
|
4055
|
+
const resultPath = path.join(DIRS.results, `${workflowRunId}.json`);
|
|
4056
|
+
const statusPath = path.join(asyncDir, "status.json");
|
|
4057
|
+
const eventsPath = path.join(asyncDir, "events.jsonl");
|
|
4058
|
+
const startedAt = Date.now();
|
|
4059
|
+
const currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
4060
|
+
fs.mkdirSync(asyncDir, { recursive: true });
|
|
4061
|
+
fs.mkdirSync(DIRS.results, { recursive: true });
|
|
4062
|
+
const controller = new AbortController();
|
|
4063
|
+
deps.state.workflowControllers ??= new Map();
|
|
4064
|
+
deps.state.workflowControllers.set(workflowRunId, controller);
|
|
4065
|
+
let status: AsyncStatus = {
|
|
4066
|
+
runId: workflowRunId,
|
|
4067
|
+
sessionId: currentSessionId ?? undefined,
|
|
4068
|
+
mode: "workflow",
|
|
4069
|
+
state: "running",
|
|
4070
|
+
startedAt,
|
|
4071
|
+
lastUpdate: startedAt,
|
|
4072
|
+
deadlineAt: startedAt + timeout,
|
|
4073
|
+
timeoutMs: timeout,
|
|
4074
|
+
cwd: ctx.cwd,
|
|
4075
|
+
pid: process.pid,
|
|
4076
|
+
steps: [],
|
|
4077
|
+
workflow: { trace: [], emits: [], console: [] },
|
|
4078
|
+
};
|
|
4079
|
+
const appendWorkflowEvent = (event: Record<string, unknown>) => fs.appendFileSync(eventsPath, `${JSON.stringify({ ts: Date.now(), runId: workflowRunId, ...event })}\n`, "utf-8");
|
|
4080
|
+
const persist = () => {
|
|
4081
|
+
status.lastUpdate = Date.now();
|
|
4082
|
+
writeAtomicJson(statusPath, status);
|
|
4083
|
+
const job = deps.state.asyncJobs.get(workflowRunId);
|
|
4084
|
+
if (job) {
|
|
4085
|
+
job.status = status.state;
|
|
4086
|
+
job.updatedAt = status.lastUpdate;
|
|
4087
|
+
if (status.steps) {
|
|
4088
|
+
job.steps = status.steps.map((step, index) => ({ ...step, index }));
|
|
4089
|
+
job.agents = status.steps.map((step) => step.agent);
|
|
4090
|
+
} else {
|
|
4091
|
+
delete job.steps;
|
|
4092
|
+
delete job.agents;
|
|
4093
|
+
}
|
|
4094
|
+
job.workflow = status.workflow;
|
|
4095
|
+
}
|
|
4096
|
+
};
|
|
4097
|
+
const workflowJob: AsyncJobState = { asyncId: workflowRunId, asyncDir, cwd: ctx.cwd, status: "running", sessionId: currentSessionId ?? undefined, mode: "workflow", agents: [], steps: [], startedAt, updatedAt: startedAt, timeoutMs: timeout, deadlineAt: startedAt + timeout, workflow: status.workflow };
|
|
4098
|
+
deps.state.asyncJobs.set(workflowRunId, workflowJob);
|
|
4099
|
+
deps.state.fleetJobs ??= new Map();
|
|
4100
|
+
deps.state.fleetJobs.set(workflowRunId, workflowJob);
|
|
4101
|
+
persist();
|
|
4102
|
+
appendWorkflowEvent({ type: "subagent.workflow.started" });
|
|
4103
|
+
const { workflowScript, async: _workflowAsync, chatProgress: _chatProgress, ...workflowRequest } = requestParams;
|
|
4104
|
+
void Promise.resolve().then(async () => {
|
|
4105
|
+
const workflowResults: SingleResult[] = [];
|
|
4106
|
+
const { action: _action, agent: _agent, task: _task, tasks: _tasks, chain: _chain, concurrency: _concurrency, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, ...workflowChildDefaults } = workflowRequest;
|
|
4107
|
+
const updateTrace = (trace: NonNullable<Details["workflow"]>["trace"]) => {
|
|
4108
|
+
status.workflow = { ...(status.workflow ?? { emits: [], console: [] }), trace };
|
|
4109
|
+
for (const entry of trace.filter((candidate) => candidate.operation === "run")) {
|
|
4110
|
+
const existing = status.steps?.find((step) => step.workflowKey === entry.key);
|
|
4111
|
+
if (entry.state === "reused" && existing) continue;
|
|
4112
|
+
const mapped = entry.state === "started" || entry.state === "reused" ? "running" : entry.state === "completed" ? "completed" : "failed";
|
|
4113
|
+
if (existing) {
|
|
4114
|
+
existing.status = mapped;
|
|
4115
|
+
if (entry.error === undefined) delete existing.error;
|
|
4116
|
+
else existing.error = entry.error;
|
|
4117
|
+
if (entry.durationMs === undefined) delete existing.durationMs;
|
|
4118
|
+
else existing.durationMs = entry.durationMs;
|
|
4119
|
+
} else {
|
|
4120
|
+
status.steps?.push({ agent: entry.key, label: entry.key, workflowKey: entry.key, parentWorkflowRunId: workflowRunId, status: mapped });
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
persist();
|
|
4124
|
+
appendWorkflowEvent({ type: "subagent.workflow.trace", trace });
|
|
4125
|
+
};
|
|
4126
|
+
try {
|
|
4127
|
+
const workflow = await runWorkflowScript({
|
|
4128
|
+
script: workflowScript,
|
|
4129
|
+
timeoutMs: timeout,
|
|
4130
|
+
signal: controller.signal,
|
|
4131
|
+
onTrace: updateTrace,
|
|
4132
|
+
onEmit: (emits) => {
|
|
4133
|
+
// Each emit is validated at the host boundary in runWorkflowScript before onEmit fires.
|
|
4134
|
+
status.workflow = { ...(status.workflow ?? { trace: [], console: [] }), emits };
|
|
4135
|
+
persist();
|
|
4136
|
+
appendWorkflowEvent({ type: "subagent.workflow.emit", value: emits.at(-1) });
|
|
4137
|
+
},
|
|
4138
|
+
launch: async (key, childParams, workflowSignal) => {
|
|
4139
|
+
if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."));
|
|
4140
|
+
const budgetState = usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults));
|
|
4141
|
+
if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)));
|
|
4142
|
+
const childRequest = prepareWorkflowChildParams({ ...workflowChildDefaults, ...childParams, workflowParentRunId: workflowRunId, workflowKey: key } as SubagentParamsLike);
|
|
4143
|
+
const result = await execute(randomUUID(), childRequest, workflowSignal, undefined, ctx, preserveActiveSession);
|
|
4144
|
+
workflowResults.push(...result.details.results);
|
|
4145
|
+
const child = workflowChildResult(key, result);
|
|
4146
|
+
if (result.details.asyncId) {
|
|
4147
|
+
const childJob = deps.state.asyncJobs.get(result.details.asyncId);
|
|
4148
|
+
if (childJob) { childJob.parentWorkflowRunId = workflowRunId; childJob.workflowKey = key; }
|
|
4149
|
+
}
|
|
4150
|
+
return child;
|
|
4151
|
+
},
|
|
4152
|
+
status: async (keyOrRunId, workflowSignal) => workflowChildResult(keyOrRunId, await execute(randomUUID(), { action: "status", id: keyOrRunId }, workflowSignal, undefined, ctx, preserveActiveSession)),
|
|
4153
|
+
});
|
|
4154
|
+
const returnPreview = formatWorkflowValue(workflow.value).slice(0, 1_000);
|
|
4155
|
+
const emitPreview = workflow.emits.length > 0 ? ` Emitted: ${workflow.emits.map(formatWorkflowValue).join(", ").slice(0, 1_000)}` : "";
|
|
4156
|
+
const summary = `Workflow completed with ${workflow.children.length} child run(s). Return: ${returnPreview}${emitPreview} Trace: ${workflow.trace.length} event(s).`;
|
|
4157
|
+
const workflowUsage = sumResultsUsage(workflowResults);
|
|
4158
|
+
status = { ...status, state: "complete", endedAt: Date.now(), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, totalTokens: { input: workflowUsage.input, output: workflowUsage.output, total: workflowUsage.input + workflowUsage.output }, totalCost: sumResultsCost(workflowResults) };
|
|
4159
|
+
persist();
|
|
4160
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: "complete" });
|
|
4161
|
+
writeAtomicJson(resultPath, { id: workflowRunId, runId: workflowRunId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary, output: summary, results: workflow.children.map((child) => ({ agent: child.key, output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, asyncDir, cwd: ctx.cwd, sessionId: currentSessionId, timestamp: Date.now(), durationMs: Date.now() - startedAt });
|
|
4162
|
+
} catch (error) {
|
|
4163
|
+
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
4164
|
+
const stopped = controller.signal.aborted;
|
|
4165
|
+
status = compactOptional<AsyncStatus>({ ...status, state: stopped ? "stopped" : "failed", stopped: stopped || undefined, error: error instanceof Error ? error.message : String(error), endedAt: Date.now(), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console } });
|
|
4166
|
+
persist();
|
|
4167
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, error: status.error });
|
|
4168
|
+
writeAtomicJson(resultPath, { id: workflowRunId, runId: workflowRunId, agent: "workflow", mode: "workflow", success: false, state: status.state, summary: status.error, error: status.error, stopped: status.stopped, results: partial.children.map((child) => ({ agent: child.key, output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, asyncDir, cwd: ctx.cwd, sessionId: currentSessionId, timestamp: Date.now(), durationMs: Date.now() - startedAt });
|
|
4169
|
+
} finally {
|
|
4170
|
+
deps.state.workflowControllers?.delete(workflowRunId);
|
|
4171
|
+
}
|
|
4172
|
+
});
|
|
4173
|
+
return {
|
|
4174
|
+
content: [{ type: "text", text: formatAsyncStartedMessage(`Async workflow [${workflowRunId}]`, ctx.hasUI === true) }],
|
|
4175
|
+
details: { mode: "workflow", runId: workflowRunId, asyncId: workflowRunId, asyncDir, results: [], chatProgress },
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4178
|
+
const { workflowScript: _workflowScript, action: _action, agent: _agent, task: _task, tasks: _tasks, chain: _chain, concurrency: _concurrency, async: _async, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, chatProgress: _chatProgress, ...workflowChildDefaults } = requestParams;
|
|
4179
|
+
const workflowResults: SingleResult[] = [];
|
|
4180
|
+
let liveWorkflow: NonNullable<Details["workflow"]> = { trace: [], emits: [], console: [] };
|
|
4181
|
+
const sendWorkflowProgress = () => {
|
|
4182
|
+
const update = workflowChatProgressUpdate(_id, chatProgress, liveWorkflow);
|
|
4183
|
+
if (update) onUpdate?.(update);
|
|
4184
|
+
};
|
|
4185
|
+
try {
|
|
4186
|
+
const workflow = await runWorkflowScript({
|
|
4187
|
+
script: requestParams.workflowScript,
|
|
4188
|
+
timeoutMs: timeout,
|
|
4189
|
+
signal,
|
|
4190
|
+
onTrace: (trace) => {
|
|
4191
|
+
liveWorkflow = { ...liveWorkflow, trace };
|
|
4192
|
+
sendWorkflowProgress();
|
|
4193
|
+
},
|
|
4194
|
+
onEmit: (emits) => {
|
|
4195
|
+
liveWorkflow = { ...liveWorkflow, emits };
|
|
4196
|
+
sendWorkflowProgress();
|
|
4197
|
+
},
|
|
4198
|
+
launch: async (key, childParams, workflowSignal) => {
|
|
4199
|
+
if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."));
|
|
4200
|
+
const budgetState = usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults));
|
|
4201
|
+
if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)));
|
|
4202
|
+
const childRequest = prepareWorkflowChildParams({ ...workflowChildDefaults, ...childParams, workflowParentRunId: _id, workflowKey: key, suppressRoutineResultIntercom: chatProgress.mode === "live-card" } as SubagentParamsLike);
|
|
4203
|
+
const result = await execute(randomUUID(), childRequest, workflowSignal, undefined, ctx, preserveActiveSession);
|
|
4204
|
+
workflowResults.push(...result.details.results);
|
|
4205
|
+
return workflowChildResult(key, result);
|
|
4206
|
+
},
|
|
4207
|
+
status: async (keyOrRunId, workflowSignal) => workflowChildResult(keyOrRunId, await execute(randomUUID(), { action: "status", id: keyOrRunId }, workflowSignal, undefined, ctx, preserveActiveSession)),
|
|
4208
|
+
});
|
|
4209
|
+
const traceLines = workflow.trace.map((entry) => `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.durationMs !== undefined ? ` in ${entry.durationMs}ms` : ""}${entry.error ? ` — ${entry.error}` : ""}`);
|
|
4210
|
+
const sections = ["Workflow completed.", `Return:\n${formatWorkflowValue(workflow.value)}`];
|
|
4211
|
+
if (workflow.emits.length > 0) sections.push(`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`);
|
|
4212
|
+
if (workflow.console.length > 0) sections.push(`Console:\n${workflow.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
4213
|
+
if (traceLines.length > 0) sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
4214
|
+
return {
|
|
4215
|
+
content: [{ type: "text", text: sections.join("\n\n") }],
|
|
4216
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, chatProgress }),
|
|
4217
|
+
};
|
|
4218
|
+
} catch (error) {
|
|
4219
|
+
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
4220
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
4221
|
+
const traceLines = partial.trace.map((entry) => `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.error ? ` — ${entry.error}` : ""}`);
|
|
4222
|
+
const sections = [`Workflow failed: ${text}`];
|
|
4223
|
+
if (partial.emits.length > 0) sections.push(`Emitted:\n${partial.emits.map(formatWorkflowValue).join("\n")}`);
|
|
4224
|
+
if (partial.console.length > 0) sections.push(`Console:\n${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
4225
|
+
if (traceLines.length > 0) sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
4226
|
+
return {
|
|
4227
|
+
content: [{ type: "text", text: sections.join("\n\n") }],
|
|
4228
|
+
isError: true,
|
|
4229
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console }, chatProgress }),
|
|
4230
|
+
};
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
const directParams = prepareWorkflowChildParams(requestParams);
|
|
4234
|
+
const requestCwd = resolveRequestedCwd(ctx.cwd, directParams.cwd);
|
|
4235
|
+
const paramsWithResolvedCwd = directParams.cwd === undefined ? directParams : { ...directParams, cwd: requestCwd };
|
|
3786
4236
|
const action = paramsWithResolvedCwd.action;
|
|
4237
|
+
let requestSessionId = "";
|
|
4238
|
+
let requestPiSessionId: string | undefined;
|
|
3787
4239
|
let requestParentModel: ParentModel | undefined;
|
|
3788
4240
|
try {
|
|
3789
|
-
|
|
4241
|
+
requestSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
4242
|
+
requestPiSessionId = ctx.sessionManager.getSessionId() ?? undefined;
|
|
4243
|
+
requestParentModel = preserveActiveSession
|
|
4244
|
+
? normalizeParentModel(ctx.model)
|
|
4245
|
+
: rememberParentModel(deps.state, requestSessionId, ctx.model);
|
|
3790
4246
|
} catch (error) {
|
|
3791
4247
|
if (action?.toLowerCase() !== "doctor") throw error;
|
|
3792
4248
|
requestParentModel = normalizeParentModel(ctx.model);
|
|
3793
4249
|
}
|
|
3794
4250
|
if (action) {
|
|
4251
|
+
if (action === "worktree.discard") {
|
|
4252
|
+
if (deps.allowMutatingManagementActions === false) {
|
|
4253
|
+
return { content: [{ type: "text", text: "Action 'worktree.discard' is not available from child-safe subagent fanout mode." }], isError: true, details: { mode: "management", results: [] } };
|
|
4254
|
+
}
|
|
4255
|
+
if (!paramsWithResolvedCwd.handoffPath?.trim()) {
|
|
4256
|
+
return { content: [{ type: "text", text: "worktree.discard requires handoffPath from parallelHandoff.path or async status." }], isError: true, details: { mode: "management", results: [] } };
|
|
4257
|
+
}
|
|
4258
|
+
const decision = resolveAuthorityDecision({ action: "discardWorktree", ...(deps.config.authorityPolicy === undefined ? {} : { policy: deps.config.authorityPolicy }) });
|
|
4259
|
+
if (decision === "forbid") {
|
|
4260
|
+
return { content: [{ type: "text", text: "Authority policy forbids worktree discard." }], isError: true, details: { mode: "management", results: [] } };
|
|
4261
|
+
}
|
|
4262
|
+
let confirmed = decision === "auto";
|
|
4263
|
+
if (decision === "confirm") {
|
|
4264
|
+
if (!ctx.hasUI) return { content: [{ type: "text", text: "Authority policy requires user confirmation for worktree discard, but this session has no interactive UI. Preserved worktrees were not changed." }], isError: true, details: { mode: "management", results: [] } };
|
|
4265
|
+
confirmed = await ctx.ui.confirm("Discard preserved subagent worktrees?", `This permanently removes preserved worktrees and temporary branches recorded in:\n${paramsWithResolvedCwd.handoffPath}`);
|
|
4266
|
+
}
|
|
4267
|
+
if (!confirmed) return { content: [{ type: "text", text: "Worktree discard canceled; preserved worktrees were not changed." }], details: { mode: "management", results: [] } };
|
|
4268
|
+
try {
|
|
4269
|
+
const discarded = discardPreservedWorktrees(
|
|
4270
|
+
path.isAbsolute(paramsWithResolvedCwd.handoffPath) ? paramsWithResolvedCwd.handoffPath : path.resolve(requestCwd, paramsWithResolvedCwd.handoffPath),
|
|
4271
|
+
{ kind: decision === "confirm" ? "confirmed" : "policy", ...(deps.config.authorityPolicy ? { policy: deps.config.authorityPolicy } : {}) },
|
|
4272
|
+
);
|
|
4273
|
+
return { content: [{ type: "text", text: discarded.text }], details: { mode: "management", results: [] } };
|
|
4274
|
+
} catch (error) {
|
|
4275
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
if ((HERDR_PROJECT_PANE_ACTIONS as readonly string[]).includes(action)) {
|
|
4279
|
+
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
4280
|
+
return { content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }], isError: true, details: { mode: "management", results: [] } };
|
|
4281
|
+
}
|
|
4282
|
+
return handleHerdrProjectPaneAction(action as (typeof HERDR_PROJECT_PANE_ACTIONS)[number], paramsWithResolvedCwd, { cwd: requestCwd, signal });
|
|
4283
|
+
}
|
|
4284
|
+
if ((HERDR_INSPECTOR_ACTIONS as readonly string[]).includes(action)) {
|
|
4285
|
+
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
4286
|
+
return { content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }], isError: true, details: { mode: "management", results: [] } };
|
|
4287
|
+
}
|
|
4288
|
+
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
4289
|
+
return handleHerdrInspectorAction(action as (typeof HERDR_INSPECTOR_ACTIONS)[number], paramsWithResolvedCwd, {
|
|
4290
|
+
state: deps.state,
|
|
4291
|
+
cwd: requestCwd,
|
|
4292
|
+
...(deps.config.missions ? { missions: deps.config.missions } : {}),
|
|
4293
|
+
...(deps.config.authorityPolicy ? { authorityPolicy: deps.config.authorityPolicy } : {}),
|
|
4294
|
+
signal,
|
|
4295
|
+
});
|
|
4296
|
+
}
|
|
4297
|
+
if ((MISSION_ACTIONS as readonly string[]).includes(action)) {
|
|
4298
|
+
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
4299
|
+
return {
|
|
4300
|
+
content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }],
|
|
4301
|
+
isError: true,
|
|
4302
|
+
details: { mode: "management", results: [] },
|
|
4303
|
+
};
|
|
4304
|
+
}
|
|
4305
|
+
const currentSessionId = deps.state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined;
|
|
4306
|
+
return handleMissionAction(action as (typeof MISSION_ACTIONS)[number], paramsWithResolvedCwd, {
|
|
4307
|
+
cwd: requestCwd,
|
|
4308
|
+
...(deps.config.missions ? { config: deps.config.missions } : {}),
|
|
4309
|
+
...(currentSessionId ? { currentSessionId } : {}),
|
|
4310
|
+
});
|
|
4311
|
+
}
|
|
4312
|
+
const policyAction = action === "stop" ? "stopRun" : action === "steer" ? "steerRun" : action === "schedule.create" ? "scheduleCreate" : undefined;
|
|
4313
|
+
if (policyAction) {
|
|
4314
|
+
const decision = resolveAuthorityDecision({ action: policyAction, ...(deps.config.authorityPolicy === undefined ? {} : { policy: deps.config.authorityPolicy }) });
|
|
4315
|
+
if (decision === "forbid") {
|
|
4316
|
+
return { content: [{ type: "text", text: `Authority policy forbids action '${action}'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
4317
|
+
}
|
|
4318
|
+
if (decision === "confirm") {
|
|
4319
|
+
if (!ctx.hasUI) return { content: [{ type: "text", text: `Authority policy requires user confirmation for action '${action}', but this session has no interactive UI.` }], isError: true, details: { mode: "management", results: [] } };
|
|
4320
|
+
const confirmed = await ctx.ui.confirm(`Authorize subagent ${action}?`, `Authority policy requires confirmation before '${action}'.`);
|
|
4321
|
+
if (!confirmed) return { content: [{ type: "text", text: `Action '${action}' canceled; authority was not granted.` }], details: { mode: "management", results: [] } };
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
3795
4324
|
if ((WATCHDOG_TOOL_ACTIONS as readonly string[]).includes(action)) {
|
|
3796
4325
|
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
3797
4326
|
return {
|
|
@@ -3836,7 +4365,15 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3836
4365
|
details: { mode: "management", results: [], spawnBudget: preview.snapshot },
|
|
3837
4366
|
};
|
|
3838
4367
|
}
|
|
3839
|
-
const
|
|
4368
|
+
const authority = resolveAuthorityDecision({ action: "spawnBudgetGrant", ...(deps.config.authorityPolicy === undefined ? {} : { policy: deps.config.authorityPolicy }) });
|
|
4369
|
+
if (authority === "forbid") {
|
|
4370
|
+
return {
|
|
4371
|
+
content: [{ type: "text", text: "Authority policy forbids spawn budget grants." }],
|
|
4372
|
+
isError: true,
|
|
4373
|
+
details: { mode: "management", results: [], spawnBudget: preview.snapshot },
|
|
4374
|
+
};
|
|
4375
|
+
}
|
|
4376
|
+
const confirmed = authority === "auto" || await ctx.ui.confirm(
|
|
3840
4377
|
"Grant subagent spawn budget?",
|
|
3841
4378
|
`Add ${additional} launches to this logical session?\n\n${formatSpawnBudget(preview.snapshot)}\n\nUsage is not reset. Compaction keeps the same budget; a new parent session starts a fresh one.`,
|
|
3842
4379
|
);
|
|
@@ -3886,7 +4423,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3886
4423
|
return {
|
|
3887
4424
|
content: [{
|
|
3888
4425
|
type: "text",
|
|
3889
|
-
text: buildDoctorReport({
|
|
4426
|
+
text: buildDoctorReport(omitUndefinedProperties({
|
|
3890
4427
|
cwd: requestCwd,
|
|
3891
4428
|
config: deps.config,
|
|
3892
4429
|
state: deps.state,
|
|
@@ -3897,13 +4434,13 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3897
4434
|
orchestratorTarget,
|
|
3898
4435
|
sessionError,
|
|
3899
4436
|
expandTilde: deps.expandTilde,
|
|
3900
|
-
}),
|
|
4437
|
+
})),
|
|
3901
4438
|
}],
|
|
3902
4439
|
details: { mode: "management", results: [], spawnBudget },
|
|
3903
4440
|
};
|
|
3904
4441
|
}
|
|
3905
4442
|
if (action === "status") {
|
|
3906
|
-
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
4443
|
+
if (!preserveActiveSession) deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
3907
4444
|
const withBudget = (result: AgentToolResult<Details>) => withSpawnBudgetStatus(
|
|
3908
4445
|
result,
|
|
3909
4446
|
deps.state,
|
|
@@ -3914,11 +4451,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3914
4451
|
const nestedScope = nestedResolutionScopeForExecutor(deps);
|
|
3915
4452
|
const sessionRoots = trustedSessionRootsForStatus(ctx, deps);
|
|
3916
4453
|
if (paramsWithResolvedCwd.view === "fleet") {
|
|
3917
|
-
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, { state: deps.state, nested: nestedScope, sessionRoots }));
|
|
4454
|
+
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots })));
|
|
3918
4455
|
}
|
|
3919
4456
|
if (targetRunId) {
|
|
3920
4457
|
try {
|
|
3921
|
-
const resolved = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedScope });
|
|
4458
|
+
const resolved = resolveSubagentRunId(targetRunId, omitUndefinedProperties({ state: deps.state, nested: nestedScope }));
|
|
3922
4459
|
if (resolved?.kind === "foreground") {
|
|
3923
4460
|
const foreground = getForegroundControl(deps.state, resolved.id);
|
|
3924
4461
|
if (foreground) {
|
|
@@ -3945,7 +4482,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3945
4482
|
});
|
|
3946
4483
|
}
|
|
3947
4484
|
}
|
|
3948
|
-
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, { state: deps.state, nested: nestedScope, sessionRoots }));
|
|
4485
|
+
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots })));
|
|
3949
4486
|
}
|
|
3950
4487
|
|
|
3951
4488
|
if (action === "approve-checkpoint" || action === "reject-checkpoint") {
|
|
@@ -3955,7 +4492,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3955
4492
|
return { content: [{ type: "text", text: `action='${action}' requires id or dir.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3956
4493
|
}
|
|
3957
4494
|
try {
|
|
3958
|
-
const resolved = targetRunId ? resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) }) : undefined;
|
|
4495
|
+
const resolved = targetRunId ? resolveSubagentRunId(targetRunId, omitUndefinedProperties({ state: deps.state, nested: nestedResolutionScopeForExecutor(deps) })) : undefined;
|
|
3959
4496
|
const decision = action === "approve-checkpoint" ? "approved" : "rejected";
|
|
3960
4497
|
if (resolved?.kind === "foreground") {
|
|
3961
4498
|
const run = deps.state.foregroundRuns?.get(resolved.id);
|
|
@@ -3966,7 +4503,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3966
4503
|
return { content: [{ type: "text", text: `Run '${resolved.id}' was not found in the active session.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3967
4504
|
}
|
|
3968
4505
|
const decidedAt = Date.now();
|
|
3969
|
-
const checkpoint
|
|
4506
|
+
const checkpoint: NonNullable<Details["checkpoint"]> = decision === "approved"
|
|
4507
|
+
? { ...run.checkpoint, status: "approved", approvedAt: decidedAt }
|
|
4508
|
+
: { ...run.checkpoint, status: "rejected", rejectedAt: decidedAt };
|
|
3970
4509
|
run.checkpoint = checkpoint;
|
|
3971
4510
|
run.updatedAt = decidedAt;
|
|
3972
4511
|
return {
|
|
@@ -3975,7 +4514,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3975
4514
|
};
|
|
3976
4515
|
}
|
|
3977
4516
|
const location = paramsWithResolvedCwd.dir
|
|
3978
|
-
? resolveAsyncRunLocation(paramsWithResolvedCwd,
|
|
4517
|
+
? resolveAsyncRunLocation(paramsWithResolvedCwd, DIRS.async, DIRS.results)
|
|
3979
4518
|
: resolved?.kind === "async"
|
|
3980
4519
|
? resolved.location
|
|
3981
4520
|
: undefined;
|
|
@@ -4001,7 +4540,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4001
4540
|
}
|
|
4002
4541
|
}
|
|
4003
4542
|
if (action === "resume") {
|
|
4004
|
-
return resumeAsyncRun({ params: paramsWithResolvedCwd, requestCwd, ctx, deps, parentModel: requestParentModel });
|
|
4543
|
+
return resumeAsyncRun(omitUndefinedProperties({ params: paramsWithResolvedCwd, requestCwd, ctx, deps, parentModel: requestParentModel }));
|
|
4005
4544
|
}
|
|
4006
4545
|
if (action === "steer") {
|
|
4007
4546
|
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
@@ -4010,9 +4549,13 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4010
4549
|
const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
|
|
4011
4550
|
if (paramsWithResolvedCwd.dir) {
|
|
4012
4551
|
try {
|
|
4013
|
-
const location = resolveAsyncRunLocation(paramsWithResolvedCwd,
|
|
4552
|
+
const location = resolveAsyncRunLocation(paramsWithResolvedCwd, DIRS.async, DIRS.results);
|
|
4014
4553
|
const runId = location.resolvedId ?? targetRunId ?? path.basename(location.asyncDir ?? paramsWithResolvedCwd.dir);
|
|
4015
|
-
|
|
4554
|
+
if (location.asyncDir) {
|
|
4555
|
+
const unsupported = externalRunnerControlError(location.asyncDir, "steer");
|
|
4556
|
+
if (unsupported) return unsupported;
|
|
4557
|
+
}
|
|
4558
|
+
return steerAsyncRun(compactOptional<Parameters<typeof steerAsyncRun>[0]>({
|
|
4016
4559
|
state: deps.state,
|
|
4017
4560
|
runId,
|
|
4018
4561
|
message,
|
|
@@ -4024,10 +4567,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4024
4567
|
? {}
|
|
4025
4568
|
: {
|
|
4026
4569
|
recover: ({ absoluteDeadlineAt, ...limits }) =>
|
|
4027
|
-
resumeAsyncRun({ params: { ...limits, action: "resume", id: runId, message }, requestCwd, ctx, deps, parentModel: requestParentModel, absoluteDeadlineAt }),
|
|
4570
|
+
resumeAsyncRun(omitUndefinedProperties({ params: { ...limits, action: "resume", id: runId, message }, requestCwd, ctx, deps, parentModel: requestParentModel, absoluteDeadlineAt })),
|
|
4028
4571
|
}
|
|
4029
4572
|
),
|
|
4030
|
-
});
|
|
4573
|
+
}));
|
|
4031
4574
|
} catch (error) {
|
|
4032
4575
|
const text = error instanceof Error ? error.message : String(error);
|
|
4033
4576
|
return { content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } };
|
|
@@ -4036,15 +4579,19 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4036
4579
|
if (!targetRunId) return { content: [{ type: "text", text: "action='steer' requires id or dir." }], isError: true, details: { mode: "management", results: [] } };
|
|
4037
4580
|
let resolved: ResolvedSubagentRunId | undefined;
|
|
4038
4581
|
try {
|
|
4039
|
-
resolved = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
4582
|
+
resolved = resolveSubagentRunId(targetRunId, omitUndefinedProperties({ state: deps.state, nested: nestedResolutionScopeForExecutor(deps) }));
|
|
4040
4583
|
} catch (error) {
|
|
4041
4584
|
const text = error instanceof Error ? error.message : String(error);
|
|
4042
4585
|
return { content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } };
|
|
4043
4586
|
}
|
|
4044
|
-
if (resolved?.kind === "nested") return steerNestedRun({ target: resolved, message, index: paramsWithResolvedCwd.index, signal });
|
|
4587
|
+
if (resolved?.kind === "nested") return steerNestedRun(omitUndefinedProperties({ target: resolved, message, index: paramsWithResolvedCwd.index, signal }));
|
|
4045
4588
|
if (resolved?.kind === "foreground") return { content: [{ type: "text", text: "action='steer' currently supports live async Pi child sessions only; use action='interrupt' or action='resume' for foreground runs." }], isError: true, details: { mode: "management", results: [] } };
|
|
4046
4589
|
if (resolved?.kind !== "async") return { content: [{ type: "text", text: `No async run found for '${targetRunId}'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
4047
|
-
|
|
4590
|
+
if (resolved.location.asyncDir) {
|
|
4591
|
+
const unsupported = externalRunnerControlError(resolved.location.asyncDir, "steer");
|
|
4592
|
+
if (unsupported) return unsupported;
|
|
4593
|
+
}
|
|
4594
|
+
return steerAsyncRun(compactOptional<Parameters<typeof steerAsyncRun>[0]>({
|
|
4048
4595
|
state: deps.state,
|
|
4049
4596
|
runId: resolved.id,
|
|
4050
4597
|
message,
|
|
@@ -4056,22 +4603,29 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4056
4603
|
? {}
|
|
4057
4604
|
: {
|
|
4058
4605
|
recover: ({ absoluteDeadlineAt, ...limits }) =>
|
|
4059
|
-
resumeAsyncRun({
|
|
4606
|
+
resumeAsyncRun(omitUndefinedProperties({
|
|
4060
4607
|
params: { ...limits, action: "resume", id: resolved!.id, message },
|
|
4061
4608
|
requestCwd,
|
|
4062
4609
|
ctx,
|
|
4063
4610
|
deps,
|
|
4064
4611
|
parentModel: requestParentModel,
|
|
4065
4612
|
absoluteDeadlineAt,
|
|
4066
|
-
}),
|
|
4613
|
+
})),
|
|
4067
4614
|
}
|
|
4068
4615
|
),
|
|
4069
|
-
});
|
|
4616
|
+
}));
|
|
4070
4617
|
}
|
|
4071
4618
|
if (action === "append-step") {
|
|
4072
|
-
return appendStepToAsyncChain({ params: paramsWithResolvedCwd, requestCwd, ctx, deps, parentModel: requestParentModel });
|
|
4619
|
+
return appendStepToAsyncChain(omitUndefinedProperties({ params: paramsWithResolvedCwd, requestCwd, ctx, deps, parentModel: requestParentModel }));
|
|
4073
4620
|
}
|
|
4074
|
-
if (action
|
|
4621
|
+
if (action.startsWith("schedule.")) {
|
|
4622
|
+
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
4623
|
+
return {
|
|
4624
|
+
content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }],
|
|
4625
|
+
isError: true,
|
|
4626
|
+
details: { mode: "management", results: [] },
|
|
4627
|
+
};
|
|
4628
|
+
}
|
|
4075
4629
|
if (!deps.handleScheduledRunAction) {
|
|
4076
4630
|
return {
|
|
4077
4631
|
content: [{ type: "text", text: `Action '${action}' is not available in this subagent context.` }],
|
|
@@ -4083,11 +4637,17 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4083
4637
|
}
|
|
4084
4638
|
if (action === "stop") {
|
|
4085
4639
|
const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
|
|
4640
|
+
const workflowController = targetRunId ? deps.state.workflowControllers?.get(targetRunId) : undefined;
|
|
4641
|
+
if (workflowController) {
|
|
4642
|
+
workflowController.abort(new Error("Workflow stopped by user."));
|
|
4643
|
+
return { content: [{ type: "text", text: `Stop requested for async workflow ${targetRunId}.` }], details: { mode: "management", results: [] } };
|
|
4644
|
+
}
|
|
4086
4645
|
let resolved: ResolvedSubagentRunId | undefined;
|
|
4087
4646
|
if (paramsWithResolvedCwd.dir) {
|
|
4088
4647
|
try {
|
|
4089
|
-
const location = resolveAsyncRunLocation(paramsWithResolvedCwd,
|
|
4090
|
-
|
|
4648
|
+
const location = resolveAsyncRunLocation(paramsWithResolvedCwd, DIRS.async, DIRS.results);
|
|
4649
|
+
const stopResult = stopAsyncRun(deps.state, location.resolvedId ?? targetRunId ?? path.basename(location.asyncDir ?? paramsWithResolvedCwd.dir), deps.kill, location);
|
|
4650
|
+
return stopResult ?? { content: [{ type: "text", text: `No running or queued async run was found for '${targetRunId ?? paramsWithResolvedCwd.dir}'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
4091
4651
|
} catch (error) {
|
|
4092
4652
|
const text = error instanceof Error ? error.message : String(error);
|
|
4093
4653
|
return { content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } };
|
|
@@ -4095,13 +4655,19 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4095
4655
|
}
|
|
4096
4656
|
if (!targetRunId) return { content: [{ type: "text", text: "action='stop' requires id or dir." }], isError: true, details: { mode: "management", results: [] } };
|
|
4097
4657
|
try {
|
|
4098
|
-
resolved = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
4658
|
+
resolved = resolveSubagentRunId(targetRunId, omitUndefinedProperties({ state: deps.state, nested: nestedResolutionScopeForExecutor(deps) }));
|
|
4099
4659
|
} catch (error) {
|
|
4100
4660
|
const message = error instanceof Error ? error.message : String(error);
|
|
4101
4661
|
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
4102
4662
|
}
|
|
4103
4663
|
if (resolved?.kind === "nested") return { content: [{ type: "text", text: "action='stop' supports current-session top-level async runs only." }], isError: true, details: { mode: "management", results: [] } };
|
|
4104
4664
|
if (resolved?.kind === "foreground") return { content: [{ type: "text", text: "action='stop' supports async runs only. Use action='interrupt' for foreground runs." }], isError: true, details: { mode: "management", results: [] } };
|
|
4665
|
+
if (resolved?.kind === "async") {
|
|
4666
|
+
const existingStatus = readStatus(resolved.location.asyncDir ?? "");
|
|
4667
|
+
if (existingStatus?.mode === "workflow" && existingStatus.state === "running") {
|
|
4668
|
+
return { content: [{ type: "text", text: `Workflow ${resolved.id} is not controlled by this extension runtime; reload recovery cannot stop it safely.` }], isError: true, details: { mode: "management", results: [] } };
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4105
4671
|
const stopResult = stopAsyncRun(
|
|
4106
4672
|
deps.state,
|
|
4107
4673
|
resolved?.kind === "async" ? resolved.id : targetRunId,
|
|
@@ -4120,7 +4686,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4120
4686
|
let resolved: ResolvedSubagentRunId | undefined;
|
|
4121
4687
|
if (targetRunId) {
|
|
4122
4688
|
try {
|
|
4123
|
-
resolved = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
4689
|
+
resolved = resolveSubagentRunId(targetRunId, omitUndefinedProperties({ state: deps.state, nested: nestedResolutionScopeForExecutor(deps) }));
|
|
4124
4690
|
} catch (error) {
|
|
4125
4691
|
const message = error instanceof Error ? error.message : String(error);
|
|
4126
4692
|
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
@@ -4132,7 +4698,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4132
4698
|
const interrupted = foreground.interrupt();
|
|
4133
4699
|
if (interrupted) {
|
|
4134
4700
|
foreground.updatedAt = Date.now();
|
|
4135
|
-
foreground.currentActivityState
|
|
4701
|
+
delete foreground.currentActivityState;
|
|
4136
4702
|
return {
|
|
4137
4703
|
content: [{ type: "text", text: `Interrupt requested for foreground run ${foreground.runId}.` }],
|
|
4138
4704
|
details: { mode: "management", results: [] },
|
|
@@ -4267,7 +4833,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4267
4833
|
const spawnPreflight = preflightSpawnBudget(
|
|
4268
4834
|
deps.state,
|
|
4269
4835
|
deps.config,
|
|
4270
|
-
|
|
4836
|
+
requestSessionId,
|
|
4271
4837
|
requestedSpawns,
|
|
4272
4838
|
);
|
|
4273
4839
|
if (spawnPreflight.error) return spawnBudgetErrorResult(spawnPreflight.error, foregroundMode);
|
|
@@ -4312,6 +4878,17 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4312
4878
|
const requestedAsync = effectiveParams.async ?? deps.asyncByDefault;
|
|
4313
4879
|
const backgroundRequestedWhileClarifying = (hasChain || hasTasks) && requestedAsync && effectiveParams.clarify === true;
|
|
4314
4880
|
const effectiveAsync = requestedAsync && effectiveParams.clarify !== true;
|
|
4881
|
+
const selectedAgentNames = hasSingle
|
|
4882
|
+
? [effectiveParams.agent!]
|
|
4883
|
+
: hasTasks
|
|
4884
|
+
? (effectiveParams.tasks ?? []).map((task) => task.agent)
|
|
4885
|
+
: (effectiveParams.chain ?? []).flatMap((step) => getStepAgents(step as ChainStep));
|
|
4886
|
+
const externalAgent = selectedAgentNames
|
|
4887
|
+
.map((name) => agents.find((agent) => agent.name === name))
|
|
4888
|
+
.find((agent) => agent?.runner?.type === "external-cli");
|
|
4889
|
+
if (externalAgent && (!effectiveAsync || effectiveParams.foregroundOnly === true)) {
|
|
4890
|
+
return buildRequestedModeError(effectiveParams, `Agent '${externalAgent.name}' uses runner.type='external-cli', which currently supports async/background execution only. Omit async or pass async:true; clarify and foregroundOnly are unsupported.`);
|
|
4891
|
+
}
|
|
4315
4892
|
const foregroundTimeout = resolveForegroundTimeout(
|
|
4316
4893
|
effectiveParams,
|
|
4317
4894
|
effectiveAsync ? undefined : DEFAULT_FOREGROUND_TIMEOUT_MS,
|
|
@@ -4319,11 +4896,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4319
4896
|
if (foregroundTimeout.error) return buildRequestedModeError(effectiveParams, foregroundTimeout.error);
|
|
4320
4897
|
const controlConfig = resolveControlConfig(deps.config.control, effectiveParams.control);
|
|
4321
4898
|
|
|
4322
|
-
const artifactConfig: ArtifactConfig = {
|
|
4899
|
+
const artifactConfig: ArtifactConfig = omitUndefinedProperties({
|
|
4323
4900
|
...DEFAULT_ARTIFACT_CONFIG,
|
|
4324
|
-
enabled: effectiveParams.artifacts
|
|
4901
|
+
enabled: effectiveParams.artifacts !== false,
|
|
4325
4902
|
dir: deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir,
|
|
4326
|
-
};
|
|
4903
|
+
});
|
|
4327
4904
|
const artifactsDir = getArtifactsDir(parentSessionFile, effectiveCwd, artifactConfig.dir);
|
|
4328
4905
|
|
|
4329
4906
|
let sessionRoot: string;
|
|
@@ -4380,15 +4957,48 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4380
4957
|
}, contextPolicy.contextSummary))
|
|
4381
4958
|
: undefined;
|
|
4382
4959
|
|
|
4960
|
+
let missionBinding: MissionLaunchBinding | undefined;
|
|
4961
|
+
let missionWarning: string | undefined;
|
|
4962
|
+
const explicitMission = effectiveParams.missionId !== undefined || effectiveParams.mission !== undefined;
|
|
4963
|
+
try {
|
|
4964
|
+
missionBinding = prepareMissionLaunch({
|
|
4965
|
+
params: effectiveParams,
|
|
4966
|
+
projectRoot: effectiveCwd,
|
|
4967
|
+
...(deps.config.missions ? { config: deps.config.missions } : {}),
|
|
4968
|
+
ownerSessionId: requestSessionId,
|
|
4969
|
+
});
|
|
4970
|
+
} catch (error) {
|
|
4971
|
+
if (explicitMission) return toExecutionErrorResult(effectiveParams, error, contextPolicy.contextSummary);
|
|
4972
|
+
missionWarning = `Mission tracking unavailable: ${error instanceof Error ? error.message : String(error)}`;
|
|
4973
|
+
}
|
|
4974
|
+
|
|
4975
|
+
const attachMission = (result: AgentToolResult<Details>): AgentToolResult<Details> => {
|
|
4976
|
+
if (!missionBinding) return missionWarning ? { ...result, details: { ...result.details, missionWarning } } : result;
|
|
4977
|
+
try {
|
|
4978
|
+
return attachMissionToLaunchResult({ binding: missionBinding, result });
|
|
4979
|
+
} catch (error) {
|
|
4980
|
+
const warning = `Mission tracking unavailable after launch: ${error instanceof Error ? error.message : String(error)}`;
|
|
4981
|
+
if (explicitMission) {
|
|
4982
|
+
return {
|
|
4983
|
+
...result,
|
|
4984
|
+
isError: true,
|
|
4985
|
+
content: [...result.content, { type: "text", text: warning }],
|
|
4986
|
+
details: { ...result.details, missionWarning: warning },
|
|
4987
|
+
};
|
|
4988
|
+
}
|
|
4989
|
+
return { ...result, details: { ...result.details, missionWarning: warning } };
|
|
4990
|
+
}
|
|
4991
|
+
};
|
|
4992
|
+
|
|
4383
4993
|
const reservation = reserveSpawnBudget(
|
|
4384
4994
|
deps.state,
|
|
4385
4995
|
deps.config,
|
|
4386
|
-
|
|
4996
|
+
requestSessionId,
|
|
4387
4997
|
requestedSpawns,
|
|
4388
4998
|
);
|
|
4389
|
-
if (reservation.error) return spawnBudgetErrorResult(reservation.error, foregroundMode);
|
|
4999
|
+
if (reservation.error) return attachMission(spawnBudgetErrorResult(reservation.error, foregroundMode));
|
|
4390
5000
|
|
|
4391
|
-
const execData: ExecutionContextData = {
|
|
5001
|
+
const execData: ExecutionContextData = omitUndefinedProperties({
|
|
4392
5002
|
params: effectiveParams,
|
|
4393
5003
|
effectiveCwd,
|
|
4394
5004
|
ctx,
|
|
@@ -4418,18 +5028,19 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4418
5028
|
contextPolicy,
|
|
4419
5029
|
modelScope,
|
|
4420
5030
|
parentModel: requestParentModel,
|
|
4421
|
-
parentSessionId:
|
|
4422
|
-
|
|
4423
|
-
|
|
5031
|
+
parentSessionId: requestSessionId,
|
|
5032
|
+
parentPiSessionId: requestPiSessionId,
|
|
5033
|
+
capabilityCeiling: resolveCurrentSubagentCapabilityCeiling(requestSessionId),
|
|
5034
|
+
});
|
|
4424
5035
|
|
|
4425
5036
|
const foregroundDescription = effectiveParams.task?.trim()
|
|
4426
5037
|
|| effectiveParams.tasks?.[0]?.task?.trim()
|
|
4427
5038
|
|| (effectiveParams.chain ? firstRawChainTask(effectiveParams.chain)?.trim() : undefined);
|
|
4428
5039
|
const foregroundControl: ForegroundRunControl | undefined = effectiveAsync
|
|
4429
5040
|
? undefined
|
|
4430
|
-
: {
|
|
5041
|
+
: compactOptional<ForegroundRunControl>({
|
|
4431
5042
|
runId,
|
|
4432
|
-
|
|
5043
|
+
sessionId: requestSessionId,
|
|
4433
5044
|
mode: foregroundMode,
|
|
4434
5045
|
startedAt: Date.now(),
|
|
4435
5046
|
updatedAt: Date.now(),
|
|
@@ -4443,7 +5054,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4443
5054
|
schedulingOwners: 1,
|
|
4444
5055
|
nestedRoute,
|
|
4445
5056
|
interrupt: undefined,
|
|
4446
|
-
};
|
|
5057
|
+
});
|
|
4447
5058
|
if (foregroundControl) {
|
|
4448
5059
|
deps.state.foregroundControls.set(runId, foregroundControl);
|
|
4449
5060
|
deps.state.lastForegroundControlId = runId;
|
|
@@ -4463,21 +5074,33 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4463
5074
|
const errorText = result?.isError
|
|
4464
5075
|
? result.content.find((item) => item.type === "text")?.text
|
|
4465
5076
|
: undefined;
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
5077
|
+
let startedLaunches: StaticLaunchSummary[];
|
|
5078
|
+
try {
|
|
5079
|
+
startedLaunches = collectStaticLaunchSummaries({
|
|
5080
|
+
params: effectiveParams,
|
|
5081
|
+
agents,
|
|
5082
|
+
parentModel: requestParentModel,
|
|
5083
|
+
availableModels: ctx.modelRegistry.getAvailable().map(toModelInfo),
|
|
5084
|
+
currentProvider: requestParentModel?.provider,
|
|
5085
|
+
modelScope,
|
|
5086
|
+
thinkingOverrideForTask: forkThinkingOverrideForTask,
|
|
5087
|
+
dynamicFanoutMaxItems: deps.config.chain?.dynamicFanout?.maxItems,
|
|
5088
|
+
});
|
|
5089
|
+
} catch (error) {
|
|
5090
|
+
console.error("Failed to resolve nested foreground launch metadata:", error);
|
|
5091
|
+
startedLaunches = selectedAgentNames.map((agent) => ({ agent }));
|
|
5092
|
+
}
|
|
5093
|
+
const agentsForSummary = startedLaunches.map((launch) => launch.agent);
|
|
4471
5094
|
const leafIntercomTarget = intercomBridge.active && agentsForSummary[0]
|
|
4472
5095
|
? resolveSubagentIntercomTarget(runId, agentsForSummary[0], 0)
|
|
4473
5096
|
: undefined;
|
|
4474
5097
|
try {
|
|
4475
|
-
writeNestedEvent(inheritedNestedRoute, {
|
|
5098
|
+
writeNestedEvent(inheritedNestedRoute, compactOptional<Parameters<typeof writeNestedEvent>[1]>({
|
|
4476
5099
|
type,
|
|
4477
5100
|
ts: now,
|
|
4478
5101
|
parentRunId: nestedParentAddress.parentRunId,
|
|
4479
5102
|
parentStepIndex: nestedParentAddress.parentStepIndex,
|
|
4480
|
-
child: {
|
|
5103
|
+
child: compactOptional<NestedRunSummary>({
|
|
4481
5104
|
id: runId,
|
|
4482
5105
|
parentRunId: nestedParentAddress.parentRunId,
|
|
4483
5106
|
parentStepIndex: nestedParentAddress.parentStepIndex,
|
|
@@ -4491,19 +5114,32 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4491
5114
|
state,
|
|
4492
5115
|
agent: agentsForSummary[0],
|
|
4493
5116
|
agents: agentsForSummary,
|
|
5117
|
+
...(agentsForSummary.length === 1 && (type === "subagent.nested.started" ? startedLaunches[0]?.model : details?.results[0]?.model) ? { model: type === "subagent.nested.started" ? startedLaunches[0]?.model : details?.results[0]?.model } : {}),
|
|
5118
|
+
...(agentsForSummary.length === 1 && (type === "subagent.nested.started" ? startedLaunches[0]?.thinking : details?.results[0]?.thinking) ? { thinking: type === "subagent.nested.started" ? startedLaunches[0]?.thinking : details?.results[0]?.thinking } : {}),
|
|
4494
5119
|
startedAt: foregroundControl?.startedAt ?? now,
|
|
4495
5120
|
...(state !== "running" ? { endedAt: now } : {}),
|
|
4496
5121
|
lastUpdate: now,
|
|
4497
5122
|
...(details?.totalCost ? { totalCost: details.totalCost } : {}),
|
|
4498
5123
|
...(errorText ? { error: errorText } : {}),
|
|
4499
|
-
...(
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
5124
|
+
...(type === "subagent.nested.started"
|
|
5125
|
+
? { steps: startedLaunches.map((launch) => ({
|
|
5126
|
+
agent: launch.agent,
|
|
5127
|
+
status: "running" as const,
|
|
5128
|
+
...(launch.model ? { model: launch.model } : {}),
|
|
5129
|
+
...(launch.thinking ? { thinking: launch.thinking } : {}),
|
|
5130
|
+
})) }
|
|
5131
|
+
: details?.results.length
|
|
5132
|
+
? { steps: details.results.map((child) => ({
|
|
5133
|
+
agent: child.agent,
|
|
5134
|
+
status: child.interrupted || child.detached ? "paused" as const : child.exitCode === 0 ? "complete" as const : "failed" as const,
|
|
5135
|
+
...(child.model ? { model: child.model } : {}),
|
|
5136
|
+
...(child.thinking ? { thinking: child.thinking } : {}),
|
|
5137
|
+
...(child.sessionFile ? { sessionFile: child.sessionFile } : {}),
|
|
5138
|
+
...(child.error ? { error: child.error } : {}),
|
|
5139
|
+
})) }
|
|
5140
|
+
: {}),
|
|
5141
|
+
}),
|
|
5142
|
+
}));
|
|
4507
5143
|
} catch (error) {
|
|
4508
5144
|
console.error("Failed to emit nested foreground status event:", error);
|
|
4509
5145
|
}
|
|
@@ -4512,7 +5148,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4512
5148
|
let nestedForegroundStarted = false;
|
|
4513
5149
|
try {
|
|
4514
5150
|
const asyncResult = runAsyncPath(execData, deps);
|
|
4515
|
-
if (asyncResult) return withResolvedContext(withForkThinkingNotes(asyncResult, forkThinkingDowngrades), contextPolicy.contextSummary);
|
|
5151
|
+
if (asyncResult) return attachMission(withResolvedContext(withForkThinkingNotes(asyncResult, forkThinkingDowngrades), contextPolicy.contextSummary));
|
|
4516
5152
|
if (foregroundControl) {
|
|
4517
5153
|
writeNestedForegroundEvent("subagent.nested.started");
|
|
4518
5154
|
nestedForegroundStarted = true;
|
|
@@ -4520,22 +5156,22 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4520
5156
|
if (hasChain && effectiveParams.chain) {
|
|
4521
5157
|
const result = await runChainPath(execData, deps);
|
|
4522
5158
|
writeNestedForegroundEvent("subagent.nested.completed", result);
|
|
4523
|
-
return withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary);
|
|
5159
|
+
return attachMission(withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary));
|
|
4524
5160
|
}
|
|
4525
5161
|
if (hasTasks && effectiveParams.tasks) {
|
|
4526
5162
|
const result = await runParallelPath(execData, deps);
|
|
4527
5163
|
writeNestedForegroundEvent("subagent.nested.completed", result);
|
|
4528
|
-
return withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary);
|
|
5164
|
+
return attachMission(withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary));
|
|
4529
5165
|
}
|
|
4530
5166
|
if (hasSingle) {
|
|
4531
5167
|
const result = await runSinglePath(execData, deps);
|
|
4532
5168
|
writeNestedForegroundEvent("subagent.nested.completed", result);
|
|
4533
|
-
return withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary);
|
|
5169
|
+
return attachMission(withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary));
|
|
4534
5170
|
}
|
|
4535
5171
|
} catch (error) {
|
|
4536
5172
|
const errorResult = withForkThinkingNotes(toExecutionErrorResult(effectiveParams, error, contextPolicy.contextSummary), forkThinkingDowngrades);
|
|
4537
5173
|
if (nestedForegroundStarted) writeNestedForegroundEvent("subagent.nested.completed", errorResult);
|
|
4538
|
-
return errorResult;
|
|
5174
|
+
return attachMission(errorResult);
|
|
4539
5175
|
} finally {
|
|
4540
5176
|
if (foregroundControl) {
|
|
4541
5177
|
settleForegroundSchedulingOwner(foregroundControl);
|
|
@@ -4593,5 +5229,23 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4593
5229
|
return execute(id, delegatedParams, signal, onUpdate, ctx);
|
|
4594
5230
|
};
|
|
4595
5231
|
|
|
4596
|
-
|
|
5232
|
+
const executeScheduled = (
|
|
5233
|
+
id: string,
|
|
5234
|
+
params: SubagentParamsLike,
|
|
5235
|
+
signal: AbortSignal,
|
|
5236
|
+
ctx: ExtensionContext,
|
|
5237
|
+
) => {
|
|
5238
|
+
const ownerSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
5239
|
+
let ownerExecutor = scheduledOwnerExecutors.get(ownerSessionId);
|
|
5240
|
+
if (!ownerExecutor) {
|
|
5241
|
+
ownerExecutor = createSubagentExecutor({
|
|
5242
|
+
...deps,
|
|
5243
|
+
state: createScheduledOwnerState(deps.state, ownerSessionId, ctx),
|
|
5244
|
+
});
|
|
5245
|
+
scheduledOwnerExecutors.set(ownerSessionId, ownerExecutor);
|
|
5246
|
+
}
|
|
5247
|
+
return ownerExecutor.execute(id, params, signal, undefined, ctx);
|
|
5248
|
+
};
|
|
5249
|
+
|
|
5250
|
+
return { execute: executeWithSingleDispatchGuard, executeDelegated, executeScheduled };
|
|
4597
5251
|
}
|