@selesai/code 0.5.27 → 0.5.29
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/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +23 -0
- package/dist/cli/credential-print.d.ts.map +1 -0
- package/dist/cli/credential-print.js +117 -0
- package/dist/cli/credential-print.js.map +1 -0
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +3 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +12 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +20 -14
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +11 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +11 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +14 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +10 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/llama/provider.d.ts.map +1 -1
- package/dist/core/llama/provider.js +8 -3
- package/dist/core/llama/provider.js.map +1 -1
- package/dist/core/model-config.d.ts +30 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +6 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -2
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +20 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +5 -4
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +13 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +24 -11
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts +15 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +66 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +34 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
- package/dist/extensions/pi-intercom/README.md +102 -39
- package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
- package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
- package/dist/extensions/pi-intercom/broker/client.ts +315 -12
- package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
- package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
- package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
- package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
- package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
- package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
- package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
- package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
- package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
- package/dist/extensions/pi-intercom/config.test.ts +93 -0
- package/dist/extensions/pi-intercom/config.ts +55 -6
- package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
- package/dist/extensions/pi-intercom/cwd.ts +31 -0
- package/dist/extensions/pi-intercom/extension-api.ts +44 -0
- package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
- package/dist/extensions/pi-intercom/format-context.ts +32 -0
- package/dist/extensions/pi-intercom/index.ts +742 -145
- package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
- package/dist/extensions/pi-intercom/package.json +15 -5
- package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
- package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
- package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
- package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
- package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
- package/dist/extensions/pi-intercom/types.ts +94 -4
- package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
- package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
- package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +85 -0
- package/dist/extensions/pi-subagents/LICENSE +21 -0
- package/dist/extensions/pi-subagents/README.md +146 -52
- package/dist/extensions/pi-subagents/agents/architect.md +1 -0
- package/dist/extensions/pi-subagents/agents/builder.md +1 -0
- package/dist/extensions/pi-subagents/package-lock.json +2 -2
- package/dist/extensions/pi-subagents/package.json +3 -3
- package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +21 -989
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +282 -0
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
- package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
- package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +63 -16
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +29 -4
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
- package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +143 -43
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
- package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
- package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
- package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
- package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +155 -10
- package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
- package/dist/extensions/pi-subagents/src/tui/render.ts +27 -28
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
- package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +26 -1
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +118 -12
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
- package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +102 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +4 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +11 -11
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +10 -2
- package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +46 -0
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
- package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
- package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +34 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +3 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
- package/dist/extensions/question/index.ts +14 -1
- package/dist/extensions/question/tests/wizard.test.ts +11 -8
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +43 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +3 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +10 -2
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +16 -46
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +72 -64
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +14 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/skills/batch-grill-me/SKILL.md +3 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +19 -8
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +14 -5
- package/docs/environment-variables.md +86 -0
- package/docs/extensions.md +15 -5
- package/docs/index.md +1 -0
- package/docs/models.md +9 -2
- package/docs/providers.md +21 -2
- package/docs/rpc.md +23 -6
- package/docs/session-format.md +2 -0
- package/docs/settings.md +1 -1
- package/docs/usage.md +0 -13
- package/examples/extensions/custom-compaction.ts +5 -2
- package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +11 -3
- package/examples/extensions/message-renderer.ts +3 -3
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +5 -2
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +3 -1
- package/package.json +15 -6
- package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
|
@@ -3,12 +3,19 @@ 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 type
|
|
6
|
+
import { resolveAgentName, type AgentConfig, type AgentScope } from "../../agents/agents.ts";
|
|
7
7
|
import { getArtifactsDir, getProjectChainRunsDir } from "../../shared/artifacts.ts";
|
|
8
8
|
import { ChainClarifyComponent, type ChainClarifyResult } from "./chain-clarify.ts";
|
|
9
|
-
import { toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
9
|
+
import { resolveEffectiveThinking, toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
10
10
|
import { executeChain } from "./chain-execution.ts";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
beginForegroundChild,
|
|
13
|
+
finishForegroundChild,
|
|
14
|
+
foregroundSchedulingSettled,
|
|
15
|
+
retainForegroundSchedulingOwner,
|
|
16
|
+
settleForegroundSchedulingOwner,
|
|
17
|
+
updateForegroundChild,
|
|
18
|
+
} from "./foreground-control.ts";
|
|
12
19
|
import { resolveExecutionAgentScope } from "../../agents/agent-scope.ts";
|
|
13
20
|
import { handleManagementAction } from "../../agents/agent-management.ts";
|
|
14
21
|
import { buildDoctorReport } from "../../extension/doctor.ts";
|
|
@@ -16,7 +23,7 @@ import { clearPendingForegroundControlNotices } from "../../extension/control-no
|
|
|
16
23
|
import { runSync } from "./execution.ts";
|
|
17
24
|
import { handleWatchdogToolAction, WATCHDOG_TOOL_ACTIONS } from "../../watchdog/tool-actions.ts";
|
|
18
25
|
import type { MainWatchdogRuntime } from "../../watchdog/runtime.ts";
|
|
19
|
-
import { buildModelCandidates, resolveEffectiveSubagentModel, resolveModelCandidate } from "../shared/model-fallback.ts";
|
|
26
|
+
import { buildModelCandidates, normalizeParentModel, resolveEffectiveSubagentModel, resolveModelCandidate, type ParentModel } from "../shared/model-fallback.ts";
|
|
20
27
|
import type { ModelScopeConfig } from "../shared/model-scope.ts";
|
|
21
28
|
import { aggregateParallelOutputs } from "../shared/parallel-utils.ts";
|
|
22
29
|
import { recordRun } from "../shared/run-history.ts";
|
|
@@ -47,6 +54,7 @@ import { formatControlIntercomMessage, formatControlNoticeMessage, resolveContro
|
|
|
47
54
|
import { resolveTurnBudgetConfig } from "../shared/turn-budget.ts";
|
|
48
55
|
import { formatSpawnBudget, getSpawnBudgetSnapshot, grantSpawnBudget, preflightSpawnBudget, preflightSpawnBudgetGrant, reserveSpawnBudget } from "../shared/spawn-budget.ts";
|
|
49
56
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
57
|
+
import { usageBudgetExceededMessage, usageBudgetState, validateUsageBudgetConfig } from "../shared/usage-budget.ts";
|
|
50
58
|
import { intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
51
59
|
import { isAgentContractV1 } from "../shared/agent-contract.ts";
|
|
52
60
|
import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
@@ -64,12 +72,13 @@ import {
|
|
|
64
72
|
stripDetailsOutputsForIntercomReceipt,
|
|
65
73
|
} from "../../intercom/result-intercom.ts";
|
|
66
74
|
import { applySteeringRecoveryAgentConfig, buildRevivedAsyncTask, resolveAsyncResumeTarget, resolveAsyncRunLocation } from "../background/async-resume.ts";
|
|
67
|
-
import {
|
|
75
|
+
import { deliverCheckpointDecisionRequest, deliverInterruptRequest, requestAsyncSteer } from "../background/control-channel.ts";
|
|
68
76
|
import { waitForSteeringAction } from "../background/steering.ts";
|
|
69
77
|
import { steerAsyncRun } from "./async-steering-action.ts";
|
|
78
|
+
import { stopAsyncRun } from "./async-stop-action.ts";
|
|
70
79
|
import { reconcileAsyncRun } from "../background/stale-run-reconciler.ts";
|
|
71
80
|
import { resolveAsyncRootResultPath } from "../background/chain-root-attachment.ts";
|
|
72
|
-
import { attachRootChildrenToSteps, createNestedRoute,
|
|
81
|
+
import { attachRootChildrenToSteps, createNestedRoute, findNestedControlResult, resolveInheritedNestedRouteFromEnv, resolveNestedAsyncDir, resolveNestedParentAddressFromEnv, snapshotNestedEventFiles, updateForegroundNestedProjection, writeNestedControlRequest, writeNestedEvent, type NestedRunResolutionScope } from "../shared/nested-events.ts";
|
|
73
82
|
import { resolveSubagentRunId, type ResolvedSubagentRunId } from "../background/run-id-resolver.ts";
|
|
74
83
|
import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
|
|
75
84
|
import { inspectSubagentStatus } from "../background/run-status.ts";
|
|
@@ -106,6 +115,7 @@ import {
|
|
|
106
115
|
type SingleResult,
|
|
107
116
|
type ToolBudgetConfig,
|
|
108
117
|
type TurnBudgetConfig,
|
|
118
|
+
type UsageBudgetConfig,
|
|
109
119
|
type SubagentRunMode,
|
|
110
120
|
type SubagentState,
|
|
111
121
|
ASYNC_DIR,
|
|
@@ -167,6 +177,7 @@ export interface SubagentParamsLike {
|
|
|
167
177
|
/** Internal-only strict turn-boundary enforcement for versioned foreground delegation. */
|
|
168
178
|
enforceHardTurnLimit?: boolean;
|
|
169
179
|
toolBudget?: ToolBudgetConfig;
|
|
180
|
+
usageBudget?: UsageBudgetConfig;
|
|
170
181
|
clarify?: boolean;
|
|
171
182
|
share?: boolean;
|
|
172
183
|
control?: ControlConfig;
|
|
@@ -192,6 +203,15 @@ export interface SubagentParamsLike {
|
|
|
192
203
|
additional?: number;
|
|
193
204
|
}
|
|
194
205
|
|
|
206
|
+
function rememberParentModel(state: { currentSessionId?: string | null; lastParentModel?: ParentModel }, sessionId: string | null, model: unknown): ParentModel | undefined {
|
|
207
|
+
if (state.currentSessionId !== sessionId) state.lastParentModel = undefined;
|
|
208
|
+
state.currentSessionId = sessionId;
|
|
209
|
+
const parentModel = normalizeParentModel(model);
|
|
210
|
+
if (!sessionId) return parentModel;
|
|
211
|
+
if (parentModel) state.lastParentModel = parentModel;
|
|
212
|
+
return parentModel ?? state.lastParentModel;
|
|
213
|
+
}
|
|
214
|
+
|
|
195
215
|
interface ExecutorDeps {
|
|
196
216
|
pi: ExtensionAPI;
|
|
197
217
|
state: SubagentState;
|
|
@@ -236,10 +256,12 @@ interface ExecutionContextData {
|
|
|
236
256
|
deadlineAt?: number;
|
|
237
257
|
turnBudget?: ResolvedTurnBudget;
|
|
238
258
|
toolBudget?: ResolvedToolBudget;
|
|
259
|
+
usageBudget?: UsageBudgetConfig;
|
|
239
260
|
allowZeroToolBudget?: boolean;
|
|
240
261
|
configToolBudget?: ResolvedToolBudget;
|
|
241
262
|
contextPolicy: AgentDefaultContextPolicy;
|
|
242
263
|
modelScope?: ModelScopeConfig;
|
|
264
|
+
parentModel?: ParentModel;
|
|
243
265
|
parentSessionId: string | null;
|
|
244
266
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
245
267
|
}
|
|
@@ -248,6 +270,15 @@ function resolveRequestedCwd(runtimeCwd: string, requestedCwd: string | undefine
|
|
|
248
270
|
return requestedCwd ? path.resolve(runtimeCwd, requestedCwd) : runtimeCwd;
|
|
249
271
|
}
|
|
250
272
|
|
|
273
|
+
function removeForegroundControlIfIdle(state: SubagentState, runId: string): boolean {
|
|
274
|
+
const control = state.foregroundControls.get(runId);
|
|
275
|
+
if (control && (!foregroundSchedulingSettled(control) || (control.activeChildren?.size ?? 0) > 0)) return false;
|
|
276
|
+
clearPendingForegroundControlNotices(state, runId);
|
|
277
|
+
state.foregroundControls.delete(runId);
|
|
278
|
+
if (state.lastForegroundControlId === runId) state.lastForegroundControlId = null;
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
|
|
251
282
|
function getForegroundControl(state: SubagentState, runId: string | undefined) {
|
|
252
283
|
if (runId) return state.foregroundControls.get(runId);
|
|
253
284
|
if (state.lastForegroundControlId) {
|
|
@@ -382,7 +413,7 @@ function foregroundChildActivityFromProgress(progress: SingleResult["progress"]
|
|
|
382
413
|
};
|
|
383
414
|
}
|
|
384
415
|
|
|
385
|
-
function rememberForegroundRun(state: SubagentState, input: { runId: string; mode: "single" | "parallel" | "chain"; cwd: string; sessionId: string | null; results: SingleResult[] }): void {
|
|
416
|
+
function rememberForegroundRun(state: SubagentState, input: { runId: string; mode: "single" | "parallel" | "chain"; cwd: string; sessionId: string | null; results: SingleResult[]; checkpoint?: Details["checkpoint"] }): void {
|
|
386
417
|
state.foregroundRuns ??= new Map();
|
|
387
418
|
const previous = state.foregroundRuns.get(input.runId);
|
|
388
419
|
const updatedAt = Date.now();
|
|
@@ -392,26 +423,41 @@ function rememberForegroundRun(state: SubagentState, input: { runId: string; mod
|
|
|
392
423
|
cwd: input.cwd,
|
|
393
424
|
...(input.sessionId ? { sessionId: input.sessionId } : {}),
|
|
394
425
|
updatedAt,
|
|
426
|
+
...(input.checkpoint ? { checkpoint: input.checkpoint } : {}),
|
|
395
427
|
children: input.results.map((result, index) => {
|
|
396
428
|
const child = {
|
|
397
429
|
agent: result.agent,
|
|
398
430
|
index,
|
|
399
431
|
...(result.context ? { context: result.context } : {}),
|
|
400
|
-
status: resolveSubagentResultStatus({
|
|
432
|
+
status: resolveSubagentResultStatus({
|
|
433
|
+
exitCode: result.exitCode,
|
|
434
|
+
interrupted: result.interrupted,
|
|
435
|
+
detached: result.detached,
|
|
436
|
+
processSignal: result.processSignal,
|
|
437
|
+
timedOut: result.timedOut,
|
|
438
|
+
stopped: result.stopped,
|
|
439
|
+
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
440
|
+
}),
|
|
401
441
|
...foregroundChildActivityFromProgress(result.progress),
|
|
402
442
|
updatedAt,
|
|
403
443
|
...(result.exitCode !== undefined ? { exitCode: result.exitCode } : {}),
|
|
404
444
|
...(result.error ? { error: result.error } : {}),
|
|
405
445
|
...(result.finalOutput ? { finalOutput: result.finalOutput } : {}),
|
|
446
|
+
...(result.outputState ? { outputState: result.outputState } : {}),
|
|
406
447
|
...(result.outputMode ? { outputMode: result.outputMode } : {}),
|
|
407
448
|
...(result.savedOutputPath ? { savedOutputPath: result.savedOutputPath } : {}),
|
|
408
449
|
...(result.outputSaveError ? { outputSaveError: result.outputSaveError } : {}),
|
|
409
450
|
...(result.sessionFile ? { sessionFile: result.sessionFile } : {}),
|
|
451
|
+
...(result.model ? { model: result.model } : {}),
|
|
452
|
+
...(result.thinking ? { thinking: result.thinking } : {}),
|
|
410
453
|
...(result.artifactPaths ? { artifactPaths: result.artifactPaths } : {}),
|
|
411
454
|
...(result.transcriptPath ? { transcriptPath: result.transcriptPath } : {}),
|
|
412
455
|
...(result.transcriptError ? { transcriptError: result.transcriptError } : {}),
|
|
413
456
|
...(result.detachedReason ? { detachedReason: result.detachedReason } : {}),
|
|
414
457
|
...(result.acceptance ? { acceptance: result.acceptance } : {}),
|
|
458
|
+
...(result.launchContractDigest ? { launchContractDigest: result.launchContractDigest } : {}),
|
|
459
|
+
...(result.launchResolvedExtensions ? { launchResolvedExtensions: result.launchResolvedExtensions } : {}),
|
|
460
|
+
...(result.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: result.runtimeAcknowledgedExtensions } : {}),
|
|
415
461
|
...(result.capabilityCeiling ? { capabilityCeiling: result.capabilityCeiling } : {}),
|
|
416
462
|
...(result.capabilityAudit ? { capabilityAudit: result.capabilityAudit } : {}),
|
|
417
463
|
};
|
|
@@ -454,35 +500,49 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
454
500
|
state.foregroundRuns.set(input.runId, run);
|
|
455
501
|
}
|
|
456
502
|
run.updatedAt = updatedAt;
|
|
503
|
+
const terminalStatus = resolveSubagentResultStatus({
|
|
504
|
+
exitCode: input.result.exitCode,
|
|
505
|
+
...(input.result.acceptance?.status === "rejected" ? { success: false } : {}),
|
|
506
|
+
interrupted: input.result.interrupted,
|
|
507
|
+
detached: false,
|
|
508
|
+
processSignal: input.result.processSignal,
|
|
509
|
+
timedOut: input.result.timedOut,
|
|
510
|
+
stopped: input.result.stopped,
|
|
511
|
+
turnBudgetExceeded: input.result.turnBudgetExceeded,
|
|
512
|
+
});
|
|
457
513
|
const child = run.children[input.index] ?? { agent: input.result.agent, index: input.index, status: "detached" as const };
|
|
458
514
|
run.children[input.index] = {
|
|
459
515
|
...child,
|
|
460
516
|
agent: input.result.agent,
|
|
461
517
|
index: input.index,
|
|
462
518
|
...(input.result.context ? { context: input.result.context } : {}),
|
|
463
|
-
status:
|
|
464
|
-
? "failed"
|
|
465
|
-
: resolveSubagentResultStatus({ exitCode: input.result.exitCode, interrupted: input.result.interrupted, detached: false }),
|
|
519
|
+
status: terminalStatus,
|
|
466
520
|
...foregroundChildActivityFromProgress(input.result.progress),
|
|
467
521
|
updatedAt,
|
|
468
522
|
...(input.result.exitCode !== undefined ? { exitCode: input.result.exitCode } : {}),
|
|
469
523
|
...(input.result.error ? { error: input.result.error } : {}),
|
|
470
524
|
...(input.result.finalOutput ? { finalOutput: input.result.finalOutput } : {}),
|
|
525
|
+
outputState: input.result.outputState,
|
|
471
526
|
outputMode: input.result.outputMode,
|
|
472
527
|
savedOutputPath: input.result.savedOutputPath,
|
|
473
528
|
outputSaveError: input.result.outputSaveError,
|
|
474
529
|
...(input.result.sessionFile ? { sessionFile: input.result.sessionFile } : {}),
|
|
530
|
+
...(input.result.model ? { model: input.result.model } : {}),
|
|
531
|
+
...(input.result.thinking ? { thinking: input.result.thinking } : {}),
|
|
475
532
|
...(input.result.artifactPaths ? { artifactPaths: input.result.artifactPaths } : {}),
|
|
476
533
|
...(input.result.transcriptPath ? { transcriptPath: input.result.transcriptPath } : {}),
|
|
477
534
|
...(input.result.transcriptError ? { transcriptError: input.result.transcriptError } : {}),
|
|
478
535
|
...(input.result.detachedReason ? { detachedReason: input.result.detachedReason } : {}),
|
|
479
536
|
...(input.result.acceptance ? { acceptance: input.result.acceptance } : {}),
|
|
537
|
+
...(input.result.launchContractDigest ? { launchContractDigest: input.result.launchContractDigest } : {}),
|
|
538
|
+
...(input.result.launchResolvedExtensions ? { launchResolvedExtensions: input.result.launchResolvedExtensions } : {}),
|
|
539
|
+
...(input.result.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: input.result.runtimeAcknowledgedExtensions } : {}),
|
|
480
540
|
...(input.result.capabilityCeiling ? { capabilityCeiling: input.result.capabilityCeiling } : {}),
|
|
481
541
|
...(input.result.capabilityAudit ? { capabilityAudit: input.result.capabilityAudit } : {}),
|
|
482
542
|
};
|
|
483
543
|
trimRememberedForegroundRuns(state);
|
|
484
544
|
const output = getSingleResultOutput(input.result).trim();
|
|
485
|
-
const success =
|
|
545
|
+
const success = terminalStatus === "completed";
|
|
486
546
|
const summary = !success && input.result.error
|
|
487
547
|
? `${input.result.error}${output ? `\n\nOutput:\n${output}` : ""}`
|
|
488
548
|
: output || input.result.error || "Detached child exited without final output.";
|
|
@@ -498,7 +558,12 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
498
558
|
success,
|
|
499
559
|
summary,
|
|
500
560
|
exitCode: input.result.exitCode,
|
|
501
|
-
state:
|
|
561
|
+
state: terminalStatus === "completed" ? "complete" : terminalStatus,
|
|
562
|
+
...(input.result.interrupted !== undefined ? { interrupted: input.result.interrupted } : {}),
|
|
563
|
+
...(input.result.stopped !== undefined ? { stopped: input.result.stopped } : {}),
|
|
564
|
+
...(input.result.processSignal !== undefined ? { processSignal: input.result.processSignal } : {}),
|
|
565
|
+
...(input.result.timedOut !== undefined ? { timedOut: input.result.timedOut } : {}),
|
|
566
|
+
...(input.result.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: input.result.turnBudgetExceeded } : {}),
|
|
502
567
|
timestamp: updatedAt,
|
|
503
568
|
cwd: input.cwd,
|
|
504
569
|
sessionFile: input.result.sessionFile,
|
|
@@ -507,7 +572,7 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
507
572
|
});
|
|
508
573
|
}
|
|
509
574
|
|
|
510
|
-
function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState): { runId: string; mode: "single" | "parallel" | "chain"; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
|
|
575
|
+
function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState): { runId: string; mode: "single" | "parallel" | "chain"; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
|
|
511
576
|
const requested = (params.id ?? params.runId)?.trim();
|
|
512
577
|
if (!requested || !state.foregroundRuns?.size || !state.currentSessionId) return undefined;
|
|
513
578
|
const sessionRuns = [...state.foregroundRuns.values()].filter((run) => run.sessionId === state.currentSessionId);
|
|
@@ -534,6 +599,9 @@ function resolveForegroundResumeTarget(params: SubagentParamsLike, state: Subage
|
|
|
534
599
|
index,
|
|
535
600
|
cwd: run.cwd,
|
|
536
601
|
sessionFile,
|
|
602
|
+
...(child.model ? { model: child.model } : {}),
|
|
603
|
+
...(child.thinking ? { thinking: child.thinking } : {}),
|
|
604
|
+
...(child.launchContractDigest ? { launchContractDigest: child.launchContractDigest } : {}),
|
|
537
605
|
...(child.capabilityCeiling ? { capabilityCeiling: child.capabilityCeiling } : {}),
|
|
538
606
|
};
|
|
539
607
|
}
|
|
@@ -714,50 +782,6 @@ function interruptAsyncRun(
|
|
|
714
782
|
}
|
|
715
783
|
}
|
|
716
784
|
|
|
717
|
-
function stopAsyncRun(
|
|
718
|
-
state: SubagentState,
|
|
719
|
-
runId: string | undefined,
|
|
720
|
-
kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean,
|
|
721
|
-
location?: { asyncDir: string | null; resolvedId?: string },
|
|
722
|
-
): AgentToolResult<Details> | null {
|
|
723
|
-
const target = getAsyncInterruptTarget(state, runId, location, { fallbackToNewest: false });
|
|
724
|
-
if (!target) return null;
|
|
725
|
-
const status = reconcileAsyncRun(target.asyncDir, { kill }).status;
|
|
726
|
-
if (state.currentSessionId && status?.sessionId !== state.currentSessionId) {
|
|
727
|
-
return {
|
|
728
|
-
content: [{ type: "text", text: `Async run '${target.asyncId}' was not found in the active session.` }],
|
|
729
|
-
isError: true,
|
|
730
|
-
details: { mode: "management", results: [] },
|
|
731
|
-
};
|
|
732
|
-
}
|
|
733
|
-
if (!status || (status.state !== "running" && status.state !== "queued")) {
|
|
734
|
-
return {
|
|
735
|
-
content: [{ type: "text", text: `No running or queued async run was found for '${runId ?? "current"}'.` }],
|
|
736
|
-
isError: true,
|
|
737
|
-
details: { mode: "management", results: [] },
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
try {
|
|
741
|
-
deliverStopRequest({ asyncDir: target.asyncDir, pid: typeof status.pid === "number" ? status.pid : undefined, kill, source: "stop-action" });
|
|
742
|
-
const tracked = state.asyncJobs.get(target.asyncId);
|
|
743
|
-
if (tracked) {
|
|
744
|
-
tracked.activityState = undefined;
|
|
745
|
-
tracked.updatedAt = Date.now();
|
|
746
|
-
}
|
|
747
|
-
return {
|
|
748
|
-
content: [{ type: "text", text: `Stop requested for async run ${target.asyncId}.` }],
|
|
749
|
-
details: { mode: "management", results: [] },
|
|
750
|
-
};
|
|
751
|
-
} catch (error) {
|
|
752
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
753
|
-
return {
|
|
754
|
-
content: [{ type: "text", text: `Failed to stop async run ${target.asyncId}: ${message}` }],
|
|
755
|
-
isError: true,
|
|
756
|
-
details: { mode: "management", results: [] },
|
|
757
|
-
};
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
|
|
761
785
|
function duplicateNames(names: string[]): string[] {
|
|
762
786
|
const seen = new Set<string>();
|
|
763
787
|
const duplicates = new Set<string>();
|
|
@@ -773,6 +797,7 @@ function appendStepToAsyncChain(input: {
|
|
|
773
797
|
requestCwd: string;
|
|
774
798
|
ctx: ExtensionContext;
|
|
775
799
|
deps: ExecutorDeps;
|
|
800
|
+
parentModel?: ParentModel;
|
|
776
801
|
}): AgentToolResult<Details> {
|
|
777
802
|
const targetRunId = input.params.id ?? input.params.runId;
|
|
778
803
|
if (!targetRunId) {
|
|
@@ -877,13 +902,14 @@ function appendStepToAsyncChain(input: {
|
|
|
877
902
|
const contextPolicy = resolveExplicitContextPolicy(input.params);
|
|
878
903
|
const chainSkillInput = normalizeSkillInput(input.params.skill);
|
|
879
904
|
const chainSkills = chainSkillInput === false ? [] : (chainSkillInput ?? []);
|
|
905
|
+
const parentModel = input.parentModel;
|
|
880
906
|
const asyncCtx = {
|
|
881
907
|
pi: input.deps.pi,
|
|
882
908
|
cwd: input.ctx.cwd,
|
|
883
909
|
currentSessionId: resolveCurrentSessionId(input.ctx.sessionManager),
|
|
884
910
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
885
|
-
currentModelProvider:
|
|
886
|
-
currentModel:
|
|
911
|
+
currentModelProvider: parentModel?.provider,
|
|
912
|
+
currentModel: parentModel,
|
|
887
913
|
modelScope: discoveredForAppend.modelScope,
|
|
888
914
|
interactive: input.ctx.hasUI,
|
|
889
915
|
};
|
|
@@ -1011,10 +1037,10 @@ function resolveNestedResumeTarget(match: ResolvedSubagentRunId & { kind: "neste
|
|
|
1011
1037
|
};
|
|
1012
1038
|
}
|
|
1013
1039
|
|
|
1014
|
-
async function waitForNestedControlResult(target: ResolvedSubagentRunId & { kind: "nested" }, requestId: string, timeoutMs = 1_000) {
|
|
1040
|
+
async function waitForNestedControlResult(target: ResolvedSubagentRunId & { kind: "nested" }, requestId: string, ignoredFiles: ReadonlySet<string>, timeoutMs = 1_000) {
|
|
1015
1041
|
const deadline = Date.now() + timeoutMs;
|
|
1016
1042
|
while (Date.now() < deadline) {
|
|
1017
|
-
const result =
|
|
1043
|
+
const result = findNestedControlResult(target.match.route, requestId, target.match.run.id, ignoredFiles);
|
|
1018
1044
|
if (result) return result;
|
|
1019
1045
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
1020
1046
|
}
|
|
@@ -1023,14 +1049,16 @@ async function waitForNestedControlResult(target: ResolvedSubagentRunId & { kind
|
|
|
1023
1049
|
|
|
1024
1050
|
async function sendNestedControlRequest(target: ResolvedSubagentRunId & { kind: "nested" }, action: "interrupt" | "resume", message?: string) {
|
|
1025
1051
|
const requestId = randomUUID();
|
|
1052
|
+
const ignoredFiles = snapshotNestedEventFiles(target.match.route);
|
|
1053
|
+
const requestedAt = Date.now();
|
|
1026
1054
|
writeNestedControlRequest(target.match.route, {
|
|
1027
|
-
ts:
|
|
1055
|
+
ts: requestedAt,
|
|
1028
1056
|
requestId,
|
|
1029
1057
|
targetRunId: target.match.run.id,
|
|
1030
1058
|
action,
|
|
1031
1059
|
...(message ? { message } : {}),
|
|
1032
1060
|
});
|
|
1033
|
-
return waitForNestedControlResult(target, requestId);
|
|
1061
|
+
return waitForNestedControlResult(target, requestId, ignoredFiles);
|
|
1034
1062
|
}
|
|
1035
1063
|
|
|
1036
1064
|
function directNestedAsyncInterrupt(target: ResolvedSubagentRunId & { kind: "nested" }): AgentToolResult<Details> | undefined {
|
|
@@ -1121,6 +1149,7 @@ async function resumeAsyncRun(input: {
|
|
|
1121
1149
|
requestCwd: string;
|
|
1122
1150
|
ctx: ExtensionContext;
|
|
1123
1151
|
deps: ExecutorDeps;
|
|
1152
|
+
parentModel?: ParentModel;
|
|
1124
1153
|
absoluteDeadlineAt?: number;
|
|
1125
1154
|
}): Promise<AgentToolResult<Details>> {
|
|
1126
1155
|
const followUp = (input.params.message ?? input.params.task ?? "").trim();
|
|
@@ -1132,6 +1161,13 @@ async function resumeAsyncRun(input: {
|
|
|
1132
1161
|
details: { mode: "management", results: [] },
|
|
1133
1162
|
};
|
|
1134
1163
|
}
|
|
1164
|
+
if (input.params.model !== undefined) {
|
|
1165
|
+
return {
|
|
1166
|
+
content: [{ type: "text", text: "action='resume' reuses the persisted child model and does not accept a model override." }],
|
|
1167
|
+
isError: true,
|
|
1168
|
+
details: { mode: "management", results: [] },
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1135
1171
|
const acceptanceErrors = validateExecutionAcceptance(input.params);
|
|
1136
1172
|
if (acceptanceErrors.length > 0) {
|
|
1137
1173
|
return {
|
|
@@ -1259,6 +1295,7 @@ async function resumeAsyncRun(input: {
|
|
|
1259
1295
|
const goal = resolveAsyncEventGoal(workflowTask, attachChain);
|
|
1260
1296
|
const chain = wrapChainTasksForFork(attachChain, contextPolicy);
|
|
1261
1297
|
const normalized = normalizeSkillInput(input.params.skill);
|
|
1298
|
+
const parentModel = input.parentModel;
|
|
1262
1299
|
const result = executeAsyncChain(runId, {
|
|
1263
1300
|
chain,
|
|
1264
1301
|
task: workflowTask,
|
|
@@ -1277,8 +1314,8 @@ async function resumeAsyncRun(input: {
|
|
|
1277
1314
|
cwd: input.requestCwd,
|
|
1278
1315
|
currentSessionId: input.deps.state.currentSessionId,
|
|
1279
1316
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1280
|
-
currentModelProvider:
|
|
1281
|
-
currentModel:
|
|
1317
|
+
currentModelProvider: parentModel?.provider,
|
|
1318
|
+
currentModel: parentModel,
|
|
1282
1319
|
modelScope,
|
|
1283
1320
|
interactive: input.ctx.hasUI,
|
|
1284
1321
|
},
|
|
@@ -1320,6 +1357,7 @@ async function resumeAsyncRun(input: {
|
|
|
1320
1357
|
const artifactConfig: ArtifactConfig = recoveryDescriptor?.artifactConfig ?? { ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false, dir: input.deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir };
|
|
1321
1358
|
const artifactsDir = recoveryDescriptor?.artifactsDir ?? getArtifactsDir(parentSessionFile, effectiveCwd, artifactConfig.dir);
|
|
1322
1359
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1360
|
+
const parentModel = input.parentModel;
|
|
1323
1361
|
const result = executeAsyncSingle(runId, {
|
|
1324
1362
|
agent: target.agent,
|
|
1325
1363
|
task: buildRevivedAsyncTask(target, followUp),
|
|
@@ -1330,8 +1368,8 @@ async function resumeAsyncRun(input: {
|
|
|
1330
1368
|
cwd: input.requestCwd,
|
|
1331
1369
|
currentSessionId: input.deps.state.currentSessionId,
|
|
1332
1370
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
1333
|
-
currentModelProvider:
|
|
1334
|
-
currentModel:
|
|
1371
|
+
currentModelProvider: parentModel?.provider,
|
|
1372
|
+
currentModel: parentModel,
|
|
1335
1373
|
modelScope,
|
|
1336
1374
|
interactive: input.ctx.hasUI,
|
|
1337
1375
|
},
|
|
@@ -1349,8 +1387,8 @@ async function resumeAsyncRun(input: {
|
|
|
1349
1387
|
sourceRunId: target.runId,
|
|
1350
1388
|
...(input.deps.state.currentSessionId ? { parentSessionId: input.deps.state.currentSessionId } : {}),
|
|
1351
1389
|
},
|
|
1352
|
-
modelOverride:
|
|
1353
|
-
thinkingOverride:
|
|
1390
|
+
modelOverride: recoveryDescriptor?.model ?? target.model,
|
|
1391
|
+
thinkingOverride: recoveryDescriptor?.thinking ?? target.thinking,
|
|
1354
1392
|
outputBaseDir: resolveSingleRunOutputBaseDir(input.deps, artifactsDir, runId),
|
|
1355
1393
|
maxSubagentDepth: recoveryDescriptor?.maxSubagentDepth ?? resolveCurrentMaxSubagentDepth(input.deps.config.maxSubagentDepth),
|
|
1356
1394
|
waitToolEnabled: input.deps.waitToolEnabled,
|
|
@@ -1361,8 +1399,8 @@ async function resumeAsyncRun(input: {
|
|
|
1361
1399
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
1362
1400
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
1363
1401
|
availableModels,
|
|
1364
|
-
output: recoveryDescriptor?.outputPath,
|
|
1365
|
-
outputMode: recoveryDescriptor?.outputMode,
|
|
1402
|
+
output: typeof input.params.output === "string" ? input.params.output : recoveryDescriptor?.outputPath,
|
|
1403
|
+
outputMode: input.params.outputMode ?? recoveryDescriptor?.outputMode,
|
|
1366
1404
|
...(recoveryDescriptor?.agentContract ? { agentContract: recoveryDescriptor.agentContract } : {}),
|
|
1367
1405
|
...(recoveryDescriptor?.structuredOutputSchema ? { structuredOutputSchema: recoveryDescriptor.structuredOutputSchema } : {}),
|
|
1368
1406
|
...(recoveryDescriptor?.skills ? { skills: [...recoveryDescriptor.skills] } : {}),
|
|
@@ -1387,7 +1425,13 @@ async function resumeAsyncRun(input: {
|
|
|
1387
1425
|
revivedTarget ? `Intercom target: ${revivedTarget} (if registered)` : undefined,
|
|
1388
1426
|
`Status if needed: subagent({ action: "status", id: "${revivedId}" })`,
|
|
1389
1427
|
].filter((line): line is string => Boolean(line));
|
|
1390
|
-
return {
|
|
1428
|
+
return {
|
|
1429
|
+
content: [{ type: "text", text: formatAsyncStartedMessage(lines.join("\n"), input.ctx.hasUI) }],
|
|
1430
|
+
details: {
|
|
1431
|
+
...result.details,
|
|
1432
|
+
...(target.launchContractDigest ? { sourceLaunchContractDigest: target.launchContractDigest } : {}),
|
|
1433
|
+
},
|
|
1434
|
+
};
|
|
1391
1435
|
}
|
|
1392
1436
|
|
|
1393
1437
|
function resultSummaryForIntercom(result: SingleResult): string {
|
|
@@ -1433,14 +1477,19 @@ async function emitForegroundResultIntercom(input: {
|
|
|
1433
1477
|
nestedChildren?: NestedRunSummary[];
|
|
1434
1478
|
parallelHandoff?: Details["parallelHandoff"];
|
|
1435
1479
|
}): Promise<ReturnType<typeof buildSubagentResultIntercomPayload> | null> {
|
|
1436
|
-
if (!input.intercomBridge.active || !input.intercomBridge.orchestratorTarget) return null;
|
|
1480
|
+
if (!input.intercomBridge.active || !input.intercomBridge.resultDelivery || !input.intercomBridge.orchestratorTarget) return null;
|
|
1437
1481
|
const children = input.results.flatMap((result, index) => result.detached ? [] : [{
|
|
1438
1482
|
agent: result.agent,
|
|
1439
1483
|
status: resolveSubagentResultStatus({
|
|
1440
1484
|
exitCode: result.exitCode,
|
|
1441
1485
|
interrupted: result.interrupted,
|
|
1442
1486
|
detached: result.detached,
|
|
1487
|
+
processSignal: result.processSignal,
|
|
1488
|
+
timedOut: result.timedOut,
|
|
1489
|
+
stopped: result.stopped,
|
|
1490
|
+
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
1443
1491
|
}),
|
|
1492
|
+
outputState: result.outputState ?? "unknown",
|
|
1444
1493
|
summary: resultSummaryForIntercom(result),
|
|
1445
1494
|
index,
|
|
1446
1495
|
artifactPath: result.artifactPaths?.outputPath,
|
|
@@ -1487,6 +1536,67 @@ async function maybeBuildForegroundIntercomReceipt(input: {
|
|
|
1487
1536
|
};
|
|
1488
1537
|
}
|
|
1489
1538
|
|
|
1539
|
+
function canonicalizeAgentName(name: string, agents: AgentConfig[]): { name?: string; error?: string } {
|
|
1540
|
+
const resolved = resolveAgentName(name, agents);
|
|
1541
|
+
if (resolved.error) return { error: resolved.error };
|
|
1542
|
+
if (!resolved.agent) return { error: `Unknown agent: ${name}` };
|
|
1543
|
+
return { name: resolved.agent.name };
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
function canonicalizeExecutionParams(params: SubagentParamsLike, agents: AgentConfig[]): { params?: SubagentParamsLike; error?: string } {
|
|
1547
|
+
const resolve = (name: string, location?: string): { name?: string; error?: string } => {
|
|
1548
|
+
const result = canonicalizeAgentName(name, agents);
|
|
1549
|
+
return result.error && location ? { error: `${result.error} (${location})` } : result;
|
|
1550
|
+
};
|
|
1551
|
+
if (params.agent) {
|
|
1552
|
+
const result = resolve(params.agent);
|
|
1553
|
+
if (result.error) return { error: result.error };
|
|
1554
|
+
params = { ...params, agent: result.name };
|
|
1555
|
+
}
|
|
1556
|
+
if (params.tasks) {
|
|
1557
|
+
const tasks: TaskParam[] = [];
|
|
1558
|
+
for (let index = 0; index < params.tasks.length; index++) {
|
|
1559
|
+
const task = params.tasks[index]!;
|
|
1560
|
+
const result = resolve(task.agent, `task ${index + 1}`);
|
|
1561
|
+
if (result.error) return { error: result.error };
|
|
1562
|
+
tasks.push({ ...task, agent: result.name! });
|
|
1563
|
+
}
|
|
1564
|
+
params = { ...params, tasks };
|
|
1565
|
+
}
|
|
1566
|
+
if (params.chain) {
|
|
1567
|
+
const chain: ChainStep[] = [];
|
|
1568
|
+
for (let index = 0; index < params.chain.length; index++) {
|
|
1569
|
+
const step = params.chain[index]!;
|
|
1570
|
+
if (isParallelStep(step)) {
|
|
1571
|
+
const parallel: typeof step.parallel = [];
|
|
1572
|
+
for (let taskIndex = 0; taskIndex < step.parallel.length; taskIndex++) {
|
|
1573
|
+
const task = step.parallel[taskIndex]!;
|
|
1574
|
+
const result = resolve(task.agent, `step ${index + 1}, task ${taskIndex + 1}`);
|
|
1575
|
+
if (result.error) return { error: result.error };
|
|
1576
|
+
parallel.push({ ...task, agent: result.name! });
|
|
1577
|
+
}
|
|
1578
|
+
chain.push({ ...step, parallel });
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
if (isDynamicParallelStep(step)) {
|
|
1582
|
+
const result = resolve(step.parallel.agent, `step ${index + 1}`);
|
|
1583
|
+
if (result.error) return { error: result.error };
|
|
1584
|
+
chain.push({ ...step, parallel: { ...step.parallel, agent: result.name! } });
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
if ("agent" in step && typeof step.agent === "string") {
|
|
1588
|
+
const result = resolve(step.agent, `step ${index + 1}`);
|
|
1589
|
+
if (result.error) return { error: result.error };
|
|
1590
|
+
chain.push({ ...step, agent: result.name! });
|
|
1591
|
+
continue;
|
|
1592
|
+
}
|
|
1593
|
+
chain.push(step);
|
|
1594
|
+
}
|
|
1595
|
+
params = { ...params, chain };
|
|
1596
|
+
}
|
|
1597
|
+
return { params };
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1490
1600
|
function validateExecutionInput(
|
|
1491
1601
|
params: SubagentParamsLike,
|
|
1492
1602
|
agents: AgentConfig[],
|
|
@@ -1699,10 +1809,14 @@ function applySingleAgentLaunchDefaults(params: SubagentParamsLike, agents: Agen
|
|
|
1699
1809
|
};
|
|
1700
1810
|
}
|
|
1701
1811
|
|
|
1702
|
-
|
|
1812
|
+
export const DEFAULT_FOREGROUND_TIMEOUT_MS = 30 * 60 * 1000;
|
|
1813
|
+
|
|
1814
|
+
function resolveForegroundTimeout(params: SubagentParamsLike, defaultTimeoutMs?: number): { timeoutMs?: number; error?: string } {
|
|
1703
1815
|
const rawTimeout = params.timeoutMs;
|
|
1704
1816
|
const rawMaxRuntime = params.maxRuntimeMs;
|
|
1705
|
-
if (rawTimeout === undefined && rawMaxRuntime === undefined)
|
|
1817
|
+
if (rawTimeout === undefined && rawMaxRuntime === undefined) {
|
|
1818
|
+
return defaultTimeoutMs === undefined ? {} : { timeoutMs: defaultTimeoutMs };
|
|
1819
|
+
}
|
|
1706
1820
|
for (const [name, value] of [["timeoutMs", rawTimeout], ["maxRuntimeMs", rawMaxRuntime]] as const) {
|
|
1707
1821
|
if (value === undefined) continue;
|
|
1708
1822
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
@@ -2044,19 +2158,20 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2044
2158
|
};
|
|
2045
2159
|
}
|
|
2046
2160
|
const id = randomUUID();
|
|
2161
|
+
const parentModel = data.parentModel;
|
|
2047
2162
|
const asyncCtx = {
|
|
2048
2163
|
pi: deps.pi,
|
|
2049
2164
|
cwd: ctx.cwd,
|
|
2050
2165
|
currentSessionId: deps.state.currentSessionId!,
|
|
2051
2166
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
2052
|
-
currentModelProvider:
|
|
2053
|
-
currentModel:
|
|
2167
|
+
currentModelProvider: parentModel?.provider,
|
|
2168
|
+
currentModel: parentModel,
|
|
2054
2169
|
modelScope: data.modelScope,
|
|
2055
2170
|
interactive: ctx.hasUI,
|
|
2056
2171
|
};
|
|
2057
2172
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
2058
2173
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
2059
|
-
const currentProvider =
|
|
2174
|
+
const currentProvider = parentModel?.provider;
|
|
2060
2175
|
const controlIntercomTarget = intercomBridge.active ? intercomBridge.orchestratorTarget : undefined;
|
|
2061
2176
|
const childIntercomTarget = intercomBridge.active ? (agent: string, index: number) => resolveSubagentIntercomTarget(id, agent, index) : undefined;
|
|
2062
2177
|
|
|
@@ -2111,6 +2226,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2111
2226
|
timeoutMs: data.timeoutMs,
|
|
2112
2227
|
turnBudget: data.turnBudget,
|
|
2113
2228
|
toolBudget: data.toolBudget,
|
|
2229
|
+
usageBudget: data.usageBudget,
|
|
2114
2230
|
configToolBudget: data.configToolBudget,
|
|
2115
2231
|
capabilityCeiling: data.capabilityCeiling,
|
|
2116
2232
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -2153,6 +2269,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2153
2269
|
timeoutMs: data.timeoutMs,
|
|
2154
2270
|
turnBudget: data.turnBudget,
|
|
2155
2271
|
toolBudget: data.toolBudget,
|
|
2272
|
+
usageBudget: data.usageBudget,
|
|
2156
2273
|
configToolBudget: data.configToolBudget,
|
|
2157
2274
|
capabilityCeiling: data.capabilityCeiling,
|
|
2158
2275
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -2174,7 +2291,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2174
2291
|
const normalizedSkills = normalizeSkillInput(params.skill);
|
|
2175
2292
|
const skills = normalizedSkills === false ? [] : normalizedSkills;
|
|
2176
2293
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, a.maxSubagentDepth);
|
|
2177
|
-
const modelOverride = resolveEffectiveSubagentModel(params.model as string | undefined, a.model,
|
|
2294
|
+
const modelOverride = resolveEffectiveSubagentModel(params.model as string | undefined, a.model, parentModel, availableModels, currentProvider, { scope: data.modelScope });
|
|
2178
2295
|
return executeAsyncSingle(id, {
|
|
2179
2296
|
agent: params.agent!,
|
|
2180
2297
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
@@ -2211,6 +2328,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2211
2328
|
timeoutMs: data.timeoutMs,
|
|
2212
2329
|
turnBudget: data.turnBudget,
|
|
2213
2330
|
toolBudget: data.toolBudget,
|
|
2331
|
+
usageBudget: data.usageBudget,
|
|
2214
2332
|
configToolBudget: data.configToolBudget,
|
|
2215
2333
|
capabilityCeiling: data.capabilityCeiling,
|
|
2216
2334
|
});
|
|
@@ -2246,11 +2364,12 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2246
2364
|
const chainSkills = normalized === false ? [] : (normalized ?? []);
|
|
2247
2365
|
const chain = wrapChainTasksForFork(params.chain as ChainStep[], contextPolicy);
|
|
2248
2366
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
2367
|
+
const chainCtx = normalizeParentModel(ctx.model) || !data.parentModel ? ctx : { ...ctx, model: data.parentModel };
|
|
2249
2368
|
const chainResult = await executeChain({
|
|
2250
2369
|
chain,
|
|
2251
2370
|
task: params.task,
|
|
2252
2371
|
agents,
|
|
2253
|
-
ctx,
|
|
2372
|
+
ctx: chainCtx,
|
|
2254
2373
|
modelScope: data.modelScope,
|
|
2255
2374
|
intercomEvents: deps.pi.events,
|
|
2256
2375
|
signal,
|
|
@@ -2284,8 +2403,18 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2284
2403
|
timeoutMs: data.timeoutMs,
|
|
2285
2404
|
deadlineAt: data.deadlineAt,
|
|
2286
2405
|
turnBudget: data.turnBudget,
|
|
2287
|
-
onDetachedExit: (index, result) =>
|
|
2406
|
+
onDetachedExit: (index, result) => {
|
|
2407
|
+
try {
|
|
2408
|
+
updateRememberedForegroundChild(deps.state, { runId, mode: "chain", cwd: effectiveCwd, sessionId: data.parentSessionId, index, result, events: deps.pi.events });
|
|
2409
|
+
} finally {
|
|
2410
|
+
removeForegroundControlIfIdle(deps.state, runId);
|
|
2411
|
+
}
|
|
2412
|
+
},
|
|
2413
|
+
onForegroundChildSettled: () => {
|
|
2414
|
+
removeForegroundControlIfIdle(deps.state, runId);
|
|
2415
|
+
},
|
|
2288
2416
|
toolBudget: data.toolBudget,
|
|
2417
|
+
usageBudget: data.usageBudget,
|
|
2289
2418
|
configToolBudget: data.configToolBudget,
|
|
2290
2419
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
2291
2420
|
capabilityCeiling: data.capabilityCeiling,
|
|
@@ -2300,13 +2429,14 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2300
2429
|
};
|
|
2301
2430
|
}
|
|
2302
2431
|
const id = randomUUID();
|
|
2432
|
+
const parentModel = data.parentModel;
|
|
2303
2433
|
const asyncCtx = {
|
|
2304
2434
|
pi: deps.pi,
|
|
2305
2435
|
cwd: ctx.cwd,
|
|
2306
2436
|
currentSessionId: deps.state.currentSessionId!,
|
|
2307
2437
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
2308
|
-
currentModelProvider:
|
|
2309
|
-
currentModel:
|
|
2438
|
+
currentModelProvider: parentModel?.provider,
|
|
2439
|
+
currentModel: parentModel,
|
|
2310
2440
|
modelScope: data.modelScope,
|
|
2311
2441
|
interactive: ctx.hasUI,
|
|
2312
2442
|
};
|
|
@@ -2344,20 +2474,22 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2344
2474
|
timeoutMs: data.timeoutMs,
|
|
2345
2475
|
turnBudget: data.turnBudget,
|
|
2346
2476
|
toolBudget: data.toolBudget,
|
|
2477
|
+
usageBudget: data.usageBudget,
|
|
2347
2478
|
configToolBudget: data.configToolBudget,
|
|
2348
2479
|
capabilityCeiling: data.capabilityCeiling,
|
|
2349
2480
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
2350
2481
|
});
|
|
2351
2482
|
}
|
|
2352
2483
|
|
|
2353
|
-
const rawChainDetails = chainResult.details ? { ...chainResult.details, runId } : undefined;
|
|
2484
|
+
const rawChainDetails = chainResult.details ? { ...chainResult.details, runId, timeoutMs: data.timeoutMs } : undefined;
|
|
2354
2485
|
if (foregroundControl && rawChainDetails) {
|
|
2355
2486
|
updateForegroundNestedProjection(foregroundControl);
|
|
2356
2487
|
attachRootChildrenToSteps(runId, rawChainDetails.results, foregroundControl.nestedChildren);
|
|
2357
2488
|
rawChainDetails.totalCost = sumResultsCost(rawChainDetails.results);
|
|
2489
|
+
rawChainDetails.usageBudget = usageBudgetState(data.usageBudget, rawChainDetails.totalCost);
|
|
2358
2490
|
}
|
|
2359
2491
|
const chainDetails = rawChainDetails ? compactForegroundDetails(rawChainDetails) : undefined;
|
|
2360
|
-
if (chainDetails) rememberForegroundRun(deps.state, { runId, mode: "chain", cwd: effectiveCwd, sessionId: data.parentSessionId, results: chainDetails.results });
|
|
2492
|
+
if (chainDetails) rememberForegroundRun(deps.state, { runId, mode: "chain", cwd: effectiveCwd, sessionId: data.parentSessionId, results: chainDetails.results, checkpoint: chainDetails.checkpoint });
|
|
2361
2493
|
const intercomReceipt = chainDetails && !chainDetails.results.some((result) => result.interrupted || result.detached)
|
|
2362
2494
|
? await maybeBuildForegroundIntercomReceipt({
|
|
2363
2495
|
pi: deps.pi,
|
|
@@ -2406,6 +2538,7 @@ interface ForegroundParallelRunInput {
|
|
|
2406
2538
|
waitToolEnabled?: boolean;
|
|
2407
2539
|
availableModels: ModelInfo[];
|
|
2408
2540
|
modelScope?: ModelScopeConfig;
|
|
2541
|
+
parentModel?: ParentModel;
|
|
2409
2542
|
modelOverrides: (string | undefined)[];
|
|
2410
2543
|
behaviors: Array<ReturnType<typeof resolveStepBehavior>>;
|
|
2411
2544
|
firstProgressIndex: number;
|
|
@@ -2424,6 +2557,7 @@ interface ForegroundParallelRunInput {
|
|
|
2424
2557
|
timeoutMs?: number;
|
|
2425
2558
|
deadlineAt?: number;
|
|
2426
2559
|
turnBudget?: ResolvedTurnBudget;
|
|
2560
|
+
usageBudget?: UsageBudgetConfig;
|
|
2427
2561
|
toolBudgets: (ResolvedToolBudget | undefined)[];
|
|
2428
2562
|
agentContract?: AgentContract;
|
|
2429
2563
|
}
|
|
@@ -2530,6 +2664,10 @@ function finalizeParallelWorktreeHandoff(input: {
|
|
|
2530
2664
|
interrupted: result.interrupted,
|
|
2531
2665
|
detached: result.detached,
|
|
2532
2666
|
state: result.stopped ? "stopped" : undefined,
|
|
2667
|
+
processSignal: result.processSignal,
|
|
2668
|
+
timedOut: result.timedOut,
|
|
2669
|
+
stopped: result.stopped,
|
|
2670
|
+
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
2533
2671
|
}),
|
|
2534
2672
|
summary: resultSummaryForIntercom(result),
|
|
2535
2673
|
...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
|
|
@@ -2578,7 +2716,22 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2578
2716
|
for (let i = 0; i < input.tasks.length; i++) {
|
|
2579
2717
|
input.sessionFileForTask(input.tasks[i]!.agent, i, input.modelOverrides[i]);
|
|
2580
2718
|
}
|
|
2719
|
+
const completedResults: SingleResult[] = [];
|
|
2720
|
+
if (input.foregroundControl) retainForegroundSchedulingOwner(input.foregroundControl);
|
|
2581
2721
|
return mapConcurrent(input.tasks, input.concurrencyLimit, async (task, index) => {
|
|
2722
|
+
const budgetState = usageBudgetState(input.usageBudget, sumResultsCost(completedResults));
|
|
2723
|
+
if (budgetState?.exhausted) {
|
|
2724
|
+
return {
|
|
2725
|
+
index,
|
|
2726
|
+
agent: task.agent,
|
|
2727
|
+
task: input.taskTexts[index] ?? "(skipped)",
|
|
2728
|
+
exitCode: 1,
|
|
2729
|
+
messages: [],
|
|
2730
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 },
|
|
2731
|
+
error: usageBudgetExceededMessage(budgetState),
|
|
2732
|
+
skipped: true,
|
|
2733
|
+
} as SingleResult;
|
|
2734
|
+
}
|
|
2582
2735
|
const behavior = input.behaviors[index];
|
|
2583
2736
|
const effectiveSkills = behavior?.skills;
|
|
2584
2737
|
const taskCwd = resolveParallelTaskCwd(task, input.paramsCwd, input.worktreeSetup, index);
|
|
@@ -2597,10 +2750,14 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2597
2750
|
);
|
|
2598
2751
|
const interruptController = new AbortController();
|
|
2599
2752
|
if (input.foregroundControl) {
|
|
2753
|
+
const model = input.modelOverrides[index];
|
|
2754
|
+
const thinking = resolveEffectiveThinking(model, input.thinkingOverrideForTask(task.agent, index, model));
|
|
2600
2755
|
beginForegroundChild(input.foregroundControl, {
|
|
2601
2756
|
index,
|
|
2602
2757
|
agent: task.agent,
|
|
2603
2758
|
description: input.taskDescriptions[index],
|
|
2759
|
+
...(model ? { model } : {}),
|
|
2760
|
+
...(thinking ? { thinking } : {}),
|
|
2604
2761
|
interrupt: () => {
|
|
2605
2762
|
if (interruptController.signal.aborted) return false;
|
|
2606
2763
|
interruptController.abort();
|
|
@@ -2611,7 +2768,8 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2611
2768
|
const structuredRuntime = task.outputSchema
|
|
2612
2769
|
? createStructuredOutputRuntime(task.outputSchema, path.join(input.artifactsDir, "structured-output", input.runId))
|
|
2613
2770
|
: undefined;
|
|
2614
|
-
|
|
2771
|
+
let detachedReceipt = false;
|
|
2772
|
+
const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskText, {
|
|
2615
2773
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
2616
2774
|
context: input.contextPolicy.contextForAgent(task.agent),
|
|
2617
2775
|
cwd: taskCwd,
|
|
@@ -2634,14 +2792,24 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2634
2792
|
capabilityCeiling: input.capabilityCeiling,
|
|
2635
2793
|
controlConfig: input.controlConfig,
|
|
2636
2794
|
onControlEvent: input.onControlEvent,
|
|
2637
|
-
onDetachedExit: (result) =>
|
|
2795
|
+
onDetachedExit: (result) => {
|
|
2796
|
+
try {
|
|
2797
|
+
updateRememberedForegroundChild(input.state, { runId: input.runId, mode: "parallel", cwd: taskCwd, sessionId: input.parentSessionId, index, result, events: input.intercomEvents });
|
|
2798
|
+
} finally {
|
|
2799
|
+
try {
|
|
2800
|
+
if (input.foregroundControl) finishForegroundChild(input.foregroundControl, index);
|
|
2801
|
+
} finally {
|
|
2802
|
+
removeForegroundControlIfIdle(input.state, input.runId);
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
},
|
|
2638
2806
|
intercomSessionName: input.childIntercomTarget?.(task.agent, index),
|
|
2639
2807
|
orchestratorIntercomTarget: input.orchestratorIntercomTarget,
|
|
2640
2808
|
nestedRoute: input.foregroundControl?.nestedRoute,
|
|
2641
2809
|
modelOverride: input.modelOverrides[index],
|
|
2642
2810
|
thinkingOverride: input.thinkingOverrideForTask(task.agent, index, input.modelOverrides[index]),
|
|
2643
2811
|
availableModels: input.availableModels,
|
|
2644
|
-
preferredModelProvider: input.
|
|
2812
|
+
preferredModelProvider: input.parentModel?.provider,
|
|
2645
2813
|
modelScope: input.modelScope,
|
|
2646
2814
|
skills: effectiveSkills === false ? [] : effectiveSkills,
|
|
2647
2815
|
structuredOutput: structuredRuntime,
|
|
@@ -2675,10 +2843,24 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
2675
2843
|
});
|
|
2676
2844
|
}
|
|
2677
2845
|
: undefined,
|
|
2846
|
+
}).then((result) => {
|
|
2847
|
+
detachedReceipt = result.detached === true;
|
|
2848
|
+
return result;
|
|
2678
2849
|
}).finally(() => {
|
|
2679
|
-
|
|
2850
|
+
// mapConcurrent rejects before siblings settle, so every attached child
|
|
2851
|
+
// attempts idle removal after releasing its own control. Detached receipts
|
|
2852
|
+
// transfer both responsibilities to the authoritative exit callback.
|
|
2853
|
+
if (!detachedReceipt) {
|
|
2854
|
+
if (input.foregroundControl) finishForegroundChild(input.foregroundControl, index);
|
|
2855
|
+
removeForegroundControlIfIdle(input.state, input.runId);
|
|
2856
|
+
}
|
|
2680
2857
|
});
|
|
2681
|
-
|
|
2858
|
+
completedResults.push(result);
|
|
2859
|
+
return result;
|
|
2860
|
+
}, input.globalSemaphore, () => {
|
|
2861
|
+
if (input.foregroundControl) settleForegroundSchedulingOwner(input.foregroundControl);
|
|
2862
|
+
removeForegroundControlIfIdle(input.state, input.runId);
|
|
2863
|
+
});
|
|
2682
2864
|
}
|
|
2683
2865
|
|
|
2684
2866
|
async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps): Promise<AgentToolResult<Details>> {
|
|
@@ -2746,7 +2928,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
2746
2928
|
if (worktreeTaskCwdError) return buildParallelModeError(worktreeTaskCwdError);
|
|
2747
2929
|
}
|
|
2748
2930
|
|
|
2749
|
-
const
|
|
2931
|
+
const parentModel = data.parentModel;
|
|
2932
|
+
const currentProvider = parentModel?.provider;
|
|
2750
2933
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
2751
2934
|
let taskTexts = tasks.map((t) => t.task);
|
|
2752
2935
|
const skillOverrides: (string[] | false | undefined)[] = tasks.map((t) =>
|
|
@@ -2761,7 +2944,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
2761
2944
|
...(task.model !== undefined ? { model: task.model } : {}),
|
|
2762
2945
|
}));
|
|
2763
2946
|
const modelOverrides: (string | undefined)[] = tasks.map((_, i) =>
|
|
2764
|
-
resolveEffectiveSubagentModel(behaviorOverrides[i]?.model, agentConfigs[i]?.model,
|
|
2947
|
+
resolveEffectiveSubagentModel(behaviorOverrides[i]?.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, { scope: data.modelScope }),
|
|
2765
2948
|
);
|
|
2766
2949
|
|
|
2767
2950
|
if (params.clarify === true && ctx.hasUI) {
|
|
@@ -2796,7 +2979,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
2796
2979
|
for (let i = 0; i < result.behaviorOverrides.length; i++) {
|
|
2797
2980
|
const override = result.behaviorOverrides[i];
|
|
2798
2981
|
if (override?.model !== undefined) {
|
|
2799
|
-
modelOverrides[i] = resolveEffectiveSubagentModel(override.model, agentConfigs[i]?.model,
|
|
2982
|
+
modelOverrides[i] = resolveEffectiveSubagentModel(override.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, { scope: data.modelScope });
|
|
2800
2983
|
behaviorOverrides[i]!.model = override.model;
|
|
2801
2984
|
}
|
|
2802
2985
|
if (override?.output !== undefined) behaviorOverrides[i]!.output = override.output;
|
|
@@ -2822,8 +3005,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
2822
3005
|
cwd: ctx.cwd,
|
|
2823
3006
|
currentSessionId: deps.state.currentSessionId!,
|
|
2824
3007
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
2825
|
-
currentModelProvider:
|
|
2826
|
-
currentModel:
|
|
3008
|
+
currentModelProvider: parentModel?.provider,
|
|
3009
|
+
currentModel: parentModel,
|
|
2827
3010
|
modelScope: data.modelScope,
|
|
2828
3011
|
interactive: ctx.hasUI,
|
|
2829
3012
|
};
|
|
@@ -2875,6 +3058,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
2875
3058
|
nestedRoute: data.nestedRoute,
|
|
2876
3059
|
timeoutMs: data.timeoutMs,
|
|
2877
3060
|
turnBudget: data.turnBudget,
|
|
3061
|
+
usageBudget: data.usageBudget,
|
|
2878
3062
|
toolBudget: data.toolBudget,
|
|
2879
3063
|
configToolBudget: data.configToolBudget,
|
|
2880
3064
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -2958,6 +3142,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
2958
3142
|
progressDir: parallelProgressDir,
|
|
2959
3143
|
availableModels,
|
|
2960
3144
|
modelScope: data.modelScope,
|
|
3145
|
+
parentModel,
|
|
2961
3146
|
modelOverrides,
|
|
2962
3147
|
behaviors,
|
|
2963
3148
|
firstProgressIndex: parallelProgressPrecreated ? -1 : firstProgressIndex,
|
|
@@ -2978,6 +3163,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
2978
3163
|
timeoutMs: data.timeoutMs,
|
|
2979
3164
|
deadlineAt,
|
|
2980
3165
|
turnBudget: data.turnBudget,
|
|
3166
|
+
usageBudget: data.usageBudget,
|
|
2981
3167
|
toolBudgets,
|
|
2982
3168
|
agentContract: params.agentContract,
|
|
2983
3169
|
});
|
|
@@ -3001,14 +3187,17 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3001
3187
|
handoff = finalizeParallelWorktreeHandoff({ worktreeSetup, artifactsDir, runId, cwd: effectiveCwd, tasks, results });
|
|
3002
3188
|
}
|
|
3003
3189
|
const interrupted = results.find((result) => result.interrupted);
|
|
3190
|
+
const totalCost = sumResultsCost(results);
|
|
3004
3191
|
const details = compactForegroundDetails({
|
|
3005
3192
|
mode: "parallel",
|
|
3006
3193
|
runId,
|
|
3194
|
+
timeoutMs: data.timeoutMs,
|
|
3007
3195
|
results,
|
|
3008
3196
|
progress: params.includeProgress ? allProgress : undefined,
|
|
3009
3197
|
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
3010
3198
|
totalChildUsage: sumResultsUsage(results),
|
|
3011
|
-
totalCost
|
|
3199
|
+
totalCost,
|
|
3200
|
+
usageBudget: usageBudgetState(data.usageBudget, totalCost),
|
|
3012
3201
|
...(handoff?.reference ? { parallelHandoff: handoff.reference } : {}),
|
|
3013
3202
|
});
|
|
3014
3203
|
rememberForegroundRun(deps.state, { runId, mode: "parallel", cwd: effectiveCwd, sessionId: data.parentSessionId, results: details.results });
|
|
@@ -3105,13 +3294,14 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3105
3294
|
const effectiveToolBudget = resolveEffectiveToolBudget({ runBudget: data.toolBudget, agentBudget: agentConfig.toolBudget, configBudget: data.configToolBudget });
|
|
3106
3295
|
if (effectiveToolBudget.error) return toExecutionErrorResult(params, new Error(effectiveToolBudget.error), data.contextPolicy.contextSummary);
|
|
3107
3296
|
|
|
3108
|
-
const
|
|
3297
|
+
const parentModel = data.parentModel;
|
|
3298
|
+
const currentProvider = parentModel?.provider;
|
|
3109
3299
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
3110
3300
|
let task = params.task ?? "";
|
|
3111
3301
|
let modelOverride: string | undefined = resolveEffectiveSubagentModel(
|
|
3112
3302
|
params.model as string | undefined,
|
|
3113
3303
|
agentConfig.model,
|
|
3114
|
-
|
|
3304
|
+
parentModel,
|
|
3115
3305
|
availableModels,
|
|
3116
3306
|
currentProvider,
|
|
3117
3307
|
{ scope: data.modelScope },
|
|
@@ -3151,7 +3341,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3151
3341
|
|
|
3152
3342
|
task = result.templates[0]!;
|
|
3153
3343
|
const override = result.behaviorOverrides[0];
|
|
3154
|
-
if (override?.model !== undefined) modelOverride = resolveEffectiveSubagentModel(override.model, agentConfig.model,
|
|
3344
|
+
if (override?.model !== undefined) modelOverride = resolveEffectiveSubagentModel(override.model, agentConfig.model, parentModel, availableModels, currentProvider, { scope: data.modelScope });
|
|
3155
3345
|
if (override?.output !== undefined) effectiveOutput = normalizeSingleOutputOverride(override.output, agentConfig.output);
|
|
3156
3346
|
if (override?.skills !== undefined) skillOverride = override.skills;
|
|
3157
3347
|
|
|
@@ -3169,8 +3359,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3169
3359
|
cwd: ctx.cwd,
|
|
3170
3360
|
currentSessionId: deps.state.currentSessionId!,
|
|
3171
3361
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
3172
|
-
currentModelProvider:
|
|
3173
|
-
currentModel:
|
|
3362
|
+
currentModelProvider: parentModel?.provider,
|
|
3363
|
+
currentModel: parentModel,
|
|
3174
3364
|
modelScope: data.modelScope,
|
|
3175
3365
|
interactive: ctx.hasUI,
|
|
3176
3366
|
};
|
|
@@ -3210,6 +3400,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3210
3400
|
timeoutMs: data.timeoutMs,
|
|
3211
3401
|
turnBudget: data.turnBudget,
|
|
3212
3402
|
toolBudget: effectiveToolBudget.toolBudget,
|
|
3403
|
+
usageBudget: data.usageBudget,
|
|
3213
3404
|
allowZeroToolBudget: data.allowZeroToolBudget && effectiveToolBudget.toolBudget === data.toolBudget,
|
|
3214
3405
|
});
|
|
3215
3406
|
}
|
|
@@ -3236,17 +3427,22 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3236
3427
|
effectiveSkills = skillOverride;
|
|
3237
3428
|
}
|
|
3238
3429
|
const interruptController = new AbortController();
|
|
3430
|
+
let detachForeground: ((reason?: string) => boolean) | undefined;
|
|
3239
3431
|
const foregroundControl = deps.state.foregroundControls.get(runId);
|
|
3240
3432
|
if (foregroundControl) {
|
|
3433
|
+
const thinking = resolveEffectiveThinking(modelOverride, thinkingOverrideForTask(params.agent!, 0, modelOverride));
|
|
3241
3434
|
beginForegroundChild(foregroundControl, {
|
|
3242
3435
|
index: 0,
|
|
3243
3436
|
agent: params.agent!,
|
|
3244
3437
|
description: foregroundControl.description,
|
|
3438
|
+
...(modelOverride ? { model: modelOverride } : {}),
|
|
3439
|
+
...(thinking ? { thinking } : {}),
|
|
3245
3440
|
interrupt: () => {
|
|
3246
3441
|
if (interruptController.signal.aborted) return false;
|
|
3247
3442
|
interruptController.abort();
|
|
3248
3443
|
return true;
|
|
3249
3444
|
},
|
|
3445
|
+
detach: () => detachForeground?.("user request") === true,
|
|
3250
3446
|
});
|
|
3251
3447
|
}
|
|
3252
3448
|
|
|
@@ -3296,7 +3492,29 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3296
3492
|
agentContract: params.agentContract,
|
|
3297
3493
|
acceptance: params.acceptance,
|
|
3298
3494
|
acceptanceContext: { mode: "single" },
|
|
3299
|
-
|
|
3495
|
+
onDetachReady: (detach) => {
|
|
3496
|
+
detachForeground = detach;
|
|
3497
|
+
},
|
|
3498
|
+
onDetachedExit: (result) => {
|
|
3499
|
+
try {
|
|
3500
|
+
try {
|
|
3501
|
+
updateRememberedForegroundChild(deps.state, { runId, mode: "single", cwd: effectiveCwd, sessionId: data.parentSessionId, index: 0, result, events: deps.pi.events });
|
|
3502
|
+
} catch {
|
|
3503
|
+
// Remembered foreground state is best-effort; run history and cleanup must still complete.
|
|
3504
|
+
}
|
|
3505
|
+
} finally {
|
|
3506
|
+
try {
|
|
3507
|
+
if (!artifactConfig.enabled) cleanupStructuredOutputRuntime(structuredRuntime);
|
|
3508
|
+
} finally {
|
|
3509
|
+
try {
|
|
3510
|
+
if (foregroundControl) finishForegroundChild(foregroundControl, 0);
|
|
3511
|
+
} finally {
|
|
3512
|
+
removeForegroundControlIfIdle(deps.state, runId);
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
recordRun(params.agent!, cleanTask, result.exitCode, result.progressSummary?.durationMs ?? 0);
|
|
3517
|
+
},
|
|
3300
3518
|
timeoutMs: data.timeoutMs,
|
|
3301
3519
|
deadlineAt,
|
|
3302
3520
|
turnBudget: data.turnBudget,
|
|
@@ -3306,10 +3524,17 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3306
3524
|
allowZeroToolBudget: data.allowZeroToolBudget && effectiveToolBudget.toolBudget === data.toolBudget,
|
|
3307
3525
|
});
|
|
3308
3526
|
} finally {
|
|
3309
|
-
|
|
3527
|
+
// An attached runSync rejection still owns its child and structured runtime.
|
|
3528
|
+
// A successful detached receipt transfers both to onDetachedExit while the
|
|
3529
|
+
// authoritative completion remains live.
|
|
3530
|
+
if (!r?.detached) {
|
|
3531
|
+
if (!artifactConfig.enabled) cleanupStructuredOutputRuntime(structuredRuntime);
|
|
3532
|
+
if (foregroundControl) finishForegroundChild(foregroundControl, 0);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
if (!r.detached) {
|
|
3536
|
+
recordRun(params.agent!, cleanTask, r.exitCode, r.progressSummary?.durationMs ?? 0);
|
|
3310
3537
|
}
|
|
3311
|
-
if (foregroundControl) finishForegroundChild(foregroundControl, 0);
|
|
3312
|
-
recordRun(params.agent!, cleanTask, r.exitCode, r.progressSummary?.durationMs ?? 0);
|
|
3313
3538
|
|
|
3314
3539
|
if (r.progress) allProgress.push(r.progress);
|
|
3315
3540
|
if (r.artifactPaths) allArtifactPaths.push(r.artifactPaths);
|
|
@@ -3329,9 +3554,11 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3329
3554
|
updateForegroundNestedProjection(foregroundControl);
|
|
3330
3555
|
attachRootChildrenToSteps(runId, [r], foregroundControl.nestedChildren);
|
|
3331
3556
|
}
|
|
3557
|
+
const totalCost = sumResultsCost([r]);
|
|
3332
3558
|
const details = compactForegroundDetails({
|
|
3333
3559
|
mode: "single",
|
|
3334
3560
|
runId,
|
|
3561
|
+
timeoutMs: data.timeoutMs,
|
|
3335
3562
|
results: [r],
|
|
3336
3563
|
...(data.turnBudget ? { turnBudget: data.turnBudget } : {}),
|
|
3337
3564
|
...(effectiveToolBudget.toolBudget ? { toolBudget: effectiveToolBudget.toolBudget } : {}),
|
|
@@ -3339,7 +3566,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3339
3566
|
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
3340
3567
|
truncation: r.truncation,
|
|
3341
3568
|
totalChildUsage: sumResultsUsage([r]),
|
|
3342
|
-
totalCost
|
|
3569
|
+
totalCost,
|
|
3570
|
+
usageBudget: usageBudgetState(data.usageBudget, totalCost),
|
|
3343
3571
|
});
|
|
3344
3572
|
rememberForegroundRun(deps.state, { runId, mode: "single", cwd: effectiveCwd, sessionId: data.parentSessionId, results: details.results });
|
|
3345
3573
|
|
|
@@ -3460,6 +3688,13 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3460
3688
|
const requestCwd = resolveRequestedCwd(ctx.cwd, requestParams.cwd);
|
|
3461
3689
|
const paramsWithResolvedCwd = requestParams.cwd === undefined ? requestParams : { ...requestParams, cwd: requestCwd };
|
|
3462
3690
|
const action = paramsWithResolvedCwd.action;
|
|
3691
|
+
let requestParentModel: ParentModel | undefined;
|
|
3692
|
+
try {
|
|
3693
|
+
requestParentModel = rememberParentModel(deps.state, resolveCurrentSessionId(ctx.sessionManager), ctx.model);
|
|
3694
|
+
} catch (error) {
|
|
3695
|
+
if (action?.toLowerCase() !== "doctor") throw error;
|
|
3696
|
+
requestParentModel = normalizeParentModel(ctx.model);
|
|
3697
|
+
}
|
|
3463
3698
|
if (action) {
|
|
3464
3699
|
if ((WATCHDOG_TOOL_ACTIONS as readonly string[]).includes(action)) {
|
|
3465
3700
|
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
|
|
@@ -3616,8 +3851,61 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3616
3851
|
}
|
|
3617
3852
|
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, { state: deps.state, nested: nestedScope, sessionRoots }));
|
|
3618
3853
|
}
|
|
3854
|
+
|
|
3855
|
+
if (action === "approve-checkpoint" || action === "reject-checkpoint") {
|
|
3856
|
+
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
3857
|
+
const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
|
|
3858
|
+
if (!targetRunId && !paramsWithResolvedCwd.dir) {
|
|
3859
|
+
return { content: [{ type: "text", text: `action='${action}' requires id or dir.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3860
|
+
}
|
|
3861
|
+
try {
|
|
3862
|
+
const resolved = targetRunId ? resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) }) : undefined;
|
|
3863
|
+
const decision = action === "approve-checkpoint" ? "approved" : "rejected";
|
|
3864
|
+
if (resolved?.kind === "foreground") {
|
|
3865
|
+
const run = deps.state.foregroundRuns?.get(resolved.id);
|
|
3866
|
+
if (!run?.checkpoint || run.checkpoint.status !== "pending") {
|
|
3867
|
+
return { content: [{ type: "text", text: `Run '${resolved.id}' is not paused at an approval checkpoint.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3868
|
+
}
|
|
3869
|
+
if (deps.state.currentSessionId && run.sessionId !== deps.state.currentSessionId) {
|
|
3870
|
+
return { content: [{ type: "text", text: `Run '${resolved.id}' was not found in the active session.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3871
|
+
}
|
|
3872
|
+
const decidedAt = Date.now();
|
|
3873
|
+
const checkpoint = { ...run.checkpoint, status: decision, ...(decision === "approved" ? { approvedAt: decidedAt } : { rejectedAt: decidedAt }) };
|
|
3874
|
+
run.checkpoint = checkpoint;
|
|
3875
|
+
run.updatedAt = decidedAt;
|
|
3876
|
+
return {
|
|
3877
|
+
content: [{ type: "text", text: `Checkpoint '${checkpoint.name}' ${decision} for foreground run ${resolved.id}.` }],
|
|
3878
|
+
details: { mode: "management", results: [], checkpoint },
|
|
3879
|
+
};
|
|
3880
|
+
}
|
|
3881
|
+
const location = paramsWithResolvedCwd.dir
|
|
3882
|
+
? resolveAsyncRunLocation(paramsWithResolvedCwd, ASYNC_DIR, RESULTS_DIR)
|
|
3883
|
+
: resolved?.kind === "async"
|
|
3884
|
+
? resolved.location
|
|
3885
|
+
: undefined;
|
|
3886
|
+
if (!location?.asyncDir) {
|
|
3887
|
+
return { content: [{ type: "text", text: `action='${action}' targets paused foreground or async checkpoints. No matching run found.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3888
|
+
}
|
|
3889
|
+
const status = readStatus(location.asyncDir);
|
|
3890
|
+
const runId = status?.runId ?? location.resolvedId ?? targetRunId ?? path.basename(location.asyncDir);
|
|
3891
|
+
if (!status?.checkpoint || status.state !== "paused") {
|
|
3892
|
+
return { content: [{ type: "text", text: `Run '${runId}' is not paused at an approval checkpoint.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3893
|
+
}
|
|
3894
|
+
if (deps.state.currentSessionId && status.sessionId !== deps.state.currentSessionId) {
|
|
3895
|
+
return { content: [{ type: "text", text: `Run '${runId}' was not found in the active session.` }], isError: true, details: { mode: "management", results: [] } };
|
|
3896
|
+
}
|
|
3897
|
+
deliverCheckpointDecisionRequest({ asyncDir: location.asyncDir, decision, source: "subagent-action", ...(paramsWithResolvedCwd.message ? { reason: paramsWithResolvedCwd.message } : {}) });
|
|
3898
|
+
return {
|
|
3899
|
+
content: [{ type: "text", text: `Checkpoint '${status.checkpoint.name}' ${decision} for run ${runId}.` }],
|
|
3900
|
+
details: { mode: "management", results: [], checkpoint: { ...status.checkpoint, status: decision } },
|
|
3901
|
+
};
|
|
3902
|
+
} catch (error) {
|
|
3903
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
3904
|
+
return { content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } };
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3619
3907
|
if (action === "resume") {
|
|
3620
|
-
return resumeAsyncRun({ params: paramsWithResolvedCwd, requestCwd, ctx, deps });
|
|
3908
|
+
return resumeAsyncRun({ params: paramsWithResolvedCwd, requestCwd, ctx, deps, parentModel: requestParentModel });
|
|
3621
3909
|
}
|
|
3622
3910
|
if (action === "steer") {
|
|
3623
3911
|
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
@@ -3640,7 +3928,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3640
3928
|
? {}
|
|
3641
3929
|
: {
|
|
3642
3930
|
recover: ({ absoluteDeadlineAt, ...limits }) =>
|
|
3643
|
-
resumeAsyncRun({ params: { ...limits, action: "resume", id: runId, message }, requestCwd, ctx, deps, absoluteDeadlineAt }),
|
|
3931
|
+
resumeAsyncRun({ params: { ...limits, action: "resume", id: runId, message }, requestCwd, ctx, deps, parentModel: requestParentModel, absoluteDeadlineAt }),
|
|
3644
3932
|
}
|
|
3645
3933
|
),
|
|
3646
3934
|
});
|
|
@@ -3677,6 +3965,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3677
3965
|
requestCwd,
|
|
3678
3966
|
ctx,
|
|
3679
3967
|
deps,
|
|
3968
|
+
parentModel: requestParentModel,
|
|
3680
3969
|
absoluteDeadlineAt,
|
|
3681
3970
|
}),
|
|
3682
3971
|
}
|
|
@@ -3684,7 +3973,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3684
3973
|
});
|
|
3685
3974
|
}
|
|
3686
3975
|
if (action === "append-step") {
|
|
3687
|
-
return appendStepToAsyncChain({ params: paramsWithResolvedCwd, requestCwd, ctx, deps });
|
|
3976
|
+
return appendStepToAsyncChain({ params: paramsWithResolvedCwd, requestCwd, ctx, deps, parentModel: requestParentModel });
|
|
3688
3977
|
}
|
|
3689
3978
|
if (action === "schedule" || action === "schedule-list" || action === "schedule-status" || action === "schedule-cancel") {
|
|
3690
3979
|
if (!deps.handleScheduledRunAction) {
|
|
@@ -3790,6 +4079,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3790
4079
|
...ctx,
|
|
3791
4080
|
cwd: requestCwd,
|
|
3792
4081
|
config: deps.config,
|
|
4082
|
+
currentSessionId: deps.state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined,
|
|
3793
4083
|
});
|
|
3794
4084
|
}
|
|
3795
4085
|
|
|
@@ -3827,17 +4117,19 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3827
4117
|
if (runToolBudget.error) return buildRequestedModeError(effectiveParams, runToolBudget.error);
|
|
3828
4118
|
const configToolBudget = resolveToolBudget(deps.config.toolBudget, "config.toolBudget");
|
|
3829
4119
|
if (configToolBudget.error) return buildRequestedModeError(effectiveParams, configToolBudget.error);
|
|
4120
|
+
const usageBudget = validateUsageBudgetConfig(effectiveParams.usageBudget ?? deps.config.usageBudget, effectiveParams.usageBudget ? "usageBudget" : "config.usageBudget");
|
|
4121
|
+
if (usageBudget.error) return buildRequestedModeError(effectiveParams, usageBudget.error);
|
|
3830
4122
|
|
|
3831
4123
|
const scope: AgentScope = resolveExecutionAgentScope(effectiveParams.agentScope);
|
|
3832
4124
|
const effectiveCwd = effectiveParams.cwd ?? ctx.cwd;
|
|
3833
4125
|
const parentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
|
|
3834
|
-
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
3835
4126
|
const discovered = deps.discoverAgents(effectiveCwd, scope);
|
|
3836
4127
|
const discoveredAgents = discovered.agents;
|
|
4128
|
+
const canonicalParams = canonicalizeExecutionParams(effectiveParams, discoveredAgents);
|
|
4129
|
+
if (canonicalParams.error) return buildRequestedModeError(effectiveParams, canonicalParams.error);
|
|
4130
|
+
effectiveParams = canonicalParams.params!;
|
|
3837
4131
|
const modelScope = discovered.modelScope;
|
|
3838
4132
|
effectiveParams = applySingleAgentLaunchDefaults(effectiveParams, discoveredAgents);
|
|
3839
|
-
const foregroundTimeout = resolveForegroundTimeout(effectiveParams);
|
|
3840
|
-
if (foregroundTimeout.error) return buildRequestedModeError(effectiveParams, foregroundTimeout.error);
|
|
3841
4133
|
const turnBudget = resolveTurnBudgetConfig(effectiveParams.turnBudget ?? deps.config.turnBudget);
|
|
3842
4134
|
if (turnBudget.error) return buildRequestedModeError(effectiveParams, turnBudget.error);
|
|
3843
4135
|
const contextPolicy = resolveAgentDefaultContextPolicy(effectiveParams, discoveredAgents);
|
|
@@ -3891,25 +4183,26 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3891
4183
|
const forkThinkingDowngrades = new Map<number, string>();
|
|
3892
4184
|
try {
|
|
3893
4185
|
const forkAvailableModels = contextPolicy.usesFork ? ctx.modelRegistry.getAvailable().map(toModelInfo) : [];
|
|
4186
|
+
const parentModel = requestParentModel;
|
|
3894
4187
|
prepareForkThinking = (agentName, index, modelOverride) => {
|
|
3895
4188
|
const agentConfig = agents.find((agent) => agent.name === agentName);
|
|
3896
4189
|
const primaryModel = resolveEffectiveSubagentModel(
|
|
3897
4190
|
modelOverride,
|
|
3898
4191
|
agentConfig?.model,
|
|
3899
|
-
|
|
4192
|
+
parentModel,
|
|
3900
4193
|
forkAvailableModels,
|
|
3901
|
-
|
|
4194
|
+
parentModel?.provider,
|
|
3902
4195
|
);
|
|
3903
4196
|
const candidates = buildModelCandidates(
|
|
3904
4197
|
primaryModel,
|
|
3905
4198
|
agentConfig?.fallbackModels,
|
|
3906
4199
|
forkAvailableModels,
|
|
3907
|
-
|
|
4200
|
+
parentModel?.provider,
|
|
3908
4201
|
);
|
|
3909
4202
|
forkThinkingRequirements.set(
|
|
3910
4203
|
index,
|
|
3911
4204
|
candidates.length === 0
|
|
3912
|
-
|| candidates.some((candidate) => forkedChildRequiresThinkingOff(candidate, forkAvailableModels,
|
|
4205
|
+
|| candidates.some((candidate) => forkedChildRequiresThinkingOff(candidate, forkAvailableModels, parentModel?.provider)),
|
|
3913
4206
|
);
|
|
3914
4207
|
};
|
|
3915
4208
|
const forkContextResolver = createForkContextResolver(ctx.sessionManager, contextPolicy.usesFork ? "fork" : undefined, {
|
|
@@ -3923,6 +4216,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3923
4216
|
const requestedAsync = effectiveParams.async ?? deps.asyncByDefault;
|
|
3924
4217
|
const backgroundRequestedWhileClarifying = (hasChain || hasTasks) && requestedAsync && effectiveParams.clarify === true;
|
|
3925
4218
|
const effectiveAsync = requestedAsync && effectiveParams.clarify !== true;
|
|
4219
|
+
const foregroundTimeout = resolveForegroundTimeout(
|
|
4220
|
+
effectiveParams,
|
|
4221
|
+
effectiveAsync ? undefined : DEFAULT_FOREGROUND_TIMEOUT_MS,
|
|
4222
|
+
);
|
|
4223
|
+
if (foregroundTimeout.error) return buildRequestedModeError(effectiveParams, foregroundTimeout.error);
|
|
3926
4224
|
const controlConfig = resolveControlConfig(deps.config.control, effectiveParams.control);
|
|
3927
4225
|
|
|
3928
4226
|
const artifactConfig: ArtifactConfig = {
|
|
@@ -3980,7 +4278,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
3980
4278
|
if (chainBindingsError) return withResolvedContext(chainBindingsError, contextPolicy.contextSummary);
|
|
3981
4279
|
|
|
3982
4280
|
const onUpdateWithContext = onUpdate
|
|
3983
|
-
? (r: AgentToolResult<Details>) => onUpdate(withResolvedContext(
|
|
4281
|
+
? (r: AgentToolResult<Details>) => onUpdate(withResolvedContext({
|
|
4282
|
+
...r,
|
|
4283
|
+
details: { ...r.details, runId },
|
|
4284
|
+
}, contextPolicy.contextSummary))
|
|
3984
4285
|
: undefined;
|
|
3985
4286
|
|
|
3986
4287
|
const reservation = reserveSpawnBudget(
|
|
@@ -4015,10 +4316,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4015
4316
|
timeoutMs: foregroundTimeout.timeoutMs,
|
|
4016
4317
|
turnBudget: turnBudget.turnBudget,
|
|
4017
4318
|
toolBudget: runToolBudget.toolBudget,
|
|
4319
|
+
usageBudget: usageBudget.budget,
|
|
4018
4320
|
allowZeroToolBudget,
|
|
4019
4321
|
configToolBudget: configToolBudget.toolBudget,
|
|
4020
4322
|
contextPolicy,
|
|
4021
4323
|
modelScope,
|
|
4324
|
+
parentModel: requestParentModel,
|
|
4022
4325
|
parentSessionId: deps.state.currentSessionId,
|
|
4023
4326
|
capabilityCeiling: resolveCurrentSubagentCapabilityCeiling(deps.state.currentSessionId ?? undefined),
|
|
4024
4327
|
};
|
|
@@ -4030,6 +4333,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4030
4333
|
? undefined
|
|
4031
4334
|
: {
|
|
4032
4335
|
runId,
|
|
4336
|
+
...(deps.state.currentSessionId ? { sessionId: deps.state.currentSessionId } : {}),
|
|
4033
4337
|
mode: foregroundMode,
|
|
4034
4338
|
startedAt: Date.now(),
|
|
4035
4339
|
updatedAt: Date.now(),
|
|
@@ -4039,6 +4343,8 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4039
4343
|
description: foregroundDescription,
|
|
4040
4344
|
currentActivityState: undefined,
|
|
4041
4345
|
activeChildren: new Map(),
|
|
4346
|
+
// The outer executor owns scheduling until its finally block settles.
|
|
4347
|
+
schedulingOwners: 1,
|
|
4042
4348
|
nestedRoute,
|
|
4043
4349
|
interrupt: undefined,
|
|
4044
4350
|
};
|
|
@@ -4136,11 +4442,8 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4136
4442
|
return errorResult;
|
|
4137
4443
|
} finally {
|
|
4138
4444
|
if (foregroundControl) {
|
|
4139
|
-
|
|
4140
|
-
deps.state
|
|
4141
|
-
if (deps.state.lastForegroundControlId === runId) {
|
|
4142
|
-
deps.state.lastForegroundControlId = null;
|
|
4143
|
-
}
|
|
4445
|
+
settleForegroundSchedulingOwner(foregroundControl);
|
|
4446
|
+
removeForegroundControlIfIdle(deps.state, runId);
|
|
4144
4447
|
}
|
|
4145
4448
|
}
|
|
4146
4449
|
|