@selesai/code 0.13.40 → 0.14.3
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 +3 -0
- package/dist/bun/runtime-setup.js +4 -1
- package/dist/cli/args.d.ts +3 -1
- package/dist/cli/args.js +76 -33
- package/dist/cli/auth-check.d.ts +18 -0
- package/dist/cli/auth-check.js +49 -0
- package/dist/cli/credential-print.d.ts +5 -15
- package/dist/cli/credential-print.js +42 -82
- package/dist/cli/file-processor.d.ts +1 -1
- package/dist/cli/file-processor.js +2 -1
- package/dist/cli/list-models.d.ts +1 -1
- package/dist/cli/list-models.js +2 -2
- package/dist/cli/startup-ui.js +38 -30
- package/dist/config.d.ts +45 -7
- package/dist/config.js +134 -18
- package/dist/core/agent-session-custom-tools.test.js +64 -0
- package/dist/core/agent-session-length-continuation.test.js +7 -3
- package/dist/core/agent-session-runtime.js +2 -2
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.js +14 -0
- package/dist/core/agent-session.d.ts +180 -40
- package/dist/core/agent-session.js +1061 -485
- package/dist/core/auth-storage.d.ts +25 -15
- package/dist/core/auth-storage.js +242 -66
- package/dist/core/bash-executor.js +42 -52
- package/dist/core/bug-report.js +1 -1
- package/dist/core/cache-warmer.d.ts +1 -0
- package/dist/core/cache-warmer.js +15 -1
- package/dist/core/compaction/branch-summarization.js +3 -0
- package/dist/core/compaction/compaction.d.ts +3 -1
- package/dist/core/compaction/compaction.js +156 -79
- package/dist/core/compaction/utils.d.ts +2 -1
- package/dist/core/compaction/utils.js +25 -18
- package/dist/core/crash-log.d.ts +5 -0
- package/dist/core/crash-log.js +69 -0
- package/dist/core/defaults.d.ts +1 -1
- package/dist/core/defaults.js +1 -1
- package/dist/core/export-html/template.css +10 -0
- package/dist/core/export-html/template.js +72 -18
- package/dist/core/export-html/tool-renderer.d.ts +3 -3
- package/dist/core/export-html/tool-renderer.js +5 -3
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/loader.js +138 -55
- package/dist/core/extensions/runner.d.ts +38 -5
- package/dist/core/extensions/runner.js +220 -7
- package/dist/core/extensions/types.d.ts +438 -51
- package/dist/core/extensions/types.js +3 -0
- package/dist/core/extensions/virtual-modules.js +6 -0
- package/dist/core/extensions/wrapper.d.ts +2 -2
- package/dist/core/extensions/wrapper.js +3 -3
- package/dist/core/footer-data-provider.d.ts +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/handoff.d.ts +0 -1
- package/dist/core/handoff.js +0 -1
- package/dist/core/http-dispatcher.js +5 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/keybindings.d.ts +25 -24
- package/dist/core/keybindings.js +27 -6
- package/dist/core/mcp-servers.d.ts +134 -0
- package/dist/core/mcp-servers.js +223 -0
- package/dist/core/model-config.d.ts +122 -5
- package/dist/core/model-config.js +35 -1
- package/dist/core/model-registry.d.ts +23 -15
- package/dist/core/model-registry.js +46 -22
- package/dist/core/model-resolver.d.ts +6 -5
- package/dist/core/model-resolver.js +51 -21
- package/dist/core/model-runtime.d.ts +73 -14
- package/dist/core/model-runtime.js +398 -104
- package/dist/core/models-store.d.ts +12 -7
- package/dist/core/models-store.js +85 -15
- package/dist/core/nested-tool-calls.d.ts +102 -0
- package/dist/core/nested-tool-calls.js +178 -0
- package/dist/core/package-manager.d.ts +8 -1
- package/dist/core/package-manager.js +144 -61
- package/dist/core/package-manager.test.js +5 -5
- package/dist/core/pi-manifest.d.ts +9 -0
- package/dist/core/pi-manifest.js +25 -0
- package/dist/core/prompt-templates.d.ts +6 -1
- package/dist/core/prompt-templates.js +61 -35
- package/dist/core/provider-composer.d.ts +44 -19
- package/dist/core/provider-composer.js +166 -64
- package/dist/core/radius.d.ts +2 -0
- package/dist/core/radius.js +2 -0
- package/dist/core/remote-catalog-provider.d.ts +8 -1
- package/dist/core/remote-catalog-provider.js +25 -13
- package/dist/core/resource-loader.d.ts +9 -1
- package/dist/core/resource-loader.js +179 -45
- package/dist/core/runtime-credentials.d.ts +5 -5
- package/dist/core/runtime-credentials.js +11 -8
- package/dist/core/sdk.d.ts +16 -7
- package/dist/core/sdk.js +57 -24
- package/dist/core/session-manager.d.ts +45 -9
- package/dist/core/session-manager.js +124 -31
- package/dist/core/settings-diagnostics.d.ts +8 -0
- package/dist/core/settings-diagnostics.js +20 -0
- package/dist/core/settings-manager.d.ts +62 -32
- package/dist/core/settings-manager.js +147 -69
- package/dist/core/skills.d.ts +5 -2
- package/dist/core/skills.js +58 -35
- package/dist/core/slash-commands.js +2 -1
- package/dist/core/source-info.d.ts +8 -0
- package/dist/core/source-info.js +16 -0
- package/dist/core/system-prompt.d.ts +9 -3
- package/dist/core/system-prompt.js +9 -12
- package/dist/core/system-prompt.test.js +2 -7
- package/dist/core/tools/bash.d.ts +12 -0
- package/dist/core/tools/bash.js +33 -2
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.js +2 -5
- package/dist/core/tools/edit.d.ts +4 -0
- package/dist/core/tools/edit.js +31 -11
- package/dist/core/tools/find.d.ts +7 -0
- package/dist/core/tools/find.js +16 -19
- package/dist/core/tools/grep.d.ts +4 -0
- package/dist/core/tools/grep.js +5 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.js +11 -2
- package/dist/core/tools/ls.d.ts +4 -0
- package/dist/core/tools/ls.js +5 -1
- package/dist/core/tools/output-accumulator.d.ts +11 -0
- package/dist/core/tools/output-accumulator.js +40 -10
- package/dist/core/tools/read.d.ts +17 -2
- package/dist/core/tools/read.js +23 -2
- package/dist/core/tools/render-utils.d.ts +6 -0
- package/dist/core/tools/render-utils.js +26 -0
- package/dist/core/tools/renderers/bash.js +19 -35
- package/dist/core/tools/renderers/edit.js +5 -4
- package/dist/core/tools/renderers/index.d.ts +2 -2
- package/dist/core/tools/renderers/read.js +3 -2
- package/dist/core/tools/tool-definition-wrapper.d.ts +5 -3
- package/dist/core/tools/tool-definition-wrapper.js +3 -1
- package/dist/core/tools/truncate.d.ts +14 -0
- package/dist/core/tools/truncate.js +29 -0
- package/dist/core/tools/write.d.ts +4 -0
- package/dist/core/tools/write.js +6 -2
- package/dist/core/trust-manager.js +3 -1
- package/dist/core/usage-totals.d.ts +2 -0
- package/dist/core/usage-totals.js +23 -0
- package/dist/core/virtual-models.d.ts +116 -0
- package/dist/core/virtual-models.js +123 -0
- package/dist/defaults/models.json +32 -0
- package/dist/defaults/settings.json +1 -9
- package/dist/extensions/codemode/execute.d.ts +15 -0
- package/dist/extensions/codemode/execute.js +645 -0
- package/dist/extensions/codemode/execute.lazy.d.ts +2 -0
- package/dist/extensions/codemode/execute.lazy.js +2 -0
- package/dist/extensions/codemode/index.d.ts +20 -0
- package/dist/extensions/codemode/index.js +31 -0
- package/dist/extensions/codemode/renderer.d.ts +11 -0
- package/dist/extensions/codemode/renderer.js +136 -0
- package/dist/extensions/codemode/tool.d.ts +129 -0
- package/dist/extensions/codemode/tool.js +275 -0
- package/dist/extensions/context-compaction-reminder.ts +1 -1
- package/dist/extensions/grep-app/index.ts +2 -10
- package/dist/extensions/herdr-agent-state.ts +1 -1
- package/dist/extensions/{pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/index.d.ts → index.d.ts} +0 -1
- package/dist/extensions/index.js +12 -0
- package/dist/extensions/jev/classifier-context.ts +54 -0
- package/dist/extensions/jev/classifier.test.ts +150 -0
- package/dist/extensions/jev/classifier.ts +191 -0
- package/dist/extensions/jev/decisions.test.ts +56 -47
- package/dist/extensions/jev/decisions.ts +94 -109
- package/dist/extensions/jev/test-support.ts +33 -38
- package/dist/extensions/jev-advisory-lifecycle.test.ts +12 -12
- package/dist/extensions/jev-advisory-memory.test.ts +9 -9
- package/dist/extensions/jev-advisory-recommendations.test.ts +8 -8
- package/dist/extensions/jev-ask-tool.test.ts +41 -45
- package/dist/extensions/jev-ask-tool.ts +11 -39
- package/dist/extensions/jev-find-source.test.ts +26 -0
- package/dist/extensions/jev-find-source.ts +58 -19
- package/dist/extensions/jev-tool-ranker.test.ts +185 -0
- package/dist/extensions/jev-tool-ranker.ts +169 -0
- package/dist/{core → extensions}/llama/client.d.ts +2 -0
- package/dist/{core → extensions}/llama/client.js +7 -3
- package/dist/{core → extensions}/llama/index.js +13 -2
- package/dist/{core → extensions}/llama/provider.d.ts +1 -1
- package/dist/extensions/llama/provider.js +235 -0
- package/dist/extensions/mcp/cli.d.ts +20 -0
- package/dist/extensions/mcp/cli.js +496 -0
- package/dist/extensions/mcp/cli.lazy.d.ts +2 -0
- package/dist/extensions/mcp/cli.lazy.js +2 -0
- package/dist/extensions/mcp/config.d.ts +83 -0
- package/dist/extensions/mcp/config.js +193 -0
- package/dist/extensions/mcp/index.d.ts +78 -0
- package/dist/extensions/mcp/index.js +1201 -0
- package/dist/extensions/mcp/log.d.ts +15 -0
- package/dist/extensions/mcp/log.js +65 -0
- package/dist/extensions/mcp/oauth.d.ts +97 -0
- package/dist/extensions/mcp/oauth.js +401 -0
- package/dist/extensions/mcp/resources.d.ts +41 -0
- package/dist/extensions/mcp/resources.js +260 -0
- package/dist/extensions/mcp/runtime.d.ts +96 -0
- package/dist/extensions/mcp/runtime.js +412 -0
- package/dist/extensions/mcp/runtime.lazy.d.ts +2 -0
- package/dist/extensions/mcp/runtime.lazy.js +2 -0
- package/dist/extensions/mcp/tools.d.ts +86 -0
- package/dist/extensions/mcp/tools.js +252 -0
- package/dist/extensions/mcp/ui.d.ts +59 -0
- package/dist/extensions/mcp/ui.js +185 -0
- package/dist/extensions/package.json +2 -1
- package/dist/extensions/pi-graft/index.ts +4 -19
- package/dist/extensions/pi-graft/lifecycle.test.ts +32 -25
- package/dist/extensions/pi-graft/tools.ts +6 -0
- package/dist/extensions/pi-hermes-memory/CHANGELOG.md +25 -0
- package/dist/extensions/pi-hermes-memory/README.md +140 -4
- package/dist/extensions/pi-hermes-memory/package-lock.json +624 -2720
- package/dist/extensions/pi-hermes-memory/package.json +9 -7
- package/dist/extensions/pi-hermes-memory/scripts/benchmark-memory-startup.mjs +72 -0
- package/dist/extensions/pi-hermes-memory/scripts/check-production-install.mjs +107 -0
- package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +2 -1
- package/dist/extensions/pi-hermes-memory/src/config.ts +35 -0
- package/dist/extensions/pi-hermes-memory/src/constants.ts +62 -15
- package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +374 -50
- package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +7 -4
- package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +19 -14
- package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +75 -1
- package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +322 -22
- package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +8 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +193 -54
- package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +6 -2
- package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +33 -5
- package/dist/extensions/pi-hermes-memory/src/index.ts +116 -47
- package/dist/extensions/pi-hermes-memory/src/memory-initialization.ts +101 -0
- package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +10 -2
- package/dist/extensions/pi-hermes-memory/src/store/db.ts +34 -9
- package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +44 -8
- package/dist/extensions/pi-hermes-memory/src/store/schema.ts +3 -1
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +141 -0
- package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +17 -6
- package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +20 -10
- package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +1 -17
- package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +2 -10
- package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +4 -8
- package/dist/extensions/pi-hermes-memory/src/types.ts +48 -0
- package/dist/extensions/pi-hermes-memory/tests/config.test.ts +108 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +1185 -42
- package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +57 -1
- package/dist/extensions/pi-hermes-memory/tests/handlers/lazy-memory-hooks.test.ts +128 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +844 -1
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +16 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +512 -3
- package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +38 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +183 -2
- package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +1 -3
- package/dist/extensions/pi-hermes-memory/tests/index.test.ts +17 -0
- package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +21 -0
- package/dist/extensions/pi-hermes-memory/tests/lazy-startup.test.ts +313 -0
- package/dist/extensions/pi-hermes-memory/tests/memory-initialization.test.ts +182 -0
- package/dist/extensions/pi-hermes-memory/tests/prompt-injection.test.ts +184 -0
- package/dist/extensions/pi-hermes-memory/tests/skill-discovery-contract.test.ts +60 -0
- package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-lazy-probe.test.ts +80 -0
- package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +2 -0
- package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +79 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +268 -0
- package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +29 -0
- package/dist/extensions/pi-hermes-memory/tests/store/usage-tracking.test.ts +170 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +80 -1
- package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +51 -0
- package/dist/extensions/pi-intercom/CHANGELOG.md +66 -0
- package/dist/extensions/pi-intercom/README.md +100 -12
- package/dist/extensions/pi-intercom/broker/broker.ts +28 -12
- package/dist/extensions/pi-intercom/broker/client.ts +3 -0
- package/dist/extensions/pi-intercom/broker/cross-machine-provenance.test.ts +63 -0
- package/dist/extensions/pi-intercom/broker/protocol.ts +64 -0
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +58 -167
- package/dist/extensions/pi-intercom/broker/spawn.ts +40 -87
- package/dist/extensions/pi-intercom/cli.mjs +6 -0
- package/dist/extensions/pi-intercom/cli.test.ts +428 -0
- package/dist/extensions/pi-intercom/cli.ts +343 -0
- package/dist/extensions/pi-intercom/config.test.ts +61 -1
- package/dist/extensions/pi-intercom/config.ts +53 -2
- package/dist/extensions/pi-intercom/cross-machine-discovery.test.ts +218 -0
- package/dist/extensions/pi-intercom/cross-machine-discovery.ts +140 -0
- package/dist/extensions/pi-intercom/cross-machine-envelope.test.ts +106 -0
- package/dist/extensions/pi-intercom/cross-machine-envelope.ts +92 -0
- package/dist/extensions/pi-intercom/cross-machine-integration.test.ts +25 -0
- package/dist/extensions/pi-intercom/cross-machine-transport.test.ts +106 -0
- package/dist/extensions/pi-intercom/cross-machine-transport.ts +110 -0
- package/dist/extensions/pi-intercom/extension-api.ts +14 -0
- package/dist/extensions/pi-intercom/handover.test.ts +88 -0
- package/dist/extensions/pi-intercom/handover.ts +115 -0
- package/dist/extensions/pi-intercom/herdr-location.test.ts +173 -0
- package/dist/extensions/pi-intercom/herdr-location.ts +137 -0
- package/dist/extensions/pi-intercom/human-priority.pi.test.ts +489 -0
- package/dist/extensions/pi-intercom/index.ts +582 -164
- package/dist/extensions/pi-intercom/intercom.integration.test.ts +590 -22
- package/dist/extensions/pi-intercom/package.json +12 -2
- package/dist/extensions/pi-intercom/project-agent.ts +1 -1
- package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +26 -2
- package/dist/extensions/pi-intercom/test/handover-picker.test.ts +134 -0
- package/dist/extensions/pi-intercom/test/inline-message.test.ts +43 -0
- package/dist/extensions/pi-intercom/types.d.ts +247 -0
- package/dist/extensions/pi-intercom/types.js +2 -0
- package/dist/extensions/pi-intercom/types.ts +39 -1
- package/dist/extensions/pi-intercom/ui/handover-picker.ts +318 -0
- package/dist/extensions/pi-intercom/ui/inline-message.ts +10 -3
- package/dist/extensions/pi-intercom/ui/session-list.ts +28 -15
- package/dist/extensions/pi-subagents/.github/workflows/release.yml +5 -1
- package/dist/extensions/pi-subagents/.github/workflows/test.yml +188 -18
- package/dist/extensions/pi-subagents/CHANGELOG.md +514 -1
- package/dist/extensions/pi-subagents/README.md +7 -5
- package/dist/extensions/pi-subagents/VISION.md +6 -0
- package/dist/extensions/pi-subagents/agents/reviewer.md +7 -5
- package/dist/extensions/pi-subagents/agents/worker.md +1 -1
- package/dist/extensions/pi-subagents/docs/agents.md +75 -35
- package/dist/extensions/pi-subagents/docs/configuration.md +156 -25
- package/dist/extensions/pi-subagents/docs/extension-api.md +113 -29
- package/dist/extensions/pi-subagents/docs/missions.md +46 -14
- package/dist/extensions/pi-subagents/docs/models.md +22 -84
- package/dist/extensions/pi-subagents/docs/observability.md +49 -24
- package/dist/extensions/pi-subagents/docs/standalone-background.md +59 -0
- package/dist/extensions/pi-subagents/docs/tool-reference.md +167 -116
- package/dist/extensions/pi-subagents/docs/watchdog.md +41 -10
- package/dist/extensions/pi-subagents/docs/workflows.md +239 -163
- package/dist/extensions/pi-subagents/examples/typed-gate/.pi/agents/classifier.md +14 -0
- package/dist/extensions/pi-subagents/examples/typed-gate/README.md +42 -0
- package/dist/extensions/pi-subagents/examples/typed-gate/classify +38 -0
- package/dist/extensions/pi-subagents/examples/typed-gate/workflow.js +32 -0
- package/dist/extensions/pi-subagents/index.ts +11 -3
- package/dist/extensions/pi-subagents/inspector-runner.mjs +3 -3
- package/dist/extensions/pi-subagents/package-lock.json +517 -1129
- package/dist/extensions/pi-subagents/package.json +22 -11
- package/dist/extensions/pi-subagents/prompts/council.md +7 -4
- package/dist/extensions/pi-subagents/prompts/parallel-review.md +2 -2
- package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
- package/dist/extensions/pi-subagents/runner-peer-loader.mjs +21 -0
- package/dist/extensions/pi-subagents/runner-peer-preload.mjs +30 -0
- package/dist/extensions/pi-subagents/scripts/build-package.mjs +79 -0
- package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +2 -2
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +46 -27
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +11 -7
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +78 -73
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +4 -5
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +10 -2
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +69 -67
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/review-and-validation.md +3 -3
- package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +21 -10
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +113 -113
- package/dist/extensions/pi-subagents/src/agents/agent-memory.ts +91 -4
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +15 -9
- package/dist/extensions/pi-subagents/src/agents/agents.ts +432 -193
- package/dist/extensions/pi-subagents/src/agents/chain-serializer.ts +6 -1
- package/dist/extensions/pi-subagents/src/agents/global-npm-root.ts +58 -0
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +5 -2
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +22 -18
- package/dist/extensions/pi-subagents/src/agents/skills.ts +43 -10
- package/dist/extensions/pi-subagents/src/api/delegation.ts +20 -1
- package/dist/extensions/pi-subagents/src/api/inspectors.ts +27 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +140 -62
- package/dist/extensions/pi-subagents/src/api/required-child-extensions.ts +6 -0
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +24 -40
- package/dist/extensions/pi-subagents/src/extension/control-notices.ts +4 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +18 -15
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +87 -13
- package/dist/extensions/pi-subagents/src/extension/herdr-pi-bridge.ts +162 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +280 -268
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +76 -37
- package/dist/extensions/pi-subagents/src/extension/reply-workflow-script.ts +67 -0
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +34 -11
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +116 -205
- package/dist/extensions/pi-subagents/src/extension/subagent-guide.ts +13 -5
- package/dist/extensions/pi-subagents/src/extension/tool-activation.ts +146 -0
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +77 -90
- package/dist/extensions/pi-subagents/src/extension/upgrade-notice.ts +40 -0
- package/dist/extensions/pi-subagents/src/inspectors/actions.ts +148 -0
- package/dist/extensions/pi-subagents/src/inspectors/ghostty/actions.ts +74 -0
- package/dist/extensions/pi-subagents/src/inspectors/ghostty/plugin.ts +29 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +100 -180
- package/dist/extensions/pi-subagents/src/inspectors/herdr/plugin.ts +20 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -2
- package/dist/extensions/pi-subagents/src/inspectors/{herdr/inspector-runner.ts → inspector-runner.ts} +13 -13
- package/dist/extensions/pi-subagents/src/inspectors/plugins.ts +75 -0
- package/dist/extensions/pi-subagents/src/inspectors/{herdr/session-roots-codec.ts → session-roots-codec.ts} +4 -15
- package/dist/extensions/pi-subagents/src/inspectors/{herdr/shell-command.ts → shell-command.ts} +1 -1
- package/dist/extensions/pi-subagents/src/inspectors/types.ts +51 -0
- package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +38 -53
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +53 -9
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +69 -55
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +7 -2
- package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +45 -32
- package/dist/extensions/pi-subagents/src/missions/store.ts +11 -2
- package/dist/extensions/pi-subagents/src/policy/authority.ts +5 -1
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +30 -18
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +59 -9
- package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +18 -2
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +463 -248
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +106 -66
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +33 -20
- package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +47 -17
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -5
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +24 -11
- package/dist/extensions/pi-subagents/src/runs/background/await-async-run.ts +78 -0
- package/dist/extensions/pi-subagents/src/runs/background/binary-bootstrap.ts +66 -0
- package/dist/extensions/pi-subagents/src/runs/background/calendar-schedule.ts +90 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +19 -38
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +62 -3
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +82 -10
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +259 -21
- package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +30 -3
- package/dist/extensions/pi-subagents/src/runs/background/pid-namespace.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal-candidate.ts +98 -0
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +18 -97
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +14 -5
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +66 -12
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +4 -3
- package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +126 -45
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +11 -6
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +18 -7
- package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +43 -51
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +8 -1
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/background/runner-http-dispatcher.ts +119 -0
- package/dist/extensions/pi-subagents/src/runs/background/runner-startup-failure.ts +56 -0
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +233 -69
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +67 -16
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +21 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner-bootstrap.ts +276 -0
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +592 -573
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +177 -29
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +77 -28
- package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +10 -4
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +7 -13
- package/dist/extensions/pi-subagents/src/runs/background/workflow-terminal-proof.ts +41 -23
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +19 -8
- package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +130 -7
- package/dist/extensions/pi-subagents/src/runs/foreground/command-action.ts +41 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +267 -385
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +4 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +6 -10
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1158 -413
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +200 -74
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +133 -34
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +6 -1
- package/dist/extensions/pi-subagents/src/runs/shared/child-commands.ts +228 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +18 -18
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +16 -4
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +55 -12
- package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +6 -3
- package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +11 -1
- package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +367 -74
- package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +50 -86
- package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +288 -0
- package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
- package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +5 -5
- package/dist/extensions/pi-subagents/src/runs/shared/effective-system-prompt.ts +33 -0
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +49 -10
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +61 -9
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +16 -9
- package/dist/extensions/pi-subagents/src/runs/shared/external-job-bridge.ts +55 -1
- package/dist/extensions/pi-subagents/src/runs/shared/git-environment.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/herdr-connection.ts +134 -0
- package/dist/extensions/pi-subagents/src/runs/shared/herdr-external-adapters.ts +169 -0
- package/dist/extensions/pi-subagents/src/runs/shared/herdr-machine.ts +279 -0
- package/dist/extensions/pi-subagents/src/runs/shared/herdr-pi-protocol.ts +59 -0
- package/dist/extensions/pi-subagents/src/runs/shared/herdr-placed-run.ts +263 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +6 -2
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +108 -13
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +23 -7
- package/dist/extensions/pi-subagents/src/runs/shared/model-resolution-diagnostic.ts +76 -0
- package/dist/extensions/pi-subagents/src/runs/shared/{model-fallback.ts → model-resolution.ts} +65 -245
- package/dist/extensions/pi-subagents/src/runs/shared/model-scope.ts +30 -11
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +24 -3
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +55 -7
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +14 -4
- package/dist/extensions/pi-subagents/src/runs/shared/partial-output.ts +48 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +12 -4
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +88 -1
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +12 -3
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +160 -9
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +35 -34
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +58 -19
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +21 -0
- package/dist/extensions/pi-subagents/src/runs/shared/usage-reconciliation.ts +73 -0
- package/dist/extensions/pi-subagents/src/runs/shared/workflow-async-child-guidance.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-apply.ts +160 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +42 -20
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-lock.ts +29 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +27 -4
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +94 -26
- package/dist/extensions/pi-subagents/src/shared/child-cache-retention.ts +43 -0
- package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +5 -3
- package/dist/extensions/pi-subagents/src/shared/disabled-features.ts +123 -0
- package/dist/extensions/pi-subagents/src/shared/extension-context.ts +14 -1
- package/dist/extensions/pi-subagents/src/shared/file-lease.ts +74 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +27 -77
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +70 -10
- package/dist/extensions/pi-subagents/src/shared/model-info.ts +10 -1
- package/dist/extensions/pi-subagents/src/shared/opencode-session-headers.ts +30 -0
- package/dist/extensions/pi-subagents/src/shared/package-version.ts +17 -0
- package/dist/extensions/pi-subagents/src/shared/parent-wake.ts +66 -0
- package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +71 -58
- package/dist/extensions/pi-subagents/src/shared/required-child-extensions.ts +115 -0
- package/dist/extensions/pi-subagents/src/shared/settings-file-lease.ts +36 -0
- package/dist/extensions/pi-subagents/src/shared/settings.ts +7 -4
- package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +1 -5
- package/dist/extensions/pi-subagents/src/shared/types.ts +146 -48
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +28 -2
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +15 -1
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +19 -4
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +13 -2
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +15 -15
- package/dist/extensions/pi-subagents/src/slash/subagent-cost.ts +46 -9
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +29 -16
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +201 -26
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +33 -16
- package/dist/extensions/pi-subagents/src/tui/render.ts +334 -103
- package/dist/extensions/pi-subagents/src/tui/running-tone.ts +28 -0
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +27 -28
- package/dist/extensions/pi-subagents/src/watchdog/diff-tool.ts +47 -12
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +2 -2
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +22 -2
- package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +17 -17
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +24 -8
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +43 -39
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +2 -2
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +127 -78
- package/dist/extensions/pi-subagents/src/watchdog/rules.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +107 -31
- package/dist/extensions/pi-subagents/src/watchdog/scope.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +22 -14
- package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +14 -13
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +35 -6
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +6 -4
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +2 -2
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +500 -65
- package/dist/extensions/pi-subagents/src/workflows/structured-workflow-scripts.ts +177 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +8 -2
- package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +5 -3
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +70 -10
- package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +57 -18
- package/dist/extensions/pi-subagents/src/workflows/workflow-reuse.ts +120 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-revival.ts +123 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +5 -2
- package/dist/extensions/pi-subagents/test/fixtures/cwd-workflow-child.ts +37 -0
- package/dist/extensions/pi-subagents/test/fixtures/herdr-allocation-lock-child.ts +16 -0
- package/dist/extensions/pi-subagents/test/fixtures/herdr-provision-child.ts +15 -0
- package/dist/extensions/pi-subagents/test/fixtures/native-nested-wait-provider.ts +76 -0
- package/dist/extensions/pi-subagents/test/fixtures/runner-bootstrap-harness.ts +36 -0
- package/dist/extensions/pi-subagents/test/fixtures/schedule-history-writer.mjs +48 -0
- package/dist/extensions/pi-subagents/test/fixtures/settings-race-writer.mjs +57 -0
- package/dist/extensions/pi-subagents/test/fixtures/workflow-cwd-access-failure.ts +33 -0
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +40 -7
- package/dist/extensions/pi-subagents/test/integration/async-attention-clearing.test.ts +9 -8
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +435 -276
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +435 -397
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +918 -497
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +264 -17
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +185 -22
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +3 -2
- package/dist/extensions/pi-subagents/test/integration/claude-code-dispatch.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/integration/deadline-checkpoint.test.ts +126 -0
- package/dist/extensions/pi-subagents/test/integration/doctor-executor.test.ts +29 -1
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +88 -0
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +450 -13
- package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +10 -6
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +105 -86
- package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +403 -18
- package/dist/extensions/pi-subagents/test/integration/inline-workflow-visibility.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +195 -10
- package/dist/extensions/pi-subagents/test/integration/model-resolution-diagnostic.test.ts +108 -0
- package/dist/extensions/pi-subagents/test/integration/nested-async-wait.test.ts +61 -0
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +5 -4
- package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +6 -4
- package/dist/extensions/pi-subagents/test/integration/render-widget-mouse.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +242 -16
- package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +158 -4
- package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +1435 -248
- package/dist/extensions/pi-subagents/test/integration/single-execution.part-2.test.ts +454 -515
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +140 -21
- package/dist/extensions/pi-subagents/test/integration/structured-workflows.test.ts +105 -0
- package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +90 -11
- package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +18 -15
- package/dist/extensions/pi-subagents/test/integration/workflow-worktree-admission.test.ts +100 -0
- package/dist/extensions/pi-subagents/test/smoke/clean-install.mjs +106 -0
- package/dist/extensions/pi-subagents/test/smoke/npm-background.mjs +43 -0
- package/dist/extensions/pi-subagents/test/smoke/packed-runner-selection.mjs +42 -0
- package/dist/extensions/pi-subagents/test/smoke/runner-loader-capability.mjs +50 -0
- package/dist/extensions/pi-subagents/test/smoke/sdk-child.ts +57 -0
- package/dist/extensions/pi-subagents/test/smoke/{pi085-extension.ts → sdk-extension.ts} +2 -2
- package/dist/extensions/pi-subagents/test/smoke/standalone-background.mjs +140 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-fault.ts +43 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-matrix.mjs +65 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-observer.ts +8 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-parent.ts +220 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-provider.ts +58 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-release.json +8 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-revival.ts +109 -0
- package/dist/extensions/pi-subagents/test/smoke/standalone-shared.ts +79 -0
- package/dist/extensions/pi-subagents/test/smoke/tool-activation.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +6 -25
- package/dist/extensions/pi-subagents/test/support/async-result-timeout-evidence.ts +61 -0
- package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +122 -9
- package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +15 -7
- package/dist/extensions/pi-subagents/test/support/helpers.ts +11 -14
- package/dist/extensions/pi-subagents/test/support/isolated-temp-root.mjs +21 -3
- package/dist/extensions/pi-subagents/test/support/native-peer-loader.mjs +15 -0
- package/dist/extensions/pi-subagents/test/support/node-command.ts +29 -6
- package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +5 -3
- package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +7 -15
- package/dist/extensions/pi-subagents/test/support/watchdog-stable-host-loader.mjs +23 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +158 -155
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +52 -1
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +21 -17
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +105 -36
- package/dist/extensions/pi-subagents/test/unit/advertisement-barrier.test.ts +151 -0
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -2
- package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +33 -3
- package/dist/extensions/pi-subagents/test/unit/agent-end-auto-drain.test.ts +149 -0
- package/dist/extensions/pi-subagents/test/unit/agent-exclude-dirs.test.ts +246 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +62 -87
- package/dist/extensions/pi-subagents/test/unit/agent-global-root-override.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +398 -48
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +126 -1
- package/dist/extensions/pi-subagents/test/unit/agent-name-resolution.test.ts +75 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +94 -42
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +73 -3
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +428 -2
- package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +112 -1
- package/dist/extensions/pi-subagents/test/unit/async-result-timeout-evidence.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +92 -4
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +58 -6
- package/dist/extensions/pi-subagents/test/unit/async-run-history.test.ts +123 -0
- package/dist/extensions/pi-subagents/test/unit/async-spawn-package-dir.test.ts +203 -0
- package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +26 -35
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +185 -0
- package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +9 -1
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +106 -1
- package/dist/extensions/pi-subagents/test/unit/await-async-run.test.ts +202 -0
- package/dist/extensions/pi-subagents/test/unit/binary-async-spawn.test.ts +115 -0
- package/dist/extensions/pi-subagents/test/unit/binary-pi-spawn.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/calendar-schedule.test.ts +70 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +38 -0
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +10 -2
- package/dist/extensions/pi-subagents/test/unit/changelog-format.test.ts +11 -0
- package/dist/extensions/pi-subagents/test/unit/child-cache-retention.test.ts +87 -0
- package/dist/extensions/pi-subagents/test/unit/child-commands.test.ts +243 -0
- package/dist/extensions/pi-subagents/test/unit/child-external-job-bridge.test.ts +126 -0
- package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +12 -1
- package/dist/extensions/pi-subagents/test/unit/child-lifecycle.test.ts +36 -0
- package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +24 -0
- package/dist/extensions/pi-subagents/test/unit/child-session-commands.test.ts +162 -0
- package/dist/extensions/pi-subagents/test/unit/child-session-host-sdk.test.ts +226 -0
- package/dist/extensions/pi-subagents/test/unit/child-session-parent-providers.test.ts +200 -0
- package/dist/extensions/pi-subagents/test/unit/child-session-queued.test.ts +260 -0
- package/dist/extensions/pi-subagents/test/unit/child-tool-plan-permission-system.test.ts +3 -98
- package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +222 -1
- package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +314 -0
- package/dist/extensions/pi-subagents/test/unit/claude-code-dispatch.test.ts +182 -0
- package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +157 -0
- package/dist/extensions/pi-subagents/test/unit/command-action.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +25 -11
- package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +7 -1
- package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +220 -0
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +104 -32
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +138 -1
- package/dist/extensions/pi-subagents/test/unit/disabled-features.test.ts +227 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +48 -9
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +7 -4
- package/dist/extensions/pi-subagents/test/unit/extension-lazy-loading.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/extension-maintenance-lifecycle.test.ts +66 -0
- package/dist/extensions/pi-subagents/test/unit/extension-module-preload.test.ts +49 -0
- package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +104 -3
- package/dist/extensions/pi-subagents/test/unit/file-lease.test.ts +17 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +316 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +58 -7
- package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +25 -96
- package/dist/extensions/pi-subagents/test/unit/ghostty-inspector.test.ts +92 -0
- package/dist/extensions/pi-subagents/test/unit/global-npm-root.test.ts +108 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-connection.test.ts +43 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-external-adapters.test.ts +89 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +11 -20
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +113 -19
- package/dist/extensions/pi-subagents/test/unit/herdr-machine.test.ts +161 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-native-placement.test.ts +187 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +7 -12
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +182 -87
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +68 -49
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +295 -135
- package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/inspector-authority-policy.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/unit/inspector-registration.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +74 -1
- package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-resolution.test.ts +112 -0
- package/dist/extensions/pi-subagents/test/unit/mission-global-projection.test.ts +215 -0
- package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +65 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +2 -1
- package/dist/extensions/pi-subagents/test/unit/model-resolution-diagnostic.test.ts +78 -0
- package/dist/extensions/pi-subagents/test/unit/model-resolution.test.ts +153 -0
- package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +43 -1
- package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +1 -21
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +279 -2
- package/dist/extensions/pi-subagents/test/unit/nested-control-fanout.test.ts +73 -0
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +297 -3
- package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +431 -23
- package/dist/extensions/pi-subagents/test/unit/opencode-session-headers.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +89 -21
- package/dist/extensions/pi-subagents/test/unit/owned-process-tree.test.ts +31 -1
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +18 -24
- package/dist/extensions/pi-subagents/test/unit/parent-wake.test.ts +206 -0
- package/dist/extensions/pi-subagents/test/unit/partial-output.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +216 -32
- package/dist/extensions/pi-subagents/test/unit/pi-spawn-host-root.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/pi-subagents-policy-guidance.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +193 -104
- package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +16 -1
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +17 -1
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +89 -9
- package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +6 -0
- package/dist/extensions/pi-subagents/test/unit/prompt-audit-provider-routing.test.ts +69 -0
- package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +23 -1
- package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +117 -3
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +35 -14
- package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +3 -2
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +261 -9
- package/dist/extensions/pi-subagents/test/unit/reply-workflow-script.test.ts +37 -0
- package/dist/extensions/pi-subagents/test/unit/required-child-extensions.test.ts +114 -0
- package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +11 -1
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +22 -2
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +125 -18
- package/dist/extensions/pi-subagents/test/unit/run-child-session.test.ts +230 -0
- package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +50 -1
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +301 -4
- package/dist/extensions/pi-subagents/test/unit/runner-bootstrap.test.ts +182 -0
- package/dist/extensions/pi-subagents/test/unit/runner-http-dispatcher.test.ts +136 -0
- package/dist/extensions/pi-subagents/test/unit/runner-peer-loader.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/runner-peer-symlinks.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/running-tone.test.ts +13 -0
- package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +155 -4
- package/dist/extensions/pi-subagents/test/unit/schedule-claim-initialization.test.ts +71 -0
- package/dist/extensions/pi-subagents/test/unit/schedule-claim-preservation.test.ts +98 -0
- package/dist/extensions/pi-subagents/test/unit/schedule-history-transactions.test.ts +201 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-mission.test.ts +317 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +412 -11
- package/dist/extensions/pi-subagents/test/unit/scheduled-store-root.test.ts +2 -8
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +70 -71
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +748 -5
- package/dist/extensions/pi-subagents/test/unit/session-liveness-delivery.test.ts +337 -0
- package/dist/extensions/pi-subagents/test/unit/settings-atomic-save.test.ts +419 -0
- package/dist/extensions/pi-subagents/test/unit/settings-transactions.test.ts +88 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +13 -1
- package/dist/extensions/pi-subagents/test/unit/skills-disable-model-invocation.test.ts +164 -0
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +35 -2
- package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +334 -9
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +170 -0
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +34 -5
- package/dist/extensions/pi-subagents/test/unit/structured-output-validation.test.ts +199 -0
- package/dist/extensions/pi-subagents/test/unit/structured-workflow-resources.test.ts +241 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +47 -38
- package/dist/extensions/pi-subagents/test/unit/subagent-cost.test.ts +97 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +343 -44
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +410 -11
- package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +459 -22
- package/dist/extensions/pi-subagents/test/unit/temp-paths.test.ts +43 -3
- package/dist/extensions/pi-subagents/test/unit/timeout-defaults.test.ts +11 -1
- package/dist/extensions/pi-subagents/test/unit/tool-activation-stale-peer.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/tool-activation.test.ts +313 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +76 -89
- package/dist/extensions/pi-subagents/test/unit/typed-gate-output.test.ts +141 -0
- package/dist/extensions/pi-subagents/test/unit/upgrade-notice.test.ts +31 -0
- package/dist/extensions/pi-subagents/test/unit/usage-reconciliation-owners.test.ts +66 -0
- package/dist/extensions/pi-subagents/test/unit/usage-reconciliation.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +195 -1
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +48 -45
- package/dist/extensions/pi-subagents/test/unit/watchdog-compaction-scope.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-diff-tool.test.ts +48 -3
- package/dist/extensions/pi-subagents/test/unit/watchdog-native-scheduling.test.ts +107 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +95 -7
- package/dist/extensions/pi-subagents/test/unit/watchdog-register-child.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +7 -4
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +111 -24
- package/dist/extensions/pi-subagents/test/unit/watchdog-rules.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +283 -2
- package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +3 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +12 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-stable-host-layout.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +30 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +39 -2
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +18 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +8 -4
- package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +6 -3
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +44 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +28 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-revival.test.ts +85 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-scripts-feature.test.ts +177 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-terminal-proof.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-worktree-admission.test.ts +29 -0
- package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +343 -4
- package/dist/extensions/pi-subagents/test/unit/worktree-lock.test.ts +123 -0
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +252 -22
- package/dist/extensions/pi-subagents/tsconfig.build.json +13 -0
- package/dist/extensions/pi-tool-display/tests/custom-tool-overrides.test.ts +1 -1
- package/dist/extensions/pi-tool-display/tests/tool-overrides-config.test.ts +1 -1
- package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +24 -1
- package/dist/extensions/pi-tool-display/tests/tool-overrides-registration.test.ts +6 -2
- package/dist/extensions/pi-web-agent/src/extension.ts +1 -5
- package/dist/extensions/pi-zentui/.github/workflows/ci.yml +67 -4
- package/dist/extensions/pi-zentui/AGENTS.md +3 -2
- package/dist/extensions/pi-zentui/README.md +60 -32
- package/dist/extensions/pi-zentui/docs/configuration.md +662 -51
- package/dist/extensions/pi-zentui/docs/footer-format.md +174 -5
- package/dist/extensions/pi-zentui/extensions/zentui/accent-rail-editor.ts +15 -4
- package/dist/extensions/pi-zentui/extensions/zentui/average-token-rate.ts +146 -0
- package/dist/extensions/pi-zentui/extensions/zentui/codex-quota-display.ts +34 -0
- package/dist/extensions/pi-zentui/extensions/zentui/codex-quota.ts +298 -0
- package/dist/extensions/pi-zentui/extensions/zentui/component-colors.ts +172 -0
- package/dist/extensions/pi-zentui/extensions/zentui/component-settings.ts +243 -0
- package/dist/extensions/pi-zentui/extensions/zentui/config.ts +851 -114
- package/dist/extensions/pi-zentui/extensions/zentui/custom-value-colors.ts +93 -0
- package/dist/extensions/pi-zentui/extensions/zentui/custom-variable-demand.ts +61 -0
- package/dist/extensions/pi-zentui/extensions/zentui/custom-variable-format.ts +80 -0
- package/dist/extensions/pi-zentui/extensions/zentui/custom-variables.ts +152 -0
- package/dist/extensions/pi-zentui/extensions/zentui/editor-metadata-format.ts +138 -23
- package/dist/extensions/pi-zentui/extensions/zentui/editor-mouse.ts +89 -0
- package/dist/extensions/pi-zentui/extensions/zentui/extension-status-controller.ts +148 -0
- package/dist/extensions/pi-zentui/extensions/zentui/extension-status-settings.ts +40 -0
- package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +109 -1
- package/dist/extensions/pi-zentui/extensions/zentui/footer-format.ts +203 -23
- package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +80 -3
- package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +1 -1
- package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +432 -125
- package/dist/extensions/pi-zentui/extensions/zentui/format.ts +92 -4
- package/dist/extensions/pi-zentui/extensions/zentui/git.ts +47 -30
- package/dist/extensions/pi-zentui/extensions/zentui/github-status.ts +575 -0
- package/dist/extensions/pi-zentui/extensions/zentui/host-project-changes.ts +25 -0
- package/dist/extensions/pi-zentui/extensions/zentui/host-template-values.ts +29 -0
- package/dist/extensions/pi-zentui/extensions/zentui/icons.ts +53 -13
- package/dist/extensions/pi-zentui/extensions/zentui/index.ts +778 -258
- package/dist/extensions/pi-zentui/extensions/zentui/interaction-summary.ts +70 -5
- package/dist/extensions/pi-zentui/extensions/zentui/layered-editor.ts +55 -0
- package/dist/extensions/pi-zentui/extensions/zentui/live-context.ts +6 -1
- package/dist/extensions/pi-zentui/extensions/zentui/live-metadata-demand.ts +72 -0
- package/dist/extensions/pi-zentui/extensions/zentui/live-metadata-display.ts +21 -0
- package/dist/extensions/pi-zentui/extensions/zentui/live-metadata.ts +255 -0
- package/dist/extensions/pi-zentui/extensions/zentui/minimalist-editor.ts +476 -36
- package/dist/extensions/pi-zentui/extensions/zentui/minimalist-settings.ts +118 -0
- package/dist/extensions/pi-zentui/extensions/zentui/minimalist-template.ts +177 -0
- package/dist/extensions/pi-zentui/extensions/zentui/omp-editor-frame.ts +148 -0
- package/dist/extensions/pi-zentui/extensions/zentui/omp-statusline.ts +569 -0
- package/dist/extensions/pi-zentui/extensions/zentui/omp-template-lookups.ts +344 -0
- package/dist/extensions/pi-zentui/extensions/zentui/omp-template-metrics.ts +91 -0
- package/dist/extensions/pi-zentui/extensions/zentui/omp-template-modes.ts +323 -0
- package/dist/extensions/pi-zentui/extensions/zentui/omp-ui.ts +210 -0
- package/dist/extensions/pi-zentui/extensions/zentui/package-version.ts +30 -12
- package/dist/extensions/pi-zentui/extensions/zentui/project-demand.ts +46 -0
- package/dist/extensions/pi-zentui/extensions/zentui/project-discovery.ts +58 -0
- package/dist/extensions/pi-zentui/extensions/zentui/project-refresh.ts +10 -3
- package/dist/extensions/pi-zentui/extensions/zentui/project-state.ts +37 -0
- package/dist/extensions/pi-zentui/extensions/zentui/repository-root.ts +1 -0
- package/dist/extensions/pi-zentui/extensions/zentui/runtime.ts +119 -43
- package/dist/extensions/pi-zentui/extensions/zentui/selector-border.ts +40 -29
- package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +1268 -722
- package/dist/extensions/pi-zentui/extensions/zentui/settings-keys.ts +59 -0
- package/dist/extensions/pi-zentui/extensions/zentui/settings-list-selection.ts +13 -0
- package/dist/extensions/pi-zentui/extensions/zentui/settings-previews.ts +11 -4
- package/dist/extensions/pi-zentui/extensions/zentui/state.ts +24 -11
- package/dist/extensions/pi-zentui/extensions/zentui/style.ts +6 -0
- package/dist/extensions/pi-zentui/extensions/zentui/telemetry.ts +113 -11
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-experimental.ts +234 -46
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-steps.ts +20 -5
- package/dist/extensions/pi-zentui/extensions/zentui/token-rate.ts +313 -0
- package/dist/extensions/pi-zentui/extensions/zentui/turn-summary-format.ts +59 -0
- package/dist/extensions/pi-zentui/extensions/zentui/turn-summary-rate.ts +52 -0
- package/dist/extensions/pi-zentui/extensions/zentui/ui.ts +640 -172
- package/dist/extensions/pi-zentui/extensions/zentui/user-message-styles.ts +72 -34
- package/dist/extensions/pi-zentui/extensions/zentui/user-message.ts +219 -34
- package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +495 -119
- package/dist/extensions/pi-zentui/omp.ts +157 -0
- package/dist/extensions/pi-zentui/package-lock.json +3762 -1507
- package/dist/extensions/pi-zentui/package.json +50 -12
- package/dist/extensions/pi-zentui/test/accent-rail-editor.test.ts +13 -2
- package/dist/extensions/pi-zentui/test/average-token-rate.test.ts +297 -0
- package/dist/extensions/pi-zentui/test/behavior-compatibility.mjs +89 -0
- package/dist/extensions/pi-zentui/test/codex-quota-lifecycle.test.ts +284 -0
- package/dist/extensions/pi-zentui/test/codex-quota-rendering.test.ts +466 -0
- package/dist/extensions/pi-zentui/test/codex-quota.test.ts +440 -0
- package/dist/extensions/pi-zentui/test/component-colors.test.ts +554 -0
- package/dist/extensions/pi-zentui/test/component-settings.test.ts +364 -0
- package/dist/extensions/pi-zentui/test/config-component-independence.test.ts +402 -0
- package/dist/extensions/pi-zentui/test/config-extension-status-choice.test.ts +233 -0
- package/dist/extensions/pi-zentui/test/config-hidden-extension-status-colors.test.ts +118 -0
- package/dist/extensions/pi-zentui/test/config-hidden-extension-status-placement.test.ts +142 -0
- package/dist/extensions/pi-zentui/test/config-minimalist-templates.test.ts +240 -0
- package/dist/extensions/pi-zentui/test/config-template-variables.test.ts +85 -0
- package/dist/extensions/pi-zentui/test/config.test.ts +80 -17
- package/dist/extensions/pi-zentui/test/custom-value-colors-integration.test.ts +453 -0
- package/dist/extensions/pi-zentui/test/custom-value-colors.test.ts +399 -0
- package/dist/extensions/pi-zentui/test/custom-variable-alias-prototypes.test.ts +177 -0
- package/dist/extensions/pi-zentui/test/custom-variable-consumers.test.ts +194 -0
- package/dist/extensions/pi-zentui/test/custom-variable-demand.test.ts +169 -0
- package/dist/extensions/pi-zentui/test/custom-variable-probe-reservation.test.ts +141 -0
- package/dist/extensions/pi-zentui/test/custom-variables-lifecycle.integration.test.ts +365 -0
- package/dist/extensions/pi-zentui/test/custom-variables.test.ts +330 -0
- package/dist/extensions/pi-zentui/test/editor-metadata-format.test.ts +121 -0
- package/dist/extensions/pi-zentui/test/editor-mouse.test.ts +507 -0
- package/dist/extensions/pi-zentui/test/editor-viewport-indicators.test.ts +247 -20
- package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +204 -260
- package/dist/extensions/pi-zentui/test/extension-status-controller.test.ts +323 -0
- package/dist/extensions/pi-zentui/test/extension-status-lifecycle.integration.test.ts +466 -0
- package/dist/extensions/pi-zentui/test/extension-status-settings.test.ts +79 -0
- package/dist/extensions/pi-zentui/test/footer-alignment.test.ts +135 -0
- package/dist/extensions/pi-zentui/test/footer-authority.test.ts +69 -0
- package/dist/extensions/pi-zentui/test/footer-auto-compaction.test.ts +148 -0
- package/dist/extensions/pi-zentui/test/footer-format-cache.test.ts +186 -0
- package/dist/extensions/pi-zentui/test/footer-format.test.ts +154 -4
- package/dist/extensions/pi-zentui/test/footer-hidden.test.ts +312 -0
- package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +22 -0
- package/dist/extensions/pi-zentui/test/footer-layout.test.ts +80 -0
- package/dist/extensions/pi-zentui/test/footer-thinking-level.test.ts +123 -0
- package/dist/extensions/pi-zentui/test/format.test.ts +75 -1
- package/dist/extensions/pi-zentui/test/git-probes.test.ts +182 -0
- package/dist/extensions/pi-zentui/test/github-status.test.ts +931 -0
- package/dist/extensions/pi-zentui/test/host-template-surfaces.test.ts +287 -0
- package/dist/extensions/pi-zentui/test/icons.test.ts +86 -16
- package/dist/extensions/pi-zentui/test/layered-editor.test.ts +53 -0
- package/dist/extensions/pi-zentui/test/live-context-integration.test.ts +154 -7
- package/dist/extensions/pi-zentui/test/live-context.test.ts +45 -0
- package/dist/extensions/pi-zentui/test/live-metadata-lifecycle.integration.test.ts +963 -0
- package/dist/extensions/pi-zentui/test/live-metadata.test.ts +767 -0
- package/dist/extensions/pi-zentui/test/minimalist-cache-hit-colors.test.ts +183 -0
- package/dist/extensions/pi-zentui/test/minimalist-editor.test.ts +222 -4
- package/dist/extensions/pi-zentui/test/minimalist-settings.test.ts +103 -0
- package/dist/extensions/pi-zentui/test/minimalist-templates.test.ts +489 -0
- package/dist/extensions/pi-zentui/test/omp-editor-composers.test.ts +324 -0
- package/dist/extensions/pi-zentui/test/omp-statusline.test.ts +579 -0
- package/dist/extensions/pi-zentui/test/omp-template-lookups.test.ts +630 -0
- package/dist/extensions/pi-zentui/test/omp-template-metrics.test.ts +72 -0
- package/dist/extensions/pi-zentui/test/omp-template-modes.test.ts +557 -0
- package/dist/extensions/pi-zentui/test/omp-ui.test.ts +93 -0
- package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
- package/dist/extensions/pi-zentui/test/pi-version-policy.test.ts +37 -0
- package/dist/extensions/pi-zentui/test/project-demand-integration.test.ts +542 -0
- package/dist/extensions/pi-zentui/test/project-discovery.test.ts +412 -0
- package/dist/extensions/pi-zentui/test/project-refresh.test.ts +44 -0
- package/dist/extensions/pi-zentui/test/project-state.test.ts +38 -1
- package/dist/extensions/pi-zentui/test/responsive-dependencies.test.ts +7 -7
- package/dist/extensions/pi-zentui/test/runtime.test.ts +127 -2
- package/dist/extensions/pi-zentui/test/selesai-v030-gate.json +939 -0
- package/dist/extensions/pi-zentui/test/settings-command.test.ts +1330 -82
- package/dist/extensions/pi-zentui/test/settings-keys.test.ts +41 -0
- package/dist/extensions/pi-zentui/test/settings-list-selection.test.ts +88 -0
- package/dist/extensions/pi-zentui/test/settings-previews.test.ts +4 -1
- package/dist/extensions/pi-zentui/test/state.test.ts +15 -1
- package/dist/extensions/pi-zentui/test/telemetry-lifecycle-integration.test.ts +214 -12
- package/dist/extensions/pi-zentui/test/telemetry-snapshot.test.ts +246 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-cache.test.ts +246 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-rows.test.ts +22 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-tui.mjs +113 -51
- package/dist/extensions/pi-zentui/test/thinking-experimental.test.ts +576 -76
- package/dist/extensions/pi-zentui/test/thinking-steps.test.ts +23 -0
- package/dist/extensions/pi-zentui/test/token-rate.test.ts +450 -0
- package/dist/extensions/pi-zentui/test/turn-summary-format.test.ts +207 -0
- package/dist/extensions/pi-zentui/test/turn-summary-lifecycle.integration.test.ts +72 -5
- package/dist/extensions/pi-zentui/test/turn-summary-rate.test.ts +158 -0
- package/dist/extensions/pi-zentui/test/usage-lifecycle-integration.test.ts +421 -0
- package/dist/extensions/pi-zentui/test/usage-snapshot.test.ts +154 -0
- package/dist/extensions/pi-zentui/test/user-message-cache.test.ts +239 -0
- package/dist/extensions/pi-zentui/test/user-message-native-reduced-capabilities.test.ts +61 -0
- package/dist/extensions/pi-zentui/test/user-message-native.test.ts +447 -0
- package/dist/extensions/pi-zentui/test/user-message-styles.test.ts +2 -2
- package/dist/extensions/pi-zentui/test/working-line-editor-placement.test.ts +317 -0
- package/dist/extensions/pi-zentui/test/working-line-generation-cache.test.ts +238 -0
- package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +674 -179
- package/dist/extensions/pi-zentui/test/working-line-message-ownership.test.ts +239 -0
- package/dist/extensions/pi-zentui/test/working-line-metric-animation.test.ts +284 -0
- package/dist/extensions/pi-zentui/test/working-line-placement.test.ts +298 -0
- package/dist/extensions/pi-zentui/test/working-line.test.ts +386 -18
- package/dist/extensions/pi-zentui/test/wrapped-editor-consumers.integration.test.ts +579 -0
- package/dist/extensions/pi-zentui/test/wrapped-editor-usage.integration.test.ts +298 -0
- package/dist/extensions/pi-zentui/tsconfig.json +1 -1
- package/dist/extensions/pi-zentui/vitest.host.config.ts +33 -0
- package/dist/extensions/question/index.ts +1 -5
- package/dist/extensions/rtk.test.ts +28 -15
- package/dist/extensions/rtk.ts +22 -22
- package/dist/extensions/skills-index/index.test.ts +99 -0
- package/dist/extensions/skills-index/index.ts +105 -0
- package/dist/extensions/skills-index/package.json +9 -0
- package/dist/extensions/tokenin-onboarding.ts +48 -208
- package/dist/extensions/tool-search/index.d.ts +11 -0
- package/dist/extensions/tool-search/index.js +14 -0
- package/dist/extensions/tool-search/tool.d.ts +91 -0
- package/dist/extensions/tool-search/tool.js +214 -0
- package/dist/index.d.ts +17 -9
- package/dist/index.js +11 -5
- package/dist/main.d.ts +4 -0
- package/dist/main.js +106 -42
- package/dist/migrations.js +4 -3
- package/dist/modes/index.d.ts +1 -0
- package/dist/modes/interactive/bug-report.js +4 -0
- package/dist/modes/interactive/components/armin.d.ts +3 -0
- package/dist/modes/interactive/components/armin.js +7 -5
- package/dist/modes/interactive/components/assistant-message.js +1 -1
- package/dist/modes/interactive/components/auth-url.d.ts +13 -0
- package/dist/modes/interactive/components/auth-url.js +36 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
- package/dist/modes/interactive/components/bash-execution.js +17 -14
- package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
- package/dist/modes/interactive/components/branch-summary-message.js +5 -2
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +5 -2
- package/dist/modes/interactive/components/config-selector.js +13 -3
- package/dist/modes/interactive/components/custom-editor.js +7 -0
- package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
- package/dist/modes/interactive/components/custom-entry.js +8 -2
- package/dist/modes/interactive/components/custom-message.js +1 -0
- package/dist/modes/interactive/components/first-time-setup.d.ts +4 -4
- package/dist/modes/interactive/components/first-time-setup.js +8 -2
- package/dist/modes/interactive/components/footer.d.ts +7 -0
- package/dist/modes/interactive/components/footer.js +44 -4
- package/dist/modes/interactive/components/index.d.ts +0 -1
- package/dist/modes/interactive/components/index.js +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +2 -0
- package/dist/modes/interactive/components/login-dialog.js +11 -5
- package/dist/modes/interactive/components/mermaid.d.ts +10 -0
- package/dist/modes/interactive/components/mermaid.js +74 -0
- package/dist/modes/interactive/components/model-selector.d.ts +14 -9
- package/dist/modes/interactive/components/model-selector.js +79 -31
- package/dist/modes/interactive/components/oauth-selector.d.ts +8 -2
- package/dist/modes/interactive/components/oauth-selector.js +24 -21
- package/dist/modes/interactive/components/pi-logo.d.ts +18 -0
- package/dist/modes/interactive/components/pi-logo.js +36 -0
- package/dist/modes/interactive/components/radius-login-selector.d.ts +14 -0
- package/dist/modes/interactive/components/radius-login-selector.js +84 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
- package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -11
- package/dist/modes/interactive/components/settings-selector.js +60 -102
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
- package/dist/modes/interactive/components/themed-text.d.ts +16 -0
- package/dist/modes/interactive/components/themed-text.js +28 -0
- package/dist/modes/interactive/components/tool-execution.d.ts +11 -18
- package/dist/modes/interactive/components/tool-execution.js +34 -47
- package/dist/modes/interactive/components/tree-selector.js +7 -0
- package/dist/modes/interactive/components/user-message.d.ts +3 -1
- package/dist/modes/interactive/components/user-message.js +14 -6
- package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
- package/dist/modes/interactive/components/visual-truncate.js +39 -6
- package/dist/modes/interactive/external-editor.js +2 -1
- package/dist/modes/interactive/interactive-mode.d.ts +41 -8
- package/dist/modes/interactive/interactive-mode.js +854 -492
- package/dist/modes/interactive/program-status-reporter.d.ts +33 -0
- package/dist/modes/interactive/program-status-reporter.js +109 -0
- package/dist/modes/interactive/theme/dark.json +59 -72
- package/dist/modes/interactive/theme/light.json +57 -69
- package/dist/modes/interactive/theme/system-theme.d.ts +54 -0
- package/dist/modes/interactive/theme/system-theme.js +545 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +46 -6
- package/dist/modes/interactive/theme/theme-controller.js +127 -47
- package/dist/modes/interactive/theme/theme-json.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-json.js +3 -1
- package/dist/modes/interactive/theme/theme-schema.json +7 -2
- package/dist/modes/interactive/theme/theme.d.ts +66 -39
- package/dist/modes/interactive/theme/theme.js +243 -320
- package/dist/modes/interactive/tui-renderer.d.ts +2 -1
- package/dist/modes/interactive/tui-renderer.js +1 -0
- package/dist/modes/json-event.d.ts +33 -0
- package/dist/modes/json-event.js +28 -0
- package/dist/modes/print-mode.js +12 -2
- package/dist/modes/rpc/rpc-client.d.ts +11 -19
- package/dist/modes/rpc/rpc-client.js +52 -35
- package/dist/modes/rpc/rpc-mode.js +11 -26
- package/dist/modes/rpc/rpc-types.d.ts +12 -23
- package/dist/package-manager-cli.js +16 -5
- package/dist/rpc-entry.js +1 -0
- package/dist/skills/pi-subagents/SKILL.md +109 -35
- package/dist/skills/pi-subagents/references/constraints-and-recipes.md +38 -238
- package/dist/skills/pi-subagents/references/execution-controls.md +181 -83
- package/dist/skills/pi-subagents/references/management-authoring-rpc.md +9 -9
- package/dist/skills/pi-subagents/references/multi-lane-orchestration.md +24 -2
- package/dist/skills/pi-subagents/references/prompting-and-roles.md +121 -91
- package/dist/skills/pi-subagents/references/review-and-validation.md +73 -0
- package/dist/utils/ansi.d.ts +8 -0
- package/dist/utils/ansi.js +30 -11
- package/dist/utils/clipboard-image.js +14 -17
- package/dist/utils/clipboard.d.ts +2 -0
- package/dist/utils/clipboard.js +17 -11
- package/dist/utils/frontmatter.js +2 -1
- package/dist/utils/image-convert.d.ts +12 -0
- package/dist/utils/image-convert.js +45 -6
- package/dist/utils/image-resize-core.d.ts +12 -0
- package/dist/utils/image-resize-core.js +5 -0
- package/dist/utils/image-resize-worker.js +3 -2
- package/dist/utils/image-resize.js +9 -10
- package/dist/utils/mime.js +1 -1
- package/dist/utils/output-files.d.ts +14 -0
- package/dist/utils/output-files.js +29 -0
- package/dist/utils/paths.d.ts +6 -3
- package/dist/utils/paths.js +28 -5
- package/dist/utils/shell.d.ts +1 -3
- package/dist/utils/shell.js +3 -30
- package/dist/utils/syntax-highlight.d.ts +1 -0
- package/dist/utils/syntax-highlight.js +68 -2
- package/dist/utils/tool-result-images.d.ts +20 -0
- package/dist/utils/tool-result-images.js +47 -0
- package/dist/utils/tools-manager.d.ts +5 -0
- package/dist/utils/tools-manager.js +6 -6
- package/dist/utils/version-check.d.ts +4 -0
- package/dist/utils/version-check.js +20 -2
- package/docs/cli-integration.md +104 -0
- package/docs/cli.md +333 -0
- package/docs/codemode.md +230 -0
- package/docs/configuration.md +47 -0
- package/docs/environment-variables.md +5 -0
- package/docs/extensions.md +107 -30
- package/docs/json.md +8 -4
- package/docs/keybindings.md +10 -10
- package/docs/mcp.md +262 -0
- package/docs/models.md +104 -3
- package/docs/providers.md +20 -2
- package/docs/rpc.md +13 -12
- package/docs/sdk.md +41 -33
- package/docs/security.md +21 -20
- package/docs/settings.md +18 -46
- package/docs/terminal-setup.md +14 -0
- package/docs/virtual-models.md +114 -0
- package/examples/extensions/jev-router.ts +113 -0
- package/examples/extensions/tokenin-usage-widget.ts +124 -0
- package/examples/rpc-client.ts +35 -0
- package/examples/sdk/14-codemode-mcp.ts +67 -0
- package/package.json +15 -8
- package/dist/core/agent-session-auto-handoff.test.js +0 -195
- package/dist/core/built-in-extensions.d.ts +0 -2
- package/dist/core/built-in-extensions.js +0 -2
- package/dist/core/llama/provider.js +0 -143
- package/dist/core/settings-manager-auto-handoff.test.d.ts +0 -1
- package/dist/core/settings-manager-auto-handoff.test.js +0 -53
- package/dist/extensions/capability-gateway/catalog.ts +0 -177
- package/dist/extensions/capability-gateway/index.test.ts +0 -226
- package/dist/extensions/capability-gateway/index.ts +0 -669
- package/dist/extensions/capability-gateway/integration.test.ts +0 -803
- package/dist/extensions/capability-gateway/package.json +0 -16
- package/dist/extensions/capability-gateway/routing.test.ts +0 -574
- package/dist/extensions/capability-gateway/routing.ts +0 -403
- package/dist/extensions/pi-subagents/runner-server-preload.mjs +0 -13
- package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +0 -89
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +0 -259
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +0 -312
- package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +0 -374
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +0 -69
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +0 -307
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +0 -211
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/cli.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/register-bedrock.d.ts +0 -2
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/restore-sandbox-env.d.ts +0 -17
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/args.d.ts +0 -57
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/config-selector.d.ts +0 -16
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/file-processor.d.ts +0 -15
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/initial-message.d.ts +0 -18
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/list-models.d.ts +0 -9
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/project-trust.d.ts +0 -10
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/session-picker.d.ts +0 -10
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/startup-ui.d.ts +0 -20
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/config.d.ts +0 -96
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-runtime.d.ts +0 -119
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-services.d.ts +0 -85
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session.d.ts +0 -620
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-guidance.d.ts +0 -5
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-storage.d.ts +0 -56
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/bash-executor.d.ts +0 -32
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/cache-stats.d.ts +0 -49
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/branch-summarization.d.ts +0 -93
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/compaction.d.ts +0 -128
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/index.d.ts +0 -7
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/utils.d.ts +0 -38
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/defaults.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/diagnostics.d.ts +0 -15
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/event-bus.d.ts +0 -9
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/exec.d.ts +0 -29
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/experimental.d.ts +0 -2
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/ansi-to-html.d.ts +0 -22
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/index.d.ts +0 -37
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/tool-renderer.d.ts +0 -34
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/index.d.ts +0 -12
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/loader.d.ts +0 -23
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/runner.d.ts +0 -171
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +0 -1261
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/wrapper.d.ts +0 -20
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/footer-data-provider.d.ts +0 -54
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/http-dispatcher.d.ts +0 -22
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/index.d.ts +0 -13
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/keybindings.d.ts +0 -358
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/messages.d.ts +0 -77
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-config.d.ts +0 -512
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-registry.d.ts +0 -43
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-resolver.d.ts +0 -121
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-runtime.d.ts +0 -82
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/models-store.d.ts +0 -17
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/output-guard.d.ts +0 -7
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/package-manager.d.ts +0 -210
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/project-trust.d.ts +0 -15
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/prompt-templates.d.ts +0 -54
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-attribution.d.ts +0 -4
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-composer.d.ts +0 -55
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/radius.d.ts +0 -2
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/remote-catalog-provider.d.ts +0 -5
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resolve-config-value.d.ts +0 -30
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resource-loader.d.ts +0 -206
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/runtime-credentials.d.ts +0 -15
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/sdk.d.ts +0 -106
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-cwd.d.ts +0 -19
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-manager.d.ts +0 -356
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/settings-manager.d.ts +0 -297
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/skills.d.ts +0 -60
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/slash-commands.d.ts +0 -15
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/source-info.d.ts +0 -18
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/system-prompt.d.ts +0 -28
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/telemetry.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/timings.d.ts +0 -10
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/bash.d.ts +0 -68
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit-diff.d.ts +0 -106
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit.d.ts +0 -51
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/file-mutation-queue.d.ts +0 -6
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/find.d.ts +0 -35
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/grep.d.ts +0 -37
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/index.d.ts +0 -40
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/ls.d.ts +0 -37
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/output-accumulator.d.ts +0 -52
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/path-utils.d.ts +0 -10
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/read.d.ts +0 -35
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/render-utils.d.ts +0 -24
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/tool-definition-wrapper.d.ts +0 -14
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/truncate.d.ts +0 -70
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/write.d.ts +0 -26
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/trust-manager.d.ts +0 -36
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/usage-totals.d.ts +0 -19
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/client.d.ts +0 -61
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/huggingface.d.ts +0 -23
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/index.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/provider.d.ts +0 -10
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/ui.d.ts +0 -42
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/index.d.ts +0 -35
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/main.d.ts +0 -12
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/migrations.d.ts +0 -33
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/index.d.ts +0 -9
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/armin.d.ts +0 -34
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/assistant-message.d.ts +0 -22
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bash-execution.d.ts +0 -34
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bordered-loader.d.ts +0 -16
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/branch-summary-message.d.ts +0 -16
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/config-selector.d.ts +0 -102
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/countdown-timer.d.ts +0 -14
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-editor.d.ts +0 -21
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-entry.d.ts +0 -19
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-message.d.ts +0 -20
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/daxnuts.d.ts +0 -23
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/diff.d.ts +0 -12
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/dynamic-border.d.ts +0 -15
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/earendil-announcement.d.ts +0 -5
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-editor.d.ts +0 -22
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-input.d.ts +0 -23
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-selector.d.ts +0 -26
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/first-time-setup.d.ts +0 -25
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/footer.d.ts +0 -32
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/index.d.ts +0 -34
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/keybinding-hints.d.ts +0 -13
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/login-dialog.d.ts +0 -52
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/model-selector.d.ts +0 -54
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/oauth-selector.d.ts +0 -33
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -42
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector-search.d.ts +0 -23
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector.d.ts +0 -95
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/settings-selector.d.ts +0 -77
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/show-images-selector.d.ts +0 -10
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -17
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/status-indicator.d.ts +0 -28
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/theme-selector.d.ts +0 -11
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/thinking-selector.d.ts +0 -11
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tool-execution.d.ts +0 -63
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tree-selector.d.ts +0 -94
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/trust-selector.d.ts +0 -23
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message-selector.d.ts +0 -30
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message.d.ts +0 -14
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/visual-truncate.d.ts +0 -24
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/interactive-mode.d.ts +0 -394
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/model-search.d.ts +0 -12
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme-controller.d.ts +0 -29
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme.d.ts +0 -120
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/print-mode.d.ts +0 -28
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/jsonl.d.ts +0 -17
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-client.d.ts +0 -246
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-mode.d.ts +0 -20
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-types.d.ts +0 -457
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/package-manager-cli.d.ts +0 -8
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/rpc-entry.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/ansi.d.ts +0 -2
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/changelog.d.ts +0 -22
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/child-process.d.ts +0 -18
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-image.d.ts +0 -11
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-native.d.ts +0 -11
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard.d.ts +0 -4
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/deprecation.d.ts +0 -4
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/exif-orientation.d.ts +0 -5
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/frontmatter.d.ts +0 -8
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/fs-watch.d.ts +0 -5
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/git.d.ts +0 -26
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/html.d.ts +0 -7
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-convert.d.ts +0 -10
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-process.d.ts +0 -18
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-core.d.ts +0 -30
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-worker.d.ts +0 -2
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize.d.ts +0 -16
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/json.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/mime.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/open-browser.d.ts +0 -9
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/paths.d.ts +0 -31
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/photon.d.ts +0 -21
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/pi-user-agent.d.ts +0 -2
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/shell.d.ts +0 -31
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/sleep.d.ts +0 -5
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/syntax-highlight.d.ts +0 -12
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/tools-manager.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/version-check.d.ts +0 -15
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/windows-self-update.d.ts +0 -3
- package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +0 -31
- package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +0 -74
- package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +0 -150
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +0 -766
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +0 -327
- package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +0 -309
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +0 -1093
- package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +0 -94
- package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +0 -1329
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +0 -153
- package/dist/extensions/pi-zentui/extensions/zentui/accent-rail-layout-patch.ts +0 -457
- package/dist/extensions/pi-zentui/test/accent-rail-layout-patch.test.ts +0 -669
- package/dist/extensions/pi-zentui/test/thinking-experimental-docs.test.ts +0 -51
- package/dist/modes/interactive/components/daxnuts.d.ts +0 -22
- package/dist/modes/interactive/components/daxnuts.js +0 -139
- /package/dist/core/{agent-session-auto-handoff.test.d.ts → agent-session-custom-tools.test.d.ts} +0 -0
- /package/dist/{core → extensions}/llama/huggingface.d.ts +0 -0
- /package/dist/{core → extensions}/llama/huggingface.js +0 -0
- /package/dist/{core → extensions}/llama/index.d.ts +0 -0
- /package/dist/{core → extensions}/llama/ui.d.ts +0 -0
- /package/dist/{core → extensions}/llama/ui.js +0 -0
|
@@ -3,8 +3,8 @@ import * as fs from "node:fs";
|
|
|
3
3
|
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
|
-
import { discoverAgents, findBlockingAgentDiagnostic, formatUnknownAgentError, resolveAgentName, unknownAgentDiagnosticContext, type AgentConfig, type AgentDiscoveryDiagnostic, type AgentScope, type UnknownAgentDiagnosticContext } from "../../agents/agents.ts";
|
|
7
|
-
import { getArtifactsDir,
|
|
6
|
+
import { discoverAgents, discoverAgentsAll, findBlockingAgentDiagnostic, formatUnknownAgentError, resolveAgentName, unknownAgentDiagnosticContext, type AgentConfig, type AgentDiscoveryDiagnostic, type AgentScope, type UnknownAgentDiagnosticContext } from "../../agents/agents.ts";
|
|
7
|
+
import { getArtifactsDir, getProjectArtifactPackagingWarning, getProjectSubagentsDir } from "../../shared/artifacts.ts";
|
|
8
8
|
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
9
9
|
import { createCapacityResilientJsonWriter } from "../../shared/capacity-resilient-json.ts";
|
|
10
10
|
import { isStorageCapacityError } from "../../shared/file-system-retry.ts";
|
|
@@ -24,12 +24,17 @@ import { handleManagementAction } from "../../agents/agent-management.ts";
|
|
|
24
24
|
import { handleRefinementAction } from "../../agents/agent-refinements.ts";
|
|
25
25
|
import { buildDoctorReport } from "../../extension/doctor.ts";
|
|
26
26
|
import { readSubagentGuide } from "../../extension/subagent-guide.ts";
|
|
27
|
-
import { normalizePublicSubagentExecution, validateWorkflowCapacityOverrides } from "../../extension/public-execution.ts";
|
|
27
|
+
import { isWorkflowScriptPath, normalizePublicSubagentExecution, validateWorkflowCapacityOverrides } from "../../extension/public-execution.ts";
|
|
28
|
+
import { readReplyWorkflowScript } from "../../extension/reply-workflow-script.ts";
|
|
29
|
+
import { disabledFeatureNotice, disabledFeatureUseError, resolveDisabledFeatureSurface, type DisabledFeatureSurface } from "../../shared/disabled-features.ts";
|
|
28
30
|
import { runSync } from "./execution.ts";
|
|
31
|
+
import { commandAction } from "./command-action.ts";
|
|
29
32
|
import { handleWatchdogToolAction, WATCHDOG_TOOL_ACTIONS } from "../../watchdog/tool-actions.ts";
|
|
30
33
|
import type { MainWatchdogRuntime } from "../../watchdog/runtime.ts";
|
|
31
34
|
import { applyWatchdogLaunchRules } from "../../watchdog/rules.ts";
|
|
32
|
-
import {
|
|
35
|
+
import { childWatchdogProgressForModel } from "../../watchdog/child-status.ts";
|
|
36
|
+
import { normalizeParentModel, resolveEffectiveSubagentModel, resolveModelOrigin, resolveModelSelection, scopedModelIdsFromContext, type ModelOrigin, type ParentModel } from "../shared/model-resolution.ts";
|
|
37
|
+
import { projectChainOutputSchemas, resolveEffectiveOutputSchema } from "../shared/child-launch-plan.ts";
|
|
33
38
|
import { formatRetainedChildren, listRetainedChildren } from "../background/retained-children.ts";
|
|
34
39
|
import { resolveModelScopesForAgent, type ModelScopeConfig } from "../shared/model-scope.ts";
|
|
35
40
|
import { recordRun } from "../shared/run-history.ts";
|
|
@@ -53,27 +58,29 @@ import { isScheduledRunAction } from "../background/scheduled-runs.ts";
|
|
|
53
58
|
import { encodeIndexSegment } from "../background/index-segment.ts";
|
|
54
59
|
import { enqueueChainAppendRequest, readPendingChainAppendRequests, runnerStepOutputNames } from "../background/chain-append.ts";
|
|
55
60
|
import { ChainOutputValidationError, validateChainOutputBindingsWithContext } from "../shared/chain-outputs.ts";
|
|
56
|
-
import { normalizeGateAcceptance, resolveAcceptanceReportMode, validateAcceptanceInput, validateExecutionAcceptance } from "../shared/acceptance.ts";
|
|
57
|
-
import { canPreferFork, createForkContextResolver,
|
|
61
|
+
import { acceptanceHasTypedVerify, normalizeGateAcceptance, resolveAcceptanceReportMode, TYPED_VERIFY_OUTPUT_SCHEMA_CONFLICT, validateAcceptanceInput, validateExecutionAcceptance, validateExecutionAcceptancePolicy } from "../shared/acceptance.ts";
|
|
62
|
+
import { canPreferFork, createForkContextResolver, resolveSubagentLaunchContext } from "../../shared/fork-context.ts";
|
|
58
63
|
import { createPrunedForkSessionWriter } from "../../shared/pruned-fork.ts";
|
|
59
64
|
import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
|
|
60
65
|
import { currentCompletionOwnerId } from "../../shared/completion-owner.ts";
|
|
66
|
+
import { SUBAGENT_ASYNC_COMPLETE_EVENT } from "../../shared/types.ts";
|
|
61
67
|
import { applyIntercomBridgeToAgent, INTERCOM_BRIDGE_MARKER, resolveIntercomBridge, resolveIntercomSessionTarget, resolveSubagentIntercomTarget, type IntercomBridgeState } from "../../intercom/intercom-bridge.ts";
|
|
62
68
|
import { formatControlIntercomMessage, formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "../shared/subagent-control.ts";
|
|
63
69
|
import { formatSpawnBudget, getSpawnBudgetSnapshot, grantSpawnBudget, preflightSpawnBudget, preflightSpawnBudgetGrant, reserveSpawnBudget } from "../shared/spawn-budget.ts";
|
|
64
70
|
import { claimRunFanoutBatch, claimRunFanoutBatchWithCommit, createRunFanoutBudget, formatRunFanoutBudget, getRunFanoutBudgetSnapshot, readRunFanoutBudgetDescriptor, RunFanoutLimitError, writeRunFanoutBudgetDescriptor } from "../shared/run-fanout-budget.ts";
|
|
65
71
|
import { retainLiveForegroundNestedRoute } from "../../integrations/pi-web-session-liveness.ts";
|
|
72
|
+
import { HERDR_FOREGROUND_CONTROL_CHANGED_EVENT } from "../../integrations/herdr-status.ts";
|
|
66
73
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
67
74
|
import { usageBudgetExceededMessage, usageBudgetState, validateUsageBudgetConfig } from "../shared/usage-budget.ts";
|
|
68
|
-
import { intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
75
|
+
import { assertAgentAllowedByCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
69
76
|
import { describeSubagentRouting, emitSubagentRoutingTelemetry, readSubagentRoutingSettings, routeSubagentLaunch, warnJevUnavailableOnce } from "../shared/jev-subagent-routing.ts";
|
|
70
77
|
import { isAgentContract } from "../shared/agent-contract.ts";
|
|
71
78
|
import { normalizeExtensionBindings, type ExtensionBindings } from "../shared/extension-bindings.ts";
|
|
79
|
+
import { assertRequiredChildExtensionsAdmitted, hasMandatoryRequiredChildExtensions, readRetainedRequiredChildExtensions, resolveRequiredChildExtensions, type RequiredChildExtensionSnapshot } from "../../shared/required-child-extensions.ts";
|
|
72
80
|
import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, outputPathMappingFromTask, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
73
81
|
import { assertJsonSchemaObject, cleanupStructuredOutputRuntime, createStructuredOutputRuntime } from "../shared/structured-output.ts";
|
|
74
|
-
import { compactForegroundDetails, getSingleResultOutput, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.ts";
|
|
75
|
-
import {
|
|
76
|
-
import { discardPreservedWorktrees, formatParallelHandoffError, formatParallelHandoffReference, formatStoredParallelHandoffCleanup, parallelHandoffPath, readParallelHandoffManifest, recordParallelHandoffMerge, recordParallelHandoffSupersession, writeParallelHandoffGroup, writeWorktreeSetupHandoff } from "../shared/parallel-handoff.ts";
|
|
82
|
+
import { compactForegroundDetails, getSingleResultOutput, PROMPT_REDACTED, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.ts";
|
|
83
|
+
import { discardPreservedWorktrees, formatParallelHandoffError, formatParallelHandoffReference, protectRetainedWorktreeForResume, formatStoredParallelHandoffCleanup, parallelHandoffPath, readParallelHandoffManifest, recordParallelHandoffMerge, recordParallelHandoffSupersession, writeParallelHandoffGroup, writeWorktreeSetupHandoff } from "../shared/parallel-handoff.ts";
|
|
77
84
|
import { summarizeContextModes, type ContextMode, type ContextSummary } from "../shared/context-mode.ts";
|
|
78
85
|
import {
|
|
79
86
|
attachNestedChildrenToResultChildren,
|
|
@@ -97,16 +104,18 @@ import { dismissRecoveredWorkflow } from "./async-dismiss-action.ts";
|
|
|
97
104
|
import { promotePausedWorkflowIfSettled, reconcileDetachedWorkflowChildCompletion } from "./workflow-detach-reconcile.ts";
|
|
98
105
|
import { reconcileAsyncRun } from "../background/stale-run-reconciler.ts";
|
|
99
106
|
import { resolveAsyncRootResultPath, waitForImportedAsyncRoot } from "../background/chain-root-attachment.ts";
|
|
100
|
-
import {
|
|
101
|
-
import {
|
|
107
|
+
import { awaitExistingAsyncRun, claimWorkflowAwaitedResult } from "../background/await-async-run.ts";
|
|
108
|
+
import { fallbackResultPayloadPathForSessionRun, removeResultIndex, resultFilePath, writeAsyncResultFile } from "../background/result-files.ts";
|
|
109
|
+
import { attachRootChildrenToSteps, createNestedRoute, findNestedControlResult, inheritedNestedParentAddressOf, inheritedNestedRouteOf, nestedRunScope, resolveNestedAsyncDir, retainNestedLookupRoute, snapshotNestedEventFiles, updateForegroundNestedProjection, writeNestedControlRequest, writeNestedEvent, type NestedParentAddress, type NestedRoute, type NestedRunResolutionScope } from "../shared/nested-events.ts";
|
|
102
110
|
import type { ChildRuntimeConfig } from "../shared/child-runtime-config.ts";
|
|
103
111
|
import { resolveSubagentRunId, type ResolvedSubagentRunId } from "../background/run-id-resolver.ts";
|
|
104
112
|
import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
|
|
105
|
-
import { isStoppableAsyncStatusStep, resolveAsyncStatusChild
|
|
113
|
+
import { isStoppableAsyncStatusStep, resolveAsyncStatusChild } from "../shared/child-identity.ts";
|
|
106
114
|
import { inspectSubagentStatus } from "../background/run-status.ts";
|
|
107
115
|
import { getExternalJobProvider } from "../../api/external-job-provider.ts";
|
|
108
116
|
import { externalJobFollowUpRequestDigest, externalJobFollowUpRequestId, externalJobFollowUpRunId, externalJobPromptDigest, externalJobStableJson } from "../shared/external-job-runner.ts";
|
|
109
117
|
import { externalCliReceiptMetadata, normalizeExternalCliRunnerStatus } from "../shared/external-cli-contract.ts";
|
|
118
|
+
import { formatHerdrMachineRunnerUnsupported, resolveHerdrMachinePlacement } from "../shared/herdr-machine.ts";
|
|
110
119
|
import { applyForceTopLevelAsyncOverride } from "../background/top-level-async.ts";
|
|
111
120
|
import { handleMissionAction, MISSION_ACTIONS } from "../../missions/actions.ts";
|
|
112
121
|
import { attachMissionToLaunchResult, prepareMissionLaunch, writeMissionAsyncBinding, type MissionLaunchBinding } from "../../missions/lifecycle.ts";
|
|
@@ -114,11 +123,15 @@ import { MissionNotFoundError, updateMission } from "../../missions/store.ts";
|
|
|
114
123
|
import type { MissionWorkflowChildUpdate } from "../../missions/types.ts";
|
|
115
124
|
import { createMissionWorkflowState } from "../../missions/workflow-state.ts";
|
|
116
125
|
import { resolveAuthorityDecision } from "../../policy/authority.ts";
|
|
117
|
-
import {
|
|
126
|
+
import { handleInspectorAction, INSPECTOR_ACTIONS } from "../../inspectors/actions.ts";
|
|
127
|
+
import { getInspectorPlugins } from "../../inspectors/plugins.ts";
|
|
118
128
|
import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.ts";
|
|
119
|
-
import { previewSimpleWorkflowRun, runWorkflowScript, validateWorkflowScript, WorkflowScriptError, type WorkflowLanePlan, type WorkflowReceiptResumeReference, type WorkflowScriptChildResult, type WorkflowScriptTraceEntry, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
|
|
129
|
+
import { previewSimpleWorkflowRun, runWorkflowScript, validateWorkflowScript, WorkflowScriptError, type WorkflowChildSettledNotification, type WorkflowLanePlan, type WorkflowReceiptResumeReference, type WorkflowScriptChildResult, type WorkflowScriptTraceEntry, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
|
|
130
|
+
import { formatIncrementalChildCompletion, incrementalChildCompletionTriggersTurn } from "../background/notify.ts";
|
|
131
|
+
import { appendWorkflowChildJournal, findWorkflowReuseSource, matchWorkflowReuse, workflowChildFingerprint, workflowScriptDigest, workflowStopCause, WORKFLOW_RUNTIME_REPLACED_RELAUNCH_NOTICE } from "../../workflows/workflow-reuse.ts";
|
|
120
132
|
import { executeWorkflowHostCommand, resolveWorkflowHostOutputClaimPath, type WorkflowHostCommandParams, type WorkflowHostCommandResult } from "../../workflows/host-command.ts";
|
|
121
133
|
import { buildWorkflowReceipt, readWorkflowReceipt, workflowReceiptPath, resolveWorkflowReceiptResumeEntry, writeWorkflowReceipt, type WorkflowReceipt, type WorkflowReceiptState } from "../../workflows/workflow-receipt.ts";
|
|
134
|
+
import { formatWorkflowKeyRevival, recordWorkflowRevival, withWorkflowRevivals } from "../../workflows/workflow-revival.ts";
|
|
122
135
|
import { upsertHostStep, validHostStepNodes } from "../shared/host-step-status.ts";
|
|
123
136
|
import { assertWorkflowLaneKey, normalizeWorkflowLaneMetadata } from "../shared/lane-metadata.ts";
|
|
124
137
|
import { parseWorkflowChildSummary, workflowChildProgress, workflowChildSummary } from "../../workflows/workflow-child-summary.ts";
|
|
@@ -134,16 +147,19 @@ import {
|
|
|
134
147
|
type WorkflowResourceAuthority,
|
|
135
148
|
type WorkflowResourcePermit,
|
|
136
149
|
} from "../../shared/workflow-child-permit.ts";
|
|
137
|
-
import { resolveWorkflowResource } from "../../workflows/workflow-resources.ts";
|
|
150
|
+
import { deepFreezeWorkflowArgs, normalizeWorkflowArgs, resolveStructuredWorkflowResource, resolveWorkflowResource } from "../../workflows/workflow-resources.ts";
|
|
151
|
+
import { stableJsonDigest } from "../../shared/launch-contract.ts";
|
|
138
152
|
import {
|
|
139
153
|
cleanupWorktrees,
|
|
140
154
|
createWorktrees,
|
|
155
|
+
preflightWorktreeSource,
|
|
141
156
|
withWorktreeTransaction,
|
|
142
157
|
type WorktreeSetupProgress,
|
|
143
158
|
diffWorktrees,
|
|
144
159
|
formatWorktreeDiffSummary,
|
|
145
160
|
type WorktreeSetup,
|
|
146
161
|
} from "../shared/worktree.ts";
|
|
162
|
+
import { applyReviewedCleanupPlan, formatCleanupReceipt, loadReviewedCleanupPlan } from "../shared/worktree-cleanup-apply.ts";
|
|
147
163
|
import { createWorktreeCleanupPlan, formatWorktreeCleanupPlan } from "../shared/worktree-cleanup-plan.ts";
|
|
148
164
|
import {
|
|
149
165
|
type AgentProgress,
|
|
@@ -188,23 +204,28 @@ import {
|
|
|
188
204
|
type SubagentState,
|
|
189
205
|
DIRS,
|
|
190
206
|
DEFAULT_ARTIFACT_CONFIG,
|
|
207
|
+
DEFAULT_MAX_OUTPUT,
|
|
191
208
|
DEFAULT_FORK_PREAMBLE,
|
|
192
209
|
SUBAGENT_ACTIONS,
|
|
210
|
+
SUBAGENT_ASYNC_STARTED_EVENT,
|
|
211
|
+
SUBAGENT_CHILD_STATUS_EVENT,
|
|
193
212
|
SUBAGENT_CONTROL_EVENT,
|
|
194
213
|
SUBAGENT_CONTROL_INTERCOM_EVENT,
|
|
195
214
|
SUBAGENT_FOREGROUND_COMPLETE_EVENT,
|
|
215
|
+
SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
196
216
|
checkSubagentDepth,
|
|
197
217
|
resolveChildMaxSubagentDepth,
|
|
198
218
|
resolveCurrentMaxSubagentDepth,
|
|
199
219
|
resolveMaxSubagentSpawnsPerRun,
|
|
220
|
+
truncateOutput,
|
|
200
221
|
wrapForkTask,
|
|
201
222
|
type ScheduleOrigin,
|
|
202
223
|
type SteeringTargetState,
|
|
203
224
|
} from "../../shared/types.ts";
|
|
204
225
|
import { deriveChildSessionName } from "../../shared/child-session-name.ts";
|
|
205
226
|
|
|
206
|
-
const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure", "mission.create", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "inspector.open", "inspector.close", "project.open", "project.close", "worktree.discard", "worktree.cleanup", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.rollback", "dismiss", "schedule.create", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"]);
|
|
207
|
-
const DESTRUCTIVE_MANAGEMENT_ACTIONS = new Set(["delete", "eject", "disable", "reset", "mission.close", "worktree.discard", "refine.rollback", "inspector.close", "project.close", "stop", "interrupt", "schedule.delete"]);
|
|
227
|
+
const MUTATING_MANAGEMENT_ACTIONS = new Set(["command.yield", "command.cancel", "create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure", "mission.create", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "inspector.open", "inspector.close", "project.open", "project.close", "worktree.discard", "worktree.cleanup", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.rollback", "dismiss", "schedule.create", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"]);
|
|
228
|
+
const DESTRUCTIVE_MANAGEMENT_ACTIONS = new Set(["command.cancel", "delete", "eject", "disable", "reset", "mission.close", "worktree.discard", "refine.rollback", "inspector.close", "project.close", "stop", "interrupt", "schedule.delete"]);
|
|
208
229
|
|
|
209
230
|
function resolveSteerDeliveryMode(mode: SubagentParamsLike["mode"]): SteerDeliveryMode | undefined {
|
|
210
231
|
return mode === "steer" || mode === "follow_up" || mode === "auto" ? mode : undefined;
|
|
@@ -235,16 +256,17 @@ function hasSingleAdjacentTransposition(left: string, right: string): boolean {
|
|
|
235
256
|
&& left.slice(mismatch + 2) === right.slice(mismatch + 2);
|
|
236
257
|
}
|
|
237
258
|
|
|
238
|
-
export function unknownSubagentActionMessage(action: string): string {
|
|
259
|
+
export function unknownSubagentActionMessage(action: string, disabled?: DisabledFeatureSurface): string {
|
|
239
260
|
const requested = action.toLowerCase();
|
|
240
|
-
const
|
|
261
|
+
const enabledActions = SUBAGENT_ACTIONS.filter((candidate) => !disabled?.actions.has(candidate));
|
|
262
|
+
const suggestion = enabledActions.find((candidate) => {
|
|
241
263
|
const distance = editDistance(requested, candidate);
|
|
242
264
|
const closeMatch = distance <= Math.max(1, Math.floor(candidate.length / 4)) || hasSingleAdjacentTransposition(requested, candidate);
|
|
243
265
|
if (DESTRUCTIVE_MANAGEMENT_ACTIONS.has(candidate)) return distance === 1 && requested.length >= candidate.length - 1;
|
|
244
266
|
return closeMatch;
|
|
245
267
|
});
|
|
246
268
|
const nextStep = 'Use subagent({ action: "status" }) to inspect runs or subagent({ action: "list" }) to inspect agents.';
|
|
247
|
-
const validActions = `Valid: ${
|
|
269
|
+
const validActions = `Valid: ${enabledActions.join(", ")}.`;
|
|
248
270
|
return suggestion
|
|
249
271
|
? `Unknown action: ${action}. Did you mean ${suggestion}? ${nextStep} ${validActions}`
|
|
250
272
|
: `Unknown action: ${action}. ${nextStep} ${validActions}`;
|
|
@@ -285,6 +307,7 @@ interface TaskParam {
|
|
|
285
307
|
agent: string;
|
|
286
308
|
task: string;
|
|
287
309
|
cwd?: string;
|
|
310
|
+
machine?: string;
|
|
288
311
|
count?: number;
|
|
289
312
|
output?: string | boolean;
|
|
290
313
|
outputMode?: "inline" | "file-only";
|
|
@@ -293,7 +316,7 @@ interface TaskParam {
|
|
|
293
316
|
model?: string;
|
|
294
317
|
fast?: boolean;
|
|
295
318
|
skill?: string | string[] | boolean;
|
|
296
|
-
outputSchema?: JsonSchemaObject;
|
|
319
|
+
outputSchema?: JsonSchemaObject | false;
|
|
297
320
|
acceptance?: AcceptanceInput;
|
|
298
321
|
agentContract?: AgentContract;
|
|
299
322
|
toolBudget?: ToolBudgetConfig;
|
|
@@ -309,6 +332,7 @@ export interface SubagentParamsLike {
|
|
|
309
332
|
merge?: unknown;
|
|
310
333
|
supersession?: unknown;
|
|
311
334
|
index?: number;
|
|
335
|
+
toolCallId?: string;
|
|
312
336
|
childId?: string;
|
|
313
337
|
view?: "fleet" | "transcript";
|
|
314
338
|
lines?: number;
|
|
@@ -328,8 +352,8 @@ export interface SubagentParamsLike {
|
|
|
328
352
|
mode?: SteerDeliveryMode | "plan" | "apply";
|
|
329
353
|
repo?: string;
|
|
330
354
|
planId?: string;
|
|
355
|
+
/** Internal script carrier (slash, prompt-workflow, scheduled, RPC, named resources). The model-facing tool rejects it. */
|
|
331
356
|
workflowScript?: string;
|
|
332
|
-
workflowScriptPath?: string;
|
|
333
357
|
globalConcurrencyLimit?: number;
|
|
334
358
|
maxSubagentSpawnsPerRun?: number;
|
|
335
359
|
preflight?: import("../../shared/types.ts").WorkflowPreflight;
|
|
@@ -355,7 +379,7 @@ export interface SubagentParamsLike {
|
|
|
355
379
|
runFanoutAdmitted?: boolean;
|
|
356
380
|
/** Internal inherited tool/agent ceiling for delegated child launches. */
|
|
357
381
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
358
|
-
/** Internal durable-run compatibility fields. Public callers must use
|
|
382
|
+
/** Internal durable-run compatibility fields. Public callers must use workflow. */
|
|
359
383
|
chain?: ChainStep[];
|
|
360
384
|
tasks?: TaskParam[];
|
|
361
385
|
concurrency?: number;
|
|
@@ -369,6 +393,8 @@ export interface SubagentParamsLike {
|
|
|
369
393
|
foregroundOnly?: boolean;
|
|
370
394
|
timeoutMs?: number;
|
|
371
395
|
maxRuntimeMs?: number;
|
|
396
|
+
/** Async runs only: steer the child to checkpoint and stop this many ms before the run deadline. */
|
|
397
|
+
checkpointBeforeDeadlineMs?: number;
|
|
372
398
|
/** Optional hard per-tool-call timeout (ms). Known-fast tools also have a default. */
|
|
373
399
|
toolTimeoutMs?: number;
|
|
374
400
|
toolBudget?: ToolBudgetConfig;
|
|
@@ -378,6 +404,9 @@ export interface SubagentParamsLike {
|
|
|
378
404
|
control?: ControlConfig;
|
|
379
405
|
sessionDir?: string;
|
|
380
406
|
cwd?: string;
|
|
407
|
+
machine?: string;
|
|
408
|
+
/** Internal: the typed cwd when a machine is set, kept as a remote path and never resolved locally. */
|
|
409
|
+
machineCwd?: string;
|
|
381
410
|
maxOutput?: MaxOutputConfig;
|
|
382
411
|
artifacts?: boolean;
|
|
383
412
|
includeProgress?: boolean;
|
|
@@ -386,8 +415,8 @@ export interface SubagentParamsLike {
|
|
|
386
415
|
modelOrigin?: ModelOrigin;
|
|
387
416
|
fast?: boolean;
|
|
388
417
|
thinking?: string | false;
|
|
389
|
-
/**
|
|
390
|
-
workflow?: string;
|
|
418
|
+
/** true = the ```js workflow block in the calling reply; a string containing "/" or "\" = script path; otherwise a named workflow resource. */
|
|
419
|
+
workflow?: string | true;
|
|
391
420
|
args?: Record<string, unknown>;
|
|
392
421
|
scope?: string;
|
|
393
422
|
target?: string;
|
|
@@ -397,7 +426,7 @@ export interface SubagentParamsLike {
|
|
|
397
426
|
/** Internal-only; not part of the public tool schema. Wired for single-run reads (chain steps use their own field). */
|
|
398
427
|
reads?: string[] | false;
|
|
399
428
|
outputMode?: "inline" | "file-only";
|
|
400
|
-
outputSchema?: JsonSchemaObject;
|
|
429
|
+
outputSchema?: JsonSchemaObject | false;
|
|
401
430
|
agentScope?: unknown;
|
|
402
431
|
chainDir?: string;
|
|
403
432
|
acceptance?: AcceptanceInput;
|
|
@@ -406,7 +435,8 @@ export interface SubagentParamsLike {
|
|
|
406
435
|
at?: string;
|
|
407
436
|
every?: string;
|
|
408
437
|
sessionOnly?: boolean;
|
|
409
|
-
|
|
438
|
+
quiet?: boolean;
|
|
439
|
+
on?: string[];
|
|
410
440
|
timezone?: string;
|
|
411
441
|
overlap?: "skip";
|
|
412
442
|
catchUp?: "none" | "latest";
|
|
@@ -432,6 +462,7 @@ function rememberParentModel(state: { currentSessionId?: string | null; lastPare
|
|
|
432
462
|
|
|
433
463
|
interface ExecutorDeps {
|
|
434
464
|
pi: ExtensionAPI;
|
|
465
|
+
parentWake?: Pick<ExtensionAPI, "sendMessage">;
|
|
435
466
|
state: SubagentState;
|
|
436
467
|
config: ExtensionConfig;
|
|
437
468
|
asyncByDefault: boolean;
|
|
@@ -443,6 +474,7 @@ interface ExecutorDeps {
|
|
|
443
474
|
getSubagentSessionRoot: (parentSessionFile: string | null) => string;
|
|
444
475
|
expandTilde: (p: string) => string;
|
|
445
476
|
discoverAgents: (cwd: string, scope: AgentScope, preferredModelProvider?: string) => { agents: AgentConfig[]; agentDiagnostics?: AgentDiscoveryDiagnostic[]; modelScope?: ModelScopeConfig; maxThinking?: AgentConfig["maxThinking"]; cwd?: string; scope?: AgentScope; directories?: UnknownAgentDiagnosticContext["directories"] };
|
|
477
|
+
discoverAgentsAll?: typeof discoverAgentsAll;
|
|
446
478
|
onAgentsChanged?: () => void;
|
|
447
479
|
allowMutatingManagementActions?: boolean;
|
|
448
480
|
activateSupervisorTransport?: () => void;
|
|
@@ -468,7 +500,7 @@ function inheritedRunFanoutBudget(deps: Pick<ExecutorDeps, "childRuntime">): Run
|
|
|
468
500
|
|
|
469
501
|
type ForkSessionFileForTask = (agentName: string, idx?: number, modelOverride?: string, modelOverrideFromParent?: boolean, modelOrigin?: ModelOrigin) => string | undefined;
|
|
470
502
|
type PrepareForkSessionForTask = (agentName: string, idx?: number, modelOverride?: string, modelOverrideFromParent?: boolean, modelOrigin?: ModelOrigin) => Promise<void>;
|
|
471
|
-
type
|
|
503
|
+
type ThinkingOverrideForTask = () => AgentConfig["thinking"] | undefined;
|
|
472
504
|
|
|
473
505
|
interface ExecutionContextData {
|
|
474
506
|
params: SubagentParamsLike;
|
|
@@ -488,7 +520,7 @@ interface ExecutionContextData {
|
|
|
488
520
|
sessionDirForIndex: (idx?: number) => string;
|
|
489
521
|
sessionFileForIndex: (idx?: number) => string | undefined;
|
|
490
522
|
sessionFileForTask: ForkSessionFileForTask;
|
|
491
|
-
thinkingOverrideForTask:
|
|
523
|
+
thinkingOverrideForTask: ThinkingOverrideForTask;
|
|
492
524
|
artifactConfig: ArtifactConfig;
|
|
493
525
|
artifactsDir: string;
|
|
494
526
|
backgroundRequestedWhileClarifying: boolean;
|
|
@@ -507,11 +539,14 @@ interface ExecutionContextData {
|
|
|
507
539
|
usageBudget?: UsageBudgetConfig;
|
|
508
540
|
/** Parent workflow owns this allowance; presence vetoes unverifiable child continuation. */
|
|
509
541
|
inheritedUsageBudget?: UsageBudgetConfig;
|
|
542
|
+
/** Mandatory host extensions retained by a parent workflow; they outlive a later registration disposal. */
|
|
543
|
+
requiredExtensions?: RequiredChildExtensionSnapshot;
|
|
510
544
|
allowZeroToolBudget?: boolean;
|
|
511
545
|
configToolBudget?: ResolvedToolBudget;
|
|
512
546
|
contextPolicy: AgentDefaultContextPolicy;
|
|
513
547
|
modelScope?: ModelScopeConfig;
|
|
514
548
|
parentModel?: ParentModel;
|
|
549
|
+
scopedModelIds?: string[];
|
|
515
550
|
parentSessionId: string | null;
|
|
516
551
|
parentPiSessionId?: string;
|
|
517
552
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
@@ -525,18 +560,16 @@ function resolveRequestedCwd(runtimeCwd: string, requestedCwd: string | undefine
|
|
|
525
560
|
return requestedCwd ? path.resolve(runtimeCwd, requestedCwd) : runtimeCwd;
|
|
526
561
|
}
|
|
527
562
|
|
|
528
|
-
function
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
let workflowScript: string;
|
|
563
|
+
function readWorkflowScriptFile(requestedPath: string, requestedCwd: string | undefined, runtimeCwd: string): { script: string } | { error: string } {
|
|
564
|
+
const scriptPath = path.resolve(resolveRequestedCwd(runtimeCwd, requestedCwd), requestedPath);
|
|
565
|
+
let script: string;
|
|
532
566
|
try {
|
|
533
|
-
|
|
567
|
+
script = fs.readFileSync(scriptPath, "utf8");
|
|
534
568
|
} catch (error) {
|
|
535
|
-
return { error: `Failed to read
|
|
569
|
+
return { error: `Failed to read workflow script '${scriptPath}': ${error instanceof Error ? error.message : String(error)}` };
|
|
536
570
|
}
|
|
537
|
-
if (!
|
|
538
|
-
|
|
539
|
-
return { params: { ...rest, workflowScript } };
|
|
571
|
+
if (!script.trim()) return { error: `Workflow script file '${scriptPath}' is empty.` };
|
|
572
|
+
return { script };
|
|
540
573
|
}
|
|
541
574
|
|
|
542
575
|
export function removeForegroundControlIfIdle(state: SubagentState, runId: string, trackRetainedNestedRoute?: (rootRunId: string) => void): boolean {
|
|
@@ -549,6 +582,7 @@ export function removeForegroundControlIfIdle(state: SubagentState, runId: strin
|
|
|
549
582
|
console.error(`Failed to retain live nested descendants for foreground run '${runId}':`, error);
|
|
550
583
|
}
|
|
551
584
|
}
|
|
585
|
+
retainNestedLookupRoute(state, control?.nestedRoute, control?.sessionId);
|
|
552
586
|
state.foregroundControls.delete(runId);
|
|
553
587
|
if (state.lastForegroundControlId === runId) state.lastForegroundControlId = null;
|
|
554
588
|
return true;
|
|
@@ -616,6 +650,11 @@ function trustedSessionRootsForStatus(ctx: ExtensionContext, deps: ExecutorDeps)
|
|
|
616
650
|
return [...new Set(roots)];
|
|
617
651
|
}
|
|
618
652
|
|
|
653
|
+
/** Children follow the launching session's trust; hosts older than Pi's trust concept keep Pi's default. */
|
|
654
|
+
function sessionProjectTrust(ctx: ExtensionContext): boolean | undefined {
|
|
655
|
+
return typeof ctx.isProjectTrusted === "function" ? ctx.isProjectTrusted() : undefined;
|
|
656
|
+
}
|
|
657
|
+
|
|
619
658
|
function spawnBudgetErrorResult(message: string, mode: "single" | "parallel" | "chain"): AgentToolResult<Details> {
|
|
620
659
|
return {
|
|
621
660
|
content: [{ type: "text", text: message }],
|
|
@@ -743,7 +782,7 @@ function foregroundChildActivityFromProgress(progress: SingleResult["progress"]
|
|
|
743
782
|
};
|
|
744
783
|
}
|
|
745
784
|
|
|
746
|
-
function rememberForegroundRun(state: SubagentState, input: { modelResponseAliases?: Record<string, string[]>; runId: string; mode: "single" | "parallel" | "chain"; cwd: string; sessionId: string | null; results: SingleResult[]; params: SubagentParamsLike; effectiveOutput?: string | boolean; effectiveOutputMode: OutputMode; extensionBindings?: ExtensionBindings }): void {
|
|
785
|
+
function rememberForegroundRun(state: SubagentState, input: { modelResponseAliases?: Record<string, string[]>; runId: string; mode: "single" | "parallel" | "chain"; cwd: string; sessionId: string | null; results: SingleResult[]; params: SubagentParamsLike; effectiveOutput?: string | boolean; effectiveOutputMode: OutputMode; extensionBindings?: ExtensionBindings; requiredExtensions?: SteeringRecoveryDescriptor["requiredExtensions"] }): void {
|
|
747
786
|
state.foregroundRuns ??= new Map();
|
|
748
787
|
const previous = state.foregroundRuns.get(input.runId);
|
|
749
788
|
const updatedAt = Date.now();
|
|
@@ -782,6 +821,7 @@ function rememberForegroundRun(state: SubagentState, input: { modelResponseAlias
|
|
|
782
821
|
...(result.error ? { error: result.error } : {}),
|
|
783
822
|
...(result.finalOutput ? { finalOutput: result.finalOutput } : {}),
|
|
784
823
|
...(result.outputState ? { outputState: result.outputState } : {}),
|
|
824
|
+
...(result.outputPartial ? { outputPartial: true } : {}),
|
|
785
825
|
...(result.outputMode ? { outputMode: result.outputMode } : {}),
|
|
786
826
|
...(result.savedOutputPath ? { savedOutputPath: result.savedOutputPath } : {}),
|
|
787
827
|
...(result.outputSaveError ? { outputSaveError: result.outputSaveError } : {}),
|
|
@@ -796,6 +836,7 @@ function rememberForegroundRun(state: SubagentState, input: { modelResponseAlias
|
|
|
796
836
|
...(Object.keys(resumeContract).length ? { resumeContract } : {}),
|
|
797
837
|
...(result.launchContractDigest ? { launchContractDigest: result.launchContractDigest } : {}),
|
|
798
838
|
...(input.extensionBindings ? { extensionBindings: input.extensionBindings } : {}),
|
|
839
|
+
...(input.requiredExtensions?.length ? { requiredExtensions: input.requiredExtensions } : {}),
|
|
799
840
|
...(result.launchResolvedExtensions ? { launchResolvedExtensions: result.launchResolvedExtensions } : {}),
|
|
800
841
|
...(result.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: result.runtimeAcknowledgedExtensions } : {}),
|
|
801
842
|
...(result.capabilityCeiling ? { capabilityCeiling: result.capabilityCeiling } : {}),
|
|
@@ -864,6 +905,7 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
864
905
|
...(input.result.error ? { error: input.result.error } : {}),
|
|
865
906
|
...(input.result.finalOutput ? { finalOutput: input.result.finalOutput } : {}),
|
|
866
907
|
outputState: input.result.outputState,
|
|
908
|
+
outputPartial: input.result.outputPartial,
|
|
867
909
|
outputMode: input.result.outputMode,
|
|
868
910
|
savedOutputPath: input.result.savedOutputPath,
|
|
869
911
|
outputSaveError: input.result.outputSaveError,
|
|
@@ -947,6 +989,7 @@ function resolveForegroundResumeTarget(params: SubagentParamsLike, state: Subage
|
|
|
947
989
|
...(child.launchContractDigest ? { launchContractDigest: child.launchContractDigest } : {}),
|
|
948
990
|
...(child.resumeContract ? { resumeContract: child.resumeContract } : {}),
|
|
949
991
|
...(child.extensionBindings ? { extensionBindings: normalizeExtensionBindings(child.extensionBindings)!.value } : {}),
|
|
992
|
+
...(child.requiredExtensions ? { requiredExtensions: child.requiredExtensions } : {}),
|
|
950
993
|
...(child.capabilityCeiling ? { capabilityCeiling: child.capabilityCeiling } : {}),
|
|
951
994
|
};
|
|
952
995
|
}
|
|
@@ -1237,10 +1280,14 @@ function appendStepToAsyncChain(input: {
|
|
|
1237
1280
|
};
|
|
1238
1281
|
}
|
|
1239
1282
|
const chain = [input.params.step];
|
|
1240
|
-
const
|
|
1241
|
-
|
|
1283
|
+
const validationParams = { ...input.params, chain } as SubagentParamsLike;
|
|
1284
|
+
const acceptancePolicyErrors = validateExecutionAcceptancePolicy(validationParams);
|
|
1285
|
+
const outputSchemaError = validateLaunchOutputSchemaOverrides(validationParams);
|
|
1286
|
+
const earlyErrors = [...acceptancePolicyErrors];
|
|
1287
|
+
if (outputSchemaError) earlyErrors.push(outputSchemaError);
|
|
1288
|
+
if (earlyErrors.length > 0) {
|
|
1242
1289
|
return {
|
|
1243
|
-
content: [{ type: "text", text: `Cannot append step: ${
|
|
1290
|
+
content: [{ type: "text", text: `Cannot append step: ${earlyErrors.join(" ")}` }],
|
|
1244
1291
|
isError: true,
|
|
1245
1292
|
details: { mode: "management", results: [] },
|
|
1246
1293
|
};
|
|
@@ -1299,6 +1346,16 @@ function appendStepToAsyncChain(input: {
|
|
|
1299
1346
|
};
|
|
1300
1347
|
}
|
|
1301
1348
|
|
|
1349
|
+
let retainedRequiredExtensions: RequiredChildExtensionSnapshot | undefined;
|
|
1350
|
+
try {
|
|
1351
|
+
retainedRequiredExtensions = readRetainedRequiredChildExtensions(resolved.location.asyncDir);
|
|
1352
|
+
} catch (error) {
|
|
1353
|
+
return {
|
|
1354
|
+
content: [{ type: "text", text: `Cannot append step to run '${resolved.id}': ${error instanceof Error ? error.message : String(error)}` }],
|
|
1355
|
+
isError: true,
|
|
1356
|
+
details: { mode: "management", results: [] },
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1302
1359
|
const pendingAppendRequests = readPendingChainAppendRequests(resolved.location.asyncDir);
|
|
1303
1360
|
const reservedOutputNames = new Set<string>([
|
|
1304
1361
|
...Object.keys(status.outputs ?? {}),
|
|
@@ -1322,6 +1379,14 @@ function appendStepToAsyncChain(input: {
|
|
|
1322
1379
|
const scope: AgentScope = resolveExecutionAgentScope(input.params.agentScope);
|
|
1323
1380
|
const discoveredForAppend = input.deps.discoverAgents(input.requestCwd, scope, input.parentModel?.provider);
|
|
1324
1381
|
const agents = discoveredForAppend.agents;
|
|
1382
|
+
const acceptanceErrors = validateExecutionAcceptance(projectEffectiveAcceptanceSchemas(validationParams, agents));
|
|
1383
|
+
if (acceptanceErrors.length > 0) {
|
|
1384
|
+
return {
|
|
1385
|
+
content: [{ type: "text", text: `Cannot append step: ${acceptanceErrors.join(" ")}` }],
|
|
1386
|
+
isError: true,
|
|
1387
|
+
details: { mode: "management", results: [] },
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1325
1390
|
const contextPolicy = resolveExplicitContextPolicy(input.params);
|
|
1326
1391
|
const chainSkillInput = normalizeSkillInput(input.params.skill);
|
|
1327
1392
|
const chainSkills = chainSkillInput === false ? [] : (chainSkillInput ?? []);
|
|
@@ -1333,6 +1398,7 @@ function appendStepToAsyncChain(input: {
|
|
|
1333
1398
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1334
1399
|
currentModelProvider: parentModel?.provider,
|
|
1335
1400
|
currentModel: parentModel,
|
|
1401
|
+
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
1336
1402
|
modelScope: discoveredForAppend.modelScope,
|
|
1337
1403
|
modelResponseAliases: input.deps.config.modelResponseAliases,
|
|
1338
1404
|
interactive: input.ctx.hasUI,
|
|
@@ -1360,6 +1426,7 @@ function appendStepToAsyncChain(input: {
|
|
|
1360
1426
|
asyncDir: resolved.location.asyncDir,
|
|
1361
1427
|
validateOutputBindings: false,
|
|
1362
1428
|
capabilityCeiling: intersectSubagentCapabilityCeilings(status.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(asyncCtx.currentSessionId)),
|
|
1429
|
+
requiredExtensions: retainedRequiredExtensions,
|
|
1363
1430
|
}));
|
|
1364
1431
|
if ("error" in built) {
|
|
1365
1432
|
return {
|
|
@@ -1490,6 +1557,51 @@ function resolveNestedResumeTarget(match: ResolvedSubagentRunId & { kind: "neste
|
|
|
1490
1557
|
});
|
|
1491
1558
|
}
|
|
1492
1559
|
|
|
1560
|
+
function resolveNestedExternalJobResumeTarget(match: ResolvedSubagentRunId & { kind: "nested" }, params: SubagentParamsLike, deps: ExecutorDeps): AsyncResumeSourceTarget | undefined {
|
|
1561
|
+
const run = match.match.run;
|
|
1562
|
+
if (run.state === "stopped") return undefined;
|
|
1563
|
+
const asyncDir = resolveNestedAsyncDir(match.match.rootRunId, run);
|
|
1564
|
+
if (!asyncDir) return undefined;
|
|
1565
|
+
const status = readNestedRunStatus(asyncDir, run);
|
|
1566
|
+
const steps = status?.steps ?? [];
|
|
1567
|
+
const step = steps[params.index ?? 0];
|
|
1568
|
+
if (!step) {
|
|
1569
|
+
// An index outside an external-job run gets the async resolver's index error instead of a Pi revive.
|
|
1570
|
+
if (params.index === undefined || !steps.some((candidate) => candidate.runner?.type === "external-job")) return undefined;
|
|
1571
|
+
} else if (!step.runner) {
|
|
1572
|
+
// Pi steps record no runner, and neither does a launch status before the runner starts.
|
|
1573
|
+
// A session file means a Pi run; otherwise the agent definition says what the step runs.
|
|
1574
|
+
if (nestedRunSessionFile(run)) return undefined;
|
|
1575
|
+
const agent = deps.discoverAgents(status?.cwd ?? deps.state.baseCwd, resolveExecutionAgentScope(params.agentScope)).agents.find((candidate) => candidate.name === step.agent);
|
|
1576
|
+
if (agent?.runner?.type === "external-job") throw new Error(externalJobWithoutMetadataMessage(run.id));
|
|
1577
|
+
return undefined;
|
|
1578
|
+
} else if (step.runner.type !== "external-job") {
|
|
1579
|
+
return undefined;
|
|
1580
|
+
}
|
|
1581
|
+
// External-job runs have no Pi session, so resume them as a provider follow-up from their own run directory.
|
|
1582
|
+
const target = resolveAsyncResumeTarget(compactOptional<Parameters<typeof resolveAsyncResumeTarget>[0]>({ dir: asyncDir, index: params.index }), nestedRunScope(match.match.rootRunId), { requireSessionFile: false });
|
|
1583
|
+
if (target.kind === "live") throw new Error(externalJobStillRunningMessage(target.runId));
|
|
1584
|
+
return { source: "async", ...target };
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
function readNestedRunStatus(asyncDir: string, run: NestedRunSummary): AsyncStatus | null {
|
|
1588
|
+
try {
|
|
1589
|
+
return readStatus(asyncDir);
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
// A nested Pi run revives from its session file, so its unreadable status file must not block it.
|
|
1592
|
+
if (nestedRunSessionFile(run)) return null;
|
|
1593
|
+
throw error;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
function externalJobStillRunningMessage(runId: string): string {
|
|
1598
|
+
return `External-job run '${runId}' is still running. Wait for completion, then use subagent({ action: "resume", id: "${runId}", message: "..." }).`;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
function externalJobWithoutMetadataMessage(runId: string): string {
|
|
1602
|
+
return `External-job run '${runId}' has no persisted provider metadata. Cannot follow up without the parent provider job id.`;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1493
1605
|
async function waitForNestedControlResult(target: ResolvedSubagentRunId & { kind: "nested" }, requestId: string, ignoredFiles: ReadonlySet<string>, timeoutMs = 1_000) {
|
|
1494
1606
|
const deadline = Date.now() + timeoutMs;
|
|
1495
1607
|
while (Date.now() < deadline) {
|
|
@@ -1652,12 +1764,12 @@ async function resumeExternalJobFollowUp(input: {
|
|
|
1652
1764
|
absoluteDeadlineAt?: number;
|
|
1653
1765
|
}): Promise<AgentToolResult<Details>> {
|
|
1654
1766
|
if (input.target.kind === "live" || input.target.state === "running" || input.target.state === "queued") {
|
|
1655
|
-
return { content: [{ type: "text", text:
|
|
1767
|
+
return { content: [{ type: "text", text: externalJobStillRunningMessage(input.target.runId) }], isError: true, details: { mode: "management", results: [] } };
|
|
1656
1768
|
}
|
|
1657
1769
|
const runner = input.target.runner;
|
|
1658
1770
|
const externalJob = input.target.externalJob;
|
|
1659
1771
|
if (runner?.type !== "external-job") return { content: [{ type: "text", text: "Internal error: external-job follow-up was requested for a non-external-job runner." }], isError: true, details: { mode: "management", results: [] } };
|
|
1660
|
-
if (!externalJob) return { content: [{ type: "text", text:
|
|
1772
|
+
if (!externalJob) return { content: [{ type: "text", text: externalJobWithoutMetadataMessage(input.target.runId) }], isError: true, details: { mode: "management", results: [] } };
|
|
1661
1773
|
if (externalJob.provider !== runner.provider) return { content: [{ type: "text", text: `External-job run '${input.target.runId}' has mismatched provider metadata. Refusing to follow up.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1662
1774
|
if (!externalJobOptionsEqual(externalJob.options, runner.options)) return { content: [{ type: "text", text: `External-job run '${input.target.runId}' has mismatched provider options. Refusing to follow up.` }], isError: true, details: { mode: "management", results: [] } };
|
|
1663
1775
|
if (!externalJob.providerJobId) return { content: [{ type: "text", text: `External-job run '${input.target.runId}' has no parent provider job id. Cannot follow up without reopening or redispatching, so this fails closed.` }], isError: true, details: { mode: "management", results: [] } };
|
|
@@ -1669,10 +1781,13 @@ async function resumeExternalJobFollowUp(input: {
|
|
|
1669
1781
|
const requestDigest = externalJobFollowUpRequestDigest({ provider: runner.provider, parentProviderJobId: externalJob.providerJobId, promptDigest, options: runner.options });
|
|
1670
1782
|
const requestId = externalJobFollowUpRequestId(requestDigest);
|
|
1671
1783
|
const runId = externalJobFollowUpRunId(requestDigest);
|
|
1672
|
-
|
|
1784
|
+
// A child launches the follow-up under its nested route, so look for an earlier one where it would be.
|
|
1785
|
+
const nestedRoute = inheritedNestedRoute(input.deps);
|
|
1786
|
+
const runRoots = nestedRoute ? nestedRunScope(nestedRoute.rootRunId) : { asyncDirRoot: DIRS.async, resultsDir: DIRS.results };
|
|
1787
|
+
const asyncDir = path.join(runRoots.asyncDirRoot, runId);
|
|
1673
1788
|
const currentSessionId = input.deps.state.currentSessionId;
|
|
1674
1789
|
if (!currentSessionId) return { content: [{ type: "text", text: "External-job follow-up requires an active parent session." }], isError: true, details: { mode: "management", results: [] } };
|
|
1675
|
-
if (fs.existsSync(asyncDir) || fs.existsSync(resultFilePath(
|
|
1790
|
+
if (fs.existsSync(asyncDir) || fs.existsSync(resultFilePath(runRoots.resultsDir, runId))) {
|
|
1676
1791
|
return externalJobFollowUpStarted({ sourceRunId: input.target.runId, runId, asyncDir, duplicate: true, interactive: input.ctx.hasUI });
|
|
1677
1792
|
}
|
|
1678
1793
|
|
|
@@ -1702,7 +1817,7 @@ async function resumeExternalJobFollowUp(input: {
|
|
|
1702
1817
|
...input.baseAgentConfig,
|
|
1703
1818
|
runner: { type: "external-job", provider: runner.provider, options: runner.options },
|
|
1704
1819
|
};
|
|
1705
|
-
const result = executeAsyncSingle(runId, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
1820
|
+
const result = await executeAsyncSingle(runId, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
1706
1821
|
agent: input.target.agent,
|
|
1707
1822
|
task: input.followUp,
|
|
1708
1823
|
goal: input.followUp,
|
|
@@ -1715,11 +1830,13 @@ async function resumeExternalJobFollowUp(input: {
|
|
|
1715
1830
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1716
1831
|
currentModelProvider: parentModel?.provider,
|
|
1717
1832
|
currentModel: parentModel,
|
|
1833
|
+
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
1718
1834
|
modelScope: input.modelScope,
|
|
1719
1835
|
modelResponseAliases: input.deps.config.modelResponseAliases,
|
|
1720
1836
|
interactive: input.ctx.hasUI,
|
|
1721
1837
|
permissions: input.deps.config.permissions,
|
|
1722
1838
|
childRuntime: input.deps.childRuntime,
|
|
1839
|
+
projectTrusted: sessionProjectTrust(input.ctx),
|
|
1723
1840
|
}),
|
|
1724
1841
|
cwd: input.effectiveCwd,
|
|
1725
1842
|
artifactsDir,
|
|
@@ -1765,6 +1882,8 @@ function resolveRequestedResumeTarget(params: SubagentParamsLike, deps: Executor
|
|
|
1765
1882
|
if (resolved?.kind === "nested") {
|
|
1766
1883
|
if (params.chain?.length) throw new Error("Attaching a running subagent as a chain root is currently available for top-level async runs only.");
|
|
1767
1884
|
if (resolved.match.run.state === "running" || resolved.match.run.state === "queued") return { kind: "live-nested", target: resolved };
|
|
1885
|
+
const externalJobTarget = resolveNestedExternalJobResumeTarget(resolved, params, deps);
|
|
1886
|
+
if (externalJobTarget) return externalJobTarget;
|
|
1768
1887
|
const trustedSessionRoots = [
|
|
1769
1888
|
...(deps.config.defaultSessionDir ? [path.resolve(deps.expandTilde(deps.config.defaultSessionDir))] : []),
|
|
1770
1889
|
...(parentSessionFile ? [deps.getSubagentSessionRoot(parentSessionFile)] : []),
|
|
@@ -1782,6 +1901,7 @@ async function resumeAsyncRun(input: {
|
|
|
1782
1901
|
parentModel?: ParentModel;
|
|
1783
1902
|
absoluteDeadlineAt?: number;
|
|
1784
1903
|
signal?: AbortSignal;
|
|
1904
|
+
onLaunch?: (launch: { agent: string; sessionName?: string; sessionFile?: string; async: boolean; runId?: string }) => void;
|
|
1785
1905
|
}): Promise<AgentToolResult<Details>> {
|
|
1786
1906
|
const followUp = (input.params.message ?? input.params.task ?? "").trim();
|
|
1787
1907
|
const attachChain = (input.params.chain?.length ?? 0) > 0 ? input.params.chain as ChainStep[] : undefined;
|
|
@@ -1792,21 +1912,29 @@ async function resumeAsyncRun(input: {
|
|
|
1792
1912
|
details: { mode: "management", results: [] },
|
|
1793
1913
|
};
|
|
1794
1914
|
}
|
|
1795
|
-
|
|
1915
|
+
const timeoutOverflowError = timerDelayOverflowError("timeoutMs", input.params.timeoutMs);
|
|
1916
|
+
if (timeoutOverflowError) {
|
|
1796
1917
|
return {
|
|
1797
|
-
content: [{ type: "text", text:
|
|
1918
|
+
content: [{ type: "text", text: timeoutOverflowError }],
|
|
1798
1919
|
isError: true,
|
|
1799
1920
|
details: { mode: "management", results: [] },
|
|
1800
1921
|
};
|
|
1801
1922
|
}
|
|
1802
|
-
|
|
1803
|
-
if (acceptanceErrors.length > 0) {
|
|
1923
|
+
if (input.params.model !== undefined) {
|
|
1804
1924
|
return {
|
|
1805
|
-
content: [{ type: "text", text:
|
|
1925
|
+
content: [{ type: "text", text: "action='resume' reuses the persisted child model and does not accept a model override." }],
|
|
1806
1926
|
isError: true,
|
|
1807
1927
|
details: { mode: "management", results: [] },
|
|
1808
1928
|
};
|
|
1809
1929
|
}
|
|
1930
|
+
const acceptancePolicyErrors = validateExecutionAcceptancePolicy(input.params);
|
|
1931
|
+
if (acceptancePolicyErrors.length > 0) {
|
|
1932
|
+
return { content: [{ type: "text", text: `Cannot resume: ${acceptancePolicyErrors.join(" ")}` }], isError: true, details: { mode: "management", results: [] } };
|
|
1933
|
+
}
|
|
1934
|
+
const outputSchemaError = validateLaunchOutputSchemaOverrides(input.params);
|
|
1935
|
+
if (outputSchemaError) {
|
|
1936
|
+
return { content: [{ type: "text", text: `Cannot resume: ${outputSchemaError}` }], isError: true, details: { mode: "management", results: [] } };
|
|
1937
|
+
}
|
|
1810
1938
|
input.deps.state.currentSessionId = resolveCurrentSessionId(input.ctx.sessionManager);
|
|
1811
1939
|
|
|
1812
1940
|
let target: ResumeSourceTarget;
|
|
@@ -1850,7 +1978,7 @@ async function resumeAsyncRun(input: {
|
|
|
1850
1978
|
const discoveredAgents = discovered.agents;
|
|
1851
1979
|
const unknownAgentDiagnosticContext = diagnosticContextFromDiscovery(discovered, effectiveCwd, scope);
|
|
1852
1980
|
const modelScope = discovered.modelScope;
|
|
1853
|
-
const sessionName = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
|
|
1981
|
+
const sessionName = resolveIntercomSessionTarget(input.deps.childRuntime?.intercomSessionName ?? input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
|
|
1854
1982
|
const recoveryDescriptor = "recoveryDescriptor" in target ? target.recoveryDescriptor : undefined;
|
|
1855
1983
|
const recoveryContext = recoveryDescriptor?.context ?? (input.params.context === "profile" ? undefined : input.params.context);
|
|
1856
1984
|
const intercomBridge = resolveIntercomBridge({
|
|
@@ -1889,9 +2017,21 @@ async function resumeAsyncRun(input: {
|
|
|
1889
2017
|
: "External runners do not persist Pi sessions and cannot be resumed.";
|
|
1890
2018
|
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
1891
2019
|
}
|
|
2020
|
+
if (input.params.baseRef !== undefined && "managedWorktree" in target && target.managedWorktree === true) {
|
|
2021
|
+
return { content: [{ type: "text", text: "Cannot resume with baseRef: retained managed-worktree children continue in their existing worktree. Start a new worktree run from that base ref instead." }], isError: true, details: { mode: "management", results: [] } };
|
|
2022
|
+
}
|
|
2023
|
+
if (target.source === "async" && target.managedWorktree && target.asyncDir) {
|
|
2024
|
+
try {
|
|
2025
|
+
const protectedCwd = await protectRetainedWorktreeForResume(parallelHandoffPath(target.asyncDir), target.runId, target.index, input.signal);
|
|
2026
|
+
if (path.resolve(protectedCwd) !== path.resolve(effectiveCwd)) throw new Error("Retained worktree cwd changed during resume admission.");
|
|
2027
|
+
} catch (error) {
|
|
2028
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
|
|
1892
2032
|
if (target.source === "async" && target.runner?.type === "external-job") {
|
|
1893
2033
|
if (attachChain) return { content: [{ type: "text", text: "External-job follow-up does not support chain attachment. Use action='resume' with message instead." }], isError: true, details: { mode: "management", results: [] } };
|
|
1894
|
-
|
|
2034
|
+
const resumed = await resumeExternalJobFollowUp({
|
|
1895
2035
|
target,
|
|
1896
2036
|
followUp,
|
|
1897
2037
|
baseAgentConfig,
|
|
@@ -1905,6 +2045,9 @@ async function resumeAsyncRun(input: {
|
|
|
1905
2045
|
parentSessionFile,
|
|
1906
2046
|
absoluteDeadlineAt: input.absoluteDeadlineAt,
|
|
1907
2047
|
});
|
|
2048
|
+
const resumedRunId = resumed.details.runId ?? resumed.details.asyncId;
|
|
2049
|
+
if (!resumed.isError && resumedRunId) input.onLaunch?.({ agent: target.agent, async: true, runId: resumedRunId });
|
|
2050
|
+
return resumed;
|
|
1908
2051
|
}
|
|
1909
2052
|
|
|
1910
2053
|
if (attachChain) {
|
|
@@ -1922,6 +2065,10 @@ async function resumeAsyncRun(input: {
|
|
|
1922
2065
|
details: { mode: "chain", results: [] },
|
|
1923
2066
|
};
|
|
1924
2067
|
}
|
|
2068
|
+
const acceptanceErrors = validateExecutionAcceptance(projectEffectiveAcceptanceSchemas(input.params, agents));
|
|
2069
|
+
if (acceptanceErrors.length > 0) {
|
|
2070
|
+
return { content: [{ type: "text", text: `Cannot resume: ${acceptanceErrors.join(" ")}` }], isError: true, details: { mode: "chain", results: [] } };
|
|
2071
|
+
}
|
|
1925
2072
|
const runId = randomUUID();
|
|
1926
2073
|
const topLevelResume = depth === 0 && !inheritedNestedRoute(input.deps) && !input.params.workflowParentRunId;
|
|
1927
2074
|
let activeAsyncCapacity: ActiveAsyncCapacityHandle | undefined;
|
|
@@ -1966,11 +2113,13 @@ async function resumeAsyncRun(input: {
|
|
|
1966
2113
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1967
2114
|
currentModelProvider: parentModel?.provider,
|
|
1968
2115
|
currentModel: parentModel,
|
|
2116
|
+
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
1969
2117
|
modelScope,
|
|
1970
2118
|
modelResponseAliases: input.deps.config.modelResponseAliases,
|
|
1971
2119
|
interactive: input.ctx.hasUI,
|
|
1972
2120
|
permissions: input.deps.config.permissions,
|
|
1973
2121
|
childRuntime: input.deps.childRuntime,
|
|
2122
|
+
projectTrusted: sessionProjectTrust(input.ctx),
|
|
1974
2123
|
}),
|
|
1975
2124
|
availableModels,
|
|
1976
2125
|
cwd: effectiveCwd,
|
|
@@ -1990,6 +2139,7 @@ async function resumeAsyncRun(input: {
|
|
|
1990
2139
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
1991
2140
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1992
2141
|
baseRef: input.params.baseRef ?? target.recoveryDescriptor?.baseRef,
|
|
2142
|
+
...(recoveryDescriptor?.requiredExtensions ? { requiredExtensions: recoveryDescriptor.requiredExtensions } : {}),
|
|
1993
2143
|
worktreeProvider: input.deps.config.worktreeProvider,
|
|
1994
2144
|
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1995
2145
|
controlConfig: resolveControlConfig(input.deps.config.control, input.params.control),
|
|
@@ -2006,6 +2156,7 @@ async function resumeAsyncRun(input: {
|
|
|
2006
2156
|
return result;
|
|
2007
2157
|
}
|
|
2008
2158
|
const attachedId = result.details.asyncId ?? runId;
|
|
2159
|
+
input.onLaunch?.({ agent: target.agent, ...(target.sessionFile ? { sessionFile: target.sessionFile } : {}), async: true, runId: attachedId });
|
|
2009
2160
|
const lines = [
|
|
2010
2161
|
`Attached async subagent ${target.runId} as the first step of a new chain.`,
|
|
2011
2162
|
`Chain run: ${attachedId}`,
|
|
@@ -2026,8 +2177,25 @@ async function resumeAsyncRun(input: {
|
|
|
2026
2177
|
if (target.source === "async" && asyncReviveRequiresRecoveryDescriptor(target)) {
|
|
2027
2178
|
return { content: [{ type: "text", text: `Async child '${target.runId}' is missing its required run fan-out recovery identity. Start a new run instead.` }], isError: true, details: { mode: "management", results: [] } };
|
|
2028
2179
|
}
|
|
2029
|
-
if (
|
|
2030
|
-
return { content: [{ type: "text", text:
|
|
2180
|
+
if (target.source === "nested" && !target.recoveryDescriptor) {
|
|
2181
|
+
return { content: [{ type: "text", text: `Nested child '${target.runId}' is missing its required recovery identity. Start a new run instead.` }], isError: true, details: { mode: "management", results: [] } };
|
|
2182
|
+
}
|
|
2183
|
+
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(baseAgentConfig, recoveryDescriptor) : baseAgentConfig;
|
|
2184
|
+
const agentConfig = intercomBridge.active ? applyIntercomBridgeToAgent(recoveryAgentConfig, intercomBridge) : recoveryAgentConfig;
|
|
2185
|
+
const foregroundContract = target.source === "foreground" ? target.resumeContract : undefined;
|
|
2186
|
+
const outputSchema = Object.hasOwn(input.params, "outputSchema")
|
|
2187
|
+
? input.params.outputSchema
|
|
2188
|
+
: Object.hasOwn(foregroundContract ?? {}, "outputSchema")
|
|
2189
|
+
? foregroundContract?.outputSchema
|
|
2190
|
+
: recoveryDescriptor?.structuredOutputSchema;
|
|
2191
|
+
const acceptance = input.params.acceptance !== undefined
|
|
2192
|
+
? input.params.acceptance
|
|
2193
|
+
: foregroundContract?.acceptance !== undefined
|
|
2194
|
+
? foregroundContract.acceptance
|
|
2195
|
+
: recoveryDescriptor?.acceptance;
|
|
2196
|
+
const acceptanceErrors = validateExecutionAcceptance({ ...input.params, acceptance, outputSchema });
|
|
2197
|
+
if (acceptanceErrors.length > 0) {
|
|
2198
|
+
return { content: [{ type: "text", text: `Cannot resume: ${acceptanceErrors.join(" ")}` }], isError: true, details: { mode: "management", results: [] } };
|
|
2031
2199
|
}
|
|
2032
2200
|
const runId = randomUUID();
|
|
2033
2201
|
const topLevelResume = depth === 0 && !inheritedNestedRoute(input.deps) && !input.params.workflowParentRunId;
|
|
@@ -2052,17 +2220,13 @@ async function resumeAsyncRun(input: {
|
|
|
2052
2220
|
if (error instanceof ActiveAsyncCapacityError) return { content: [{ type: "text", text: error.message }], isError: true, details: { mode: "single", results: [], activeAsyncCapacity: error.snapshot } };
|
|
2053
2221
|
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "single", results: [] } };
|
|
2054
2222
|
}
|
|
2055
|
-
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(baseAgentConfig, recoveryDescriptor) : baseAgentConfig;
|
|
2056
|
-
const agentConfig = intercomBridge.active ? applyIntercomBridgeToAgent(recoveryAgentConfig, intercomBridge) : recoveryAgentConfig;
|
|
2057
|
-
const foregroundContract = target.source === "foreground" ? target.resumeContract : undefined;
|
|
2058
|
-
const outputSchema = input.params.outputSchema ?? foregroundContract?.outputSchema ?? recoveryDescriptor?.structuredOutputSchema;
|
|
2059
2223
|
const agentContract = input.params.agentContract ?? foregroundContract?.agentContract ?? recoveryDescriptor?.agentContract;
|
|
2060
2224
|
const artifactConfig: ArtifactConfig = recoveryDescriptor?.artifactConfig ?? omitUndefinedProperties({ ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false, dir: input.deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir });
|
|
2061
2225
|
const artifactsDir = recoveryDescriptor?.artifactsDir ?? getArtifactsDir(parentSessionFile, effectiveCwd, artifactConfig.dir);
|
|
2062
2226
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
2063
2227
|
const parentModel = input.parentModel;
|
|
2064
2228
|
const revivalAsyncDir = path.join(DIRS.async, runId);
|
|
2065
|
-
const result = executeAsyncSingle(runId, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
2229
|
+
const result = await executeAsyncSingle(runId, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
2066
2230
|
agent: target.agent,
|
|
2067
2231
|
task: buildRevivedAsyncTask(target as Parameters<typeof buildRevivedAsyncTask>[0], effectiveFollowUp),
|
|
2068
2232
|
goal: effectiveFollowUp,
|
|
@@ -2075,12 +2239,14 @@ async function resumeAsyncRun(input: {
|
|
|
2075
2239
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
2076
2240
|
currentModelProvider: parentModel?.provider,
|
|
2077
2241
|
currentModel: parentModel,
|
|
2242
|
+
scopedModelIds: scopedModelIdsFromContext(input.ctx),
|
|
2078
2243
|
modelScope,
|
|
2079
2244
|
// Absence in the retained contract is meaningful; never acquire current aliases.
|
|
2080
2245
|
modelResponseAliases: recoveryDescriptor ? recoveryDescriptor.modelResponseAliases : foregroundContract?.modelResponseAliases,
|
|
2081
2246
|
interactive: input.ctx.hasUI,
|
|
2082
2247
|
permissions: input.deps.config.permissions,
|
|
2083
2248
|
childRuntime: input.deps.childRuntime,
|
|
2249
|
+
projectTrusted: sessionProjectTrust(input.ctx),
|
|
2084
2250
|
}),
|
|
2085
2251
|
cwd: effectiveCwd,
|
|
2086
2252
|
maxOutput: input.params.maxOutput ?? recoveryDescriptor?.maxOutput,
|
|
@@ -2104,6 +2270,7 @@ async function resumeAsyncRun(input: {
|
|
|
2104
2270
|
thinkingOverride: recoveryDescriptor?.thinking ?? target.thinking,
|
|
2105
2271
|
thinkingCeiling: recoveryDescriptor?.thinkingCeiling ?? ("thinkingCeiling" in target ? target.thinkingCeiling : undefined),
|
|
2106
2272
|
extensionBindings: recoveryDescriptor?.extensionBindings ?? ("extensionBindings" in target ? target.extensionBindings : undefined),
|
|
2273
|
+
requiredExtensions: recoveryDescriptor?.requiredExtensions ?? (target as { requiredExtensions?: SteeringRecoveryDescriptor["requiredExtensions"] }).requiredExtensions,
|
|
2107
2274
|
outputBaseDir: resolveSingleRunOutputBaseDir(input.deps, artifactsDir, runId),
|
|
2108
2275
|
maxSubagentDepth: recoveryDescriptor?.maxSubagentDepth ?? resolveCurrentMaxSubagentDepth(input.deps.config.maxSubagentDepth, input.deps.childRuntime),
|
|
2109
2276
|
waitToolEnabled: input.deps.waitToolEnabled,
|
|
@@ -2129,19 +2296,23 @@ async function resumeAsyncRun(input: {
|
|
|
2129
2296
|
...(agentContract ? { agentContract } : {}),
|
|
2130
2297
|
...(outputSchema ? { structuredOutputSchema: outputSchema } : {}),
|
|
2131
2298
|
...(recoveryDescriptor?.skills ? { skills: [...recoveryDescriptor.skills] } : {}),
|
|
2132
|
-
...(
|
|
2299
|
+
...(acceptance !== undefined ? { acceptance } : {}),
|
|
2133
2300
|
...(input.params.timeoutMs !== undefined ? { timeoutMs: input.params.timeoutMs } : {}),
|
|
2134
2301
|
...(input.absoluteDeadlineAt !== undefined ? { absoluteDeadlineAt: input.absoluteDeadlineAt } : {}),
|
|
2135
2302
|
...(input.params.toolBudget !== undefined ? { toolBudget: input.params.toolBudget } : {}),
|
|
2136
|
-
|
|
2303
|
+
// Recovery descriptors, remembered foreground runs, and current workflow roots
|
|
2304
|
+
// preserve parent authority before the selected agent's descendant ceiling.
|
|
2305
|
+
capabilityCeiling: intersectSubagentCapabilityCeilings(recoveryDescriptor?.capabilityCeiling ?? (target.source === "foreground" || (target.source === "async" && target.mode === "workflow") ? target.capabilityCeiling : undefined), resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
|
|
2137
2306
|
runFanoutBudget: input.params.runFanoutBudget ?? recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
2138
2307
|
parentWorkflowRunId: input.params.workflowParentRunId,
|
|
2139
2308
|
workflowKey: input.params.workflowKey,
|
|
2140
2309
|
activeAsyncCapacity,
|
|
2141
2310
|
}));
|
|
2311
|
+
const notifyLaunch = (): void => input.onLaunch?.({ agent: target.agent, sessionFile: revivalSessionFile, async: true, runId });
|
|
2142
2312
|
if (result.isError) {
|
|
2143
2313
|
const startedStatus = readStatus(revivalAsyncDir);
|
|
2144
2314
|
if (input.params.workflowParentRunId !== undefined && startedStatus?.runId === runId && startedStatus.processTerminal?.runnerProcessInstanceId) {
|
|
2315
|
+
notifyLaunch();
|
|
2145
2316
|
return {
|
|
2146
2317
|
...result,
|
|
2147
2318
|
details: {
|
|
@@ -2156,6 +2327,7 @@ async function resumeAsyncRun(input: {
|
|
|
2156
2327
|
activeAsyncCapacity?.rollback();
|
|
2157
2328
|
return result;
|
|
2158
2329
|
}
|
|
2330
|
+
notifyLaunch();
|
|
2159
2331
|
for (const brief of queuedBriefs) fs.rmSync(brief.path, { force: true });
|
|
2160
2332
|
if (queuedBriefs.length > 0 && sourceAsyncDir) {
|
|
2161
2333
|
const sourceStatus = readStatus(sourceAsyncDir);
|
|
@@ -2169,63 +2341,31 @@ async function resumeAsyncRun(input: {
|
|
|
2169
2341
|
if (input.params.workflowParentRunId !== undefined && result.details.asyncDir) {
|
|
2170
2342
|
const asyncDir = result.details.asyncDir;
|
|
2171
2343
|
const resultPath = workflowAwaitedAsyncResultPath(asyncDir);
|
|
2172
|
-
const
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
}
|
|
2181
|
-
fs.rmSync(resultPath, { force: true });
|
|
2182
|
-
const usage = importedAsyncRootUsage(completed);
|
|
2183
|
-
const childResult: SingleResult = {
|
|
2184
|
-
index: 0,
|
|
2185
|
-
agent: completed.agent,
|
|
2186
|
-
...(completed.sessionName ? { sessionName: completed.sessionName } : {}),
|
|
2187
|
-
task: effectiveFollowUp,
|
|
2188
|
-
exitCode: completed.exitCode,
|
|
2189
|
-
usage,
|
|
2190
|
-
finalOutput: completed.output,
|
|
2191
|
-
outputState: completed.output.trim() ? "present" : "absent",
|
|
2192
|
-
...(completed.error ? { error: completed.error } : {}),
|
|
2193
|
-
...(completed.timedOut ? { timedOut: true } : {}),
|
|
2194
|
-
...(completed.stopped ? { stopped: true } : {}),
|
|
2195
|
-
...(completed.sessionFile ? { sessionFile: completed.sessionFile } : {}),
|
|
2196
|
-
...(completed.model ? { model: completed.model } : {}),
|
|
2197
|
-
...(completed.attemptedModels ? { attemptedModels: completed.attemptedModels } : {}),
|
|
2198
|
-
...(completed.modelAttempts ? { modelAttempts: completed.modelAttempts } : {}),
|
|
2199
|
-
...(completed.contextOverflow ? { contextOverflow: true } : {}),
|
|
2200
|
-
...(completed.structuredOutput !== undefined ? { structuredOutput: completed.structuredOutput } : {}),
|
|
2201
|
-
...(completed.structuredOutputPath ? { structuredOutputPath: completed.structuredOutputPath } : {}),
|
|
2202
|
-
...(completed.structuredOutputSchemaPath ? { structuredOutputSchemaPath: completed.structuredOutputSchemaPath } : {}),
|
|
2203
|
-
...(completed.acceptance ? { acceptance: completed.acceptance } : {}),
|
|
2204
|
-
...(completed.artifactPaths ? { artifactPaths: completed.artifactPaths } : {}),
|
|
2205
|
-
...(completed.savedOutputPath ? { savedOutputPath: completed.savedOutputPath } : {}),
|
|
2206
|
-
...(completed.outputSaveError ? { outputSaveError: completed.outputSaveError } : {}),
|
|
2207
|
-
...(completed.transcriptPath ? { transcriptPath: completed.transcriptPath } : {}),
|
|
2208
|
-
...(completed.transcriptError ? { transcriptError: completed.transcriptError } : {}),
|
|
2209
|
-
};
|
|
2210
|
-
return {
|
|
2211
|
-
content: [{ type: "text", text: completed.success ? completed.output || completed.error || `Revived ${target.source} subagent ${revivedId} completed without output.` : completed.error || completed.output || `Revived ${target.source} subagent ${revivedId} completed without output.` }],
|
|
2212
|
-
...(completed.success ? {} : { isError: true }),
|
|
2213
|
-
details: {
|
|
2214
|
-
...result.details,
|
|
2215
|
-
runId: revivedId,
|
|
2216
|
-
results: [childResult],
|
|
2217
|
-
...(target.launchContractDigest ? { sourceLaunchContractDigest: target.launchContractDigest } : {}),
|
|
2218
|
-
},
|
|
2219
|
-
};
|
|
2344
|
+
const stopListener = stopAwaitedAsyncChildOnAbort(input.signal, input.deps.state, revivedId, asyncDir, input.deps.kill);
|
|
2345
|
+
const completed = await waitForImportedAsyncRoot({ runId: revivedId, asyncDir, resultPath, index: 0 }, {
|
|
2346
|
+
shouldAbort: () => input.signal?.aborted === true,
|
|
2347
|
+
timeoutMessage: "Workflow stopped before async child completed.",
|
|
2348
|
+
abortedAsStopped: true,
|
|
2349
|
+
}).finally(stopListener.remove);
|
|
2350
|
+
const details: Details = { ...result.details };
|
|
2351
|
+
if (target.launchContractDigest) details.sourceLaunchContractDigest = target.launchContractDigest;
|
|
2352
|
+
return importWorkflowAwaitedChildResult(completed, { runId: revivedId, asyncDir, resultPath, task: effectiveFollowUp, parentWorkflowRunId: input.params.workflowParentRunId, details, emptyOutputText: `Revived ${target.source} subagent ${revivedId} completed without output.`, state: input.deps.state, pi: input.deps.pi });
|
|
2220
2353
|
}
|
|
2221
2354
|
const revivedTarget = intercomBridge.active ? resolveSubagentIntercomTarget(revivedId, target.agent, 0) : undefined;
|
|
2222
2355
|
const sourceLabel = target.source;
|
|
2356
|
+
let workflowRevivalWarning: string | undefined;
|
|
2357
|
+
try {
|
|
2358
|
+
if (target.source === "async") recordWorkflowRevival(DIRS.async, target.runId, revivedId);
|
|
2359
|
+
} catch (error) {
|
|
2360
|
+
workflowRevivalWarning = `Warning: workflow key link not recorded: ${error instanceof Error ? error.message : String(error)}`;
|
|
2361
|
+
}
|
|
2223
2362
|
const lines = [
|
|
2224
2363
|
`Revived ${sourceLabel} subagent from ${target.runId}.`,
|
|
2225
2364
|
`Revived run: ${revivedId}`,
|
|
2226
2365
|
`Agent: ${target.agent}`,
|
|
2227
2366
|
`Session: ${target.sessionFile}`,
|
|
2228
2367
|
result.details.asyncDir ? `Async dir: ${result.details.asyncDir}` : undefined,
|
|
2368
|
+
workflowRevivalWarning,
|
|
2229
2369
|
revivedTarget ? `Intercom target: ${revivedTarget} (if registered)` : undefined,
|
|
2230
2370
|
`Status if needed: subagent({ action: "status", id: "${revivedId}" })`,
|
|
2231
2371
|
].filter((line): line is string => Boolean(line));
|
|
@@ -2327,6 +2467,7 @@ async function emitForegroundResultIntercom(input: {
|
|
|
2327
2467
|
...(result.sessionName ? { sessionName: result.sessionName } : {}),
|
|
2328
2468
|
status: foregroundResultIntercomStatus(result),
|
|
2329
2469
|
outputState: result.outputState ?? "unknown",
|
|
2470
|
+
...(result.outputPartial ? { outputPartial: true } : {}),
|
|
2330
2471
|
summary: resultSummaryForIntercom(result),
|
|
2331
2472
|
index,
|
|
2332
2473
|
artifactPath: result.artifactPaths?.outputPath,
|
|
@@ -2393,6 +2534,28 @@ function canonicalizeAgentName(name: string, agents: AgentConfig[], diagnostics:
|
|
|
2393
2534
|
return { name: resolved.agent.name };
|
|
2394
2535
|
}
|
|
2395
2536
|
|
|
2537
|
+
// Mirrors child launch: workflow children without their own cwd/agentScope discover agents at the workflow cwd and scope.
|
|
2538
|
+
function workflowValidationOptions(deps: ExecutorDeps, params: SubagentParamsLike, runtimeCwd: string, parentModelProvider: () => string | undefined): Parameters<typeof validateWorkflowScript>[1] {
|
|
2539
|
+
const cwd = resolveRequestedCwd(runtimeCwd, params.cwd);
|
|
2540
|
+
const scope = resolveExecutionAgentScope(params.agentScope);
|
|
2541
|
+
let discovered: ReturnType<ExecutorDeps["discoverAgents"]> | undefined;
|
|
2542
|
+
return {
|
|
2543
|
+
maxSubagentSpawnsPerRun: params.maxSubagentSpawnsPerRun ?? resolveMaxSubagentSpawnsPerRun(deps.config.maxSubagentSpawnsPerRun),
|
|
2544
|
+
agentNameError: (name) => {
|
|
2545
|
+
discovered ??= deps.discoverAgents(cwd, scope, parentModelProvider());
|
|
2546
|
+
const { agents } = discovered;
|
|
2547
|
+
const resolved = resolveAgentName(name, agents);
|
|
2548
|
+
if (resolved.agent || resolved.error) return canonicalizeAgentName(name, agents, discovered.agentDiagnostics, diagnosticContextFromDiscovery(discovered, cwd, scope)).error;
|
|
2549
|
+
const requested = name.trim().toLowerCase();
|
|
2550
|
+
const suggestion = [...new Set(agents.flatMap((agent) => [agent.name, ...(agent.localName ? [agent.localName] : []), ...(agent.aliases ?? [])]))]
|
|
2551
|
+
.map((candidate) => ({ candidate, distance: editDistance(requested, candidate.toLowerCase()) }))
|
|
2552
|
+
.filter(({ candidate, distance }) => distance <= Math.max(1, Math.floor(candidate.length / 4)) || hasSingleAdjacentTransposition(requested, candidate.toLowerCase()))
|
|
2553
|
+
.sort((left, right) => left.distance - right.distance || left.candidate.localeCompare(right.candidate))[0]?.candidate;
|
|
2554
|
+
return `Unknown agent '${name}'.${suggestion ? ` Did you mean '${suggestion}'?` : ""} Use subagent({ action: "list" }) to inspect agents.`;
|
|
2555
|
+
},
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2396
2559
|
function canonicalizeExecutionParams(params: SubagentParamsLike, agents: AgentConfig[], diagnostics: AgentDiscoveryDiagnostic[] | undefined, context: UnknownAgentDiagnosticContext): { params?: SubagentParamsLike; error?: string } {
|
|
2397
2560
|
const resolve = (name: string, location?: string): { name?: string; error?: string } => {
|
|
2398
2561
|
const result = canonicalizeAgentName(name, agents, diagnostics, context);
|
|
@@ -2404,6 +2567,8 @@ function canonicalizeExecutionParams(params: SubagentParamsLike, agents: AgentCo
|
|
|
2404
2567
|
params = omitUndefinedProperties({ ...params, agent: result.name });
|
|
2405
2568
|
const agent = agents.find((candidate) => candidate.name === result.name);
|
|
2406
2569
|
if (params.extensionBindings !== undefined && (agent?.runner?.type === "external-cli" || agent?.runner?.type === "external-job")) return { error: `extensionBindings is not supported for runner.type='${agent.runner.type}'.` };
|
|
2570
|
+
const machineError = agent ? formatHerdrMachineRunnerUnsupported({ machine: params.machine ?? agent.machine, agentName: agent.name, runnerType: agent.runner?.type, adapter: agent.runner?.type === "external-cli" ? agent.runner.adapter : undefined, worktree: params.worktree }) : undefined;
|
|
2571
|
+
if (machineError) return { error: machineError };
|
|
2407
2572
|
}
|
|
2408
2573
|
if (params.extensionBindings !== undefined) {
|
|
2409
2574
|
try {
|
|
@@ -2456,6 +2621,18 @@ function canonicalizeExecutionParams(params: SubagentParamsLike, agents: AgentCo
|
|
|
2456
2621
|
return { params };
|
|
2457
2622
|
}
|
|
2458
2623
|
|
|
2624
|
+
function projectEffectiveAcceptanceSchemas(params: SubagentParamsLike, agents: AgentConfig[]): SubagentParamsLike {
|
|
2625
|
+
const withEffectiveSchema = <T extends { agent: string; outputSchema?: JsonSchemaObject | false }>(step: T): T => {
|
|
2626
|
+
const agent = agents.find((candidate) => candidate.name === step.agent);
|
|
2627
|
+
return agent ? { ...step, outputSchema: resolveEffectiveOutputSchema(agent, step.outputSchema) } : step;
|
|
2628
|
+
};
|
|
2629
|
+
return {
|
|
2630
|
+
...params,
|
|
2631
|
+
...(params.tasks ? { tasks: params.tasks.map(withEffectiveSchema) } : {}),
|
|
2632
|
+
...(params.chain ? { chain: projectChainOutputSchemas(params.chain, agents) as ChainStep[] } : {}),
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2459
2636
|
function validateExecutionInput(
|
|
2460
2637
|
params: SubagentParamsLike,
|
|
2461
2638
|
agents: AgentConfig[],
|
|
@@ -2466,11 +2643,15 @@ function validateExecutionInput(
|
|
|
2466
2643
|
context: UnknownAgentDiagnosticContext,
|
|
2467
2644
|
): AgentToolResult<Details> | null {
|
|
2468
2645
|
if (Number(hasChain) + Number(hasTasks) + Number(hasSingle) !== 1) {
|
|
2646
|
+
const agentList = agents.map((a) => a.name).join(", ") || "none";
|
|
2647
|
+
const noMode = !hasChain && !hasTasks && !hasSingle;
|
|
2469
2648
|
return {
|
|
2470
2649
|
content: [
|
|
2471
2650
|
{
|
|
2472
2651
|
type: "text",
|
|
2473
|
-
text:
|
|
2652
|
+
text: noMode && typeof params.workflowKey === "string"
|
|
2653
|
+
? `Workflow child '${params.workflowKey}' has no agent. Pass { key, agent, task }. Agents: ${agentList}`
|
|
2654
|
+
: `Provide exactly one mode. Agents: ${agentList}`,
|
|
2474
2655
|
},
|
|
2475
2656
|
],
|
|
2476
2657
|
isError: true,
|
|
@@ -2478,7 +2659,7 @@ function validateExecutionInput(
|
|
|
2478
2659
|
};
|
|
2479
2660
|
}
|
|
2480
2661
|
|
|
2481
|
-
const acceptanceErrors = validateExecutionAcceptance(params
|
|
2662
|
+
const acceptanceErrors = validateExecutionAcceptance(projectEffectiveAcceptanceSchemas(params, agents));
|
|
2482
2663
|
if (acceptanceErrors.length > 0) {
|
|
2483
2664
|
return {
|
|
2484
2665
|
content: [{ type: "text", text: acceptanceErrors.join(" ") }],
|
|
@@ -2723,6 +2904,19 @@ function buildRequestedModeError(params: SubagentParamsLike, message: string): A
|
|
|
2723
2904
|
);
|
|
2724
2905
|
}
|
|
2725
2906
|
|
|
2907
|
+
function buildWorkflowValidationResult(
|
|
2908
|
+
validation: ReturnType<typeof validateWorkflowScript>,
|
|
2909
|
+
mode: "management" | "workflow",
|
|
2910
|
+
preflight?: import("../../shared/types.ts").WorkflowPreflight,
|
|
2911
|
+
): AgentToolResult<Details> {
|
|
2912
|
+
const payload = preflight ? { ...validation, preflight } : validation;
|
|
2913
|
+
return {
|
|
2914
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
2915
|
+
...(validation.ok ? {} : { isError: true }),
|
|
2916
|
+
details: { mode, results: [] },
|
|
2917
|
+
};
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2726
2920
|
function applySingleAgentLaunchDefaults(params: SubagentParamsLike, agents: AgentConfig[]): SubagentParamsLike {
|
|
2727
2921
|
if ((params.chain?.length ?? 0) > 0 || (params.tasks?.length ?? 0) > 0 || !params.agent) return params;
|
|
2728
2922
|
const agent = agents.find((candidate) => candidate.name === params.agent);
|
|
@@ -2730,6 +2924,7 @@ function applySingleAgentLaunchDefaults(params: SubagentParamsLike, agents: Agen
|
|
|
2730
2924
|
const parentTimeoutMs = params.timeoutMs === undefined && params.maxRuntimeMs === undefined && agent.defaultTimeoutMs === undefined && params.workflowParentDeadlineAt !== undefined
|
|
2731
2925
|
? Math.max(1, params.workflowParentDeadlineAt - Date.now())
|
|
2732
2926
|
: undefined;
|
|
2927
|
+
const outputSchema = params.outputSchema === false ? false : resolveEffectiveOutputSchema(agent, params.outputSchema);
|
|
2733
2928
|
return {
|
|
2734
2929
|
...params,
|
|
2735
2930
|
...(params.async === undefined && agent.defaultAsync !== undefined ? { async: agent.defaultAsync } : {}),
|
|
@@ -2740,9 +2935,28 @@ function applySingleAgentLaunchDefaults(params: SubagentParamsLike, agents: Agen
|
|
|
2740
2935
|
...(params.acceptance === undefined && agent.defaultAcceptance !== undefined
|
|
2741
2936
|
? { acceptance: agent.defaultAcceptance }
|
|
2742
2937
|
: {}),
|
|
2938
|
+
...(outputSchema !== undefined ? { outputSchema } : {}),
|
|
2743
2939
|
};
|
|
2744
2940
|
}
|
|
2745
2941
|
|
|
2942
|
+
function validateLaunchOutputSchemaOverrides(params: SubagentParamsLike): string | undefined {
|
|
2943
|
+
const values: unknown[] = [params.outputSchema, ...(params.tasks ?? []).map((task) => task.outputSchema)];
|
|
2944
|
+
for (const step of params.chain ?? []) {
|
|
2945
|
+
if (isParallelStep(step)) values.push(...step.parallel.map((task) => task.outputSchema));
|
|
2946
|
+
else if (isDynamicParallelStep(step)) values.push(step.parallel.outputSchema);
|
|
2947
|
+
else values.push(step.outputSchema);
|
|
2948
|
+
}
|
|
2949
|
+
for (const value of values) {
|
|
2950
|
+
if (value === undefined || value === false) continue;
|
|
2951
|
+
try {
|
|
2952
|
+
assertJsonSchemaObject(value, "outputSchema");
|
|
2953
|
+
} catch (error) {
|
|
2954
|
+
return error instanceof Error ? error.message : String(error);
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
return undefined;
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2746
2960
|
export const DEFAULT_FOREGROUND_TIMEOUT_MS = 30 * 60 * 1000;
|
|
2747
2961
|
|
|
2748
2962
|
// Async single-agent runs also need a wall-clock backstop: a child whose bash
|
|
@@ -2764,6 +2978,12 @@ export { DEFAULT_ASYNC_TIMEOUT_MS };
|
|
|
2764
2978
|
*/
|
|
2765
2979
|
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
2766
2980
|
|
|
2981
|
+
function timerDelayOverflowError(name: string, value: unknown): string | undefined {
|
|
2982
|
+
return typeof value === "number" && value > MAX_TIMER_DELAY_MS
|
|
2983
|
+
? `${name} must be a positive integer no larger than ${MAX_TIMER_DELAY_MS}.`
|
|
2984
|
+
: undefined;
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2767
2987
|
/**
|
|
2768
2988
|
* Resolve the optional global default runtime deadline from extension config
|
|
2769
2989
|
* (`config.timeoutMs`). Returns undefined for unset or invalid values so callers
|
|
@@ -2787,6 +3007,8 @@ export function resolveForegroundTimeout(params: SubagentParamsLike, defaultTime
|
|
|
2787
3007
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
2788
3008
|
return { error: `${name} must be a positive integer.` };
|
|
2789
3009
|
}
|
|
3010
|
+
const overflowError = timerDelayOverflowError(name, value);
|
|
3011
|
+
if (overflowError) return { error: overflowError };
|
|
2790
3012
|
}
|
|
2791
3013
|
if (rawTimeout !== undefined && rawMaxRuntime !== undefined && rawTimeout !== rawMaxRuntime) {
|
|
2792
3014
|
return { error: "timeoutMs and maxRuntimeMs are aliases; provide only one value or use the same value for both." };
|
|
@@ -2906,24 +3128,20 @@ function withResolvedContext(
|
|
|
2906
3128
|
}
|
|
2907
3129
|
|
|
2908
3130
|
function withAggregatedToolUsage(result: AgentToolResult<Details>): AgentToolResult<Details> {
|
|
2909
|
-
|
|
2910
|
-
const
|
|
3131
|
+
const highWarnings = result.details.results.flatMap((child) => child.watchdog?.warnings?.filter((warning) => warning.importance === "high") ?? []);
|
|
3132
|
+
const projected: AgentToolResult<Details> = {
|
|
3133
|
+
...result,
|
|
3134
|
+
...(highWarnings.length ? { content: [...result.content, { type: "text", text: ["High-importance watchdog findings:", ...highWarnings.map((warning) => `- ${warning.severity}: ${warning.summary}\n Evidence: ${warning.evidence}\n Recommended action: ${warning.recommendedAction}`)].join("\n") }] } : {}),
|
|
3135
|
+
details: {
|
|
3136
|
+
...result.details,
|
|
3137
|
+
results: result.details.results.map((child) => ({ ...child, ...(child.watchdog ? { watchdog: childWatchdogProgressForModel(child.watchdog) } : {}) })),
|
|
3138
|
+
},
|
|
3139
|
+
};
|
|
3140
|
+
if (projected.details.results.length === 0) return projected;
|
|
3141
|
+
const usage = sumResultsUsage(projected.details.results);
|
|
2911
3142
|
return usage.input !== 0 || usage.output !== 0 || usage.cacheRead !== 0 || usage.cacheWrite !== 0 || usage.cost !== 0 || usage.turns !== 0
|
|
2912
|
-
? { ...
|
|
2913
|
-
:
|
|
2914
|
-
}
|
|
2915
|
-
|
|
2916
|
-
function withForkThinkingNotes(
|
|
2917
|
-
result: AgentToolResult<Details>,
|
|
2918
|
-
downgrades: Map<number, string>,
|
|
2919
|
-
): AgentToolResult<Details> {
|
|
2920
|
-
if (downgrades.size === 0) return result;
|
|
2921
|
-
const children = [...downgrades.entries()]
|
|
2922
|
-
.sort(([a], [b]) => a - b)
|
|
2923
|
-
.map(([index, agent]) => `${agent} (child ${index})`)
|
|
2924
|
-
.join(", ");
|
|
2925
|
-
const note = `Note: fork context forced thinking off for ${children}. The forked transcript contained signed Anthropic thinking blocks that were sanitized, and Anthropic children cannot resume such a transcript with thinking enabled. Use context: "fresh" when an Anthropic child needs thinking.`;
|
|
2926
|
-
return { ...result, content: [...result.content, { type: "text", text: note }] };
|
|
3143
|
+
? { ...projected, usage: toAgentToolUsage(usage) }
|
|
3144
|
+
: projected;
|
|
2927
3145
|
}
|
|
2928
3146
|
|
|
2929
3147
|
function toExecutionErrorResult(params: SubagentParamsLike, error: unknown, contextSummary?: ContextSummary): AgentToolResult<Details> {
|
|
@@ -2946,14 +3164,15 @@ function resolveStaticLaunchSummary(input: {
|
|
|
2946
3164
|
explicitModel?: string;
|
|
2947
3165
|
agents: AgentConfig[];
|
|
2948
3166
|
parentModel?: ParentModel;
|
|
3167
|
+
scopedModelIds?: string[];
|
|
2949
3168
|
availableModels: ModelInfo[];
|
|
2950
3169
|
currentProvider?: string;
|
|
2951
3170
|
modelScope?: ModelScopeConfig;
|
|
2952
|
-
thinkingOverrideForTask:
|
|
3171
|
+
thinkingOverrideForTask: ThinkingOverrideForTask;
|
|
2953
3172
|
}): StaticLaunchSummary {
|
|
2954
3173
|
const agentConfig = input.agents.find((agent) => agent.name === input.agent);
|
|
2955
3174
|
const externalRunner = agentConfig?.runner?.type === "external-cli" || agentConfig?.runner?.type === "external-job";
|
|
2956
|
-
const modelScopes = resolveModelScopesForAgent(input.modelScope, input.agent, input.parentModel);
|
|
3175
|
+
const modelScopes = resolveModelScopesForAgent(input.modelScope, input.agent, input.parentModel, input.scopedModelIds);
|
|
2957
3176
|
const model = externalRunner
|
|
2958
3177
|
? undefined
|
|
2959
3178
|
: resolveEffectiveSubagentModel(
|
|
@@ -2964,7 +3183,7 @@ function resolveStaticLaunchSummary(input: {
|
|
|
2964
3183
|
agentConfig?.modelProvider ?? input.currentProvider,
|
|
2965
3184
|
modelScopes.length === 0 ? {} : { scope: modelScopes },
|
|
2966
3185
|
);
|
|
2967
|
-
const thinkingOverride = externalRunner ? undefined : input.thinkingOverrideForTask(
|
|
3186
|
+
const thinkingOverride = externalRunner ? undefined : input.thinkingOverrideForTask();
|
|
2968
3187
|
const thinking = externalRunner ? undefined : resolveEffectiveThinking(model, thinkingOverride ?? agentConfig?.thinking);
|
|
2969
3188
|
return {
|
|
2970
3189
|
agent: input.agent,
|
|
@@ -2977,10 +3196,11 @@ function collectStaticLaunchSummaries(input: {
|
|
|
2977
3196
|
params: SubagentParamsLike;
|
|
2978
3197
|
agents: AgentConfig[];
|
|
2979
3198
|
parentModel?: ParentModel;
|
|
3199
|
+
scopedModelIds?: string[];
|
|
2980
3200
|
availableModels: ModelInfo[];
|
|
2981
3201
|
currentProvider?: string;
|
|
2982
3202
|
modelScope?: ModelScopeConfig;
|
|
2983
|
-
thinkingOverrideForTask:
|
|
3203
|
+
thinkingOverrideForTask: ThinkingOverrideForTask;
|
|
2984
3204
|
dynamicFanoutMaxItems?: number;
|
|
2985
3205
|
}): StaticLaunchSummary[] {
|
|
2986
3206
|
const summary = (agent: string, index: number, explicitModel?: string) => resolveStaticLaunchSummary({
|
|
@@ -2989,6 +3209,7 @@ function collectStaticLaunchSummaries(input: {
|
|
|
2989
3209
|
explicitModel,
|
|
2990
3210
|
agents: input.agents,
|
|
2991
3211
|
parentModel: input.parentModel,
|
|
3212
|
+
scopedModelIds: input.scopedModelIds,
|
|
2992
3213
|
availableModels: input.availableModels,
|
|
2993
3214
|
currentProvider: input.currentProvider,
|
|
2994
3215
|
modelScope: input.modelScope,
|
|
@@ -3134,27 +3355,53 @@ function importedAsyncRootUsage(completed: Awaited<ReturnType<typeof waitForImpo
|
|
|
3134
3355
|
};
|
|
3135
3356
|
}
|
|
3136
3357
|
|
|
3137
|
-
|
|
3138
|
-
params: SubagentParamsLike,
|
|
3139
|
-
launchResult: AgentToolResult<Details>,
|
|
3140
|
-
options: { runId: string; task: string; signal?: AbortSignal; state: SubagentState; kill?: ExecutorDeps["kill"] },
|
|
3141
|
-
): Promise<AgentToolResult<Details>> {
|
|
3142
|
-
if (params.workflowAwaitAsync !== true || !launchResult.details.asyncDir) return launchResult;
|
|
3143
|
-
const asyncDir = launchResult.details.asyncDir;
|
|
3144
|
-
const resultPath = workflowAwaitedAsyncResultPath(asyncDir);
|
|
3145
|
-
const stopOnAbort = () => { stopAsyncRun(options.state, options.runId, options.kill, { asyncDir, resolvedId: options.runId }); };
|
|
3146
|
-
if (options.signal?.aborted) stopOnAbort();
|
|
3147
|
-
else options.signal?.addEventListener("abort", stopOnAbort, { once: true });
|
|
3148
|
-
let completed: Awaited<ReturnType<typeof waitForImportedAsyncRoot>>;
|
|
3358
|
+
function removeWorkflowAwaitedResult(asyncDir: string, resultPath: string, runId: string, publication: NonNullable<Awaited<ReturnType<typeof waitForImportedAsyncRoot>>["importedPublication"]>): void {
|
|
3149
3359
|
try {
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
}));
|
|
3154
|
-
} finally {
|
|
3155
|
-
options.signal?.removeEventListener("abort", stopOnAbort);
|
|
3360
|
+
fs.rmSync(resultPath, { force: true });
|
|
3361
|
+
} catch {
|
|
3362
|
+
// Payload cleanup must not replace an already imported delivery.
|
|
3156
3363
|
}
|
|
3157
|
-
|
|
3364
|
+
removeResultIndex(asyncDir, publication.sessionId, runId, publication.toolCallId);
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3367
|
+
function emitWorkflowAwaitedChildComplete(
|
|
3368
|
+
pi: ExtensionAPI,
|
|
3369
|
+
state: SubagentState,
|
|
3370
|
+
runId: string,
|
|
3371
|
+
asyncDir: string,
|
|
3372
|
+
parentWorkflowRunId: string | undefined,
|
|
3373
|
+
completed: Awaited<ReturnType<typeof waitForImportedAsyncRoot>>,
|
|
3374
|
+
): void {
|
|
3375
|
+
let status: ReturnType<typeof readStatus> | undefined;
|
|
3376
|
+
try {
|
|
3377
|
+
status = readStatus(asyncDir);
|
|
3378
|
+
} catch (error) {
|
|
3379
|
+
console.error(`Failed to read awaited workflow child status for ${runId}; emitting completion with fallback metadata:`, error);
|
|
3380
|
+
}
|
|
3381
|
+
pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
|
|
3382
|
+
id: runId,
|
|
3383
|
+
runId,
|
|
3384
|
+
sessionId: status?.sessionId ?? completed.importedPublication?.sessionId ?? state.currentSessionId,
|
|
3385
|
+
completionOwnerId: status?.completionOwnerId ?? state.completionOwnerId ?? currentCompletionOwnerId(),
|
|
3386
|
+
asyncDir,
|
|
3387
|
+
agent: completed.agent,
|
|
3388
|
+
mode: "single",
|
|
3389
|
+
state: completed.stopped ? "stopped" : completed.success ? "complete" : "failed",
|
|
3390
|
+
success: completed.success,
|
|
3391
|
+
timestamp: Date.now(),
|
|
3392
|
+
triggerTurn: false,
|
|
3393
|
+
awaitedByWorkflow: true,
|
|
3394
|
+
parentWorkflowRunId,
|
|
3395
|
+
});
|
|
3396
|
+
}
|
|
3397
|
+
|
|
3398
|
+
/** Consumes an awaited workflow child's published result: clears the payload, announces completion, and builds the tool result. */
|
|
3399
|
+
function importWorkflowAwaitedChildResult(
|
|
3400
|
+
completed: Awaited<ReturnType<typeof waitForImportedAsyncRoot>>,
|
|
3401
|
+
options: { runId: string; asyncDir: string; resultPath: string; task: string; parentWorkflowRunId: string | undefined; details: Details; emptyOutputText?: string; state: SubagentState; pi: ExtensionAPI },
|
|
3402
|
+
): AgentToolResult<Details> {
|
|
3403
|
+
if (completed.importedPublication) removeWorkflowAwaitedResult(options.asyncDir, options.resultPath, options.runId, completed.importedPublication);
|
|
3404
|
+
emitWorkflowAwaitedChildComplete(options.pi, options.state, options.runId, options.asyncDir, options.parentWorkflowRunId, completed);
|
|
3158
3405
|
const usage = importedAsyncRootUsage(completed);
|
|
3159
3406
|
const childResult: SingleResult = omitUndefinedProperties({
|
|
3160
3407
|
index: 0,
|
|
@@ -3170,8 +3417,7 @@ async function waitForWorkflowAsyncSingleResult(
|
|
|
3170
3417
|
...(completed.stopped ? { stopped: true } : {}),
|
|
3171
3418
|
...(completed.sessionFile ? { sessionFile: completed.sessionFile } : {}),
|
|
3172
3419
|
...(completed.model ? { model: completed.model } : {}),
|
|
3173
|
-
...(completed.
|
|
3174
|
-
...(completed.modelAttempts ? { modelAttempts: completed.modelAttempts } : {}),
|
|
3420
|
+
...(completed.requestedModel ? { requestedModel: completed.requestedModel } : {}),
|
|
3175
3421
|
...(completed.contextOverflow ? { contextOverflow: true } : {}),
|
|
3176
3422
|
...(completed.structuredOutput !== undefined ? { structuredOutput: completed.structuredOutput } : {}),
|
|
3177
3423
|
...(completed.structuredOutputPath ? { structuredOutputPath: completed.structuredOutputPath } : {}),
|
|
@@ -3184,16 +3430,55 @@ async function waitForWorkflowAsyncSingleResult(
|
|
|
3184
3430
|
...(completed.transcriptError ? { transcriptError: completed.transcriptError } : {}),
|
|
3185
3431
|
});
|
|
3186
3432
|
return {
|
|
3187
|
-
content: [{ type: "text", text: completed.success ? completed.output || completed.error
|
|
3433
|
+
content: [{ type: "text", text: (completed.success ? completed.output || completed.error : completed.error || completed.output) || (options.emptyOutputText ?? `Async workflow child ${options.runId} completed without output.`) }],
|
|
3188
3434
|
...(completed.success ? {} : { isError: true }),
|
|
3189
3435
|
details: {
|
|
3190
|
-
...
|
|
3436
|
+
...options.details,
|
|
3191
3437
|
runId: options.runId,
|
|
3192
3438
|
results: [childResult],
|
|
3193
3439
|
},
|
|
3194
3440
|
};
|
|
3195
3441
|
}
|
|
3196
3442
|
|
|
3443
|
+
// A replaced runtime leaves the child running so a relaunch of the workflow can re-attach to it.
|
|
3444
|
+
function stopAwaitedAsyncChildOnAbort(signal: AbortSignal | undefined, state: SubagentState, runId: string, asyncDir: string, kill?: ExecutorDeps["kill"]): { remove: () => void } {
|
|
3445
|
+
const stopOnAbort = () => { if (!workflowStopCause(signal?.reason)) stopAsyncRun(state, runId, kill, { asyncDir, resolvedId: runId }); };
|
|
3446
|
+
if (signal?.aborted) stopOnAbort();
|
|
3447
|
+
else signal?.addEventListener("abort", stopOnAbort, { once: true });
|
|
3448
|
+
return { remove: () => signal?.removeEventListener("abort", stopOnAbort) };
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
// Live workflow controls are keyed by the full run id; a stop id may be a prefix or the launch tool-call id.
|
|
3452
|
+
function resolveLiveWorkflowRunId(deps: ExecutorDeps, id: string): string | undefined {
|
|
3453
|
+
const controllers = deps.state.workflowControllers;
|
|
3454
|
+
if (!controllers?.size) return undefined;
|
|
3455
|
+
if (controllers.has(id)) return id;
|
|
3456
|
+
try {
|
|
3457
|
+
const resolved = resolveSubagentRunId(id, omitUndefinedProperties({ state: deps.state, nested: nestedResolutionScopeForExecutor(deps) }));
|
|
3458
|
+
return resolved?.kind === "async" && controllers.has(resolved.id) ? resolved.id : undefined;
|
|
3459
|
+
} catch {
|
|
3460
|
+
// The generic stop path resolves the id again and reports the error.
|
|
3461
|
+
return undefined;
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
|
|
3465
|
+
async function waitForWorkflowAsyncSingleResult(
|
|
3466
|
+
params: SubagentParamsLike,
|
|
3467
|
+
launchResult: AgentToolResult<Details>,
|
|
3468
|
+
options: { runId: string; task: string; signal?: AbortSignal; state: SubagentState; pi: ExtensionAPI; kill?: ExecutorDeps["kill"] },
|
|
3469
|
+
): Promise<AgentToolResult<Details>> {
|
|
3470
|
+
if (params.workflowAwaitAsync !== true || !launchResult.details.asyncDir) return launchResult;
|
|
3471
|
+
const asyncDir = launchResult.details.asyncDir;
|
|
3472
|
+
const resultPath = workflowAwaitedAsyncResultPath(asyncDir);
|
|
3473
|
+
const stopListener = stopAwaitedAsyncChildOnAbort(options.signal, options.state, options.runId, asyncDir, options.kill);
|
|
3474
|
+
const completed = await waitForImportedAsyncRoot({ runId: options.runId, asyncDir, resultPath, index: 0 }, omitUndefinedProperties({
|
|
3475
|
+
shouldAbort: () => options.signal?.aborted === true,
|
|
3476
|
+
timeoutMessage: "Workflow stopped before async child completed.",
|
|
3477
|
+
abortedAsStopped: true,
|
|
3478
|
+
})).finally(stopListener.remove);
|
|
3479
|
+
return importWorkflowAwaitedChildResult(completed, { runId: options.runId, asyncDir, resultPath, task: options.task, parentWorkflowRunId: params.workflowParentRunId, details: launchResult.details, state: options.state, pi: options.pi });
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3197
3482
|
async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Promise<AgentToolResult<Details> | null> {
|
|
3198
3483
|
const {
|
|
3199
3484
|
params,
|
|
@@ -3235,11 +3520,13 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3235
3520
|
parentSessionId: data.parentPiSessionId,
|
|
3236
3521
|
currentModelProvider: parentModel?.provider,
|
|
3237
3522
|
currentModel: parentModel,
|
|
3523
|
+
scopedModelIds: data.scopedModelIds,
|
|
3238
3524
|
modelScope: data.modelScope,
|
|
3239
3525
|
modelResponseAliases: deps.config.modelResponseAliases,
|
|
3240
3526
|
interactive: ctx.hasUI,
|
|
3241
3527
|
permissions: deps.config.permissions,
|
|
3242
3528
|
childRuntime: deps.childRuntime,
|
|
3529
|
+
projectTrusted: sessionProjectTrust(ctx),
|
|
3243
3530
|
});
|
|
3244
3531
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
3245
3532
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth, deps.childRuntime);
|
|
@@ -3269,7 +3556,7 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3269
3556
|
if ((a.runner?.type === "external-cli" || a.runner?.type === "external-job") && (params.fast ?? a.fast) === true) {
|
|
3270
3557
|
return buildRequestedModeError(params, `Agent '${a.name}' uses runner.type='${a.runner.type}' and does not support fast mode.`);
|
|
3271
3558
|
}
|
|
3272
|
-
const modelScopes = resolveModelScopesForAgent(data.modelScope, a.name, parentModel);
|
|
3559
|
+
const modelScopes = resolveModelScopesForAgent(data.modelScope, a.name, parentModel, data.scopedModelIds);
|
|
3273
3560
|
const modelOrigin = resolveModelOrigin({
|
|
3274
3561
|
storedOrigin: params.modelOrigin as ModelOrigin | undefined,
|
|
3275
3562
|
explicitModel: params.model as string | undefined,
|
|
@@ -3285,16 +3572,19 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3285
3572
|
const modelOverrideFromParent = modelOrigin === "inherited";
|
|
3286
3573
|
const launchRuleError = applyWatchdogLaunchRules({ cwd: effectiveCwd, agent: a.name, model: modelOverride ?? (parentModel && `${parentModel.provider}/${parentModel.id}`), warn: (violation) => deps.watchdog?.displayRuleWarning(violation) });
|
|
3287
3574
|
if (launchRuleError) return toExecutionErrorResult(params, new Error(launchRuleError), data.contextPolicy.contextSummary);
|
|
3288
|
-
const asyncResult = executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
3575
|
+
const asyncResult = await executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
3289
3576
|
agent: params.agent!,
|
|
3290
3577
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
3291
3578
|
goal: params.task ?? "",
|
|
3292
3579
|
agentConfig: a,
|
|
3293
3580
|
recoveryAgentConfig: data.recoveryAgents.find((agent) => agent.name === params.agent),
|
|
3581
|
+
requiredExtensions: data.requiredExtensions,
|
|
3294
3582
|
ctx: asyncCtx,
|
|
3295
3583
|
availableModels,
|
|
3296
3584
|
cwd: effectiveCwd,
|
|
3297
3585
|
requestedCwd: data.requestedCwd,
|
|
3586
|
+
machine: params.machine,
|
|
3587
|
+
machineCwd: params.machineCwd,
|
|
3298
3588
|
maxOutput: params.maxOutput,
|
|
3299
3589
|
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
3300
3590
|
artifactConfig,
|
|
@@ -3313,7 +3603,7 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3313
3603
|
fast: params.fast,
|
|
3314
3604
|
modelOverrideFromParent,
|
|
3315
3605
|
modelOrigin,
|
|
3316
|
-
thinkingOverride: externalRunnerWithoutExplicitModel ? undefined : thinkingOverrideForTask(
|
|
3606
|
+
thinkingOverride: externalRunnerWithoutExplicitModel ? undefined : thinkingOverrideForTask(),
|
|
3317
3607
|
thinkingCeiling: a.maxThinking,
|
|
3318
3608
|
maxSubagentDepth,
|
|
3319
3609
|
waitToolEnabled: deps.waitToolEnabled,
|
|
@@ -3331,7 +3621,7 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3331
3621
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(agent, index) : undefined,
|
|
3332
3622
|
nestedRoute,
|
|
3333
3623
|
agentContract: params.agentContract,
|
|
3334
|
-
structuredOutputSchema: params.outputSchema,
|
|
3624
|
+
structuredOutputSchema: params.outputSchema || undefined,
|
|
3335
3625
|
extensionBindings: params.extensionBindings,
|
|
3336
3626
|
acceptance: params.acceptance,
|
|
3337
3627
|
timeoutMs: data.timeoutMs,
|
|
@@ -3339,6 +3629,7 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3339
3629
|
usageBudget: data.usageBudget,
|
|
3340
3630
|
configToolBudget: data.configToolBudget,
|
|
3341
3631
|
toolTimeoutMs: data.params?.toolTimeoutMs,
|
|
3632
|
+
checkpointBeforeDeadlineMs: data.params?.checkpointBeforeDeadlineMs ?? deps.config.checkpointBeforeDeadlineMs,
|
|
3342
3633
|
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
3343
3634
|
capabilityCeiling: data.capabilityCeiling,
|
|
3344
3635
|
runFanoutBudget: data.runFanoutBudget,
|
|
@@ -3347,7 +3638,7 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3347
3638
|
lane: params.lane,
|
|
3348
3639
|
workflowAwaitAsync: params.workflowAwaitAsync,
|
|
3349
3640
|
}));
|
|
3350
|
-
return waitForWorkflowAsyncSingleResult(params, asyncResult, { runId: id, task: params.task ?? "", signal: data.signal, state: deps.state, kill: deps.kill });
|
|
3641
|
+
return waitForWorkflowAsyncSingleResult(params, asyncResult, { runId: id, task: params.task ?? "", signal: data.signal, state: deps.state, pi: deps.pi, kill: deps.kill });
|
|
3351
3642
|
}
|
|
3352
3643
|
|
|
3353
3644
|
return null;
|
|
@@ -3457,6 +3748,62 @@ function appendWorkflowOutputWarning(text: string, warning: string | undefined):
|
|
|
3457
3748
|
return warning ? `${text}\n\n${warning}` : text;
|
|
3458
3749
|
}
|
|
3459
3750
|
|
|
3751
|
+
const WORKFLOW_TRACE_ERROR_MAX_CHARS = 500;
|
|
3752
|
+
|
|
3753
|
+
// Return, emits, console, and trace errors (which carry child text) have no size limit of their
|
|
3754
|
+
// own, so only they are cut; other host sections stay whole. The saved full result is uncut.
|
|
3755
|
+
function formatWorkflowResultText(input: {
|
|
3756
|
+
head: string[];
|
|
3757
|
+
script: string[];
|
|
3758
|
+
trace: Array<{ line: string; error?: string }>;
|
|
3759
|
+
tail: string[];
|
|
3760
|
+
maxOutput: MaxOutputConfig | undefined;
|
|
3761
|
+
aggregateOutputPath: string | undefined;
|
|
3762
|
+
fullResultPath: string;
|
|
3763
|
+
producedChildOutputPaths: ReadonlySet<string>;
|
|
3764
|
+
}): string {
|
|
3765
|
+
const traceSection = (error: (text: string) => string) => input.trace.length > 0
|
|
3766
|
+
? [`Call trace:\n${input.trace.map((entry) => `${entry.line}${entry.error ? ` — ${error(entry.error)}` : ""}`).join("\n")}`]
|
|
3767
|
+
: [];
|
|
3768
|
+
const fullText = [...input.head, ...input.script, ...traceSection((error) => error), ...input.tail].join("\n\n");
|
|
3769
|
+
const outputWarning = writeWorkflowAggregateOutput(input.aggregateOutputPath, fullText, input.producedChildOutputPaths);
|
|
3770
|
+
const scriptText = input.script.join("\n\n");
|
|
3771
|
+
const config = { ...DEFAULT_MAX_OUTPUT, ...input.maxOutput };
|
|
3772
|
+
const scriptCut = truncateOutput(scriptText, config).truncated;
|
|
3773
|
+
const traceCut = input.trace.some((entry) => (entry.error?.length ?? 0) > WORKFLOW_TRACE_ERROR_MAX_CHARS);
|
|
3774
|
+
let shownScriptText = scriptText;
|
|
3775
|
+
let saveWarning: string | undefined;
|
|
3776
|
+
let savedPath: string | undefined;
|
|
3777
|
+
if (scriptCut || traceCut) {
|
|
3778
|
+
const aggregateHoldsFullText = input.aggregateOutputPath !== undefined && !outputWarning
|
|
3779
|
+
&& !input.producedChildOutputPaths.has(resolveWorkflowHostOutputClaimPath(input.aggregateOutputPath));
|
|
3780
|
+
if (!aggregateHoldsFullText) saveWarning = writeWorkflowAggregateOutput(input.fullResultPath, fullText, new Set());
|
|
3781
|
+
savedPath = aggregateHoldsFullText ? input.aggregateOutputPath : saveWarning ? undefined : input.fullResultPath;
|
|
3782
|
+
if (scriptCut) shownScriptText = truncateOutput(scriptText, config, savedPath).text;
|
|
3783
|
+
}
|
|
3784
|
+
const shownTrace = traceSection((error) => error.length > WORKFLOW_TRACE_ERROR_MAX_CHARS ? `${error.slice(0, WORKFLOW_TRACE_ERROR_MAX_CHARS)}… (+${error.length - WORKFLOW_TRACE_ERROR_MAX_CHARS} chars)` : error);
|
|
3785
|
+
const traceNote = traceCut && !scriptCut && savedPath ? [`[TRUNCATED: trace errors shortened - full output at ${savedPath}]`] : [];
|
|
3786
|
+
const text = [...input.head, ...(shownScriptText ? [shownScriptText] : []), ...shownTrace, ...input.tail, ...traceNote].join("\n\n");
|
|
3787
|
+
return appendWorkflowOutputWarning(appendWorkflowOutputWarning(text, outputWarning), saveWarning);
|
|
3788
|
+
}
|
|
3789
|
+
|
|
3790
|
+
export function resolveWorkflowChildLocalCwd(input: {
|
|
3791
|
+
workflowCwd: string;
|
|
3792
|
+
discoverAgents: (cwd: string, scope: AgentScope) => { agents: AgentConfig[] };
|
|
3793
|
+
agents: AgentConfig[];
|
|
3794
|
+
workflowAgentScope?: unknown;
|
|
3795
|
+
params: Record<string, unknown>;
|
|
3796
|
+
}): string {
|
|
3797
|
+
if (input.params.machine !== undefined) return input.workflowCwd;
|
|
3798
|
+
if (typeof input.params.agent === "string") {
|
|
3799
|
+
const agentScope = resolveExecutionAgentScope(input.params.agentScope ?? input.workflowAgentScope);
|
|
3800
|
+
const workflowAgents = input.discoverAgents(input.workflowCwd, agentScope).agents;
|
|
3801
|
+
const agent = resolveAgentName(input.params.agent, workflowAgents).agent ?? resolveAgentName(input.params.agent, input.agents).agent;
|
|
3802
|
+
if (agent?.machine !== undefined) return input.workflowCwd;
|
|
3803
|
+
}
|
|
3804
|
+
return typeof input.params.cwd === "string" ? resolveChildCwd(input.workflowCwd, input.params.cwd) : input.workflowCwd;
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3460
3807
|
function resolveWorkflowChildOutputPath(input: {
|
|
3461
3808
|
ctxCwd: string;
|
|
3462
3809
|
workflowCwd: string;
|
|
@@ -3482,7 +3829,7 @@ function resolveWorkflowChildOutputPath(input: {
|
|
|
3482
3829
|
}, input.state);
|
|
3483
3830
|
return { path: "recoveryDescriptor" in target ? target.recoveryDescriptor?.outputPath : undefined, inherited: false };
|
|
3484
3831
|
}
|
|
3485
|
-
const childCwd =
|
|
3832
|
+
const childCwd = resolveWorkflowChildLocalCwd(input);
|
|
3486
3833
|
let agentOutput: string | undefined;
|
|
3487
3834
|
if (rawOutput === true || rawOutput === "true" || (!hasExplicitOutput && !input.aggregateOutputPath)) {
|
|
3488
3835
|
const agentScope = resolveExecutionAgentScope(input.params.agentScope ?? input.workflowAgentScope);
|
|
@@ -3584,7 +3931,7 @@ function prepareWorkflowChildLaunchParams(input: {
|
|
|
3584
3931
|
const resolvedOutput = resolveWorkflowChildOutputPath({ ctxCwd: input.ctxCwd, workflowCwd: input.workflowCwd, artifactsDir: input.artifactsDir, workflowRunId: input.parentWorkflowRunId, aggregateOutputPath: input.aggregateOutputPath, configuredOutputBaseDir: input.configuredOutputBaseDir, discoverAgents: input.discoverAgents, agents: input.agents, workflowAgentScope: input.workflowAgentScope, key: input.workflowKey, params: input.childParams });
|
|
3585
3932
|
if (resolvedOutput.path) childParams = { ...input.childParams, output: resolvedOutput.path };
|
|
3586
3933
|
}
|
|
3587
|
-
const childCwd =
|
|
3934
|
+
const childCwd = resolveWorkflowChildLocalCwd({ ...input, params: childParams });
|
|
3588
3935
|
const agentScope = resolveExecutionAgentScope(childParams.agentScope ?? input.workflowAgentScope);
|
|
3589
3936
|
const discoveredAgents = input.discoverAgents(childCwd, agentScope).agents;
|
|
3590
3937
|
const agent = typeof childParams.agent === "string"
|
|
@@ -3716,13 +4063,23 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3716
4063
|
details: { mode: "single", results: [] },
|
|
3717
4064
|
};
|
|
3718
4065
|
}
|
|
4066
|
+
let foregroundMachine: import("../../shared/types.ts").HerdrMachineReference | undefined;
|
|
4067
|
+
const requestedMachine = params.machine ?? agentConfig.machine;
|
|
4068
|
+
const requiredExtensions = data.requiredExtensions ?? deps.childRuntime?.requiredExtensions ?? resolveRequiredChildExtensions(data.parentPiSessionId);
|
|
4069
|
+
if (requestedMachine) {
|
|
4070
|
+
try {
|
|
4071
|
+
assertRequiredChildExtensionsAdmitted([requiredExtensions], { agent: agentConfig.name, runnerType: agentConfig.runner?.type, machine: requestedMachine });
|
|
4072
|
+
foregroundMachine = resolveHerdrMachinePlacement({ machine: requestedMachine, cwd: ctx.cwd, stepCwd: params.machineCwd }).machine;
|
|
4073
|
+
}
|
|
4074
|
+
catch (error) { return toExecutionErrorResult(params, error instanceof Error ? error : new Error(String(error)), data.contextPolicy.contextSummary); }
|
|
4075
|
+
}
|
|
3719
4076
|
const effectiveToolBudget = resolveEffectiveToolBudget(omitUndefinedProperties({ runBudget: data.toolBudget, agentBudget: agentConfig.toolBudget, configBudget: data.configToolBudget }));
|
|
3720
4077
|
if (effectiveToolBudget.error) return toExecutionErrorResult(params, new Error(effectiveToolBudget.error), data.contextPolicy.contextSummary);
|
|
3721
4078
|
|
|
3722
4079
|
const parentModel = data.parentModel;
|
|
3723
4080
|
const currentProvider = parentModel?.provider;
|
|
3724
4081
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
3725
|
-
const modelScopes = resolveModelScopesForAgent(data.modelScope, agentConfig.name, parentModel);
|
|
4082
|
+
const modelScopes = resolveModelScopesForAgent(data.modelScope, agentConfig.name, parentModel, data.scopedModelIds);
|
|
3726
4083
|
let task = typeof params.task === "string" ? params.task : "";
|
|
3727
4084
|
const modelOrigin = resolveModelOrigin({
|
|
3728
4085
|
storedOrigin: params.modelOrigin as ModelOrigin | undefined,
|
|
@@ -3753,7 +4110,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3753
4110
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, agentConfig.maxSubagentDepth);
|
|
3754
4111
|
|
|
3755
4112
|
|
|
3756
|
-
const sourceCwd = effectiveCwd;
|
|
4113
|
+
const sourceCwd = foregroundMachine?.cwd ?? effectiveCwd;
|
|
3757
4114
|
let pendingHandoff: Details["parallelHandoff"];
|
|
3758
4115
|
const { setup: worktreeSetup, errorResult: worktreeSetupError } = params.worktree ? await createSingleWorktreeSetup(
|
|
3759
4116
|
sourceCwd,
|
|
@@ -3830,7 +4187,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3830
4187
|
// Reads: caller override > agent defaultReads > none. `~`/`~/` expand to home;
|
|
3831
4188
|
// absolute paths pass through; relative paths resolve against the child cwd.
|
|
3832
4189
|
const reads = readsOverride !== undefined ? readsOverride : agentConfig.defaultReads ?? false;
|
|
3833
|
-
const readPaths = Array.isArray(reads) ? resolveExistingReadPaths(reads, singleCwd) : [];
|
|
4190
|
+
const readPaths = !foregroundMachine && Array.isArray(reads) ? resolveExistingReadPaths(reads, singleCwd) : [];
|
|
3834
4191
|
const readsInstruction = readPaths.length > 0
|
|
3835
4192
|
? `[Read from: ${readPaths.join(", ")}]\n\n`
|
|
3836
4193
|
: "";
|
|
@@ -3847,8 +4204,22 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3847
4204
|
let detachForeground: ((reason?: string) => boolean) | undefined;
|
|
3848
4205
|
let childSessionControls: ForegroundChildSessionControls | undefined;
|
|
3849
4206
|
const foregroundControl = deps.state.foregroundControls.get(runId);
|
|
4207
|
+
const syncHerdrForegroundChild = () => {
|
|
4208
|
+
if (!foregroundControl?.parentWorkflowRunId) return;
|
|
4209
|
+
try {
|
|
4210
|
+
deps.pi.events.emit(HERDR_FOREGROUND_CONTROL_CHANGED_EVENT, { runId: foregroundControl.parentWorkflowRunId });
|
|
4211
|
+
} catch (error) {
|
|
4212
|
+
console.error("Failed to sync Herdr foreground child:", error);
|
|
4213
|
+
}
|
|
4214
|
+
};
|
|
4215
|
+
const finishTrackedForegroundChild = () => {
|
|
4216
|
+
if (!foregroundControl) return;
|
|
4217
|
+
const wasActive = foregroundControl.activeChildren?.has(0) === true;
|
|
4218
|
+
finishForegroundChild(foregroundControl, 0);
|
|
4219
|
+
if (wasActive) syncHerdrForegroundChild();
|
|
4220
|
+
};
|
|
3850
4221
|
if (foregroundControl) {
|
|
3851
|
-
const thinking = resolveEffectiveThinking(modelOverride, thinkingOverrideForTask(
|
|
4222
|
+
const thinking = resolveEffectiveThinking(modelOverride, thinkingOverrideForTask());
|
|
3852
4223
|
beginForegroundChild(foregroundControl, omitUndefinedProperties({
|
|
3853
4224
|
index: 0,
|
|
3854
4225
|
agent: params.agent!,
|
|
@@ -3880,6 +4251,9 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3880
4251
|
}
|
|
3881
4252
|
},
|
|
3882
4253
|
}));
|
|
4254
|
+
// Capture the owned mailbox before a child can start and finish between polling ticks.
|
|
4255
|
+
if (deps.childRuntime?.fanoutChild) deps.activateSupervisorTransport?.();
|
|
4256
|
+
syncHerdrForegroundChild();
|
|
3883
4257
|
}
|
|
3884
4258
|
|
|
3885
4259
|
const modelResponseAliases = deps.config.modelResponseAliases === undefined ? undefined : structuredClone(deps.config.modelResponseAliases);
|
|
@@ -3898,10 +4272,14 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3898
4272
|
: undefined;
|
|
3899
4273
|
try {
|
|
3900
4274
|
const launched = await runSync(ctx.cwd, agents, params.agent!, task, compactOptional<Parameters<typeof runSync>[4]>({
|
|
4275
|
+
machine: foregroundMachine,
|
|
4276
|
+
parentProviderRegistry: ctx.modelRegistry,
|
|
4277
|
+
projectTrusted: sessionProjectTrust(ctx),
|
|
4278
|
+
remoteReads: foregroundMachine ? readsOverride : undefined,
|
|
3901
4279
|
permissions: deps.config.permissions,
|
|
3902
4280
|
runtimeSnapshotHost: deps.pi,
|
|
3903
4281
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
3904
|
-
|
|
4282
|
+
requiredExtensions,
|
|
3905
4283
|
childRuntime: deps.childRuntime,
|
|
3906
4284
|
onChildSession: (controls) => { childSessionControls = controls; },
|
|
3907
4285
|
context: data.contextPolicy.contextForAgent(params.agent!),
|
|
@@ -3910,6 +4288,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3910
4288
|
cwd: singleCwd,
|
|
3911
4289
|
requestedCwd: data.requestedCwd,
|
|
3912
4290
|
signal,
|
|
4291
|
+
abortedAsStopped: params.workflowParentRunId !== undefined,
|
|
3913
4292
|
interruptSignal: interruptController.signal,
|
|
3914
4293
|
allowIntercomDetach: agentConfig.systemPrompt?.includes(INTERCOM_BRIDGE_MARKER) === true,
|
|
3915
4294
|
intercomEvents: deps.pi.events,
|
|
@@ -3938,7 +4317,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3938
4317
|
fast: params.fast,
|
|
3939
4318
|
modelOverrideFromParent,
|
|
3940
4319
|
modelOrigin,
|
|
3941
|
-
thinkingOverride: thinkingOverrideForTask(
|
|
4320
|
+
thinkingOverride: thinkingOverrideForTask(),
|
|
3942
4321
|
thinkingCeiling: agentConfig.maxThinking,
|
|
3943
4322
|
extensionBindings: params.extensionBindings,
|
|
3944
4323
|
availableModels,
|
|
@@ -3985,7 +4364,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3985
4364
|
if (!artifactConfig.enabled) cleanupStructuredOutputRuntime(structuredRuntime);
|
|
3986
4365
|
} finally {
|
|
3987
4366
|
try {
|
|
3988
|
-
|
|
4367
|
+
finishTrackedForegroundChild();
|
|
3989
4368
|
} finally {
|
|
3990
4369
|
removeForegroundControlIfIdle(deps.state, runId, deps.trackRetainedNestedRoute);
|
|
3991
4370
|
}
|
|
@@ -4012,7 +4391,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4012
4391
|
// authoritative completion remains live.
|
|
4013
4392
|
if (!r?.detached) {
|
|
4014
4393
|
if (!artifactConfig.enabled) cleanupStructuredOutputRuntime(structuredRuntime);
|
|
4015
|
-
|
|
4394
|
+
finishTrackedForegroundChild();
|
|
4016
4395
|
}
|
|
4017
4396
|
}
|
|
4018
4397
|
if (!r.detached) {
|
|
@@ -4061,7 +4440,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4061
4440
|
usageBudget: usageBudgetState(data.usageBudget, totalCost),
|
|
4062
4441
|
...(worktreeHandoff?.reference ? { parallelHandoff: worktreeHandoff.reference } : {}),
|
|
4063
4442
|
}));
|
|
4064
|
-
rememberForegroundRun(deps.state, { modelResponseAliases, runId, mode: "single", cwd: singleCwd, sessionId: data.parentSessionId, results: details.results, params, effectiveOutput, effectiveOutputMode, extensionBindings: params.extensionBindings });
|
|
4443
|
+
rememberForegroundRun(deps.state, { modelResponseAliases, runId, mode: "single", cwd: singleCwd, sessionId: data.parentSessionId, results: details.results, params, effectiveOutput, effectiveOutputMode, extensionBindings: params.extensionBindings, requiredExtensions });
|
|
4065
4444
|
|
|
4066
4445
|
const suppressRoutineResultIntercom = shouldSuppressRoutineResultIntercom({ suppressRoutineResultIntercom: params.suppressRoutineResultIntercom, results: [r] });
|
|
4067
4446
|
if (!r.detached && !r.interrupted && !suppressRoutineResultIntercom) {
|
|
@@ -4119,7 +4498,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4119
4498
|
}
|
|
4120
4499
|
|
|
4121
4500
|
function inferExecutionMode(params: SubagentParamsLike): Details["mode"] {
|
|
4122
|
-
if (params.workflowScript !== undefined) return "workflow";
|
|
4501
|
+
if (params.workflowScript !== undefined || params.workflow !== undefined) return "workflow";
|
|
4123
4502
|
if ((params.chain?.length ?? 0) > 0) return "chain";
|
|
4124
4503
|
if ((params.tasks?.length ?? 0) > 0) return "parallel";
|
|
4125
4504
|
return "single";
|
|
@@ -4138,6 +4517,7 @@ function duplicateSubagentCallResult(params: SubagentParamsLike): AgentToolResul
|
|
|
4138
4517
|
|
|
4139
4518
|
const workflowLaunchObservers = new WeakMap<object, (launch: { agent: string; sessionName?: string; sessionFile?: string; async: boolean; runId?: string }) => void>();
|
|
4140
4519
|
const workflowOwnedUsageBudgets = new WeakMap<object, UsageBudgetConfig>();
|
|
4520
|
+
const workflowRetainedRequiredExtensions = new WeakMap<object, RequiredChildExtensionSnapshot>();
|
|
4141
4521
|
|
|
4142
4522
|
/**
|
|
4143
4523
|
* Terminal-mission retention can remove a mission while its children still
|
|
@@ -4197,12 +4577,13 @@ export function bindMissionWorkflowChildAsyncLaunch(
|
|
|
4197
4577
|
binding: MissionLaunchBinding | undefined,
|
|
4198
4578
|
asyncByDefault: boolean,
|
|
4199
4579
|
asyncId: string = randomUUID(),
|
|
4580
|
+
nestedRootRunId?: string,
|
|
4200
4581
|
): SubagentParamsLike {
|
|
4201
4582
|
const requestedAsync = params.async ?? asyncByDefault;
|
|
4202
4583
|
if (!binding || !requestedAsync || params.clarify === true) return params;
|
|
4203
4584
|
const id = asyncId.trim();
|
|
4204
4585
|
if (!id || path.basename(id) !== id) throw new Error("workflow child async id must be a single path segment");
|
|
4205
|
-
writeMissionAsyncBinding(path.join(DIRS.async, id), binding);
|
|
4586
|
+
writeMissionAsyncBinding(path.join(nestedRootRunId ? nestedRunScope(nestedRootRunId).asyncDirRoot : DIRS.async, id), binding);
|
|
4206
4587
|
return { ...params, workflowChildAsyncId: id };
|
|
4207
4588
|
}
|
|
4208
4589
|
|
|
@@ -4213,21 +4594,25 @@ function workflowChildResult(
|
|
|
4213
4594
|
resumeState?: SubagentState,
|
|
4214
4595
|
forcedTerminalOutcome?: WorkflowTerminalOutcome,
|
|
4215
4596
|
): WorkflowScriptChildResult {
|
|
4597
|
+
const running = missionWorkflowChildStatus(result) === "running";
|
|
4216
4598
|
const receiptOutput = result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
|
|
4217
|
-
const output = result.details.results.length === 1 && result.details.results[0]?.finalOutput !== undefined
|
|
4599
|
+
const output = running ? "" : result.details.results.length === 1 && result.details.results[0]?.finalOutput !== undefined
|
|
4218
4600
|
? result.details.results[0].finalOutput
|
|
4219
4601
|
: receiptOutput;
|
|
4220
4602
|
const childError = result.details.results.map((child) => child.error).find((error): error is string => Boolean(error));
|
|
4221
|
-
const
|
|
4222
|
-
|
|
4223
|
-
|
|
4603
|
+
const stopped = result.details.results.some((child) => child.stopped);
|
|
4604
|
+
// A stopped child's receipt text carries the run fan-out annotation; report the structured stop reason instead.
|
|
4605
|
+
const failureErrorBase = stopped && childError
|
|
4606
|
+
? childError
|
|
4607
|
+
: childError && receiptOutput
|
|
4608
|
+
? receiptOutput.includes(childError) ? receiptOutput : `${childError}\n\n${receiptOutput}`
|
|
4609
|
+
: childError || receiptOutput || output || "Child run failed.";
|
|
4224
4610
|
const savedOutputEvidence = [...new Set(result.details.results.map((child) => child.savedOutputPath).filter((value): value is string => Boolean(value)))]
|
|
4225
4611
|
.filter((savedOutputPath) => !failureErrorBase.includes(savedOutputPath))
|
|
4226
4612
|
.map((savedOutputPath) => `Saved output: ${savedOutputPath}`);
|
|
4227
4613
|
const failureError = [failureErrorBase, ...savedOutputEvidence].join("\n");
|
|
4228
4614
|
const detached = result.details.results.some((child) => child.detached);
|
|
4229
4615
|
const interrupted = result.details.results.some((child) => child.interrupted);
|
|
4230
|
-
const stopped = result.details.results.some((child) => child.stopped);
|
|
4231
4616
|
const terminalOutcome = forcedTerminalOutcome
|
|
4232
4617
|
?? (result.details.results.some((child) => child.timedOut)
|
|
4233
4618
|
? { state: "partial" as const, reason: "timeout" as const }
|
|
@@ -4235,7 +4620,7 @@ function workflowChildResult(
|
|
|
4235
4620
|
? { state: "partial" as const, reason: "budget_exhausted" as const }
|
|
4236
4621
|
: undefined);
|
|
4237
4622
|
const acceptanceRecovery = result.details.results.find((child) => child.acceptance?.recovery)?.acceptance?.recovery;
|
|
4238
|
-
const ok = result.isError !== true && !detached && !interrupted && !stopped && acceptanceRecovery === undefined;
|
|
4623
|
+
const ok = result.isError !== true && !running && !detached && !interrupted && !stopped && acceptanceRecovery === undefined;
|
|
4239
4624
|
const artifactPaths = new Set<string>();
|
|
4240
4625
|
if (result.details.asyncDir) artifactPaths.add(result.details.asyncDir);
|
|
4241
4626
|
if (result.details.parallelHandoff?.path) artifactPaths.add(result.details.parallelHandoff.path);
|
|
@@ -4265,6 +4650,8 @@ function workflowChildResult(
|
|
|
4265
4650
|
const resolvedContext = result.details.context ?? (resolvedContexts.length === 1 ? resolvedContexts[0] : resolvedContexts.length > 1 ? "mixed" : undefined);
|
|
4266
4651
|
const outputReference = result.details.results.find((child) => child.savedOutputPath)?.savedOutputPath
|
|
4267
4652
|
?? result.details.results.find((child) => child.outputReference?.path)?.outputReference?.path;
|
|
4653
|
+
const outputArtifactPath = running ? undefined : result.details.parallelHandoff?.path
|
|
4654
|
+
?? result.details.results.find((child) => child.artifactPaths?.outputPath)?.artifactPaths?.outputPath;
|
|
4268
4655
|
const outputPathMapping = typeof childParams.task === "string" ? outputPathMappingFromTask(childParams.task, outputReference) : undefined;
|
|
4269
4656
|
const externalResult = result.details.results.length === 1 && result.details.results[0]?.runner?.type === "external-cli" ? result.details.results[0] : undefined;
|
|
4270
4657
|
const externalStatus = result.details.asyncDir ? readStatus(result.details.asyncDir) : undefined;
|
|
@@ -4278,12 +4665,14 @@ function workflowChildResult(
|
|
|
4278
4665
|
return {
|
|
4279
4666
|
key,
|
|
4280
4667
|
ok,
|
|
4668
|
+
...(running ? { state: "running" as const } : {}),
|
|
4669
|
+
...(result.details.asyncDir ? { asyncDir: result.details.asyncDir } : {}),
|
|
4281
4670
|
...(lane ? { lane } : {}),
|
|
4282
4671
|
...(terminalOutcome ? { terminalOutcome } : {}),
|
|
4283
4672
|
...(resolvedAgents.length === 1 ? { agent: resolvedAgents[0] } : {}),
|
|
4284
4673
|
...(runId ? { runId } : {}),
|
|
4285
4674
|
output,
|
|
4286
|
-
...(!ok ? { error: failureError } : {}),
|
|
4675
|
+
...(!ok && !running ? { error: failureError } : {}),
|
|
4287
4676
|
...(detached ? { detached: true } : {}),
|
|
4288
4677
|
...(interrupted ? { interrupted: true } : {}),
|
|
4289
4678
|
...(stopped ? { stopped: true } : {}),
|
|
@@ -4291,6 +4680,7 @@ function workflowChildResult(
|
|
|
4291
4680
|
...(requestedContext ? { requestedContext } : {}),
|
|
4292
4681
|
...(resolvedContext ? { resolvedContext } : {}),
|
|
4293
4682
|
...(outputReference ? { outputReference } : {}),
|
|
4683
|
+
...(outputArtifactPath ? { outputArtifactPath } : {}),
|
|
4294
4684
|
...(acceptanceRecovery ? { recovery: acceptanceRecovery } : {}),
|
|
4295
4685
|
...(outputPathMapping ? { outputPathMapping } : {}),
|
|
4296
4686
|
...(externalAdapter ? { externalAdapter } : {}),
|
|
@@ -4312,6 +4702,18 @@ function workflowChildAccountingFields(child: WorkflowScriptChildResult): { usag
|
|
|
4312
4702
|
};
|
|
4313
4703
|
}
|
|
4314
4704
|
|
|
4705
|
+
function workflowRunningChildrenSummary(children: WorkflowScriptChildResult[]): string {
|
|
4706
|
+
const running = children.filter((child) => child.state === "running");
|
|
4707
|
+
return running.length ? `${running.length} child ${running.length === 1 ? "run remains" : "runs remain"} running or uncollected: ${running.map((child) => `${child.key}=${child.runId}`).join(", ")}. These launch receipts contain no final child results.` : "";
|
|
4708
|
+
}
|
|
4709
|
+
|
|
4710
|
+
function workflowResultChildren(children: WorkflowScriptChildResult[], status: AsyncStatus, includeFailureFields: boolean) {
|
|
4711
|
+
return withWorkflowRevivals(DIRS.async, status.runId, children).map((child) => {
|
|
4712
|
+
const sessionName = status.steps?.find((step) => step.workflowKey === child.key)?.sessionName;
|
|
4713
|
+
return { workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), ...(child.revival ? { revival: formatWorkflowKeyRevival(child.revival) } : {}), ...(sessionName ? { sessionName } : {}), ...workflowChildAccountingFields(child), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, ...(child.state === "running" ? { state: "running" } : { success: child.ok }), ...(child.asyncDir ? { asyncDir: child.asyncDir } : {}), ...(child.outputReference ? { outputReference: child.outputReference } : {}), ...(includeFailureFields && child.terminalOutcome ? { terminalOutcome: child.terminalOutcome } : {}), ...(child.outputPathMapping ? { outputPathMapping: child.outputPathMapping } : {}), ...(child.stopped ? { stopped: true } : {}), ...(child.interrupted ? { interrupted: true } : {}), ...(includeFailureFields && child.detached && status.state !== "complete" ? { detached: true } : {}), ...(child.outputArtifactPath || child.outputReference ? { artifactPaths: { outputPath: child.outputArtifactPath ?? child.outputReference } } : {}) };
|
|
4714
|
+
});
|
|
4715
|
+
}
|
|
4716
|
+
|
|
4315
4717
|
function workflowOutputPathMappingSummary(children: WorkflowScriptChildResult[]): string {
|
|
4316
4718
|
const mappings = children.flatMap((child) => child.outputPathMapping
|
|
4317
4719
|
? [`'${child.key}': requested ${child.outputPathMapping.requestedPath} -> saved ${child.outputPathMapping.savedPath}`]
|
|
@@ -4320,7 +4722,11 @@ function workflowOutputPathMappingSummary(children: WorkflowScriptChildResult[])
|
|
|
4320
4722
|
}
|
|
4321
4723
|
|
|
4322
4724
|
function workflowDetailsResults(children: WorkflowScriptChildResult[]): SingleResult[] {
|
|
4323
|
-
return children.flatMap((child) => (child.results ?? []).map((result) =>
|
|
4725
|
+
return children.flatMap((child) => (child.results ?? []).map((result) => ({
|
|
4726
|
+
...result,
|
|
4727
|
+
workflowKey: result.workflowKey ?? child.key,
|
|
4728
|
+
...(child.runId && !result.runId ? { runId: child.runId } : {}),
|
|
4729
|
+
})));
|
|
4324
4730
|
}
|
|
4325
4731
|
|
|
4326
4732
|
function workflowSteerReceipt(key: string, result: AgentToolResult<Details>): WorkflowSteerResult {
|
|
@@ -4463,8 +4869,9 @@ function terminalWorkflowReceipt(
|
|
|
4463
4869
|
terminalOutcome?: WorkflowTerminalOutcome,
|
|
4464
4870
|
hostSteps?: WorkflowReceipt["hostSteps"],
|
|
4465
4871
|
resource?: WorkflowReceipt["resource"],
|
|
4872
|
+
argsDigest?: string,
|
|
4466
4873
|
): WorkflowReceipt {
|
|
4467
|
-
return buildWorkflowReceipt({ workflowRunId, state, children, workflowChildren, terminalOutcome, hostSteps, resource });
|
|
4874
|
+
return buildWorkflowReceipt({ workflowRunId, state, children: withWorkflowRevivals(DIRS.async, workflowRunId, children), workflowChildren, terminalOutcome, hostSteps, resource, ...(argsDigest ? { argsDigest } : {}) });
|
|
4468
4875
|
}
|
|
4469
4876
|
|
|
4470
4877
|
function workflowFailureTerminalOutcome(error: unknown, _children: WorkflowScriptChildResult[], usageBudget: ReturnType<typeof usageBudgetState>): WorkflowTerminalOutcome | undefined {
|
|
@@ -4478,7 +4885,7 @@ function workflowFailureMessage(error: unknown, workflowRunId: string, children:
|
|
|
4478
4885
|
if (children.length === 0 && text.includes(validationPrefix)) {
|
|
4479
4886
|
return `Workflow '${workflowRunId}' validation failed before child launch; no children launched.${text.slice(text.indexOf(validationPrefix) + validationPrefix.length)}`;
|
|
4480
4887
|
}
|
|
4481
|
-
return text;
|
|
4888
|
+
return [text, workflowRunningChildrenSummary(children)].filter(Boolean).join(" ");
|
|
4482
4889
|
}
|
|
4483
4890
|
|
|
4484
4891
|
export async function steerWorkflowChildByKey(input: {
|
|
@@ -4547,6 +4954,35 @@ export async function steerWorkflowChildByKey(input: {
|
|
|
4547
4954
|
}
|
|
4548
4955
|
}
|
|
4549
4956
|
|
|
4957
|
+
export async function preflightWorkflowWorktrees(input: {
|
|
4958
|
+
workflowDefaults: SubagentParamsLike;
|
|
4959
|
+
defaultWorktree?: boolean;
|
|
4960
|
+
calls: Array<{ key: string; params: Record<string, unknown> }>;
|
|
4961
|
+
ctxCwd: string;
|
|
4962
|
+
signal: AbortSignal;
|
|
4963
|
+
deadlineAt?: number;
|
|
4964
|
+
}): Promise<void> {
|
|
4965
|
+
const sources = new Map<string, string[]>();
|
|
4966
|
+
for (const { key, params } of input.calls) {
|
|
4967
|
+
// The workflow validates retained IDs/receipt references before admission; resolution follows it.
|
|
4968
|
+
if (params.resume !== undefined) continue;
|
|
4969
|
+
const effective = prepareWorkflowLaunchParams(input.workflowDefaults, params, "preflight", key);
|
|
4970
|
+
if ((effective.worktree ?? input.defaultWorktree) !== true) continue;
|
|
4971
|
+
// Match recursive execute's resolution, including relative default/child cwd.
|
|
4972
|
+
const cwd = resolveRequestedCwd(input.ctxCwd, effective.cwd);
|
|
4973
|
+
const keys = sources.get(cwd) ?? [];
|
|
4974
|
+
keys.push(key);
|
|
4975
|
+
sources.set(cwd, keys);
|
|
4976
|
+
}
|
|
4977
|
+
for (const [cwd, keys] of sources) {
|
|
4978
|
+
try { await preflightWorktreeSource(cwd, { signal: input.signal, deadlineAt: input.deadlineAt }); }
|
|
4979
|
+
catch (error) {
|
|
4980
|
+
throw new Error(`Worktree admission failed for ${keys.map((key) => `'${key}'`).join(", ")} at ${cwd}: ${error instanceof Error ? error.message : String(error)} Select the correct cwd or arrange an operator-approved commit/stash.`, { cause: error });
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
input.signal.throwIfAborted();
|
|
4984
|
+
}
|
|
4985
|
+
|
|
4550
4986
|
export function prepareWorkflowLaunchParams(
|
|
4551
4987
|
workflowDefaults: SubagentParamsLike,
|
|
4552
4988
|
childParams: Record<string, unknown>,
|
|
@@ -4581,7 +5017,7 @@ export function prepareWorkflowLaunchParams(
|
|
|
4581
5017
|
const worktree = childParams.worktree ?? workflowDefaults.worktree;
|
|
4582
5018
|
const baseRef = Object.hasOwn(childParams, "baseRef") ? childParams.baseRef : undefined;
|
|
4583
5019
|
const outputSchema = Object.hasOwn(childParams, "outputSchema") ? childParams.outputSchema : workflowDefaults.outputSchema;
|
|
4584
|
-
if (outputSchema !== undefined) assertJsonSchemaObject(outputSchema, "outputSchema");
|
|
5020
|
+
if (outputSchema !== undefined && outputSchema !== false) assertJsonSchemaObject(outputSchema, "outputSchema");
|
|
4585
5021
|
const agentContract = Object.hasOwn(childParams, "agentContract") ? childParams.agentContract : workflowDefaults.agentContract;
|
|
4586
5022
|
if (agentContract !== undefined && !isAgentContract(agentContract as AgentContract)) throw new Error("agentContract must be { version: 1 }.");
|
|
4587
5023
|
const acceptance = Object.hasOwn(childParams, "acceptance") ? childParams.acceptance : workflowDefaults.acceptance;
|
|
@@ -4601,7 +5037,7 @@ export function prepareWorkflowLaunchParams(
|
|
|
4601
5037
|
...(lane ? { lane } : {}),
|
|
4602
5038
|
...(worktree !== undefined ? { worktree: worktree as boolean } : {}),
|
|
4603
5039
|
...(baseRef !== undefined ? { baseRef: baseRef as string } : {}),
|
|
4604
|
-
...(outputSchema !== undefined ? { outputSchema
|
|
5040
|
+
...(outputSchema !== undefined ? { outputSchema } : {}),
|
|
4605
5041
|
...(agentContract !== undefined ? { agentContract: agentContract as AgentContract } : {}),
|
|
4606
5042
|
...(acceptance !== undefined ? { acceptance: acceptance as AcceptanceInput } : {}),
|
|
4607
5043
|
...(output !== undefined ? { output: output as string | boolean } : {}),
|
|
@@ -4666,6 +5102,15 @@ function normalizeGateParams(params: SubagentParamsLike): GateParamsNormalizatio
|
|
|
4666
5102
|
return { ok: true, params: { ...rest, ...(normalized.acceptance !== undefined ? { acceptance: normalized.acceptance } : {}) } };
|
|
4667
5103
|
}
|
|
4668
5104
|
|
|
5105
|
+
function describeTypedVerifyOutputSchemaConflict(effective: SubagentParamsLike, requested: SubagentParamsLike): string | undefined {
|
|
5106
|
+
if (!acceptanceHasTypedVerify(effective.acceptance)) return undefined;
|
|
5107
|
+
if (effective.outputSchema === undefined || effective.outputSchema === false) return undefined;
|
|
5108
|
+
const agent = effective.agent ?? "?";
|
|
5109
|
+
const schemaSource = requested.outputSchema !== undefined && requested.outputSchema !== false ? "outputSchema" : `agent '${agent}' outputSchema`;
|
|
5110
|
+
const verifySource = requested.gate !== undefined ? "gate.output" : requested.acceptance !== undefined ? "acceptance.verify" : `agent '${agent}' defaultAcceptance`;
|
|
5111
|
+
return `${verifySource}: ${TYPED_VERIFY_OUTPUT_SCHEMA_CONFLICT.replace("with outputSchema", `with ${schemaSource}`)}`;
|
|
5112
|
+
}
|
|
5113
|
+
|
|
4669
5114
|
function formatWorkflowValue(value: unknown): string {
|
|
4670
5115
|
if (value === undefined) return "(undefined)";
|
|
4671
5116
|
if (typeof value === "string") return value;
|
|
@@ -4854,6 +5299,18 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4854
5299
|
const workflowPermitContexts = new WeakMap<object, { root: WorkflowChildPermit } | { child: WorkflowChildPermitContext }>();
|
|
4855
5300
|
const warnedArtifactPackageDirs = new Set<string>();
|
|
4856
5301
|
const scheduledOwnerExecutors = new Map<string | null, Map<string, { state: SubagentState; executor: ReturnType<typeof createSubagentExecutor> }>>();
|
|
5302
|
+
const disabledFeatures = resolveDisabledFeatureSurface(deps.config);
|
|
5303
|
+
const disabledFeatureResult = (params: SubagentParamsLike): AgentToolResult<Details> | undefined => {
|
|
5304
|
+
const error = disabledFeatureUseError(params, disabledFeatures);
|
|
5305
|
+
if (!error) return undefined;
|
|
5306
|
+
return { content: [{ type: "text", text: error }], isError: true, details: { mode: params.action === undefined ? inferExecutionMode(params) : "management", results: [] } };
|
|
5307
|
+
};
|
|
5308
|
+
const admitEnabledWorkflowChildren = (calls: Array<{ key: string; params: Record<string, unknown> }>): void => {
|
|
5309
|
+
for (const call of calls) {
|
|
5310
|
+
const error = disabledFeatureUseError(call.params, disabledFeatures, `workflow child '${call.key}'`);
|
|
5311
|
+
if (error) throw new Error(error);
|
|
5312
|
+
}
|
|
5313
|
+
};
|
|
4857
5314
|
const execute = async (
|
|
4858
5315
|
_id: string,
|
|
4859
5316
|
params: SubagentParamsLike,
|
|
@@ -4865,6 +5322,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4865
5322
|
): Promise<AgentToolResult<Details>> => {
|
|
4866
5323
|
const workflowLaunchObserver = workflowLaunchObservers.get(params);
|
|
4867
5324
|
const inheritedUsageBudget = workflowOwnedUsageBudgets.get(params);
|
|
5325
|
+
const retainedRequiredExtensions = workflowRetainedRequiredExtensions.get(params);
|
|
4868
5326
|
const delegatedThinkingOverride = delegatedThinkingOverrides.get(params);
|
|
4869
5327
|
const allowZeroToolBudget = delegatedZeroToolBudgets.has(params);
|
|
4870
5328
|
const delegatedExecution = delegatedExecutions.has(params);
|
|
@@ -4883,16 +5341,31 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4883
5341
|
const capacityOverrideError = validateWorkflowCapacityOverrides(requestParams);
|
|
4884
5342
|
if (capacityOverrideError) return buildRequestedModeError(requestParams, capacityOverrideError);
|
|
4885
5343
|
let workflowPreflight: import("../../shared/types.ts").WorkflowPreflight | undefined;
|
|
5344
|
+
// Only workflow requests read the session here; other actions (for example doctor) must not.
|
|
5345
|
+
const resolveWorkflowParentModel = () => parentModelOverride !== undefined
|
|
5346
|
+
? parentModelOverride
|
|
5347
|
+
: (() => {
|
|
5348
|
+
const currentParentModel = normalizeParentModel(ctx.model);
|
|
5349
|
+
return (preserveActiveSession
|
|
5350
|
+
? currentParentModel
|
|
5351
|
+
: rememberParentModel(deps.state, resolveCurrentSessionId(ctx.sessionManager), currentParentModel)) ?? null;
|
|
5352
|
+
})();
|
|
5353
|
+
// validate checks args with the same normalization launch uses, reported beside script errors.
|
|
5354
|
+
const validateWorkflowRequest = () => {
|
|
5355
|
+
const validation = validateWorkflowScript(requestParams.workflowScript ?? "", workflowValidationOptions(deps, requestParams, ctx.cwd, () => resolveWorkflowParentModel()?.provider));
|
|
5356
|
+
const normalizedArgs = normalizeWorkflowArgs(requestParams.args);
|
|
5357
|
+
return "error" in normalizedArgs ? { ...validation, ok: false, errors: [...validation.errors, { message: normalizedArgs.error }] } : validation;
|
|
5358
|
+
};
|
|
4886
5359
|
try {
|
|
4887
|
-
if (requestParams.preflight !== undefined && requestParams.workflowScript === undefined
|
|
4888
|
-
throw new Error("preflight requires
|
|
5360
|
+
if (requestParams.preflight !== undefined && requestParams.workflowScript === undefined) {
|
|
5361
|
+
throw new Error("preflight requires workflow: true or a workflow script path.");
|
|
4889
5362
|
}
|
|
4890
5363
|
workflowPreflight = normalizeWorkflowPreflight(requestParams.preflight);
|
|
4891
5364
|
if (workflowPreflight) requestParams = { ...requestParams, preflight: workflowPreflight };
|
|
4892
5365
|
} catch (error) {
|
|
4893
5366
|
const message = error instanceof Error ? error.message : String(error);
|
|
4894
5367
|
if (requestParams.action?.trim() === "validate") {
|
|
4895
|
-
const validation =
|
|
5368
|
+
const validation = validateWorkflowRequest();
|
|
4896
5369
|
const invalidValidation = { ...validation, ok: false, errors: [...validation.errors, { message }] };
|
|
4897
5370
|
return {
|
|
4898
5371
|
content: [{ type: "text", text: JSON.stringify(invalidValidation) }],
|
|
@@ -4903,13 +5376,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4903
5376
|
return buildRequestedModeError(requestParams, message);
|
|
4904
5377
|
}
|
|
4905
5378
|
if (requestParams.action?.trim() === "validate") {
|
|
4906
|
-
|
|
4907
|
-
const payload = workflowPreflight ? { ...validation, preflight: workflowPreflight } : validation;
|
|
4908
|
-
return {
|
|
4909
|
-
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
4910
|
-
...(validation.ok ? {} : { isError: true }),
|
|
4911
|
-
details: { mode: "management", results: [] },
|
|
4912
|
-
};
|
|
5379
|
+
return buildWorkflowValidationResult(validateWorkflowRequest(), "management", workflowPreflight);
|
|
4913
5380
|
}
|
|
4914
5381
|
const normalizedAction = typeof requestParams.action === "string" ? requestParams.action.trim() : requestParams.action;
|
|
4915
5382
|
if (normalizedAction === "resume" && requestParams.extensionBindings !== undefined) return buildRequestedModeError(requestParams, "extensionBindings is not supported with action='resume'; resume uses the original retained child binding.");
|
|
@@ -4921,22 +5388,32 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4921
5388
|
workflowResource = { permit: workflowResourcePermit, ...consumed };
|
|
4922
5389
|
}
|
|
4923
5390
|
if (requestParams.workflowScript !== undefined && normalizedAction === undefined) {
|
|
5391
|
+
const workflowArgsEvidence = requestParams.args === undefined ? undefined : { args: requestParams.args, argsDigest: stableJsonDigest(requestParams.args) };
|
|
5392
|
+
const workflowArgs = workflowArgsEvidence?.args;
|
|
5393
|
+
const workflowArgsDigest = workflowArgsEvidence?.argsDigest;
|
|
5394
|
+
const workflowParentModel = resolveWorkflowParentModel();
|
|
5395
|
+
const workflowValidation = validateWorkflowScript(requestParams.workflowScript, workflowValidationOptions(deps, requestParams, ctx.cwd, () => workflowParentModel?.provider));
|
|
5396
|
+
if (!workflowValidation.ok && publicExecution) return buildWorkflowValidationResult(workflowValidation, "workflow", workflowPreflight);
|
|
5397
|
+
const launchBlockingErrors = workflowValidation.errors.filter((error) => error.kind === "spawn-budget" || error.kind === "agent");
|
|
5398
|
+
if (launchBlockingErrors.length > 0) {
|
|
5399
|
+
return buildRequestedModeError(requestParams, `Workflow '${_id}' validation failed before child launch; no children launched. ${launchBlockingErrors.map((error) => error.message).join(" ")}`);
|
|
5400
|
+
}
|
|
5401
|
+
// A package chain's per-step stop check defeats static launch counting; runtime fan-out enforcement still applies.
|
|
5402
|
+
const structuredResource = workflowResource?.provenance.name === "chain" || workflowResource?.provenance.name === "tasks";
|
|
5403
|
+
for (const warning of workflowValidation.warnings ?? []) {
|
|
5404
|
+
if (!(structuredResource && warning.kind === "dynamic-spawn-count")) console.warn(`[pi-subagents] ${warning.message}`);
|
|
5405
|
+
}
|
|
4924
5406
|
const acceptanceErrors = validateAcceptanceInput(requestParams.acceptance);
|
|
4925
5407
|
if (acceptanceErrors.length > 0) return buildRequestedModeError(requestParams, acceptanceErrors.join(" "));
|
|
5408
|
+
// Capture mandatory host extensions at admission: script children may launch after the host disposes its registration.
|
|
5409
|
+
const admittedRequiredExtensions = retainedRequiredExtensions ?? deps.childRuntime?.requiredExtensions ?? resolveRequiredChildExtensions(ctx.sessionManager.getSessionId() ?? undefined);
|
|
5410
|
+
const workflowRequiredExtensions = hasMandatoryRequiredChildExtensions(admittedRequiredExtensions) ? admittedRequiredExtensions : undefined;
|
|
4926
5411
|
const foregroundWorkflowRunId = encodeIndexSegment(_id);
|
|
4927
5412
|
if (delegatedWorkflowPermit) {
|
|
4928
5413
|
const permitError = validateWorkflowChildPermitRoot(delegatedWorkflowPermit, foregroundWorkflowRunId);
|
|
4929
5414
|
if (permitError) return buildRequestedModeError(requestParams, permitError);
|
|
4930
5415
|
if (requestParams.async !== false) return buildRequestedModeError(requestParams, "Workflow child permit supports foreground workflow roots only; set async:false.");
|
|
4931
5416
|
}
|
|
4932
|
-
const workflowParentModel = parentModelOverride !== undefined
|
|
4933
|
-
? parentModelOverride
|
|
4934
|
-
: (() => {
|
|
4935
|
-
const currentParentModel = normalizeParentModel(ctx.model);
|
|
4936
|
-
return (preserveActiveSession
|
|
4937
|
-
? currentParentModel
|
|
4938
|
-
: rememberParentModel(deps.state, resolveCurrentSessionId(ctx.sessionManager), currentParentModel)) ?? null;
|
|
4939
|
-
})();
|
|
4940
5417
|
if (requestParams.extensionBindings !== undefined) {
|
|
4941
5418
|
try {
|
|
4942
5419
|
requestParams.extensionBindings = normalizeExtensionBindings(requestParams.extensionBindings)!.value;
|
|
@@ -4945,6 +5422,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4945
5422
|
}
|
|
4946
5423
|
}
|
|
4947
5424
|
const parentCwd = ctx.cwd;
|
|
5425
|
+
for (const [name, value] of [["timeoutMs", requestParams.timeoutMs], ["maxRuntimeMs", requestParams.maxRuntimeMs]] as const) {
|
|
5426
|
+
if (value === undefined) continue;
|
|
5427
|
+
const overflowError = timerDelayOverflowError(name, value);
|
|
5428
|
+
if (overflowError) return buildRequestedModeError(requestParams, overflowError);
|
|
5429
|
+
}
|
|
4948
5430
|
const timeout = requestParams.timeoutMs ?? requestParams.maxRuntimeMs ?? (requestParams.async === false ? resolveConfigDefaultTimeoutMs(deps.config.timeoutMs) ?? DEFAULT_FOREGROUND_TIMEOUT_MS : undefined);
|
|
4949
5431
|
const workflowUsageBudget = validateUsageBudgetConfig(requestParams.usageBudget ?? deps.config.usageBudget, requestParams.usageBudget ? "usageBudget" : "config.usageBudget");
|
|
4950
5432
|
if (workflowUsageBudget.error) return buildRequestedModeError(requestParams, workflowUsageBudget.error);
|
|
@@ -5050,6 +5532,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5050
5532
|
const workflowCapabilityCeiling = intersectSubagentCapabilityCeilings(requestParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(currentSessionId));
|
|
5051
5533
|
const completionOwnerId = deps.state.completionOwnerId ?? currentCompletionOwnerId();
|
|
5052
5534
|
deps.state.completionOwnerId = completionOwnerId;
|
|
5535
|
+
const workflowScriptSourceDigest = workflowScriptDigest(requestParams.workflowScript);
|
|
5536
|
+
const workflowReuseSource = findWorkflowReuseSource(DIRS.async, currentSessionId, workflowScriptSourceDigest, workflowArgsDigest);
|
|
5537
|
+
const workflowRunEvidence: Pick<NonNullable<AsyncStatus["workflow"]>, "args" | "argsDigest" | "scriptDigest" | "reusedFrom" | "stopCause"> = { ...workflowArgsEvidence, scriptDigest: workflowScriptSourceDigest };
|
|
5538
|
+
if (workflowReuseSource) workflowRunEvidence.reusedFrom = workflowReuseSource.runId;
|
|
5539
|
+
const workflowJournalFingerprints = new Map<string, string>();
|
|
5053
5540
|
try {
|
|
5054
5541
|
fs.mkdirSync(asyncDir, { recursive: true });
|
|
5055
5542
|
writeRunFanoutBudgetDescriptor(asyncDir, workflowFanoutBudget);
|
|
@@ -5078,9 +5565,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5078
5565
|
...(workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {}),
|
|
5079
5566
|
...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}),
|
|
5080
5567
|
pid: process.pid,
|
|
5568
|
+
...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}),
|
|
5081
5569
|
steps: [],
|
|
5082
5570
|
...(workflowPreflight ? { preflight: workflowPreflight } : {}),
|
|
5083
|
-
workflow: { trace: [], emits: [], console: [], ...(workflowResource ? { resource: workflowResource.provenance } : {}) },
|
|
5571
|
+
workflow: { trace: [], emits: [], console: [], ...workflowRunEvidence, ...(workflowResource ? { resource: workflowResource.provenance } : {}) },
|
|
5084
5572
|
workflowChildren: workflowChildSummary({ parentToolCallId: toolCallId, workflowRunId, workflowState: "running", inventoryComplete: false }),
|
|
5085
5573
|
runFanoutBudget: getRunFanoutBudgetSnapshot(workflowFanoutBudget),
|
|
5086
5574
|
};
|
|
@@ -5110,19 +5598,51 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5110
5598
|
};
|
|
5111
5599
|
let pendingResultPublication: Promise<boolean> | undefined;
|
|
5112
5600
|
let settleResultPublication: ((published: boolean) => void) | undefined;
|
|
5113
|
-
|
|
5601
|
+
let resultWriteFailureWakeDelivered = false;
|
|
5602
|
+
const reportResultWriteFailure = (error: unknown): boolean => {
|
|
5114
5603
|
const message = `Failed to write async workflow result ${resultPath}: ${error instanceof Error ? error.message : String(error)}`;
|
|
5115
5604
|
console.error(message, error);
|
|
5605
|
+
try {
|
|
5606
|
+
if (currentSessionId && fallbackResultPayloadPathForSessionRun(path.dirname(resultPath), currentSessionId, workflowRunId)) return true;
|
|
5607
|
+
} catch (pendingError) {
|
|
5608
|
+
console.error(`Failed to verify pending async workflow result '${workflowRunId}':`, pendingError);
|
|
5609
|
+
}
|
|
5116
5610
|
appendWorkflowEvent({ type: "subagent.workflow.result_write_failed", error: message });
|
|
5611
|
+
// A missing result file means the result watcher will never deliver the
|
|
5612
|
+
// terminal completion wake. Intermediate child notices are context-only
|
|
5613
|
+
// once their turns are suppressed, so surface the failure as its own
|
|
5614
|
+
// actionable wake instead of leaving the parent asleep.
|
|
5615
|
+
if (resultWriteFailureWakeDelivered) return false;
|
|
5616
|
+
if (deps.state.currentSessionId !== currentSessionId || deps.state.completionOwnerId !== completionOwnerId) return false;
|
|
5617
|
+
try {
|
|
5618
|
+
(deps.parentWake ?? deps.pi).sendMessage(
|
|
5619
|
+
{
|
|
5620
|
+
customType: "subagent-workflow-result-write-failed",
|
|
5621
|
+
content: message,
|
|
5622
|
+
display: true,
|
|
5623
|
+
},
|
|
5624
|
+
{ triggerTurn: true },
|
|
5625
|
+
);
|
|
5626
|
+
resultWriteFailureWakeDelivered = true;
|
|
5627
|
+
} catch (sendError) {
|
|
5628
|
+
console.error(`Failed to send workflow result write failure notification for '${workflowRunId}':`, sendError);
|
|
5629
|
+
}
|
|
5630
|
+
deps.refreshResultDelivery?.();
|
|
5631
|
+
return false;
|
|
5117
5632
|
};
|
|
5633
|
+
const pendingWorkflowChildAnnouncements = new Map<string, NonNullable<AsyncStatus["steps"]>[number]>();
|
|
5634
|
+
let announcePersistedWorkflowChildren = (): void => {};
|
|
5118
5635
|
const runPersistence = createCapacityResilientJsonWriter({
|
|
5119
5636
|
keepAlive: true,
|
|
5120
5637
|
onSuccess: (filePath, payload) => {
|
|
5121
|
-
if (filePath === statusPath)
|
|
5638
|
+
if (filePath === statusPath) {
|
|
5639
|
+
announcePersistedWorkflowChildren();
|
|
5640
|
+
queueActiveRunIndex(payload as AsyncStatus);
|
|
5641
|
+
}
|
|
5122
5642
|
if (filePath === resultPath) settleResultPublication?.(true);
|
|
5123
5643
|
},
|
|
5124
5644
|
onError: (error, filePath) => {
|
|
5125
|
-
if (filePath === resultPath)
|
|
5645
|
+
if (filePath === resultPath) settleResultPublication?.(reportResultWriteFailure(error));
|
|
5126
5646
|
else console.error(`Failed to persist async workflow state '${filePath}':`, error);
|
|
5127
5647
|
},
|
|
5128
5648
|
write: (filePath, payload) => filePath === resultPath
|
|
@@ -5139,7 +5659,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5139
5659
|
// terminal writes stay fail-fast on purpose: no child work is at risk by then, and
|
|
5140
5660
|
// silently dropping a terminal write would leave status.json and the active-run
|
|
5141
5661
|
// index pinned at "running" after the result already says complete.
|
|
5142
|
-
const persist = (options: { tolerateStatusWriteFailure?: boolean } = {}) => {
|
|
5662
|
+
const persist = (options: { tolerateStatusWriteFailure?: boolean } = {}): void => {
|
|
5143
5663
|
if (persistClosed) return;
|
|
5144
5664
|
const liveJob = deps.state.asyncJobs.get(workflowRunId);
|
|
5145
5665
|
if (liveJob && (liveJob.status === "complete" || liveJob.status === "failed") && status.state !== "complete" && status.state !== "failed") return;
|
|
@@ -5153,7 +5673,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5153
5673
|
} else if (options.tolerateStatusWriteFailure) {
|
|
5154
5674
|
try {
|
|
5155
5675
|
runPersistence.write(statusPath, { ...status });
|
|
5156
|
-
statusPersistenceDegraded = false;
|
|
5676
|
+
if (runPersistence.pendingCount() === 0) statusPersistenceDegraded = false;
|
|
5157
5677
|
} catch (error) {
|
|
5158
5678
|
const message = `Failed to persist async workflow state ${statusPath}: ${error instanceof Error ? error.message : String(error)}`;
|
|
5159
5679
|
console.error(message, error);
|
|
@@ -5203,8 +5723,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5203
5723
|
if (!resultPublished) pendingResultPublication = new Promise<boolean>((resolve) => { settleResultPublication = resolve; });
|
|
5204
5724
|
return true;
|
|
5205
5725
|
} catch (error) {
|
|
5206
|
-
reportResultWriteFailure(error);
|
|
5207
|
-
return false;
|
|
5726
|
+
return reportResultWriteFailure(error);
|
|
5208
5727
|
}
|
|
5209
5728
|
};
|
|
5210
5729
|
const projectWorkflowActivity = () => {
|
|
@@ -5242,7 +5761,25 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5242
5761
|
indexPersistence.dispose();
|
|
5243
5762
|
return { content: [{ type: "text", text: `Failed to create async workflow storage: ${error instanceof Error ? error.message : String(error)}` }], isError: true, details: { mode: "workflow", results: [] } };
|
|
5244
5763
|
}
|
|
5245
|
-
appendWorkflowEvent({ type: "subagent.workflow.started" });
|
|
5764
|
+
appendWorkflowEvent({ type: "subagent.workflow.started", ...(workflowArgsDigest ? { argsDigest: workflowArgsDigest } : {}) });
|
|
5765
|
+
try {
|
|
5766
|
+
deps.pi.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
|
|
5767
|
+
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
5768
|
+
id: workflowRunId,
|
|
5769
|
+
asyncDir,
|
|
5770
|
+
cwd: workflowCwd,
|
|
5771
|
+
...(workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {}),
|
|
5772
|
+
pid: process.pid,
|
|
5773
|
+
sessionId: currentSessionId ?? undefined,
|
|
5774
|
+
completionOwnerId,
|
|
5775
|
+
mode: "workflow",
|
|
5776
|
+
agent: "workflow",
|
|
5777
|
+
goal: derivedObjective.trim() ? PROMPT_REDACTED : undefined,
|
|
5778
|
+
...(timeout !== undefined ? { timeoutMs: timeout, deadlineAt: startedAt + timeout } : {}),
|
|
5779
|
+
});
|
|
5780
|
+
} catch (error) {
|
|
5781
|
+
console.error("Failed to emit async workflow start event:", error);
|
|
5782
|
+
}
|
|
5246
5783
|
// The runner does not execute workflow scripts: this active owner must consume its own
|
|
5247
5784
|
// durable steer inbox, deliver through in-process child controls, and persist receipts.
|
|
5248
5785
|
const emitWorkflowSteerEvent = (type: string, requestId: string, index?: number, extra: Record<string, unknown> = {}): void => {
|
|
@@ -5389,7 +5926,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5389
5926
|
const workflowDeadlineAt = timeout === undefined ? undefined : Date.now() + timeout;
|
|
5390
5927
|
const workflowResults: SingleResult[] = [];
|
|
5391
5928
|
const workflowChildRunIds = new Map<string, string>();
|
|
5392
|
-
const { action: _action, agent: _agent, task: _task, resume: _resume, tasks: _tasks, chain: _chain, concurrency: _concurrency, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, missionId: _missionId, mission: _mission, preflight: _preflight, globalConcurrencyLimit: _globalConcurrencyLimit, maxSubagentSpawnsPerRun: _maxSubagentSpawnsPerRun, ...workflowChildDefaults } = workflowRequest;
|
|
5929
|
+
const { args: _args, action: _action, agent: _agent, task: _task, resume: _resume, tasks: _tasks, chain: _chain, concurrency: _concurrency, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, missionId: _missionId, mission: _mission, preflight: _preflight, globalConcurrencyLimit: _globalConcurrencyLimit, maxSubagentSpawnsPerRun: _maxSubagentSpawnsPerRun, ...workflowChildDefaults } = workflowRequest;
|
|
5393
5930
|
const workflowOutput = typeof workflowChildDefaults.output === "string" || typeof workflowChildDefaults.output === "boolean" ? workflowChildDefaults.output : undefined;
|
|
5394
5931
|
const configuredOutputBaseDir = resolveConfiguredSingleRunOutputBaseDir(deps);
|
|
5395
5932
|
const workflowAggregateOutputPath = resolveSingleOutputPath(workflowOutput, parentCwd, workflowCwd, resolveSingleRunOutputBaseDir(deps, workflowArtifactsDir, workflowRunId));
|
|
@@ -5398,6 +5935,41 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5398
5935
|
const childOutputClaimPaths = new Map<string, string>();
|
|
5399
5936
|
const producedChildOutputPaths = new Set<string>();
|
|
5400
5937
|
const workflowSteps = new Map<string, NonNullable<AsyncStatus["steps"]>[number]>();
|
|
5938
|
+
const announcedWorkflowChildren = new Set<string>();
|
|
5939
|
+
const announceWorkflowChild = (key: string, step: NonNullable<AsyncStatus["steps"]>[number]): void => {
|
|
5940
|
+
if (announcedWorkflowChildren.has(key)) return;
|
|
5941
|
+
announcedWorkflowChildren.add(key);
|
|
5942
|
+
const stepIndex = status.steps?.indexOf(step);
|
|
5943
|
+
const childEvent: SubagentChildStatusEvent = {
|
|
5944
|
+
type: "subagent.child-status",
|
|
5945
|
+
version: 1,
|
|
5946
|
+
runId: workflowRunId,
|
|
5947
|
+
childId: key,
|
|
5948
|
+
status: "started",
|
|
5949
|
+
ts: Date.now(),
|
|
5950
|
+
source: "async",
|
|
5951
|
+
asyncDir,
|
|
5952
|
+
...(stepIndex !== undefined ? { stepIndex } : {}),
|
|
5953
|
+
agent: step.agent,
|
|
5954
|
+
...(step.runId ? { childRunId: step.runId } : {}),
|
|
5955
|
+
workflowKey: key,
|
|
5956
|
+
...(step.phase ? { phase: step.phase } : {}),
|
|
5957
|
+
...(step.label ? { label: step.label } : {}),
|
|
5958
|
+
};
|
|
5959
|
+
appendWorkflowEvent({ ...childEvent });
|
|
5960
|
+
try {
|
|
5961
|
+
deps.pi.events.emit(SUBAGENT_CHILD_STATUS_EVENT, childEvent);
|
|
5962
|
+
} catch (error) {
|
|
5963
|
+
console.error("Failed to emit workflow child status event:", error);
|
|
5964
|
+
}
|
|
5965
|
+
};
|
|
5966
|
+
announcePersistedWorkflowChildren = () => {
|
|
5967
|
+
for (const [key, step] of pendingWorkflowChildAnnouncements) {
|
|
5968
|
+
if (!step.runId) continue;
|
|
5969
|
+
announceWorkflowChild(key, step);
|
|
5970
|
+
pendingWorkflowChildAnnouncements.delete(key);
|
|
5971
|
+
}
|
|
5972
|
+
};
|
|
5401
5973
|
const runHostCommand = workflowHostCommandRunner({
|
|
5402
5974
|
workflowCwd,
|
|
5403
5975
|
artifactsDir: workflowArtifactsDir,
|
|
@@ -5488,6 +6060,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5488
6060
|
workflowSteps.set(entry.key, step);
|
|
5489
6061
|
}
|
|
5490
6062
|
const projectedStep = workflowSteps.get(entry.key);
|
|
6063
|
+
if (entry.reused && projectedStep) projectedStep.reused = true;
|
|
5491
6064
|
if (entry.state === "stopped" && projectedStep) {
|
|
5492
6065
|
appendWorkflowEvent({
|
|
5493
6066
|
type: "subagent.child-status",
|
|
@@ -5514,11 +6087,14 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5514
6087
|
try {
|
|
5515
6088
|
const workflow = await runWorkflowScript({
|
|
5516
6089
|
script: workflowScript,
|
|
6090
|
+
...(workflowArgs ? { args: workflowArgs } : {}),
|
|
6091
|
+
workflowRunId,
|
|
6092
|
+
processCwd: ctx.cwd,
|
|
5517
6093
|
globalConcurrencyLimit: requestParams.globalConcurrencyLimit ?? deps.config.globalConcurrencyLimit,
|
|
5518
6094
|
timeoutMs: timeout,
|
|
5519
6095
|
signal: controller.signal,
|
|
5520
6096
|
continueAfterAbortWhenChildrenSettled: (abortError) => {
|
|
5521
|
-
if (abortError
|
|
6097
|
+
if (!workflowStopCause(abortError)) return false;
|
|
5522
6098
|
const activeAsyncChild = [...(deps.state.asyncJobs?.values() ?? [])].some((job) => job.parentWorkflowRunId === workflowRunId && (job.status === "queued" || job.status === "running"));
|
|
5523
6099
|
const activeForegroundChild = [...deps.state.foregroundControls.values()].some((control) => control.parentWorkflowRunId === workflowRunId && (control.activeChildren?.size ?? 0) > 0);
|
|
5524
6100
|
return !activeAsyncChild && !activeForegroundChild;
|
|
@@ -5529,6 +6105,30 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5529
6105
|
},
|
|
5530
6106
|
...(workflowState ? { state: workflowState } : {}),
|
|
5531
6107
|
onTrace: updateTrace,
|
|
6108
|
+
onChildSettled: (notification) => {
|
|
6109
|
+
const journalFingerprint = workflowJournalFingerprints.get(notification.childKey);
|
|
6110
|
+
if (journalFingerprint) appendWorkflowChildJournal(asyncDir, { type: "settle", key: notification.childKey, fingerprint: journalFingerprint, result: notification.result });
|
|
6111
|
+
appendWorkflowEvent({
|
|
6112
|
+
type: "subagent.workflow.child_settled",
|
|
6113
|
+
childKey: notification.childKey,
|
|
6114
|
+
...(notification.childRunId ? { childRunId: notification.childRunId } : {}),
|
|
6115
|
+
outcome: notification.outcome,
|
|
6116
|
+
workflowRunning: notification.workflowRunning,
|
|
6117
|
+
});
|
|
6118
|
+
try {
|
|
6119
|
+
(deps.parentWake ?? deps.pi).sendMessage(
|
|
6120
|
+
{
|
|
6121
|
+
customType: "subagent-incremental-child-notify",
|
|
6122
|
+
content: formatIncrementalChildCompletion(notification),
|
|
6123
|
+
display: notification.outcome !== "completed",
|
|
6124
|
+
},
|
|
6125
|
+
{ triggerTurn: incrementalChildCompletionTriggersTurn(notification, requestParams.scheduleOrigin) },
|
|
6126
|
+
);
|
|
6127
|
+
} catch (sendError) {
|
|
6128
|
+
console.error(`Failed to send incremental child completion notification for '${notification.childKey}':`, sendError);
|
|
6129
|
+
}
|
|
6130
|
+
deps.refreshResultDelivery?.();
|
|
6131
|
+
},
|
|
5532
6132
|
onLanePlan: (lanes) => {
|
|
5533
6133
|
status.workflowGraph = buildWorkflowLaneGraph(workflowRunId, lanes, status.workflowGraph);
|
|
5534
6134
|
applyWorkflowLaneTrace(status.workflowGraph, status.workflow?.trace ?? []);
|
|
@@ -5541,7 +6141,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5541
6141
|
persist({ tolerateStatusWriteFailure: true });
|
|
5542
6142
|
} });
|
|
5543
6143
|
},
|
|
5544
|
-
admit: (calls) => {
|
|
6144
|
+
admit: async (calls, admissionSignal) => {
|
|
6145
|
+
admitEnabledWorkflowChildren(calls);
|
|
6146
|
+
await preflightWorkflowWorktrees({ workflowDefaults: workflowChildDefaults, defaultWorktree: deps.config.worktree, calls, ctxCwd: parentCwd, signal: admissionSignal, deadlineAt: workflowDeadlineAt });
|
|
5545
6147
|
const outputClaims = workflowChildOutputClaims({ ctxCwd: parentCwd, workflowCwd, artifactsDir: workflowArtifactsDir, workflowRunId, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: discoverWorkflowAgents, agents: workflowAgents, workflowAgentScope: workflowChildDefaults.agentScope, state: deps.state, claimedOutputPaths, entries: calls });
|
|
5546
6148
|
if (outputClaims.error) throw new Error(outputClaims.error);
|
|
5547
6149
|
status.runFanoutBudget = claimRunFanoutBatch(workflowFanoutBudget, calls.map(({ key }) => `workflow[${key}]`));
|
|
@@ -5557,6 +6159,32 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5557
6159
|
appendWorkflowEvent({ type: "subagent.workflow.emit", value: emits.at(-1) });
|
|
5558
6160
|
},
|
|
5559
6161
|
launch: async (key, childParams, workflowSignal, admission) => {
|
|
6162
|
+
const journalFingerprint = workflowJournalFingerprints.get(key) ?? workflowChildFingerprint(childParams);
|
|
6163
|
+
workflowJournalFingerprints.set(key, journalFingerprint);
|
|
6164
|
+
const priorChild = workflowReuseSource ? matchWorkflowReuse(workflowReuseSource, key, journalFingerprint) : undefined;
|
|
6165
|
+
if (priorChild?.kind === "settled") {
|
|
6166
|
+
if (priorChild.result.runId) workflowChildRunIds.set(key, priorChild.result.runId);
|
|
6167
|
+
return { ...priorChild.result, reused: true };
|
|
6168
|
+
}
|
|
6169
|
+
if (priorChild?.kind === "started") {
|
|
6170
|
+
// The previous run's awaited async child may still be running: wait for that exact run
|
|
6171
|
+
// instead of launching again. Journal it first so another reload can re-attach too.
|
|
6172
|
+
const priorRunId = priorChild.runId;
|
|
6173
|
+
const priorAsyncDir = path.join(DIRS.async, priorRunId);
|
|
6174
|
+
appendWorkflowChildJournal(asyncDir, { type: "start", key, fingerprint: journalFingerprint, runId: priorRunId });
|
|
6175
|
+
const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps.state, priorRunId, priorAsyncDir, deps.kill);
|
|
6176
|
+
const reattached = await awaitExistingAsyncRun(priorAsyncDir, priorRunId, workflowSignal).finally(stopListener.remove);
|
|
6177
|
+
const claimedPath = reattached.status === "settled" ? claimWorkflowAwaitedResult(priorAsyncDir, workflowRunId) : undefined;
|
|
6178
|
+
if (reattached.status === "settled" && claimedPath) {
|
|
6179
|
+
const imported = importWorkflowAwaitedChildResult(reattached.result, { runId: priorRunId, asyncDir: priorAsyncDir, resultPath: claimedPath, task: typeof childParams.task === "string" ? childParams.task : "", parentWorkflowRunId: workflowReuseSource?.runId, details: { mode: "single", asyncId: priorRunId, asyncDir: priorAsyncDir, results: [] }, state: deps.state, pi: deps.pi });
|
|
6180
|
+
const reattachedResult = workflowChildResult(key, imported, childParams, deps.state);
|
|
6181
|
+
// Like a settled journal match: only a successful child is reused; a failed or stopped one launches fresh.
|
|
6182
|
+
if (reattachedResult.ok) {
|
|
6183
|
+
workflowChildRunIds.set(key, priorRunId);
|
|
6184
|
+
return { ...reattachedResult, reused: true };
|
|
6185
|
+
}
|
|
6186
|
+
}
|
|
6187
|
+
}
|
|
5560
6188
|
if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."), childParams, deps.state);
|
|
5561
6189
|
const budgetState = usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults));
|
|
5562
6190
|
if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)), childParams, deps.state, { state: "partial", reason: "budget_exhausted" });
|
|
@@ -5575,10 +6203,14 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5575
6203
|
{ ...prepareWorkflowChildLaunchParams({ workflowDefaults: workflowChildDefaults, childParams, parentWorkflowRunId: workflowRunId, workflowKey: key, ctxCwd: parentCwd, workflowCwd, artifactsDir: workflowArtifactsDir, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: discoverWorkflowAgents, agents: workflowAgents, workflowAgentScope: workflowChildDefaults.agentScope, outputOverride: childOutputOverrides.get(key), outputClaimPath: childOutputClaimPaths.get(key), options: { missionDetached: detachWorkflowChildMissions, awaitDetachedChild: true, runFanoutBudget: workflowFanoutBudget, parentDeadlineAt: workflowDeadlineAt, capabilityCeiling: workflowCapabilityCeiling } }), runFanoutAdmitted: admission.admitted },
|
|
5576
6204
|
missionBinding,
|
|
5577
6205
|
deps.asyncByDefault,
|
|
6206
|
+
undefined,
|
|
6207
|
+
inheritedNestedRoute(deps)?.rootRunId,
|
|
5578
6208
|
);
|
|
5579
6209
|
preparedChildParams = childRequest;
|
|
5580
6210
|
if (workflowUsageBudget.budget) workflowOwnedUsageBudgets.set(childRequest, workflowUsageBudget.budget);
|
|
6211
|
+
if (workflowRequiredExtensions) workflowRetainedRequiredExtensions.set(childRequest, workflowRequiredExtensions);
|
|
5581
6212
|
workflowLaunchObservers.set(childRequest, (launch) => {
|
|
6213
|
+
if (launch.runId) appendWorkflowChildJournal(asyncDir, { type: "start", key, fingerprint: journalFingerprint, runId: launch.runId });
|
|
5582
6214
|
const step = status.steps?.find((candidate) => candidate.workflowKey === key);
|
|
5583
6215
|
if (step) {
|
|
5584
6216
|
step.agent = launch.agent;
|
|
@@ -5587,6 +6219,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5587
6219
|
step.async = launch.async;
|
|
5588
6220
|
if (launch.runId) step.runId = launch.runId;
|
|
5589
6221
|
if (childRequest.lane) step.lane = childRequest.lane;
|
|
6222
|
+
if (step.runId) pendingWorkflowChildAnnouncements.set(key, step);
|
|
5590
6223
|
persist({ tolerateStatusWriteFailure: true });
|
|
5591
6224
|
}
|
|
5592
6225
|
recordMissionWorkflowChild(missionBinding, workflowRunId, key, { status: "running", agent: launch.agent, ...(launch.sessionFile ? { sessionPath: launch.sessionFile } : {}) });
|
|
@@ -5653,16 +6286,20 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5653
6286
|
});
|
|
5654
6287
|
const finalPreflightWarnings = workflowPreflightWarnings(workflowPreflight, workflow.trace, { settled: true });
|
|
5655
6288
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(workflow.trace, workflowPreflight);
|
|
5656
|
-
const
|
|
5657
|
-
const
|
|
5658
|
-
const
|
|
6289
|
+
const returnText = formatWorkflowValue(workflow.value);
|
|
6290
|
+
const emitText = workflow.emits.map(formatWorkflowValue).join(", ");
|
|
6291
|
+
const returnPreview = returnText.length > 1_000 ? `${returnText.slice(0, 1_000)}…` : returnText;
|
|
6292
|
+
const emitPreview = workflow.emits.length > 0 ? ` Emitted: ${emitText.length > 1_000 ? `${emitText.slice(0, 1_000)}…` : emitText}` : "";
|
|
6293
|
+
const previewNote = returnText.length > 1_000 || emitText.length > 1_000 ? ` (truncated; full return value and emits: ${statusPath} (workflow.value, workflow.emits))` : "";
|
|
6294
|
+
const runningSummary = workflowRunningChildrenSummary(workflow.children);
|
|
6295
|
+
const summary = `${runningSummary ? `Workflow dispatch completed; ${runningSummary}` : `Workflow completed with ${workflow.children.length} child run(s).`} Return: ${returnPreview}${emitPreview}${previewNote} Trace: ${workflow.trace.length} event(s).${workflowOutputPathMappingSummary(workflow.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
|
|
5659
6296
|
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, summary, producedChildOutputPaths);
|
|
5660
6297
|
const resultSummary = appendWorkflowOutputWarning(summary, outputWarning);
|
|
5661
6298
|
const workflowUsage = sumResultsUsage(workflowResults);
|
|
5662
6299
|
settleWorkflowSteerInbox("complete");
|
|
5663
6300
|
const workflowChildren = workflowChildSummary({ parentToolCallId: toolCallId, workflowRunId, workflowState: "completed", inventoryComplete: true, trace: workflow.trace, children: workflow.children, steps: status.steps });
|
|
5664
|
-
status = { ...status, state: "complete", endedAt: Date.now(), workflow: { value: workflow.value, trace: finalPreflightTrace, emits: workflow.emits, console: workflow.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}) }, workflowChildren, totalTokens: { input: workflowUsage.input, output: workflowUsage.output, total: workflowUsage.input + workflowUsage.output }, totalCost: sumResultsCost(workflowResults) };
|
|
5665
|
-
const receipt = terminalWorkflowReceipt(workflowRunId, "complete", workflow.children, workflowChildren, undefined, validHostStepNodes(status.workflowGraph), workflowResource?.provenance);
|
|
6301
|
+
status = { ...status, state: "complete", endedAt: Date.now(), workflow: { value: workflow.value, trace: finalPreflightTrace, emits: workflow.emits, console: workflow.console, ...workflowRunEvidence, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}) }, workflowChildren, totalTokens: { input: workflowUsage.input, output: workflowUsage.output, total: workflowUsage.input + workflowUsage.output }, totalCost: sumResultsCost(workflowResults) };
|
|
6302
|
+
const receipt = terminalWorkflowReceipt(workflowRunId, "complete", workflow.children, workflowChildren, undefined, validHostStepNodes(status.workflowGraph), workflowResource?.provenance, workflowArgsDigest);
|
|
5666
6303
|
delete status.workflowReceiptPath;
|
|
5667
6304
|
let workflowReceipt: { path: string; receipt: WorkflowReceipt } | undefined;
|
|
5668
6305
|
try {
|
|
@@ -5671,17 +6308,19 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5671
6308
|
} catch (receiptError) {
|
|
5672
6309
|
appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
|
|
5673
6310
|
}
|
|
5674
|
-
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, workflowChildren, results: workflow.children
|
|
6311
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, workflowChildren, results: workflowResultChildren(workflow.children, status, false), workflow: status.workflow, ...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}), ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
5675
6312
|
if (pendingResultPublication && !await pendingResultPublication) return;
|
|
5676
6313
|
persist();
|
|
5677
6314
|
deps.refreshResultDelivery?.();
|
|
5678
6315
|
persistClosed = true;
|
|
5679
|
-
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}) });
|
|
6316
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(workflowArgsDigest ? { argsDigest: workflowArgsDigest } : {}), ...(status.error ? { error: status.error } : {}) });
|
|
5680
6317
|
} catch (error) {
|
|
5681
6318
|
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
5682
6319
|
const stopped = controller.signal.aborted;
|
|
6320
|
+
const stopCause = stopped ? workflowStopCause(controller.signal.reason) : undefined;
|
|
6321
|
+
if (stopCause) workflowRunEvidence.stopCause = stopCause;
|
|
5683
6322
|
const detachedChildKeys = new Set(partial.children.filter((child) => child.detached).map((child) => child.key));
|
|
5684
|
-
const hasRealFailedChild = partial.children.some((child) => !child.ok && !child.detached);
|
|
6323
|
+
const hasRealFailedChild = partial.children.some((child) => !child.ok && child.state !== "running" && !child.detached);
|
|
5685
6324
|
const pauseForDetached = !stopped && error instanceof WorkflowScriptError && error.errorKind === "detached-child" && detachedChildKeys.size > 0 && !hasRealFailedChild;
|
|
5686
6325
|
const state = stopped ? "stopped" : pauseForDetached ? "paused" : "failed";
|
|
5687
6326
|
for (const step of status.steps ?? []) {
|
|
@@ -5700,19 +6339,21 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5700
6339
|
const workflowChildren = workflowChildSummary({ parentToolCallId: toolCallId, workflowRunId, workflowState, inventoryComplete: true, trace: partial.trace, children: partial.children, steps: status.steps });
|
|
5701
6340
|
const finalPreflightWarnings = workflowPreflightWarnings(workflowPreflight, partial.trace, { settled: true });
|
|
5702
6341
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(partial.trace, workflowPreflight);
|
|
5703
|
-
status = compactOptional<AsyncStatus>({ ...status, state, stopped: stopped || undefined, activityState: pauseForDetached || status.activityState === "needs_attention" ? "needs_attention" : undefined, error: workflowFailureMessage(error, workflowRunId, partial.children), endedAt: Date.now(), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}) }, workflowChildren });
|
|
6342
|
+
status = compactOptional<AsyncStatus>({ ...status, state, stopped: stopped || undefined, activityState: pauseForDetached || status.activityState === "needs_attention" ? "needs_attention" : undefined, error: workflowFailureMessage(error, workflowRunId, partial.children), endedAt: Date.now(), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(error instanceof WorkflowScriptError && error.errorKind ? { failureKind: error.errorKind } : {}), ...workflowRunEvidence, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}) }, workflowChildren });
|
|
5704
6343
|
if (pauseForDetached) {
|
|
5705
6344
|
const promoted = promotePausedWorkflowIfSettled(status);
|
|
5706
6345
|
if (promoted) status = promoted;
|
|
5707
6346
|
}
|
|
6347
|
+
// A script can throw an error of any size; status.json keeps the full text.
|
|
6348
|
+
const errorPreview = status.error && status.error.length > 1_000 ? `${status.error.slice(0, 1_000)}… (truncated; full error: ${statusPath} (error))` : status.error;
|
|
5708
6349
|
const terminalSummary = `${status.state === "complete"
|
|
5709
6350
|
? "Workflow completed after detached child finished."
|
|
5710
|
-
:
|
|
6351
|
+
: errorPreview ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.")}${stopCause ? ` ${WORKFLOW_RUNTIME_REPLACED_RELAUNCH_NOTICE}` : ""}${workflowOutputPathMappingSummary(partial.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
|
|
5711
6352
|
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, terminalSummary, producedChildOutputPaths);
|
|
5712
6353
|
const resultSummary = appendWorkflowOutputWarning(terminalSummary, outputWarning);
|
|
5713
6354
|
const receiptState: WorkflowReceiptState = status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
|
|
5714
6355
|
const terminalOutcome = workflowFailureTerminalOutcome(error, partial.children, usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)));
|
|
5715
|
-
const receipt = terminalWorkflowReceipt(workflowRunId, receiptState, partial.children, workflowChildren, terminalOutcome, validHostStepNodes(status.workflowGraph), workflowResource?.provenance);
|
|
6356
|
+
const receipt = terminalWorkflowReceipt(workflowRunId, receiptState, partial.children, workflowChildren, terminalOutcome, validHostStepNodes(status.workflowGraph), workflowResource?.provenance, workflowArgsDigest);
|
|
5716
6357
|
delete status.workflowReceiptPath;
|
|
5717
6358
|
let workflowReceipt: { path: string; receipt: WorkflowReceipt } | undefined;
|
|
5718
6359
|
try {
|
|
@@ -5721,12 +6362,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5721
6362
|
} catch (receiptError) {
|
|
5722
6363
|
appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
|
|
5723
6364
|
}
|
|
5724
|
-
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: status.state === "complete", state: status.state, summary: resultSummary, error: status.state === "complete" ? undefined : status.error, stopped: status.stopped, activityState: status.activityState, workflowChildren, ...(terminalOutcome ? { terminalOutcome } : {}), results: partial.children
|
|
6365
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: status.state === "complete", state: status.state, summary: resultSummary, error: status.state === "complete" ? undefined : status.error, stopped: status.stopped, activityState: status.activityState, workflowChildren, ...(terminalOutcome ? { terminalOutcome } : {}), results: workflowResultChildren(partial.children, status, true), workflow: status.workflow, ...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}), ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
5725
6366
|
if (pendingResultPublication && !await pendingResultPublication) return;
|
|
5726
6367
|
persist();
|
|
5727
6368
|
deps.refreshResultDelivery?.();
|
|
5728
6369
|
persistClosed = true;
|
|
5729
|
-
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(terminalOutcome ? { terminalOutcome } : {}), ...(status.error ? { error: status.error } : {}), ...(status.activityState ? { activityState: status.activityState } : {}) });
|
|
6370
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(workflowArgsDigest ? { argsDigest: workflowArgsDigest } : {}), ...(terminalOutcome ? { terminalOutcome } : {}), ...(status.error ? { error: status.error } : {}), ...(status.activityState ? { activityState: status.activityState } : {}) });
|
|
5730
6371
|
} finally {
|
|
5731
6372
|
// Idempotent cleanup only: a failed result/index write must not authorize terminal status.
|
|
5732
6373
|
try {
|
|
@@ -5746,10 +6387,13 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5746
6387
|
details: { mode: "workflow", runId: workflowRunId, toolCallId, asyncId: workflowRunId, asyncDir, results: [], ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflow: status.workflow, workflowChildren: status.workflowChildren, chatProgress, ...(deps.state.activeAsyncCapacity ? { activeAsyncCapacity: deps.state.activeAsyncCapacity } : {}) },
|
|
5747
6388
|
}, workflowFanoutBudget));
|
|
5748
6389
|
}
|
|
5749
|
-
const { workflowScript: _workflowScript, action: _action, agent: _agent, task: _task, resume: _resume, tasks: _tasks, chain: _chain, concurrency: _concurrency, async: _async, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, chatProgress: _chatProgress, missionId: _missionId, mission: _mission, preflight: _preflight, globalConcurrencyLimit: _globalConcurrencyLimit, maxSubagentSpawnsPerRun: _maxSubagentSpawnsPerRun, ...workflowChildDefaults } = requestParams;
|
|
6390
|
+
const { workflowScript: _workflowScript, args: _args, action: _action, agent: _agent, task: _task, resume: _resume, tasks: _tasks, chain: _chain, concurrency: _concurrency, async: _async, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, chatProgress: _chatProgress, missionId: _missionId, mission: _mission, preflight: _preflight, globalConcurrencyLimit: _globalConcurrencyLimit, maxSubagentSpawnsPerRun: _maxSubagentSpawnsPerRun, ...workflowChildDefaults } = requestParams;
|
|
5750
6391
|
const workflowOutput = typeof workflowChildDefaults.output === "string" || typeof workflowChildDefaults.output === "boolean" ? workflowChildDefaults.output : undefined;
|
|
5751
6392
|
const configuredOutputBaseDir = resolveConfiguredSingleRunOutputBaseDir(deps);
|
|
5752
6393
|
const workflowAggregateOutputPath = resolveSingleOutputPath(workflowOutput, ctx.cwd, workflowCwd, resolveSingleRunOutputBaseDir(deps, workflowArtifactsDir, foregroundWorkflowRunId));
|
|
6394
|
+
// A top-level artifact file: outside outputs/, where children save their reports, and
|
|
6395
|
+
// within artifact retention, which only removes top-level files.
|
|
6396
|
+
const workflowFullResultPath = path.join(workflowArtifactsDir, `${sanitizeRunPathSegment(foregroundWorkflowRunId)}_workflow-result.md`);
|
|
5753
6397
|
const claimedOutputPaths = new Map<string, string>();
|
|
5754
6398
|
const childOutputOverrides = new Map<string, string>();
|
|
5755
6399
|
const childOutputClaimPaths = new Map<string, string>();
|
|
@@ -5788,6 +6432,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5788
6432
|
try {
|
|
5789
6433
|
const workflow = await runWorkflowScript({
|
|
5790
6434
|
script: requestParams.workflowScript,
|
|
6435
|
+
...(workflowArgs ? { args: workflowArgs } : {}),
|
|
6436
|
+
workflowRunId: foregroundWorkflowRunId,
|
|
6437
|
+
processCwd: ctx.cwd,
|
|
5791
6438
|
...(delegatedWorkflowPermit ? { oneUsePermit: { claim: (key: string) => claimWorkflowChildPermit(delegatedWorkflowPermit, foregroundWorkflowRunId, key) } } : {}),
|
|
5792
6439
|
globalConcurrencyLimit: requestParams.globalConcurrencyLimit ?? deps.config.globalConcurrencyLimit,
|
|
5793
6440
|
timeoutMs: timeout,
|
|
@@ -5806,7 +6453,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5806
6453
|
}
|
|
5807
6454
|
sendWorkflowProgress();
|
|
5808
6455
|
},
|
|
5809
|
-
admit: (calls) => {
|
|
6456
|
+
admit: async (calls, admissionSignal) => {
|
|
6457
|
+
admitEnabledWorkflowChildren(calls);
|
|
6458
|
+
await preflightWorkflowWorktrees({ workflowDefaults: workflowChildDefaults, defaultWorktree: deps.config.worktree, calls, ctxCwd: ctx.cwd, signal: admissionSignal, deadlineAt: workflowDeadlineAt });
|
|
5810
6459
|
const outputClaims = workflowChildOutputClaims({ ctxCwd: ctx.cwd, workflowCwd, artifactsDir: workflowArtifactsDir, workflowRunId: foregroundWorkflowRunId, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: discoverWorkflowAgents, agents: workflowAgents, workflowAgentScope: workflowChildDefaults.agentScope, state: deps.state, claimedOutputPaths, entries: calls });
|
|
5811
6460
|
if (outputClaims.error) throw new Error(outputClaims.error);
|
|
5812
6461
|
claimRunFanoutBatch(workflowFanoutBudget, calls.map(({ key }) => `workflow[${key}]`));
|
|
@@ -5840,9 +6489,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5840
6489
|
{ ...prepareWorkflowChildLaunchParams({ workflowDefaults: workflowChildDefaults, childParams: delegatedWorkflowPermit ? { ...childParams, async: false } : childParams, parentWorkflowRunId: foregroundWorkflowRunId, workflowKey: key, ctxCwd: ctx.cwd, workflowCwd, artifactsDir: workflowArtifactsDir, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: discoverWorkflowAgents, agents: workflowAgents, workflowAgentScope: workflowChildDefaults.agentScope, outputOverride: childOutputOverrides.get(key), outputClaimPath: childOutputClaimPaths.get(key), options: { missionDetached: detachWorkflowChildMissions, suppressRoutineResultIntercom: chatProgress.mode === "live-card", runFanoutBudget: workflowFanoutBudget, parentDeadlineAt: workflowDeadlineAt, capabilityCeiling: workflowCapabilityCeiling } }), runFanoutAdmitted: admission.admitted },
|
|
5841
6490
|
missionBinding,
|
|
5842
6491
|
deps.asyncByDefault,
|
|
6492
|
+
undefined,
|
|
6493
|
+
inheritedNestedRoute(deps)?.rootRunId,
|
|
5843
6494
|
);
|
|
5844
6495
|
preparedChildParams = childRequest;
|
|
5845
6496
|
if (workflowUsageBudget.budget) workflowOwnedUsageBudgets.set(childRequest, workflowUsageBudget.budget);
|
|
6497
|
+
if (workflowRequiredExtensions) workflowRetainedRequiredExtensions.set(childRequest, workflowRequiredExtensions);
|
|
5846
6498
|
if (delegatedWorkflowPermit) {
|
|
5847
6499
|
if (childRequest.async !== false) throw new Error("Workflow child permit supports one foreground child only.");
|
|
5848
6500
|
const childCwd = resolveRequestedCwd(workflowCwd, childRequest.cwd);
|
|
@@ -5902,52 +6554,62 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5902
6554
|
const finalPreflightWarnings = workflowPreflightWarnings(workflowPreflight, workflow.trace, { settled: true });
|
|
5903
6555
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(workflow.trace, workflowPreflight);
|
|
5904
6556
|
const workflowChildren = workflowChildSummary({ parentToolCallId: _id, workflowRunId: foregroundWorkflowRunId, workflowState: "completed", inventoryComplete: true, trace: workflow.trace, children: workflow.children });
|
|
5905
|
-
const receipt = terminalWorkflowReceipt(foregroundWorkflowRunId, "complete", workflow.children, workflowChildren, undefined, [...workflowHostSteps.values()], workflowResource?.provenance);
|
|
5906
|
-
const
|
|
5907
|
-
const
|
|
5908
|
-
...(workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : []),
|
|
5909
|
-
"Workflow completed.",
|
|
5910
|
-
`Return:\n${formatWorkflowValue(workflow.value)}`,
|
|
5911
|
-
];
|
|
5912
|
-
if (workflow.emits.length > 0) sections.push(`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5913
|
-
if (workflow.console.length > 0) sections.push(`Console:\n${workflow.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5914
|
-
if (traceLines.length > 0) sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
5915
|
-
if (finalPreflightWarnings.length > 0) sections.push(formatWorkflowPreflightWarnings(finalPreflightWarnings));
|
|
6557
|
+
const receipt = terminalWorkflowReceipt(foregroundWorkflowRunId, "complete", workflow.children, workflowChildren, undefined, [...workflowHostSteps.values()], workflowResource?.provenance, workflowArgsDigest);
|
|
6558
|
+
const trace = finalPreflightTrace.map((entry) => ({ line: `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.durationMs !== undefined ? ` in ${entry.durationMs}ms` : ""}${entry.warning ? ` — ${entry.warning}` : ""}`, error: entry.error }));
|
|
6559
|
+
const runningSummary = workflowRunningChildrenSummary(workflow.children);
|
|
5916
6560
|
const outputMappings = workflowOutputPathMappingSummary(workflow.children).trim();
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
6561
|
+
const displayText = formatWorkflowResultText({
|
|
6562
|
+
head: [...(workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : []), runningSummary ? `Workflow dispatch completed; ${runningSummary}` : "Workflow completed."],
|
|
6563
|
+
script: [
|
|
6564
|
+
`Return:\n${formatWorkflowValue(workflow.value)}`,
|
|
6565
|
+
...(workflow.emits.length > 0 ? [`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`] : []),
|
|
6566
|
+
...(workflow.console.length > 0 ? [`Console:\n${workflow.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`] : []),
|
|
6567
|
+
],
|
|
6568
|
+
trace,
|
|
6569
|
+
tail: [
|
|
6570
|
+
...(finalPreflightWarnings.length > 0 ? [formatWorkflowPreflightWarnings(finalPreflightWarnings)] : []),
|
|
6571
|
+
...(outputMappings ? [outputMappings] : []),
|
|
6572
|
+
],
|
|
6573
|
+
maxOutput: requestParams.maxOutput,
|
|
6574
|
+
aggregateOutputPath: workflowAggregateOutputPath,
|
|
6575
|
+
fullResultPath: workflowFullResultPath,
|
|
6576
|
+
producedChildOutputPaths,
|
|
6577
|
+
});
|
|
5921
6578
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5922
6579
|
content: [{ type: "text", text: displayText }],
|
|
5923
|
-
details: compactOptional<Details>({ mode: "workflow", runId: foregroundWorkflowRunId, results: workflowDetailsResults(workflow.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: finalPreflightTrace, emits: workflow.emits, console: workflow.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
6580
|
+
details: compactOptional<Details>({ mode: "workflow", runId: foregroundWorkflowRunId, results: workflowDetailsResults(workflow.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: finalPreflightTrace, emits: workflow.emits, console: workflow.console, ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5924
6581
|
}, workflowFanoutBudget));
|
|
5925
6582
|
} catch (error) {
|
|
5926
6583
|
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
5927
6584
|
const text = workflowFailureMessage(error, foregroundWorkflowRunId, partial.children);
|
|
5928
6585
|
const finalPreflightWarnings = workflowPreflightWarnings(workflowPreflight, partial.trace, { settled: true });
|
|
5929
6586
|
const finalPreflightTrace = annotateWorkflowPreflightTrace(partial.trace, workflowPreflight);
|
|
5930
|
-
const
|
|
5931
|
-
const sections = [
|
|
5932
|
-
...(workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : []),
|
|
5933
|
-
`Workflow failed: ${text}`,
|
|
5934
|
-
];
|
|
5935
|
-
if (partial.emits.length > 0) sections.push(`Emitted:\n${partial.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5936
|
-
if (partial.console.length > 0) sections.push(`Console:\n${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5937
|
-
if (traceLines.length > 0) sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
5938
|
-
if (finalPreflightWarnings.length > 0) sections.push(formatWorkflowPreflightWarnings(finalPreflightWarnings));
|
|
6587
|
+
const trace = finalPreflightTrace.map((entry) => ({ line: `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.warning ? ` — ${entry.warning}` : ""}`, error: entry.error }));
|
|
5939
6588
|
const outputMappings = workflowOutputPathMappingSummary(partial.children).trim();
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
6589
|
+
const displayText = formatWorkflowResultText({
|
|
6590
|
+
head: workflowPreflight ? [formatWorkflowPreflight(workflowPreflight)] : [],
|
|
6591
|
+
script: [
|
|
6592
|
+
`Workflow failed: ${text}`,
|
|
6593
|
+
...(partial.emits.length > 0 ? [`Emitted:\n${partial.emits.map(formatWorkflowValue).join("\n")}`] : []),
|
|
6594
|
+
...(partial.console.length > 0 ? [`Console:\n${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`] : []),
|
|
6595
|
+
],
|
|
6596
|
+
trace,
|
|
6597
|
+
tail: [
|
|
6598
|
+
...(finalPreflightWarnings.length > 0 ? [formatWorkflowPreflightWarnings(finalPreflightWarnings)] : []),
|
|
6599
|
+
...(outputMappings ? [outputMappings] : []),
|
|
6600
|
+
],
|
|
6601
|
+
maxOutput: requestParams.maxOutput,
|
|
6602
|
+
aggregateOutputPath: workflowAggregateOutputPath,
|
|
6603
|
+
fullResultPath: workflowFullResultPath,
|
|
6604
|
+
producedChildOutputPaths,
|
|
6605
|
+
});
|
|
5944
6606
|
const workflowChildren = workflowChildSummary({ parentToolCallId: _id, workflowRunId: foregroundWorkflowRunId, workflowState: "failed", inventoryComplete: true, trace: partial.trace, children: partial.children });
|
|
5945
6607
|
const terminalOutcome = workflowFailureTerminalOutcome(error, partial.children, usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)));
|
|
5946
|
-
const receipt = terminalWorkflowReceipt(foregroundWorkflowRunId, "failed", partial.children, workflowChildren, terminalOutcome, [...workflowHostSteps.values()], workflowResource?.provenance);
|
|
6608
|
+
const receipt = terminalWorkflowReceipt(foregroundWorkflowRunId, "failed", partial.children, workflowChildren, terminalOutcome, [...workflowHostSteps.values()], workflowResource?.provenance, workflowArgsDigest);
|
|
5947
6609
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5948
6610
|
content: [{ type: "text", text: displayText }],
|
|
5949
6611
|
isError: true,
|
|
5950
|
-
details: compactOptional<Details>({ mode: "workflow", runId: foregroundWorkflowRunId, results: workflowDetailsResults(partial.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
6612
|
+
details: compactOptional<Details>({ mode: "workflow", runId: foregroundWorkflowRunId, results: workflowDetailsResults(partial.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(error instanceof WorkflowScriptError && error.errorKind ? { failureKind: error.errorKind } : {}), ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5951
6613
|
}, workflowFanoutBudget));
|
|
5952
6614
|
} finally {
|
|
5953
6615
|
workflowProgressClosed = true;
|
|
@@ -5956,9 +6618,24 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5956
6618
|
}
|
|
5957
6619
|
}
|
|
5958
6620
|
const directParams = requestParams;
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
const
|
|
6621
|
+
// With a machine, cwd names a directory on that machine: keep it out of every local path resolution.
|
|
6622
|
+
// Placement can also come from the agent's frontmatter or settings override, so the agent is resolved first (discovery is fingerprint-cached).
|
|
6623
|
+
const placedByAgent = (): boolean => {
|
|
6624
|
+
if (directParams.machine !== undefined || directParams.cwd === undefined || typeof directParams.agent !== "string") return false;
|
|
6625
|
+
try {
|
|
6626
|
+
return resolveAgentName(directParams.agent, deps.discoverAgents(ctx.cwd, resolveExecutionAgentScope(directParams.agentScope)).agents).agent?.machine !== undefined;
|
|
6627
|
+
} catch {
|
|
6628
|
+
return false; // Discovery errors surface from the launch path itself.
|
|
6629
|
+
}
|
|
6630
|
+
};
|
|
6631
|
+
const remotePlacement = directParams.action === undefined && (directParams.machine !== undefined || placedByAgent());
|
|
6632
|
+
const requestedCwd = remotePlacement ? undefined : directParams.cwd;
|
|
6633
|
+
const requestCwd = remotePlacement ? ctx.cwd : resolveRequestedCwd(ctx.cwd, directParams.cwd);
|
|
6634
|
+
const paramsWithResolvedCwd = directParams.cwd === undefined
|
|
6635
|
+
? directParams
|
|
6636
|
+
: remotePlacement
|
|
6637
|
+
? omitUndefinedProperties({ ...directParams, cwd: undefined, machineCwd: directParams.cwd })
|
|
6638
|
+
: { ...directParams, cwd: requestCwd };
|
|
5962
6639
|
const action = paramsWithResolvedCwd.action;
|
|
5963
6640
|
let requestSessionId = "";
|
|
5964
6641
|
let requestPiSessionId: string | undefined;
|
|
@@ -5980,11 +6657,30 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5980
6657
|
if (deps.allowMutatingManagementActions === false) {
|
|
5981
6658
|
return { content: [{ type: "text", text: "Action 'worktree.cleanup' is not available from child-safe subagent fanout mode." }], isError: true, details: { mode: "management", results: [] } };
|
|
5982
6659
|
}
|
|
6660
|
+
if (paramsWithResolvedCwd.mode === "apply") {
|
|
6661
|
+
try {
|
|
6662
|
+
if (!paramsWithResolvedCwd.repo?.trim() || !paramsWithResolvedCwd.planId?.trim() || paramsWithResolvedCwd.handoffPath !== undefined) throw new Error("worktree.cleanup apply requires explicit repo and planId, without handoffPath.");
|
|
6663
|
+
const repo = path.resolve(requestCwd, paramsWithResolvedCwd.repo);
|
|
6664
|
+
const plan = loadReviewedCleanupPlan(repo, paramsWithResolvedCwd.planId);
|
|
6665
|
+
const decision = resolveAuthorityDecision({ action: "discardWorktree", ...(deps.config.authorityPolicy === undefined ? {} : { policy: deps.config.authorityPolicy }) });
|
|
6666
|
+
if (decision === "forbid") throw new Error("Authority policy forbids worktree cleanup.");
|
|
6667
|
+
if (decision === "confirm") {
|
|
6668
|
+
if (!ctx.hasUI) throw new Error("Authority policy requires interactive confirmation for worktree cleanup.");
|
|
6669
|
+
if (!await ctx.ui.confirm("Apply reviewed worktree cleanup?", `Repository: ${plan.repoRoot}\nPlan: ${plan.planId}\nRemove up to ${plan.entries.filter((entry) => entry.decision === "remove").length} eligible worktrees. All local branches are retained.`)) return { content: [{ type: "text", text: "Worktree cleanup canceled." }], details: { mode: "management", results: [] } };
|
|
6670
|
+
}
|
|
6671
|
+
const applied = await applyReviewedCleanupPlan({ repo: plan.repoRoot, planId: plan.planId, authorized: true, signal,
|
|
6672
|
+
foregroundRunOwnership: (runId) => deps.state.foregroundControls.has(runId) ? "active" : (deps.state.foregroundRuns?.get(runId)?.children.length && deps.state.foregroundRuns.get(runId)!.children.every((child) => child.status !== "detached")) ? "terminal" : "unknown",
|
|
6673
|
+
});
|
|
6674
|
+
return { content: [{ type: "text", text: formatCleanupReceipt(applied) }], details: { mode: "management", results: [] } };
|
|
6675
|
+
} catch (error) {
|
|
6676
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
6677
|
+
}
|
|
6678
|
+
}
|
|
5983
6679
|
if (paramsWithResolvedCwd.mode !== "plan") {
|
|
5984
|
-
return { content: [{ type: "text", text: "worktree.cleanup
|
|
6680
|
+
return { content: [{ type: "text", text: "worktree.cleanup requires mode='plan' or mode='apply'." }], isError: true, details: { mode: "management", results: [] } };
|
|
5985
6681
|
}
|
|
5986
6682
|
if (paramsWithResolvedCwd.planId !== undefined) {
|
|
5987
|
-
return { content: [{ type: "text", text: "worktree.cleanup plan mode does not accept planId
|
|
6683
|
+
return { content: [{ type: "text", text: "worktree.cleanup plan mode does not accept planId." }], isError: true, details: { mode: "management", results: [] } };
|
|
5988
6684
|
}
|
|
5989
6685
|
try {
|
|
5990
6686
|
const created = createWorktreeCleanupPlan({
|
|
@@ -6057,6 +6753,24 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6057
6753
|
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
6058
6754
|
}
|
|
6059
6755
|
}
|
|
6756
|
+
const policyAction = action === "stop" || action === "command.cancel" ? "stopRun" : action === "steer" || action === "command.yield" ? "steerRun" : action === "schedule.create" ? "scheduleCreate" : action === "inspector.open" ? "inspectorOpen" : action === "project.open" ? "projectOpen" : undefined;
|
|
6757
|
+
if (policyAction) {
|
|
6758
|
+
// Child-safe mode is a hard capability boundary; the policy is an operator
|
|
6759
|
+
// preference. Refuse first, so the gate never prompts for an action that is
|
|
6760
|
+
// going to be rejected anyway and never masks the more specific reason.
|
|
6761
|
+
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
6762
|
+
return { content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }], isError: true, details: { mode: "management", results: [] } };
|
|
6763
|
+
}
|
|
6764
|
+
const decision = resolveAuthorityDecision({ action: policyAction, ...(deps.config.authorityPolicy === undefined ? {} : { policy: deps.config.authorityPolicy }) });
|
|
6765
|
+
if (decision === "forbid") {
|
|
6766
|
+
return { content: [{ type: "text", text: `Authority policy forbids action '${action}'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
6767
|
+
}
|
|
6768
|
+
if (decision === "confirm") {
|
|
6769
|
+
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: [] } };
|
|
6770
|
+
const confirmed = await ctx.ui.confirm(`Authorize subagent ${action}?`, `Authority policy requires confirmation before '${action}'.`);
|
|
6771
|
+
if (!confirmed) return { content: [{ type: "text", text: `Action '${action}' canceled; authority was not granted.` }], details: { mode: "management", results: [] } };
|
|
6772
|
+
}
|
|
6773
|
+
}
|
|
6060
6774
|
if ((HERDR_PROJECT_PANE_ACTIONS as readonly string[]).includes(action)) {
|
|
6061
6775
|
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
6062
6776
|
return { content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }], isError: true, details: { mode: "management", results: [] } };
|
|
@@ -6064,16 +6778,17 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6064
6778
|
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
6065
6779
|
return handleHerdrProjectPaneAction(action as (typeof HERDR_PROJECT_PANE_ACTIONS)[number], paramsWithResolvedCwd, { cwd: requestCwd, state: deps.state, signal });
|
|
6066
6780
|
}
|
|
6067
|
-
if ((
|
|
6781
|
+
if ((INSPECTOR_ACTIONS as readonly string[]).includes(action)) {
|
|
6068
6782
|
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
6069
6783
|
return { content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }], isError: true, details: { mode: "management", results: [] } };
|
|
6070
6784
|
}
|
|
6071
6785
|
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
6072
|
-
return
|
|
6786
|
+
return handleInspectorAction(action as (typeof INSPECTOR_ACTIONS)[number], paramsWithResolvedCwd, {
|
|
6073
6787
|
state: deps.state,
|
|
6074
6788
|
cwd: requestCwd,
|
|
6075
6789
|
...(deps.config.missions ? { missions: deps.config.missions } : {}),
|
|
6076
6790
|
...(deps.config.authorityPolicy ? { authorityPolicy: deps.config.authorityPolicy } : {}),
|
|
6791
|
+
plugins: getInspectorPlugins(deps.pi),
|
|
6077
6792
|
signal,
|
|
6078
6793
|
});
|
|
6079
6794
|
}
|
|
@@ -6092,18 +6807,6 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6092
6807
|
...(currentSessionId ? { currentSessionId } : {}),
|
|
6093
6808
|
});
|
|
6094
6809
|
}
|
|
6095
|
-
const policyAction = action === "stop" ? "stopRun" : action === "steer" ? "steerRun" : action === "schedule.create" ? "scheduleCreate" : undefined;
|
|
6096
|
-
if (policyAction) {
|
|
6097
|
-
const decision = resolveAuthorityDecision({ action: policyAction, ...(deps.config.authorityPolicy === undefined ? {} : { policy: deps.config.authorityPolicy }) });
|
|
6098
|
-
if (decision === "forbid") {
|
|
6099
|
-
return { content: [{ type: "text", text: `Authority policy forbids action '${action}'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
6100
|
-
}
|
|
6101
|
-
if (decision === "confirm") {
|
|
6102
|
-
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: [] } };
|
|
6103
|
-
const confirmed = await ctx.ui.confirm(`Authorize subagent ${action}?`, `Authority policy requires confirmation before '${action}'.`);
|
|
6104
|
-
if (!confirmed) return { content: [{ type: "text", text: `Action '${action}' canceled; authority was not granted.` }], details: { mode: "management", results: [] } };
|
|
6105
|
-
}
|
|
6106
|
-
}
|
|
6107
6810
|
if ((WATCHDOG_TOOL_ACTIONS as readonly string[]).includes(action)) {
|
|
6108
6811
|
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
6109
6812
|
return {
|
|
@@ -6211,8 +6914,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6211
6914
|
}
|
|
6212
6915
|
if (action === "guide") {
|
|
6213
6916
|
try {
|
|
6917
|
+
const guide = readSubagentGuide(paramsWithResolvedCwd.topic);
|
|
6918
|
+
const notice = paramsWithResolvedCwd.topic === "tool-reference" ? disabledFeatureNotice(disabledFeatures) : undefined;
|
|
6214
6919
|
return {
|
|
6215
|
-
content: [{ type: "text", text:
|
|
6920
|
+
content: [{ type: "text", text: notice ? `${notice}\n\n${guide}` : guide }],
|
|
6216
6921
|
details: { mode: "management", results: [] },
|
|
6217
6922
|
};
|
|
6218
6923
|
} catch (error) {
|
|
@@ -6234,22 +6939,25 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6234
6939
|
if (action === "doctor") {
|
|
6235
6940
|
let currentSessionFile: string | null = null;
|
|
6236
6941
|
let currentSessionId = deps.state.currentSessionId;
|
|
6942
|
+
let budgetSessionId = deps.state.currentSessionId;
|
|
6237
6943
|
let sessionError: string | undefined;
|
|
6238
6944
|
try {
|
|
6239
6945
|
currentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
|
|
6240
6946
|
currentSessionId = ctx.sessionManager.getSessionId();
|
|
6947
|
+
// Launch admission's key (resolveCurrentSessionId) without its throw for an unbound session.
|
|
6948
|
+
budgetSessionId = currentSessionFile ?? currentSessionId;
|
|
6241
6949
|
} catch (error) {
|
|
6242
6950
|
sessionError = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
6243
6951
|
}
|
|
6244
6952
|
let orchestratorTarget: string | undefined;
|
|
6245
6953
|
try {
|
|
6246
|
-
orchestratorTarget = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
6954
|
+
orchestratorTarget = resolveIntercomSessionTarget(deps.childRuntime?.intercomSessionName ?? deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
6247
6955
|
} catch (error) {
|
|
6248
6956
|
if (!sessionError) sessionError = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
6249
6957
|
}
|
|
6250
|
-
const spawnBudget = getSpawnBudgetSnapshot(deps.state, deps.config,
|
|
6251
|
-
const activeAsyncCapacity =
|
|
6252
|
-
? getActiveAsyncCapacitySnapshot(
|
|
6958
|
+
const spawnBudget = getSpawnBudgetSnapshot(deps.state, deps.config, budgetSessionId);
|
|
6959
|
+
const activeAsyncCapacity = budgetSessionId
|
|
6960
|
+
? getActiveAsyncCapacitySnapshot(budgetSessionId, resolveMaxActiveAsyncRunsPerSession(deps.config.maxActiveAsyncRunsPerSession), { liveWorkflowRunIds: new Set(deps.state.workflowControllers?.keys() ?? []), abandonedSlotReleaseAfterMs: resolveAbandonedSlotReleaseAfterMs(deps.config.capacity?.abandonedSlotReleaseAfterMs) })
|
|
6253
6961
|
: { used: 0, limit: resolveMaxActiveAsyncRunsPerSession(deps.config.maxActiveAsyncRunsPerSession) ?? 0 };
|
|
6254
6962
|
deps.state.activeAsyncCapacity = activeAsyncCapacity;
|
|
6255
6963
|
return {
|
|
@@ -6263,6 +6971,8 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6263
6971
|
requestedSessionDir: paramsWithResolvedCwd.sessionDir,
|
|
6264
6972
|
currentSessionFile,
|
|
6265
6973
|
currentSessionId,
|
|
6974
|
+
spawnBudget,
|
|
6975
|
+
activeAsyncCapacity,
|
|
6266
6976
|
orchestratorTarget,
|
|
6267
6977
|
sessionError,
|
|
6268
6978
|
expandTilde: deps.expandTilde,
|
|
@@ -6271,6 +6981,19 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6271
6981
|
details: { mode: "management", results: [], spawnBudget, activeAsyncCapacity },
|
|
6272
6982
|
};
|
|
6273
6983
|
}
|
|
6984
|
+
if (["command.status", "command.yield", "command.cancel"].includes(action)) {
|
|
6985
|
+
try {
|
|
6986
|
+
if (deps.allowMutatingManagementActions === false && action !== "command.status") throw new Error(`Action '${action}' is not available from child-safe subagent fanout mode.`);
|
|
6987
|
+
const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
|
|
6988
|
+
if (!targetRunId || paramsWithResolvedCwd.dir) throw new Error(`${action} requires id or runId; directory targets are not supported.`);
|
|
6989
|
+
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
6990
|
+
const target = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
6991
|
+
if (!target) throw new Error(`No run found for '${targetRunId}'.`);
|
|
6992
|
+
return await commandAction({ state: deps.state, target, operation: action.slice("command.".length) as "status" | "yield" | "cancel", index: paramsWithResolvedCwd.index, toolCallId: paramsWithResolvedCwd.toolCallId, signal });
|
|
6993
|
+
} catch (error) {
|
|
6994
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
6995
|
+
}
|
|
6996
|
+
}
|
|
6274
6997
|
if (action === "status" || action === "debug.run") {
|
|
6275
6998
|
if (!preserveActiveSession) deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
6276
6999
|
const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
|
|
@@ -6319,7 +7042,18 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6319
7042
|
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots, abandonedSlotReleaseAfterMs: resolveAbandonedSlotReleaseAfterMs(deps.config.capacity?.abandonedSlotReleaseAfterMs) })));
|
|
6320
7043
|
}
|
|
6321
7044
|
if (action === "resume") {
|
|
6322
|
-
return resumeAsyncRun(omitUndefinedProperties({
|
|
7045
|
+
return resumeAsyncRun(omitUndefinedProperties({
|
|
7046
|
+
params: paramsWithResolvedCwd,
|
|
7047
|
+
requestCwd,
|
|
7048
|
+
ctx,
|
|
7049
|
+
deps,
|
|
7050
|
+
parentModel: requestParentModel,
|
|
7051
|
+
signal,
|
|
7052
|
+
...(workflowLaunchObserver ? { onLaunch: (launch: Parameters<NonNullable<typeof workflowLaunchObserver>>[0]) => {
|
|
7053
|
+
workflowLaunchObservers.delete(params);
|
|
7054
|
+
workflowLaunchObserver(launch);
|
|
7055
|
+
} } : {}),
|
|
7056
|
+
}));
|
|
6323
7057
|
}
|
|
6324
7058
|
if (action === "steer") {
|
|
6325
7059
|
if (paramsWithResolvedCwd.mode !== undefined && resolveSteerDeliveryMode(paramsWithResolvedCwd.mode) === undefined) {
|
|
@@ -6418,7 +7152,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6418
7152
|
}
|
|
6419
7153
|
if (action.startsWith("schedule.")) {
|
|
6420
7154
|
if (!isScheduledRunAction(action)) {
|
|
6421
|
-
return { content: [{ type: "text", text: unknownSubagentActionMessage(action) }], isError: true, details: { mode: "management", results: [] } };
|
|
7155
|
+
return { content: [{ type: "text", text: unknownSubagentActionMessage(action, disabledFeatures) }], isError: true, details: { mode: "management", results: [] } };
|
|
6422
7156
|
}
|
|
6423
7157
|
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
6424
7158
|
return {
|
|
@@ -6460,47 +7194,40 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6460
7194
|
}
|
|
6461
7195
|
if (action === "stop") {
|
|
6462
7196
|
const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
}
|
|
6495
|
-
console.error(`Failed to append child status event for workflow ${workflowRunId}:`, error);
|
|
6496
|
-
}
|
|
6497
|
-
return { content: [{ type: "text", text: `Stop requested for child ${resolution.child.id} in async workflow ${workflowRunId}.` }], details: { mode: "management", results: [] } };
|
|
7197
|
+
// Whole-workflow stops reach stopAsyncRun below, which stops a live workflow in-process.
|
|
7198
|
+
const workflowRunId = targetRunId && paramsWithResolvedCwd.childId !== undefined ? resolveLiveWorkflowRunId(deps, targetRunId) : undefined;
|
|
7199
|
+
if (workflowRunId && paramsWithResolvedCwd.childId !== undefined) {
|
|
7200
|
+
const stopChild = deps.state.workflowChildStops?.get(workflowRunId);
|
|
7201
|
+
const asyncJob = deps.state.asyncJobs.get(workflowRunId);
|
|
7202
|
+
if (!asyncJob?.asyncDir) return { content: [{ type: "text", text: `Status file not found for async workflow '${workflowRunId}'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
7203
|
+
const status = readStatus(asyncJob.asyncDir);
|
|
7204
|
+
if (!status) return { content: [{ type: "text", text: `Status file not found for async workflow '${workflowRunId}'.` }], isError: true, details: { mode: "management", results: [] } };
|
|
7205
|
+
const resolution = resolveAsyncStatusChild(status, paramsWithResolvedCwd.childId);
|
|
7206
|
+
if (!resolution.ok) return { content: [{ type: "text", text: resolution.message }], isError: true, details: { mode: "management", results: [] } };
|
|
7207
|
+
if (!isStoppableAsyncStatusStep(resolution.child.step)) return { content: [{ type: "text", text: `Child '${paramsWithResolvedCwd.childId}' in async run '${workflowRunId}' is ${resolution.child.step.status}; stop only supports pending or running children.` }], isError: true, details: { mode: "management", results: [] } };
|
|
7208
|
+
if (!stopChild) return { content: [{ type: "text", text: `Workflow ${workflowRunId} child stop is unavailable in this extension runtime.` }], isError: true, details: { mode: "management", results: [] } };
|
|
7209
|
+
if (!stopChild(resolution.child.id, `Workflow child '${resolution.child.id}' stopped.`)) return { content: [{ type: "text", text: `Child '${paramsWithResolvedCwd.childId}' in workflow ${workflowRunId} is not available to stop.` }], isError: true, details: { mode: "management", results: [] } };
|
|
7210
|
+
try {
|
|
7211
|
+
fs.appendFileSync(path.join(asyncJob.asyncDir, "events.jsonl"), `${JSON.stringify({
|
|
7212
|
+
type: "subagent.child-status",
|
|
7213
|
+
version: 1,
|
|
7214
|
+
runId: workflowRunId,
|
|
7215
|
+
childId: resolution.child.id,
|
|
7216
|
+
status: "stopping",
|
|
7217
|
+
ts: Date.now(),
|
|
7218
|
+
reason: "subagent-action",
|
|
7219
|
+
source: "async",
|
|
7220
|
+
stepIndex: resolution.child.index,
|
|
7221
|
+
agent: resolution.child.step.agent,
|
|
7222
|
+
...(resolution.child.step.runId ? { childRunId: resolution.child.step.runId } : {}),
|
|
7223
|
+
...(resolution.child.step.workflowKey ? { workflowKey: resolution.child.step.workflowKey } : {}),
|
|
7224
|
+
...(resolution.child.step.phase ? { phase: resolution.child.step.phase } : {}),
|
|
7225
|
+
...(resolution.child.step.label ? { label: resolution.child.step.label } : {}),
|
|
7226
|
+
} satisfies SubagentChildStatusEvent)}\n`, "utf-8");
|
|
7227
|
+
} catch (error) {
|
|
7228
|
+
console.error(`Failed to append child status event for workflow ${workflowRunId}:`, error);
|
|
6498
7229
|
}
|
|
6499
|
-
|
|
6500
|
-
const status = asyncJob?.asyncDir ? readStatus(asyncJob.asyncDir) : undefined;
|
|
6501
|
-
if (status) stopStoppableAsyncStatusChildren(status, stopChild, "Workflow stopped.");
|
|
6502
|
-
workflowController.abort(new Error("Workflow stopped."));
|
|
6503
|
-
return { content: [{ type: "text", text: `Stop requested for async workflow ${targetRunId}.` }], details: { mode: "management", results: [] } };
|
|
7230
|
+
return { content: [{ type: "text", text: `Stop requested for child ${resolution.child.id} in async workflow ${workflowRunId}.` }], details: { mode: "management", results: [] } };
|
|
6504
7231
|
}
|
|
6505
7232
|
let resolved: ResolvedSubagentRunId | undefined;
|
|
6506
7233
|
if (paramsWithResolvedCwd.dir) {
|
|
@@ -6580,7 +7307,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6580
7307
|
}
|
|
6581
7308
|
if (!(SUBAGENT_ACTIONS as readonly string[]).includes(action)) {
|
|
6582
7309
|
return {
|
|
6583
|
-
content: [{ type: "text", text: unknownSubagentActionMessage(action) }],
|
|
7310
|
+
content: [{ type: "text", text: unknownSubagentActionMessage(action, disabledFeatures) }],
|
|
6584
7311
|
isError: true,
|
|
6585
7312
|
details: { mode: "management" as const, results: [] },
|
|
6586
7313
|
};
|
|
@@ -6590,6 +7317,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6590
7317
|
cwd: requestCwd,
|
|
6591
7318
|
config: deps.config,
|
|
6592
7319
|
currentSessionId: deps.state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined,
|
|
7320
|
+
discoverAgentsAll: deps.discoverAgentsAll,
|
|
6593
7321
|
runtimeAgentOwner: deps.pi,
|
|
6594
7322
|
onAgentsChanged: deps.onAgentsChanged,
|
|
6595
7323
|
});
|
|
@@ -6615,6 +7343,8 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6615
7343
|
const normalized = normalizeRepeatedParallelCounts(paramsWithResolvedCwd);
|
|
6616
7344
|
if (normalized.error) return normalized.error;
|
|
6617
7345
|
const normalizedParams = normalized.params!;
|
|
7346
|
+
const outputSchemaError = validateLaunchOutputSchemaOverrides(normalizedParams);
|
|
7347
|
+
if (outputSchemaError) return buildRequestedModeError(normalizedParams, outputSchemaError);
|
|
6618
7348
|
|
|
6619
7349
|
let effectiveParams = applyForceTopLevelAsyncOverride(
|
|
6620
7350
|
normalizedParams,
|
|
@@ -6672,6 +7402,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6672
7402
|
}
|
|
6673
7403
|
const modelScope = discovered.modelScope;
|
|
6674
7404
|
effectiveParams = applySingleAgentLaunchDefaults(effectiveParams, discoveredAgents);
|
|
7405
|
+
// The gate shorthand, an explicit acceptance.verify list, and an agent's
|
|
7406
|
+
// defaultAcceptance all normalize to verify commands, and the agent's
|
|
7407
|
+
// frontmatter outputSchema has been merged by now, so this one check keeps
|
|
7408
|
+
// a run to a single structured-output source regardless of spelling.
|
|
7409
|
+
const typedVerifyConflict = describeTypedVerifyOutputSchemaConflict(effectiveParams, params);
|
|
7410
|
+
if (typedVerifyConflict) return buildRequestedModeError(effectiveParams, typedVerifyConflict);
|
|
6675
7411
|
// An agent-level defaultContext is a preference, unlike an explicit request.
|
|
6676
7412
|
// Prefer fork only when the parent session is persisted and has a current leaf;
|
|
6677
7413
|
// otherwise use fresh immediately instead of launching a guaranteed-to-fail fork.
|
|
@@ -6685,7 +7421,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6685
7421
|
if ("error" in contextPolicyResult) return buildRequestedModeError(effectiveParams, contextPolicyResult.error);
|
|
6686
7422
|
const contextPolicy = contextPolicyResult;
|
|
6687
7423
|
effectiveParams = contextPolicy.params;
|
|
6688
|
-
const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
7424
|
+
const sessionName = resolveIntercomSessionTarget(deps.childRuntime?.intercomSessionName ?? deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
6689
7425
|
const intercomBridge = resolveIntercomBridge({
|
|
6690
7426
|
config: deps.config.intercomBridge,
|
|
6691
7427
|
override: effectiveParams.intercomBridge,
|
|
@@ -6695,7 +7431,6 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6695
7431
|
orchestratorTarget: sessionName,
|
|
6696
7432
|
});
|
|
6697
7433
|
const agents = applyScopedIntercomBridgeToAgents(discoveredAgents, intercomBridge, contextPolicy);
|
|
6698
|
-
const runId = randomUUID();
|
|
6699
7434
|
const inheritedNestedRouteValue = inheritedNestedRoute(deps);
|
|
6700
7435
|
const nestedParentAddress = inheritedNestedRouteValue ? inheritedNestedParentAddress(deps) : undefined;
|
|
6701
7436
|
const shareEnabled = effectiveParams.share === true;
|
|
@@ -6730,65 +7465,40 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6730
7465
|
|
|
6731
7466
|
let forkSessionFileForIndex: (idx?: number) => string | undefined = () => undefined;
|
|
6732
7467
|
let prepareForkSessionForIndex: (idx?: number) => Promise<void> = async () => {};
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
const
|
|
6736
|
-
|
|
7468
|
+
// Check before pruner/session preparation, then recheck immediately before each fork
|
|
7469
|
+
// because the session capability ceiling can tighten while preparation awaits.
|
|
7470
|
+
const launchCapabilityCeiling = () => intersectSubagentCapabilityCeilings(
|
|
7471
|
+
intersectSubagentCapabilityCeilings(effectiveParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(requestSessionId)),
|
|
7472
|
+
deps.childRuntime?.capabilityCeiling,
|
|
7473
|
+
);
|
|
7474
|
+
const assertLaunchableAgentsAllowedBeforeFork = (): void => {
|
|
7475
|
+
if (!contextPolicy.usesFork) return;
|
|
7476
|
+
const ceiling = launchCapabilityCeiling();
|
|
7477
|
+
const launchable = hasSingle
|
|
7478
|
+
? [effectiveParams.agent!]
|
|
7479
|
+
: hasTasks
|
|
7480
|
+
? (effectiveParams.tasks ?? []).map((task) => task.agent)
|
|
7481
|
+
: (effectiveParams.chain ?? []).flatMap((step) => isDynamicParallelStep(step)
|
|
7482
|
+
&& (step.expand.maxItems ?? deps.config.chain?.dynamicFanout?.maxItems ?? 0) === 0
|
|
7483
|
+
? []
|
|
7484
|
+
: getStepAgents(step));
|
|
7485
|
+
for (const agent of launchable) assertAgentAllowedByCapabilityCeiling(agent, ceiling);
|
|
7486
|
+
};
|
|
7487
|
+
// Forked children keep their requested thinking level. Signed Anthropic thinking
|
|
7488
|
+
// blocks are stripped from the inherited transcript by the resolver (they are bound
|
|
7489
|
+
// to the parent session), which is not a reason to disable the child's own reasoning.
|
|
6737
7490
|
try {
|
|
6738
|
-
|
|
6739
|
-
const parentModel = requestParentModel;
|
|
6740
|
-
prepareForkThinking = (agentName, index, modelOverride, modelOverrideFromParent, storedOrigin) => {
|
|
6741
|
-
const agentConfig = agents.find((agent) => agent.name === agentName);
|
|
6742
|
-
if (agentConfig?.runner?.type === "external-cli" || agentConfig?.runner?.type === "external-job") {
|
|
6743
|
-
forkThinkingRequirements.set(index, true);
|
|
6744
|
-
return;
|
|
6745
|
-
}
|
|
6746
|
-
const effectiveStoredOrigin = storedOrigin === "configured" && modelOverride === undefined && agentConfig?.model === undefined
|
|
6747
|
-
? undefined
|
|
6748
|
-
: storedOrigin;
|
|
6749
|
-
const origin = resolveModelOrigin({
|
|
6750
|
-
fromParent: modelOverrideFromParent,
|
|
6751
|
-
storedOrigin: effectiveStoredOrigin,
|
|
6752
|
-
explicitModel: modelOverrideFromParent || effectiveStoredOrigin === "configured" ? undefined : modelOverride,
|
|
6753
|
-
agentModel: agentConfig?.model,
|
|
6754
|
-
parentModel,
|
|
6755
|
-
});
|
|
6756
|
-
const primaryModel = modelOverrideFromParent
|
|
6757
|
-
? modelOverride
|
|
6758
|
-
: resolveEffectiveSubagentModel(
|
|
6759
|
-
effectiveStoredOrigin === "configured" ? undefined : modelOverride,
|
|
6760
|
-
agentConfig?.model,
|
|
6761
|
-
parentModel,
|
|
6762
|
-
forkAvailableModels,
|
|
6763
|
-
agentConfig?.modelProvider ?? parentModel?.provider,
|
|
6764
|
-
{ source: origin === "explicit" ? "explicit" : "inherited" },
|
|
6765
|
-
);
|
|
6766
|
-
const candidates = buildModelCandidates(
|
|
6767
|
-
primaryModel,
|
|
6768
|
-
agentConfig?.fallbackModels,
|
|
6769
|
-
forkAvailableModels,
|
|
6770
|
-
agentConfig?.modelProvider ?? parentModel?.provider,
|
|
6771
|
-
{
|
|
6772
|
-
primaryModelFromParent: origin === "inherited",
|
|
6773
|
-
origin,
|
|
6774
|
-
},
|
|
6775
|
-
);
|
|
6776
|
-
forkThinkingRequirements.set(
|
|
6777
|
-
index,
|
|
6778
|
-
candidates.length === 0
|
|
6779
|
-
|| candidates.some((candidate) => forkedChildRequiresThinkingOff(candidate, forkAvailableModels, parentModel?.provider)),
|
|
6780
|
-
);
|
|
6781
|
-
};
|
|
7491
|
+
assertLaunchableAgentsAllowedBeforeFork();
|
|
6782
7492
|
const pruneSession = contextPolicy.usesFork && deps.config.forkContext?.mode === "pruned"
|
|
6783
7493
|
? await createPrunedForkSessionWriter(ctx, deps.config.forkContext, signal)
|
|
6784
7494
|
: undefined;
|
|
6785
|
-
const forkContextResolver = createForkContextResolver(
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
7495
|
+
const forkContextResolver = createForkContextResolver(
|
|
7496
|
+
ctx.sessionManager,
|
|
7497
|
+
contextPolicy.usesFork ? "fork" : undefined,
|
|
7498
|
+
pruneSession ? { pruneSession } : {},
|
|
7499
|
+
);
|
|
6789
7500
|
prepareForkSessionForIndex = forkContextResolver.prepareSessionForIndex;
|
|
6790
7501
|
forkSessionFileForIndex = forkContextResolver.sessionFileForIndex;
|
|
6791
|
-
forkThinkingOverrideForIndex = forkContextResolver.thinkingOverrideForIndex;
|
|
6792
7502
|
} catch (error) {
|
|
6793
7503
|
return toExecutionErrorResult(effectiveParams, error, contextPolicy.contextSummary);
|
|
6794
7504
|
}
|
|
@@ -6807,6 +7517,14 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6807
7517
|
if (externalAgent && (!effectiveAsync || effectiveParams.foregroundOnly === true)) {
|
|
6808
7518
|
return buildRequestedModeError(effectiveParams, `Agent '${externalAgent.name}' uses runner.type='${externalAgent.runner?.type}', which currently supports async/background execution only. Omit async or pass async:true; clarify and foregroundOnly are unsupported.`);
|
|
6809
7519
|
}
|
|
7520
|
+
if (effectiveAsync && hasSingle && effectiveParams.resume === undefined && effectiveParams.worktree === true) {
|
|
7521
|
+
try {
|
|
7522
|
+
await preflightWorktreeSource(effectiveCwd, { signal });
|
|
7523
|
+
} catch (error) {
|
|
7524
|
+
return toExecutionErrorResult(effectiveParams, error, contextPolicy.contextSummary);
|
|
7525
|
+
}
|
|
7526
|
+
}
|
|
7527
|
+
const runId = randomUUID();
|
|
6810
7528
|
const foregroundTimeout = resolveSingleAgentLaunchTimeout(
|
|
6811
7529
|
effectiveParams,
|
|
6812
7530
|
effectiveAsync,
|
|
@@ -6891,30 +7609,29 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6891
7609
|
}
|
|
6892
7610
|
const sessionDirForIndex = (idx?: number) =>
|
|
6893
7611
|
path.join(sessionRoot, `run-${idx ?? 0}`);
|
|
6894
|
-
const forkSessionFileForTask: ForkSessionFileForTask = (agentName, idx = 0
|
|
7612
|
+
const forkSessionFileForTask: ForkSessionFileForTask = (agentName, idx = 0) => {
|
|
6895
7613
|
if (!shouldForkAgent(contextPolicy, agentName)) return undefined;
|
|
6896
|
-
prepareForkThinking(agentName, idx, modelOverride, modelOverrideFromParent, modelOrigin);
|
|
6897
7614
|
return forkSessionFileForIndex(idx);
|
|
6898
7615
|
};
|
|
6899
|
-
const prepareForkSessionForTask: PrepareForkSessionForTask = async (agentName, idx = 0
|
|
7616
|
+
const prepareForkSessionForTask: PrepareForkSessionForTask = async (agentName, idx = 0) => {
|
|
6900
7617
|
if (!shouldForkAgent(contextPolicy, agentName)) return;
|
|
6901
|
-
prepareForkThinking(agentName, idx, modelOverride, modelOverrideFromParent, modelOrigin);
|
|
6902
7618
|
await prepareForkSessionForIndex(idx);
|
|
6903
7619
|
};
|
|
6904
|
-
const
|
|
6905
|
-
if (!shouldForkAgent(contextPolicy, agentName)) return delegatedThinkingOverride;
|
|
6906
|
-
prepareForkThinking(agentName, idx, modelOverride, modelOverrideFromParent, modelOrigin);
|
|
6907
|
-
const override = forkThinkingOverrideForIndex(idx);
|
|
6908
|
-
if (override === "off") forkThinkingDowngrades.set(idx, agentName);
|
|
6909
|
-
return override ?? delegatedThinkingOverride;
|
|
6910
|
-
};
|
|
7620
|
+
const thinkingOverrideForTask: ThinkingOverrideForTask = () => delegatedThinkingOverride;
|
|
6911
7621
|
const childSessionFileForTask: ForkSessionFileForTask = (agentName, idx, modelOverride, modelOverrideFromParent, modelOrigin) =>
|
|
6912
7622
|
forkSessionFileForTask(agentName, idx, modelOverride, modelOverrideFromParent, modelOrigin) ?? path.join(sessionDirForIndex(idx), "session.jsonl");
|
|
6913
7623
|
const childSessionFileForIndex = (idx?: number) =>
|
|
6914
7624
|
path.join(sessionDirForIndex(idx), "session.jsonl");
|
|
6915
7625
|
try {
|
|
7626
|
+
// The ceiling can change while the pruned writer is built; clarify skips preflight but
|
|
7627
|
+
// still branches the parent session at launch.
|
|
7628
|
+
assertLaunchableAgentsAllowedBeforeFork();
|
|
6916
7629
|
if (!(effectiveParams.clarify === true && ctx.hasUI) || deps.config.forkContext?.mode === "pruned") {
|
|
6917
|
-
|
|
7630
|
+
const prepareAllowedForkSession: PrepareForkSessionForTask = async (agent, ...rest) => {
|
|
7631
|
+
assertAgentAllowedByCapabilityCeiling(agent, launchCapabilityCeiling());
|
|
7632
|
+
await prepareForkSessionForTask(agent, ...rest);
|
|
7633
|
+
};
|
|
7634
|
+
await preflightForkSessionsForStaticTasks(effectiveParams, contextPolicy, prepareAllowedForkSession, deps.config.chain?.dynamicFanout?.maxItems);
|
|
6918
7635
|
}
|
|
6919
7636
|
} catch (error) {
|
|
6920
7637
|
activeAsyncCapacity?.rollback();
|
|
@@ -6996,7 +7713,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6996
7713
|
sessionDirForIndex,
|
|
6997
7714
|
sessionFileForIndex: childSessionFileForIndex,
|
|
6998
7715
|
sessionFileForTask: childSessionFileForTask,
|
|
6999
|
-
thinkingOverrideForTask
|
|
7716
|
+
thinkingOverrideForTask,
|
|
7000
7717
|
artifactConfig,
|
|
7001
7718
|
artifactsDir,
|
|
7002
7719
|
backgroundRequestedWhileClarifying,
|
|
@@ -7010,12 +7727,14 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
7010
7727
|
toolBudget: runToolBudget.toolBudget,
|
|
7011
7728
|
usageBudget: usageBudget.budget,
|
|
7012
7729
|
inheritedUsageBudget,
|
|
7730
|
+
requiredExtensions: retainedRequiredExtensions,
|
|
7013
7731
|
allowZeroToolBudget,
|
|
7014
7732
|
configToolBudget: configToolBudget.toolBudget,
|
|
7015
7733
|
configToolTimeoutMs: deps.config.toolTimeoutMs,
|
|
7016
7734
|
contextPolicy,
|
|
7017
7735
|
modelScope,
|
|
7018
7736
|
parentModel: requestParentModel,
|
|
7737
|
+
scopedModelIds: scopedModelIdsFromContext(ctx),
|
|
7019
7738
|
parentSessionId: requestSessionId,
|
|
7020
7739
|
parentPiSessionId: requestPiSessionId,
|
|
7021
7740
|
capabilityCeiling: intersectSubagentCapabilityCeilings(effectiveParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(requestSessionId)),
|
|
@@ -7107,10 +7826,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
7107
7826
|
params: effectiveParams,
|
|
7108
7827
|
agents,
|
|
7109
7828
|
parentModel: requestParentModel,
|
|
7829
|
+
scopedModelIds: scopedModelIdsFromContext(ctx),
|
|
7110
7830
|
availableModels: ctx.modelRegistry.getAvailable().map(toModelInfo),
|
|
7111
7831
|
currentProvider: requestParentModel?.provider,
|
|
7112
7832
|
modelScope,
|
|
7113
|
-
thinkingOverrideForTask
|
|
7833
|
+
thinkingOverrideForTask,
|
|
7114
7834
|
dynamicFanoutMaxItems: deps.config.chain?.dynamicFanout?.maxItems,
|
|
7115
7835
|
});
|
|
7116
7836
|
} catch (error) {
|
|
@@ -7201,7 +7921,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
7201
7921
|
const asyncResult = await runAsyncPath(execData, deps);
|
|
7202
7922
|
if (asyncResult) {
|
|
7203
7923
|
asyncLaunchFailed = asyncResult.isError === true;
|
|
7204
|
-
return attachMission(withRunFanoutBudget(withResolvedContext(
|
|
7924
|
+
return attachMission(withRunFanoutBudget(withResolvedContext(asyncResult, contextPolicy.contextSummary), runFanoutBudget));
|
|
7205
7925
|
}
|
|
7206
7926
|
if (foregroundControl) {
|
|
7207
7927
|
writeNestedForegroundEvent("subagent.nested.started");
|
|
@@ -7211,11 +7931,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
7211
7931
|
if (hasSingle) {
|
|
7212
7932
|
const result = await runSinglePath(execData, deps);
|
|
7213
7933
|
writeNestedForegroundEvent("subagent.nested.completed", result);
|
|
7214
|
-
return attachMission(withRunFanoutBudget(withResolvedContext(
|
|
7934
|
+
return attachMission(withRunFanoutBudget(withResolvedContext(result, contextPolicy.contextSummary), runFanoutBudget, { annotateContent: runFanoutAnnotateContent }));
|
|
7215
7935
|
}
|
|
7216
7936
|
} catch (error) {
|
|
7217
7937
|
asyncLaunchFailed = effectiveAsync;
|
|
7218
|
-
const errorResult =
|
|
7938
|
+
const errorResult = toExecutionErrorResult(effectiveParams, error, contextPolicy.contextSummary);
|
|
7219
7939
|
if (nestedForegroundStarted) writeNestedForegroundEvent("subagent.nested.completed", errorResult);
|
|
7220
7940
|
return attachMission(errorResult);
|
|
7221
7941
|
} finally {
|
|
@@ -7264,24 +7984,47 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
7264
7984
|
onUpdate: ((r: AgentToolResult<Details>) => void) | undefined,
|
|
7265
7985
|
ctx: ExtensionContext,
|
|
7266
7986
|
): Promise<AgentToolResult<Details>> => {
|
|
7267
|
-
const
|
|
7987
|
+
const disabledFeatureError = disabledFeatureResult(params);
|
|
7988
|
+
if (disabledFeatureError) return Promise.resolve(disabledFeatureError);
|
|
7989
|
+
const normalized = normalizePublicSubagentExecution(params, { structuredWorkflows: disabledFeatures.features.has("workflow-scripts") });
|
|
7268
7990
|
if (!normalized.ok) {
|
|
7269
7991
|
return Promise.resolve({ content: [{ type: "text", text: normalized.error }], isError: true, details: { mode: normalized.mode, results: [] } });
|
|
7270
7992
|
}
|
|
7271
7993
|
let publicParams = normalized.params as SubagentParamsLike;
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7994
|
+
const workflow = publicParams.workflow;
|
|
7995
|
+
const errorResult = (text: string): Promise<AgentToolResult<Details>> => Promise.resolve({ content: [{ type: "text", text }], isError: true, details: { mode: publicParams.action ? "management" : "workflow", results: [] } });
|
|
7996
|
+
// Models tend to put script text in the workflow string; say how to pass it instead.
|
|
7997
|
+
const scriptTextHint = " A workflow string is a named workflow resource or a script file path. To run script text, write it in one ```js workflow block in the same reply and call subagent({ workflow: true }).";
|
|
7998
|
+
if (publicParams.tasks !== undefined || publicParams.chain !== undefined) {
|
|
7999
|
+
// Normalization admits chain/tasks only with workflow scripts disabled; the original input was checked above.
|
|
8000
|
+
const kind = publicParams.tasks !== undefined ? "tasks" : "chain";
|
|
8001
|
+
const resolved = resolveStructuredWorkflowResource({ kind, steps: publicParams[kind], task: publicParams.task });
|
|
8002
|
+
if (!resolved.ok) return errorResult(resolved.error);
|
|
8003
|
+
const { tasks: _tasks, chain: _chain, task: _task, ...withoutStructuredInput } = publicParams;
|
|
8004
|
+
publicParams = { ...withoutStructuredInput, workflowScript: resolved.resource.script };
|
|
8005
|
+
workflowResourcePermits.set(publicParams, resolved.resource.permit);
|
|
8006
|
+
} else if (typeof workflow === "string" && !isWorkflowScriptPath(workflow)) {
|
|
8007
|
+
const resolved = resolveWorkflowResource(workflow, publicParams.args, ctx.sessionManager.getSessionId() ?? undefined);
|
|
8008
|
+
if (!resolved.ok) return Promise.resolve({ content: [{ type: "text", text: resolved.error + scriptTextHint }], isError: true, details: { mode: "workflow", results: [] } });
|
|
7275
8009
|
const { workflow: _workflow, args: _args, ...withoutResourceInput } = publicParams;
|
|
7276
8010
|
publicParams = { ...withoutResourceInput, workflowScript: resolved.resource.script };
|
|
7277
8011
|
workflowResourcePermits.set(publicParams, resolved.resource.permit);
|
|
8012
|
+
} else if (workflow !== undefined || publicParams.workflowScript !== undefined) {
|
|
8013
|
+
const normalizedArgs = normalizeWorkflowArgs(publicParams.args);
|
|
8014
|
+
// validate reports args errors with its script errors; launch rejects them here.
|
|
8015
|
+
const validateOnly = publicParams.action === "validate";
|
|
8016
|
+
if ("error" in normalizedArgs && !validateOnly) return errorResult(normalizedArgs.error);
|
|
8017
|
+
let workflowScript = publicParams.workflowScript;
|
|
8018
|
+
if (workflow !== undefined) {
|
|
8019
|
+
const source = workflow === true ? readReplyWorkflowScript(ctx.sessionManager, id) : readWorkflowScriptFile(workflow, publicParams.cwd, ctx.cwd);
|
|
8020
|
+
if ("error" in source) return errorResult(workflow === true ? source.error : source.error + scriptTextHint);
|
|
8021
|
+
workflowScript = source.script;
|
|
8022
|
+
}
|
|
8023
|
+
const { workflow: _workflow, ...withoutWorkflowSource } = publicParams;
|
|
8024
|
+
publicParams = { ...withoutWorkflowSource, workflowScript, args: "error" in normalizedArgs ? publicParams.args : deepFreezeWorkflowArgs(normalizedArgs.args) };
|
|
7278
8025
|
}
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
return Promise.resolve({ content: [{ type: "text", text: loaded.error }], isError: true, details: { mode: publicParams.action ? "management" : "workflow", results: [] } });
|
|
7282
|
-
}
|
|
7283
|
-
publicExecutions.add(loaded.params!);
|
|
7284
|
-
return executeWithSingleDispatchGuard(id, loaded.params!, signal, onUpdate, ctx);
|
|
8026
|
+
publicExecutions.add(publicParams);
|
|
8027
|
+
return executeWithSingleDispatchGuard(id, publicParams, signal, onUpdate, ctx);
|
|
7285
8028
|
};
|
|
7286
8029
|
|
|
7287
8030
|
const executeDelegated = async (
|
|
@@ -7291,6 +8034,8 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
7291
8034
|
onUpdate: ((r: AgentToolResult<Details>) => void) | undefined,
|
|
7292
8035
|
ctx: ExtensionContext,
|
|
7293
8036
|
): Promise<AgentToolResult<Details>> => {
|
|
8037
|
+
const disabledFeatureError = disabledFeatureResult(params);
|
|
8038
|
+
if (disabledFeatureError) return disabledFeatureError;
|
|
7294
8039
|
const delegatedParams = { ...params };
|
|
7295
8040
|
const privateParams = delegatedParams as SubagentParamsLike & {
|
|
7296
8041
|
delegatedThinkingOverride?: AgentConfig["thinking"];
|