@selesai/code 0.5.19 → 0.5.21
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/extensions/handoff-new.test.ts +8 -9
- package/dist/extensions/handoff-new.ts +6 -8
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
- package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
- package/dist/extensions/pi-subagents/README.md +602 -220
- package/dist/extensions/pi-subagents/banner.png +0 -0
- package/dist/extensions/pi-subagents/index.ts +1 -0
- package/dist/extensions/pi-subagents/install.mjs +3 -3
- package/dist/extensions/pi-subagents/package-lock.json +3405 -0
- package/dist/extensions/pi-subagents/package.json +26 -14
- package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
- package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
- package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
- package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
- package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
- package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
- package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
- package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
- package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
- package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
- package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
- package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
- package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
- package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
- package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
- package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
- package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
- package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
- package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
- package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
- package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
- package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
- package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
- package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
- package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
- package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
- package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
- package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
- package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
- package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
- package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
- package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
- package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
- package/dist/extensions/question/batch.ts +39 -0
- package/dist/extensions/question/dialog-adapter.ts +23 -1
- package/dist/extensions/question/index.ts +237 -7
- package/dist/extensions/question/schemas.ts +28 -15
- package/dist/extensions/question/tests/batch.test.ts +26 -0
- package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
- package/dist/extensions/question/tui-adapter.ts +2 -3
- package/dist/extensions/question/types.ts +37 -0
- package/dist/extensions/question/ui-protocol.ts +3 -3
- package/dist/skills/batch-grill-me/SKILL.md +3 -1
- package/package.json +2 -1
|
@@ -33,9 +33,11 @@ import {
|
|
|
33
33
|
import { discoverAvailableSkills, normalizeSkillInput } from "../../agents/skills.ts";
|
|
34
34
|
import { INTERCOM_BRIDGE_MARKER } from "../../intercom/intercom-bridge.ts";
|
|
35
35
|
import { runSync } from "./execution.ts";
|
|
36
|
+
import { beginForegroundChild, finishForegroundChild, updateForegroundChild } from "./foreground-control.ts";
|
|
36
37
|
import { buildChainSummary } from "../../shared/formatters.ts";
|
|
37
38
|
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, resolveChildCwd, sumResultsCost, sumResultsUsage } from "../../shared/utils.ts";
|
|
38
39
|
import { DEFAULT_GLOBAL_CONCURRENCY_LIMIT, Semaphore } from "../shared/parallel-utils.ts";
|
|
40
|
+
import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup } from "../shared/parallel-handoff.ts";
|
|
39
41
|
import { recordRun } from "../shared/run-history.ts";
|
|
40
42
|
import {
|
|
41
43
|
cleanupWorktrees,
|
|
@@ -48,11 +50,13 @@ import {
|
|
|
48
50
|
} from "../shared/worktree.ts";
|
|
49
51
|
import {
|
|
50
52
|
type ActivityState,
|
|
53
|
+
type AgentContract,
|
|
51
54
|
type AgentProgress,
|
|
52
55
|
type ArtifactConfig,
|
|
53
56
|
type ArtifactPaths,
|
|
54
57
|
type ControlEvent,
|
|
55
58
|
type Details,
|
|
59
|
+
type ForegroundRunControl,
|
|
56
60
|
type IntercomEventBus,
|
|
57
61
|
type NestedRouteInfo,
|
|
58
62
|
type ResolvedControlConfig,
|
|
@@ -63,16 +67,19 @@ import {
|
|
|
63
67
|
MAX_CONCURRENCY,
|
|
64
68
|
resolveChildMaxSubagentDepth,
|
|
65
69
|
} from "../../shared/types.ts";
|
|
66
|
-
import {
|
|
70
|
+
import { resolveEffectiveSubagentModel } from "../shared/model-fallback.ts";
|
|
67
71
|
import type { ModelScopeConfig } from "../shared/model-scope.ts";
|
|
68
|
-
import { validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
72
|
+
import { injectSingleOutputInstruction, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
69
73
|
import { buildWorkflowGraphSnapshot } from "../shared/workflow-graph.ts";
|
|
70
74
|
import { ChainOutputValidationError, outputEntryFromResult, resolveOutputReferences, validateChainOutputBindings } from "../shared/chain-outputs.ts";
|
|
71
75
|
import { createStructuredOutputRuntime } from "../shared/structured-output.ts";
|
|
72
76
|
import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection, type DynamicCollectedResult } from "../shared/dynamic-fanout.ts";
|
|
73
77
|
import { acceptanceFailureMessage, aggregateAcceptanceReport, evaluateAcceptance, resolveEffectiveAcceptance } from "../shared/acceptance.ts";
|
|
78
|
+
import { isAgentContractV1 } from "../shared/agent-contract.ts";
|
|
74
79
|
import type { ChainOutputMap } from "../../shared/types.ts";
|
|
75
80
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
81
|
+
import type { ContextMode } from "../shared/context-mode.ts";
|
|
82
|
+
import type { ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
76
83
|
|
|
77
84
|
interface ChainExecutionDetailsInput {
|
|
78
85
|
results: SingleResult[];
|
|
@@ -88,7 +95,8 @@ interface ChainExecutionDetailsInput {
|
|
|
88
95
|
outputs?: ChainOutputMap;
|
|
89
96
|
currentFlatIndex?: number;
|
|
90
97
|
dynamicChildren?: Record<number, Array<{ agent: string; label?: string; flatIndex: number; itemKey: string; outputName?: string; structured?: boolean; error?: string }>>;
|
|
91
|
-
dynamicGroupStatuses?: Record<number, { status: "pending" | "running" | "completed" | "failed" | "paused" | "detached"; error?: string; acceptance?: SingleResult["acceptance"] }>;
|
|
98
|
+
dynamicGroupStatuses?: Record<number, { status: "pending" | "running" | "completed" | "failed" | "paused" | "stopped" | "detached"; error?: string; acceptance?: SingleResult["acceptance"] }>;
|
|
99
|
+
parallelHandoff?: Details["parallelHandoff"];
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
interface ParallelChainRunInput {
|
|
@@ -109,8 +117,9 @@ interface ParallelChainRunInput {
|
|
|
109
117
|
globalTaskIndex: number;
|
|
110
118
|
sessionDirForIndex: (idx?: number) => string | undefined;
|
|
111
119
|
sessionFileForIndex?: (idx?: number) => string | undefined;
|
|
112
|
-
sessionFileForTask?: (agentName: string, idx?: number) => string | undefined;
|
|
113
|
-
thinkingOverrideForTask?: (agentName: string, idx?: number) => AgentConfig["thinking"] | undefined;
|
|
120
|
+
sessionFileForTask?: (agentName: string, idx?: number, modelOverride?: string) => string | undefined;
|
|
121
|
+
thinkingOverrideForTask?: (agentName: string, idx?: number, modelOverride?: string) => AgentConfig["thinking"] | undefined;
|
|
122
|
+
contextForAgent?: (agentName: string) => ContextMode;
|
|
114
123
|
shareEnabled: boolean;
|
|
115
124
|
artifactConfig: ArtifactConfig;
|
|
116
125
|
artifactsDir: string;
|
|
@@ -118,22 +127,10 @@ interface ParallelChainRunInput {
|
|
|
118
127
|
onUpdate?: (r: AgentToolResult<Details>) => void;
|
|
119
128
|
onControlEvent?: (event: ControlEvent) => void;
|
|
120
129
|
controlConfig: ResolvedControlConfig;
|
|
130
|
+
agentContract?: AgentContract;
|
|
121
131
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
122
132
|
orchestratorIntercomTarget?: string;
|
|
123
|
-
foregroundControl?:
|
|
124
|
-
updatedAt: number;
|
|
125
|
-
currentAgent?: string;
|
|
126
|
-
currentIndex?: number;
|
|
127
|
-
currentActivityState?: ActivityState;
|
|
128
|
-
lastActivityAt?: number;
|
|
129
|
-
currentTool?: string;
|
|
130
|
-
currentToolStartedAt?: number;
|
|
131
|
-
currentPath?: string;
|
|
132
|
-
turnCount?: number;
|
|
133
|
-
tokens?: number;
|
|
134
|
-
toolCount?: number;
|
|
135
|
-
interrupt?: () => boolean;
|
|
136
|
-
};
|
|
133
|
+
foregroundControl?: ForegroundRunControl;
|
|
137
134
|
results: SingleResult[];
|
|
138
135
|
allProgress: AgentProgress[];
|
|
139
136
|
outputs: ChainOutputMap;
|
|
@@ -152,6 +149,8 @@ interface ParallelChainRunInput {
|
|
|
152
149
|
toolBudget?: ResolvedToolBudget;
|
|
153
150
|
configToolBudget?: ToolBudgetConfig;
|
|
154
151
|
globalSemaphore?: Semaphore;
|
|
152
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
153
|
+
dynamic?: boolean;
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
function buildChainExecutionDetails(input: ChainExecutionDetailsInput): Details {
|
|
@@ -166,6 +165,7 @@ function buildChainExecutionDetails(input: ChainExecutionDetailsInput): Details
|
|
|
166
165
|
outputs: input.outputs,
|
|
167
166
|
totalChildUsage: sumResultsUsage(input.results),
|
|
168
167
|
totalCost: sumResultsCost(input.results),
|
|
168
|
+
...(input.parallelHandoff ? { parallelHandoff: input.parallelHandoff } : {}),
|
|
169
169
|
workflowGraph: buildWorkflowGraphSnapshot({
|
|
170
170
|
runId: input.runId,
|
|
171
171
|
mode: "chain",
|
|
@@ -199,17 +199,48 @@ function ensureParallelProgressFile(
|
|
|
199
199
|
return true;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
function
|
|
203
|
-
output: string
|
|
204
|
-
worktreeSetup: WorktreeSetup
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
202
|
+
function finalizeParallelWorktreeHandoff(input: {
|
|
203
|
+
output: string;
|
|
204
|
+
worktreeSetup: WorktreeSetup;
|
|
205
|
+
artifactsDir: string;
|
|
206
|
+
runId: string;
|
|
207
|
+
cwd: string;
|
|
208
|
+
stepIndex: number;
|
|
209
|
+
flatStartIndex: number;
|
|
210
|
+
agents: string[];
|
|
211
|
+
results: SingleResult[];
|
|
212
|
+
}): { output: string; reference?: NonNullable<Details["parallelHandoff"]> } {
|
|
213
|
+
const diffs = diffWorktrees(input.worktreeSetup, input.agents, path.join(input.artifactsDir, "worktree-diffs", input.runId, `step-${input.stepIndex}`));
|
|
214
|
+
const cleanup = cleanupWorktrees(input.worktreeSetup);
|
|
210
215
|
const diffSummary = formatWorktreeDiffSummary(diffs);
|
|
211
|
-
|
|
212
|
-
|
|
216
|
+
try {
|
|
217
|
+
const reference = writeParallelHandoffGroup({
|
|
218
|
+
manifestPath: parallelHandoffPath(input.artifactsDir, input.runId),
|
|
219
|
+
runId: input.runId,
|
|
220
|
+
mode: "chain",
|
|
221
|
+
source: "foreground",
|
|
222
|
+
cwd: input.cwd,
|
|
223
|
+
stepIndex: input.stepIndex,
|
|
224
|
+
flatStartIndex: input.flatStartIndex,
|
|
225
|
+
setup: input.worktreeSetup,
|
|
226
|
+
diffs,
|
|
227
|
+
cleanup,
|
|
228
|
+
results: input.results.map((result) => ({
|
|
229
|
+
agent: result.agent,
|
|
230
|
+
status: result.stopped ? "stopped" : result.detached ? "detached" : result.interrupted ? "paused" : result.exitCode === 0 ? "completed" : "failed",
|
|
231
|
+
summary: getSingleResultOutput(result) || result.error || "(no output)",
|
|
232
|
+
...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
|
|
233
|
+
...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
|
|
234
|
+
...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
|
|
235
|
+
...(result.sessionFile ? { sessionPath: result.sessionFile } : {}),
|
|
236
|
+
})),
|
|
237
|
+
});
|
|
238
|
+
const suffix = [diffSummary, formatParallelHandoffReference(reference)].filter(Boolean).join("\n\n");
|
|
239
|
+
return { output: suffix ? `${input.output}\n\n${suffix}` : input.output, reference };
|
|
240
|
+
} catch (error) {
|
|
241
|
+
const suffix = [diffSummary, formatParallelHandoffError(error)].filter(Boolean).join("\n\n");
|
|
242
|
+
return { output: suffix ? `${input.output}\n\n${suffix}` : input.output };
|
|
243
|
+
}
|
|
213
244
|
}
|
|
214
245
|
|
|
215
246
|
function resolveChainToolBudget(input: { stepBudget?: ToolBudgetConfig; runBudget?: ResolvedToolBudget; agentBudget?: ToolBudgetConfig; configBudget?: ToolBudgetConfig }): { toolBudget?: ResolvedToolBudget; error?: string } {
|
|
@@ -230,6 +261,21 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
230
261
|
const concurrency = input.step.concurrency ?? MAX_CONCURRENCY;
|
|
231
262
|
const failFast = input.step.failFast ?? false;
|
|
232
263
|
let aborted = false;
|
|
264
|
+
const effectiveModels = input.step.parallel.map((task) => {
|
|
265
|
+
const taskAgentConfig = input.agents.find((agent) => agent.name === task.agent);
|
|
266
|
+
return resolveEffectiveSubagentModel(
|
|
267
|
+
task.model,
|
|
268
|
+
taskAgentConfig?.model,
|
|
269
|
+
input.ctx.model,
|
|
270
|
+
input.availableModels,
|
|
271
|
+
input.ctx.model?.provider,
|
|
272
|
+
{ scope: input.modelScope },
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
for (let taskIndex = 0; taskIndex < input.step.parallel.length; taskIndex++) {
|
|
276
|
+
const task = input.step.parallel[taskIndex]!;
|
|
277
|
+
input.sessionFileForTask?.(task.agent, input.globalTaskIndex + taskIndex, effectiveModels[taskIndex]);
|
|
278
|
+
}
|
|
233
279
|
|
|
234
280
|
const parallelResults = await mapConcurrent(
|
|
235
281
|
input.step.parallel,
|
|
@@ -248,9 +294,10 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
248
294
|
|
|
249
295
|
const taskTemplate = input.parallelTemplates[taskIndex] ?? "{previous}";
|
|
250
296
|
const behavior = suppressProgressForReadOnlyTask(input.parallelBehaviors[taskIndex]!, taskTemplate, input.originalTask);
|
|
297
|
+
const taskAgentConfig = input.agents.find((agent) => agent.name === task.agent);
|
|
251
298
|
const templateHasPrevious = taskTemplate.includes("{previous}");
|
|
252
299
|
const { prefix, suffix } = buildChainInstructions(
|
|
253
|
-
behavior,
|
|
300
|
+
{ ...behavior, output: false },
|
|
254
301
|
input.chainDir,
|
|
255
302
|
false,
|
|
256
303
|
templateHasPrevious ? undefined : input.prev,
|
|
@@ -263,14 +310,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
263
310
|
const cleanTask = taskStr;
|
|
264
311
|
taskStr = prefix + taskStr + suffix;
|
|
265
312
|
|
|
266
|
-
const
|
|
267
|
-
const effectiveModel = resolveSubagentModelOverride(
|
|
268
|
-
task.model ?? taskAgentConfig?.model,
|
|
269
|
-
input.ctx.model,
|
|
270
|
-
input.availableModels,
|
|
271
|
-
input.ctx.model?.provider,
|
|
272
|
-
{ scope: input.modelScope, source: task.model ? "explicit" : "inherited" },
|
|
273
|
-
);
|
|
313
|
+
const effectiveModel = effectiveModels[taskIndex];
|
|
274
314
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(input.maxSubagentDepth, taskAgentConfig?.maxSubagentDepth);
|
|
275
315
|
const toolBudget = resolveChainToolBudget({ stepBudget: task.toolBudget, runBudget: input.toolBudget, agentBudget: taskAgentConfig?.toolBudget, configBudget: input.configToolBudget });
|
|
276
316
|
if (toolBudget.error) throw new Error(toolBudget.error);
|
|
@@ -282,37 +322,41 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
282
322
|
const outputPath = typeof behavior.output === "string"
|
|
283
323
|
? (path.isAbsolute(behavior.output) ? behavior.output : path.join(input.chainDir, behavior.output))
|
|
284
324
|
: undefined;
|
|
325
|
+
taskStr = injectSingleOutputInstruction(taskStr, outputPath, taskAgentConfig);
|
|
285
326
|
const interruptController = new AbortController();
|
|
327
|
+
const childIndex = input.globalTaskIndex + taskIndex;
|
|
286
328
|
if (input.foregroundControl) {
|
|
287
|
-
input.foregroundControl
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
};
|
|
329
|
+
beginForegroundChild(input.foregroundControl, {
|
|
330
|
+
index: childIndex,
|
|
331
|
+
agent: task.agent,
|
|
332
|
+
description: cleanTask.trim(),
|
|
333
|
+
interrupt: () => {
|
|
334
|
+
if (interruptController.signal.aborted) return false;
|
|
335
|
+
interruptController.abort();
|
|
336
|
+
return true;
|
|
337
|
+
},
|
|
338
|
+
});
|
|
298
339
|
}
|
|
299
340
|
|
|
300
341
|
const structuredRuntime = task.outputSchema
|
|
301
342
|
? createStructuredOutputRuntime(task.outputSchema, path.join(input.chainDir, "structured-output"))
|
|
302
343
|
: undefined;
|
|
344
|
+
const agentContract = task.agentContract ?? input.step.agentContract ?? input.agentContract;
|
|
303
345
|
const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskStr, {
|
|
304
346
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
347
|
+
capabilityCeiling: input.capabilityCeiling,
|
|
348
|
+
context: input.contextForAgent?.(task.agent),
|
|
305
349
|
cwd: taskCwd,
|
|
306
350
|
signal: input.signal,
|
|
307
351
|
interruptSignal: interruptController.signal,
|
|
308
352
|
allowIntercomDetach: taskAgentConfig?.systemPrompt?.includes(INTERCOM_BRIDGE_MARKER) === true,
|
|
309
353
|
intercomEvents: input.intercomEvents,
|
|
310
354
|
runId: input.runId,
|
|
311
|
-
index:
|
|
312
|
-
sessionDir: input.sessionDirForIndex(
|
|
313
|
-
sessionFile: input.sessionFileForTask?.(task.agent,
|
|
314
|
-
?? input.sessionFileForIndex?.(
|
|
315
|
-
thinkingOverride: input.thinkingOverrideForTask?.(task.agent,
|
|
355
|
+
index: childIndex,
|
|
356
|
+
sessionDir: input.sessionDirForIndex(childIndex),
|
|
357
|
+
sessionFile: input.sessionFileForTask?.(task.agent, childIndex, effectiveModel)
|
|
358
|
+
?? input.sessionFileForIndex?.(childIndex),
|
|
359
|
+
thinkingOverride: input.thinkingOverrideForTask?.(task.agent, childIndex, effectiveModel),
|
|
316
360
|
share: input.shareEnabled,
|
|
317
361
|
artifactsDir: input.artifactConfig.enabled ? input.artifactsDir : undefined,
|
|
318
362
|
artifactConfig: input.artifactConfig,
|
|
@@ -321,7 +365,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
321
365
|
maxSubagentDepth,
|
|
322
366
|
controlConfig: input.controlConfig,
|
|
323
367
|
onControlEvent: input.onControlEvent,
|
|
324
|
-
intercomSessionName: input.childIntercomTarget?.(task.agent,
|
|
368
|
+
intercomSessionName: input.childIntercomTarget?.(task.agent, childIndex),
|
|
325
369
|
orchestratorIntercomTarget: input.orchestratorIntercomTarget,
|
|
326
370
|
nestedRoute: input.nestedRoute,
|
|
327
371
|
modelOverride: effectiveModel,
|
|
@@ -330,13 +374,14 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
330
374
|
modelScope: input.modelScope,
|
|
331
375
|
skills: behavior.skills === false ? [] : behavior.skills,
|
|
332
376
|
structuredOutput: structuredRuntime,
|
|
377
|
+
agentContract,
|
|
333
378
|
acceptance: task.acceptance,
|
|
334
|
-
acceptanceContext: { mode: "chain" },
|
|
379
|
+
acceptanceContext: { mode: "chain", dynamic: input.dynamic && task.acceptance === undefined },
|
|
335
380
|
timeoutMs: input.timeoutMs,
|
|
336
381
|
deadlineAt: input.deadlineAt,
|
|
337
382
|
turnBudget: input.turnBudget,
|
|
338
383
|
onDetachedExit: input.onDetachedExit
|
|
339
|
-
? (result) => input.onDetachedExit?.(
|
|
384
|
+
? (result) => input.onDetachedExit?.(childIndex, result)
|
|
340
385
|
: undefined,
|
|
341
386
|
toolBudget: toolBudget.toolBudget,
|
|
342
387
|
onUpdate: input.onUpdate
|
|
@@ -344,18 +389,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
344
389
|
const stepResults = progressUpdate.details?.results || [];
|
|
345
390
|
const stepProgress = progressUpdate.details?.progress || [];
|
|
346
391
|
if (input.foregroundControl && stepProgress.length > 0) {
|
|
347
|
-
|
|
348
|
-
input.foregroundControl.currentAgent = task.agent;
|
|
349
|
-
input.foregroundControl.currentIndex = input.globalTaskIndex + taskIndex;
|
|
350
|
-
input.foregroundControl.currentActivityState = current?.activityState;
|
|
351
|
-
input.foregroundControl.lastActivityAt = current?.lastActivityAt;
|
|
352
|
-
input.foregroundControl.currentTool = current?.currentTool;
|
|
353
|
-
input.foregroundControl.currentToolStartedAt = current?.currentToolStartedAt;
|
|
354
|
-
input.foregroundControl.currentPath = current?.currentPath;
|
|
355
|
-
input.foregroundControl.turnCount = current?.turnCount;
|
|
356
|
-
input.foregroundControl.tokens = current?.tokens;
|
|
357
|
-
input.foregroundControl.toolCount = current?.toolCount;
|
|
358
|
-
input.foregroundControl.updatedAt = Date.now();
|
|
392
|
+
updateForegroundChild(input.foregroundControl, childIndex, stepProgress[0]);
|
|
359
393
|
}
|
|
360
394
|
input.onUpdate?.({
|
|
361
395
|
...progressUpdate,
|
|
@@ -374,7 +408,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
374
408
|
steps: input.chainSteps,
|
|
375
409
|
results: input.results.concat(stepResults),
|
|
376
410
|
currentStepIndex: input.stepIndex,
|
|
377
|
-
currentFlatIndex:
|
|
411
|
+
currentFlatIndex: childIndex,
|
|
378
412
|
dynamicChildren: input.dynamicChildren,
|
|
379
413
|
dynamicGroupStatuses: input.dynamicGroupStatuses,
|
|
380
414
|
}),
|
|
@@ -383,10 +417,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
383
417
|
}
|
|
384
418
|
: undefined,
|
|
385
419
|
});
|
|
386
|
-
if (input.foregroundControl
|
|
387
|
-
input.foregroundControl.interrupt = undefined;
|
|
388
|
-
input.foregroundControl.updatedAt = Date.now();
|
|
389
|
-
}
|
|
420
|
+
if (input.foregroundControl) finishForegroundChild(input.foregroundControl, childIndex);
|
|
390
421
|
|
|
391
422
|
if (result.exitCode !== 0 && failFast) {
|
|
392
423
|
aborted = true;
|
|
@@ -412,8 +443,10 @@ interface ChainExecutionParams {
|
|
|
412
443
|
shareEnabled: boolean;
|
|
413
444
|
sessionDirForIndex: (idx?: number) => string | undefined;
|
|
414
445
|
sessionFileForIndex?: (idx?: number) => string | undefined;
|
|
415
|
-
sessionFileForTask?: (agentName: string, idx?: number) => string | undefined;
|
|
416
|
-
thinkingOverrideForTask?: (agentName: string, idx?: number) => AgentConfig["thinking"] | undefined;
|
|
446
|
+
sessionFileForTask?: (agentName: string, idx?: number, modelOverride?: string) => string | undefined;
|
|
447
|
+
thinkingOverrideForTask?: (agentName: string, idx?: number, modelOverride?: string) => AgentConfig["thinking"] | undefined;
|
|
448
|
+
contextForAgent?: (agentName: string) => ContextMode;
|
|
449
|
+
modelScope?: ModelScopeConfig;
|
|
417
450
|
artifactsDir: string;
|
|
418
451
|
artifactConfig: ArtifactConfig;
|
|
419
452
|
includeProgress?: boolean;
|
|
@@ -421,22 +454,10 @@ interface ChainExecutionParams {
|
|
|
421
454
|
onUpdate?: (r: AgentToolResult<Details>) => void;
|
|
422
455
|
onControlEvent?: (event: ControlEvent) => void;
|
|
423
456
|
controlConfig: ResolvedControlConfig;
|
|
457
|
+
agentContract?: AgentContract;
|
|
424
458
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
425
459
|
orchestratorIntercomTarget?: string;
|
|
426
|
-
foregroundControl?:
|
|
427
|
-
updatedAt: number;
|
|
428
|
-
currentAgent?: string;
|
|
429
|
-
currentIndex?: number;
|
|
430
|
-
currentActivityState?: ActivityState;
|
|
431
|
-
lastActivityAt?: number;
|
|
432
|
-
currentTool?: string;
|
|
433
|
-
currentToolStartedAt?: number;
|
|
434
|
-
currentPath?: string;
|
|
435
|
-
turnCount?: number;
|
|
436
|
-
tokens?: number;
|
|
437
|
-
toolCount?: number;
|
|
438
|
-
interrupt?: () => boolean;
|
|
439
|
-
};
|
|
460
|
+
foregroundControl?: ForegroundRunControl;
|
|
440
461
|
chainSkills?: string[];
|
|
441
462
|
chainDir?: string;
|
|
442
463
|
dynamicFanoutMaxItems?: number;
|
|
@@ -453,6 +474,7 @@ interface ChainExecutionParams {
|
|
|
453
474
|
configToolBudget?: ToolBudgetConfig;
|
|
454
475
|
/** Global cap on simultaneously-running tasks within this chain. Defaults to DEFAULT_GLOBAL_CONCURRENCY_LIMIT. */
|
|
455
476
|
globalConcurrencyLimit?: number;
|
|
477
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
456
478
|
}
|
|
457
479
|
|
|
458
480
|
interface ChainExecutionResult {
|
|
@@ -506,6 +528,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
506
528
|
const dynamicGroupStatuses: ChainExecutionDetailsInput["dynamicGroupStatuses"] = {};
|
|
507
529
|
const allProgress: AgentProgress[] = [];
|
|
508
530
|
const allArtifactPaths: ArtifactPaths[] = [];
|
|
531
|
+
let parallelHandoff: Details["parallelHandoff"];
|
|
509
532
|
|
|
510
533
|
const chainAgents: string[] = chainSteps.map((step) =>
|
|
511
534
|
isParallelStep(step)
|
|
@@ -529,6 +552,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
529
552
|
outputs,
|
|
530
553
|
dynamicChildren,
|
|
531
554
|
dynamicGroupStatuses,
|
|
555
|
+
...(parallelHandoff ? { parallelHandoff } : {}),
|
|
532
556
|
...overrides,
|
|
533
557
|
});
|
|
534
558
|
|
|
@@ -627,7 +651,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
627
651
|
return {
|
|
628
652
|
...step,
|
|
629
653
|
task: result.templates[i]!,
|
|
630
|
-
...(override?.model ? { model: override.model } : {}),
|
|
654
|
+
...(override?.model !== undefined ? { model: override.model } : {}),
|
|
631
655
|
...(override?.output !== undefined ? { output: override.output } : {}),
|
|
632
656
|
...("outputMode" in step && step.outputMode !== undefined ? { outputMode: step.outputMode } : {}),
|
|
633
657
|
...(override?.reads !== undefined ? { reads: override.reads } : {}),
|
|
@@ -660,6 +684,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
660
684
|
const parallelTemplates = stepTemplates as string[];
|
|
661
685
|
const parallelCwd = resolveChildCwd(cwd ?? ctx.cwd, step.cwd);
|
|
662
686
|
let worktreeSetup: WorktreeSetup | undefined;
|
|
687
|
+
let worktreeFinalized = false;
|
|
663
688
|
if (step.worktree) {
|
|
664
689
|
const worktreeTaskCwdConflict = findWorktreeTaskCwdConflict(step.parallel, parallelCwd);
|
|
665
690
|
if (worktreeTaskCwdConflict) {
|
|
@@ -717,6 +742,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
717
742
|
sessionFileForIndex,
|
|
718
743
|
sessionFileForTask,
|
|
719
744
|
thinkingOverrideForTask,
|
|
745
|
+
contextForAgent: params.contextForAgent,
|
|
720
746
|
shareEnabled,
|
|
721
747
|
artifactConfig,
|
|
722
748
|
artifactsDir,
|
|
@@ -731,6 +757,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
731
757
|
dynamicChildren,
|
|
732
758
|
dynamicGroupStatuses,
|
|
733
759
|
controlConfig,
|
|
760
|
+
agentContract: params.agentContract,
|
|
734
761
|
onControlEvent,
|
|
735
762
|
childIntercomTarget,
|
|
736
763
|
orchestratorIntercomTarget,
|
|
@@ -753,6 +780,23 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
753
780
|
if (result.progress) allProgress.push(result.progress);
|
|
754
781
|
if (result.artifactPaths) allArtifactPaths.push(result.artifactPaths);
|
|
755
782
|
}
|
|
783
|
+
let worktreeSuffix = "";
|
|
784
|
+
if (worktreeSetup) {
|
|
785
|
+
worktreeFinalized = true;
|
|
786
|
+
const finalized = finalizeParallelWorktreeHandoff({
|
|
787
|
+
output: "",
|
|
788
|
+
worktreeSetup,
|
|
789
|
+
artifactsDir,
|
|
790
|
+
runId,
|
|
791
|
+
cwd: parallelCwd,
|
|
792
|
+
stepIndex,
|
|
793
|
+
flatStartIndex: globalTaskIndex - step.parallel.length,
|
|
794
|
+
agents: agentNames,
|
|
795
|
+
results: parallelResults,
|
|
796
|
+
});
|
|
797
|
+
if (finalized.reference) parallelHandoff = finalized.reference;
|
|
798
|
+
worktreeSuffix = finalized.output.trim();
|
|
799
|
+
}
|
|
756
800
|
const interruptedIndexInStep = parallelResults.findIndex((result) => result.interrupted);
|
|
757
801
|
const interrupted = interruptedIndexInStep >= 0 ? parallelResults[interruptedIndexInStep] : undefined;
|
|
758
802
|
if (interrupted) {
|
|
@@ -768,7 +812,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
768
812
|
const detached = detachedIndexInStep >= 0 ? parallelResults[detachedIndexInStep] : undefined;
|
|
769
813
|
if (detached) {
|
|
770
814
|
return {
|
|
771
|
-
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${detached.agent}). Reply to the supervisor request first.
|
|
815
|
+
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${detached.agent}). Reply to the supervisor request first, then wait with subagent_wait({ id: "${runId}" }). Use subagent({ action: "status", id: "${runId}" }) to recover the result; do not resume or launch a replacement while it remains detached.` }],
|
|
772
816
|
details: buildChainExecutionDetails(makeDetailsInput({
|
|
773
817
|
currentStepIndex: stepIndex,
|
|
774
818
|
currentFlatIndex: globalTaskIndex - step.parallel.length + detachedIndexInStep,
|
|
@@ -797,6 +841,24 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
797
841
|
})),
|
|
798
842
|
};
|
|
799
843
|
}
|
|
844
|
+
const acceptanceFailures = parallelResults
|
|
845
|
+
.map((result, originalIndex) => ({ result, originalIndex, task: step.parallel[originalIndex] }))
|
|
846
|
+
.filter(({ result, task }) => isAgentContractV1(task?.agentContract ?? step.agentContract ?? params.agentContract) && (task?.gateOn ?? step.gateOn) === "acceptance" && result.acceptance?.status === "rejected");
|
|
847
|
+
if (acceptanceFailures.length > 0) {
|
|
848
|
+
const acceptanceSummary = acceptanceFailures
|
|
849
|
+
.map(({ result, originalIndex }) => `- Task ${originalIndex + 1} (${result.agent}): ${acceptanceFailureMessage(result.acceptance) ?? "acceptance rejected"}`)
|
|
850
|
+
.join("\n");
|
|
851
|
+
const errorMsg = `Parallel step ${stepIndex + 1} acceptance gate failed:\n${acceptanceSummary}`;
|
|
852
|
+
const summary = buildChainSummary(chainSteps, results, chainDir, "failed", { index: stepIndex, error: errorMsg });
|
|
853
|
+
return {
|
|
854
|
+
content: [{ type: "text", text: summary }],
|
|
855
|
+
isError: true,
|
|
856
|
+
details: buildChainExecutionDetails(makeDetailsInput({
|
|
857
|
+
currentStepIndex: stepIndex,
|
|
858
|
+
currentFlatIndex: globalTaskIndex - step.parallel.length + acceptanceFailures[0]!.originalIndex,
|
|
859
|
+
})),
|
|
860
|
+
};
|
|
861
|
+
}
|
|
800
862
|
|
|
801
863
|
for (let taskIndex = 0; taskIndex < parallelResults.length; taskIndex++) {
|
|
802
864
|
const outputName = step.parallel[taskIndex]?.as;
|
|
@@ -820,14 +882,9 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
820
882
|
};
|
|
821
883
|
});
|
|
822
884
|
prev = aggregateParallelOutputs(taskResults);
|
|
823
|
-
prev =
|
|
824
|
-
prev,
|
|
825
|
-
worktreeSetup,
|
|
826
|
-
path.join(chainDir, "worktree-diffs", `step-${stepIndex}`),
|
|
827
|
-
agentNames,
|
|
828
|
-
);
|
|
885
|
+
if (worktreeSuffix) prev = `${prev}\n\n${worktreeSuffix}`;
|
|
829
886
|
} finally {
|
|
830
|
-
if (worktreeSetup) cleanupWorktrees(worktreeSetup);
|
|
887
|
+
if (worktreeSetup && !worktreeFinalized) cleanupWorktrees(worktreeSetup);
|
|
831
888
|
}
|
|
832
889
|
} else if (isDynamicParallelStep(step)) {
|
|
833
890
|
const dynamicStartIndex = globalTaskIndex;
|
|
@@ -852,7 +909,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
852
909
|
if (materialized.parallel.length === 0) {
|
|
853
910
|
const collection: DynamicCollectedResult[] = [];
|
|
854
911
|
try {
|
|
855
|
-
validateDynamicCollection(step.collect.outputSchema, collection);
|
|
912
|
+
await validateDynamicCollection(step.collect.outputSchema, collection);
|
|
856
913
|
} catch (error) {
|
|
857
914
|
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
858
915
|
dynamicGroupStatuses[stepIndex] = { status: "failed", error: message };
|
|
@@ -869,9 +926,11 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
869
926
|
const effectiveGroupAcceptance = resolveEffectiveAcceptance({
|
|
870
927
|
explicit: step.acceptance,
|
|
871
928
|
agentName: step.parallel.agent,
|
|
872
|
-
|
|
929
|
+
acceptanceRole: agents.find((agent) => agent.name === step.parallel.agent)?.acceptanceRole,
|
|
930
|
+
task: (step.parallel.task ?? originalTask ?? "").replace(/\{task\}/g, originalTask ?? ""),
|
|
873
931
|
mode: "chain",
|
|
874
932
|
dynamicGroup: true,
|
|
933
|
+
agentContract: step.agentContract ?? params.agentContract,
|
|
875
934
|
});
|
|
876
935
|
const groupAcceptance = await evaluateAcceptance({
|
|
877
936
|
acceptance: effectiveGroupAcceptance,
|
|
@@ -881,9 +940,10 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
881
940
|
notes: "Dynamic fanout produced 0 results.",
|
|
882
941
|
}),
|
|
883
942
|
cwd: cwd ?? ctx.cwd,
|
|
943
|
+
reportOptional: isAgentContractV1(step.agentContract ?? params.agentContract),
|
|
884
944
|
});
|
|
885
945
|
dynamicGroupStatuses[stepIndex].acceptance = groupAcceptance;
|
|
886
|
-
const groupAcceptanceFailure = acceptanceFailureMessage(groupAcceptance);
|
|
946
|
+
const groupAcceptanceFailure = !isAgentContractV1(step.agentContract ?? params.agentContract) || step.gateOn === "acceptance" ? acceptanceFailureMessage(groupAcceptance) : undefined;
|
|
887
947
|
if (groupAcceptanceFailure) {
|
|
888
948
|
dynamicGroupStatuses[stepIndex] = { status: "failed", error: groupAcceptanceFailure, acceptance: groupAcceptance };
|
|
889
949
|
return buildChainExecutionErrorResult(groupAcceptanceFailure, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
@@ -898,6 +958,8 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
898
958
|
parallel: materialized.parallel,
|
|
899
959
|
concurrency: step.concurrency,
|
|
900
960
|
failFast: step.failFast,
|
|
961
|
+
agentContract: step.agentContract,
|
|
962
|
+
gateOn: step.gateOn,
|
|
901
963
|
};
|
|
902
964
|
const parallelTemplates = materialized.parallel.map((task) => task.task ?? "{previous}");
|
|
903
965
|
const parallelBehaviors = resolveParallelBehaviors(dynamicParallelStep.parallel, agents, stepIndex, chainSkills)
|
|
@@ -937,6 +999,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
937
999
|
sessionFileForIndex,
|
|
938
1000
|
sessionFileForTask,
|
|
939
1001
|
thinkingOverrideForTask,
|
|
1002
|
+
contextForAgent: params.contextForAgent,
|
|
940
1003
|
shareEnabled,
|
|
941
1004
|
artifactConfig,
|
|
942
1005
|
artifactsDir,
|
|
@@ -951,6 +1014,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
951
1014
|
dynamicChildren,
|
|
952
1015
|
dynamicGroupStatuses,
|
|
953
1016
|
controlConfig,
|
|
1017
|
+
agentContract: params.agentContract,
|
|
954
1018
|
onControlEvent,
|
|
955
1019
|
childIntercomTarget,
|
|
956
1020
|
orchestratorIntercomTarget,
|
|
@@ -964,6 +1028,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
964
1028
|
toolBudget: params.toolBudget,
|
|
965
1029
|
configToolBudget: params.configToolBudget,
|
|
966
1030
|
globalSemaphore,
|
|
1031
|
+
dynamic: true,
|
|
967
1032
|
});
|
|
968
1033
|
globalTaskIndex = dynamicStartIndex + reservedDynamicItems;
|
|
969
1034
|
|
|
@@ -988,7 +1053,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
988
1053
|
const detached = detachedIndexInStep >= 0 ? parallelResults[detachedIndexInStep] : undefined;
|
|
989
1054
|
if (detached) {
|
|
990
1055
|
return {
|
|
991
|
-
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${detached.agent}). Reply to the supervisor request first.
|
|
1056
|
+
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${detached.agent}). Reply to the supervisor request first, then wait with subagent_wait({ id: "${runId}" }). Use subagent({ action: "status", id: "${runId}" }) to recover the result; do not resume or launch a replacement while it remains detached.` }],
|
|
992
1057
|
details: buildChainExecutionDetails(makeDetailsInput({
|
|
993
1058
|
currentStepIndex: stepIndex,
|
|
994
1059
|
currentFlatIndex: dynamicStartIndex + detachedIndexInStep,
|
|
@@ -1017,8 +1082,24 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1017
1082
|
})),
|
|
1018
1083
|
};
|
|
1019
1084
|
}
|
|
1085
|
+
const acceptanceFailures = parallelResults
|
|
1086
|
+
.map((result, originalIndex) => ({ result, originalIndex, task: dynamicParallelStep.parallel[originalIndex] }))
|
|
1087
|
+
.filter(({ result, task }) => isAgentContractV1(task?.agentContract ?? dynamicParallelStep.agentContract ?? params.agentContract) && (task?.gateOn ?? dynamicParallelStep.gateOn) === "acceptance" && result.acceptance?.status === "rejected");
|
|
1088
|
+
if (acceptanceFailures.length > 0) {
|
|
1089
|
+
const acceptanceSummary = acceptanceFailures
|
|
1090
|
+
.map(({ result, originalIndex }) => `- Item ${originalIndex + 1} (${result.agent}, key ${materialized.items[originalIndex]?.key ?? originalIndex}): ${acceptanceFailureMessage(result.acceptance) ?? "acceptance rejected"}`)
|
|
1091
|
+
.join("\n");
|
|
1092
|
+
const errorMsg = `Dynamic step ${stepIndex + 1} acceptance gate failed:\n${acceptanceSummary}`;
|
|
1093
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: errorMsg };
|
|
1094
|
+
const summary = buildChainSummary(chainSteps, results, chainDir, "failed", { index: stepIndex, error: errorMsg });
|
|
1095
|
+
return {
|
|
1096
|
+
content: [{ type: "text", text: summary }],
|
|
1097
|
+
isError: true,
|
|
1098
|
+
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: dynamicStartIndex + acceptanceFailures[0]!.originalIndex })),
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1020
1101
|
try {
|
|
1021
|
-
validateDynamicCollection(step.collect.outputSchema, collected);
|
|
1102
|
+
await validateDynamicCollection(step.collect.outputSchema, collected);
|
|
1022
1103
|
} catch (error) {
|
|
1023
1104
|
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
1024
1105
|
dynamicGroupStatuses[stepIndex] = { status: "failed", error: message };
|
|
@@ -1034,9 +1115,13 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1034
1115
|
const effectiveGroupAcceptance = resolveEffectiveAcceptance({
|
|
1035
1116
|
explicit: step.acceptance,
|
|
1036
1117
|
agentName: step.parallel.agent,
|
|
1037
|
-
|
|
1118
|
+
acceptanceRole: agents.find((agent) => agent.name === step.parallel.agent)?.acceptanceRole,
|
|
1119
|
+
task: materialized.parallel
|
|
1120
|
+
.map((task) => (task.task ?? originalTask ?? "").replace(/\{task\}/g, originalTask ?? ""))
|
|
1121
|
+
.join("\n"),
|
|
1038
1122
|
mode: "chain",
|
|
1039
1123
|
dynamicGroup: true,
|
|
1124
|
+
agentContract: step.agentContract ?? params.agentContract,
|
|
1040
1125
|
});
|
|
1041
1126
|
const groupAcceptance = await evaluateAcceptance({
|
|
1042
1127
|
acceptance: effectiveGroupAcceptance,
|
|
@@ -1046,9 +1131,10 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1046
1131
|
notes: `Dynamic fanout collected ${collected.length} result(s) into ${step.collect.as}.`,
|
|
1047
1132
|
}),
|
|
1048
1133
|
cwd: cwd ?? ctx.cwd,
|
|
1134
|
+
reportOptional: isAgentContractV1(step.agentContract ?? params.agentContract),
|
|
1049
1135
|
});
|
|
1050
1136
|
dynamicGroupStatuses[stepIndex].acceptance = groupAcceptance;
|
|
1051
|
-
const groupAcceptanceFailure = acceptanceFailureMessage(groupAcceptance);
|
|
1137
|
+
const groupAcceptanceFailure = effectiveGroupAcceptance.explicit && (!isAgentContractV1(step.agentContract ?? params.agentContract) || step.gateOn === "acceptance") ? acceptanceFailureMessage(groupAcceptance) : undefined;
|
|
1052
1138
|
if (groupAcceptanceFailure) {
|
|
1053
1139
|
dynamicGroupStatuses[stepIndex] = { status: "failed", error: groupAcceptanceFailure, acceptance: groupAcceptance };
|
|
1054
1140
|
return buildChainExecutionErrorResult(groupAcceptanceFailure, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex - dynamicParallelStep.parallel.length }));
|
|
@@ -1096,7 +1182,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1096
1182
|
|
|
1097
1183
|
const templateHasPrevious = stepTemplate.includes("{previous}");
|
|
1098
1184
|
const { prefix, suffix } = buildChainInstructions(
|
|
1099
|
-
behavior,
|
|
1185
|
+
{ ...behavior, output: false },
|
|
1100
1186
|
chainDir,
|
|
1101
1187
|
isFirstProgress,
|
|
1102
1188
|
templateHasPrevious ? undefined : prev,
|
|
@@ -1110,17 +1196,19 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1110
1196
|
stepTask = prefix + stepTask + suffix;
|
|
1111
1197
|
|
|
1112
1198
|
const explicitStepModel = tuiOverride?.model ?? seqStep.model;
|
|
1113
|
-
const effectiveModel =
|
|
1114
|
-
explicitStepModel
|
|
1199
|
+
const effectiveModel = resolveEffectiveSubagentModel(
|
|
1200
|
+
explicitStepModel,
|
|
1201
|
+
agentConfig.model,
|
|
1115
1202
|
ctx.model,
|
|
1116
1203
|
availableModels,
|
|
1117
1204
|
ctx.model?.provider,
|
|
1118
|
-
{ scope: modelScope
|
|
1205
|
+
{ scope: modelScope },
|
|
1119
1206
|
);
|
|
1120
1207
|
|
|
1121
1208
|
const outputPath = typeof behavior.output === "string"
|
|
1122
1209
|
? (path.isAbsolute(behavior.output) ? behavior.output : path.join(chainDir, behavior.output))
|
|
1123
1210
|
: undefined;
|
|
1211
|
+
stepTask = injectSingleOutputInstruction(stepTask, outputPath, agentConfig);
|
|
1124
1212
|
const validationError = validateFileOnlyOutputMode(behavior.outputMode, outputPath, `Chain step ${stepIndex + 1} (${seqStep.agent})`);
|
|
1125
1213
|
if (validationError) {
|
|
1126
1214
|
return buildChainExecutionErrorResult(validationError, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
@@ -1129,22 +1217,22 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1129
1217
|
const childIndex = globalTaskIndex;
|
|
1130
1218
|
const interruptController = new AbortController();
|
|
1131
1219
|
if (foregroundControl) {
|
|
1132
|
-
foregroundControl
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
};
|
|
1220
|
+
beginForegroundChild(foregroundControl, {
|
|
1221
|
+
index: childIndex,
|
|
1222
|
+
agent: seqStep.agent,
|
|
1223
|
+
description: cleanTask.trim(),
|
|
1224
|
+
interrupt: () => {
|
|
1225
|
+
if (interruptController.signal.aborted) return false;
|
|
1226
|
+
interruptController.abort();
|
|
1227
|
+
return true;
|
|
1228
|
+
},
|
|
1229
|
+
});
|
|
1143
1230
|
}
|
|
1144
1231
|
|
|
1145
1232
|
const structuredRuntime = seqStep.outputSchema
|
|
1146
1233
|
? createStructuredOutputRuntime(seqStep.outputSchema, path.join(chainDir, "structured-output"))
|
|
1147
1234
|
: undefined;
|
|
1235
|
+
const agentContract = seqStep.agentContract ?? params.agentContract;
|
|
1148
1236
|
const toolBudget = resolveChainToolBudget({ stepBudget: seqStep.toolBudget, runBudget: params.toolBudget, agentBudget: agentConfig?.toolBudget, configBudget: params.configToolBudget });
|
|
1149
1237
|
if (toolBudget.error) return buildChainExecutionErrorResult(toolBudget.error, {
|
|
1150
1238
|
results,
|
|
@@ -1164,6 +1252,8 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1164
1252
|
});
|
|
1165
1253
|
const r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
|
|
1166
1254
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
1255
|
+
capabilityCeiling: params.capabilityCeiling,
|
|
1256
|
+
context: params.contextForAgent?.(seqStep.agent),
|
|
1167
1257
|
cwd: resolveChildCwd(cwd ?? ctx.cwd, seqStep.cwd),
|
|
1168
1258
|
signal,
|
|
1169
1259
|
interruptSignal: interruptController.signal,
|
|
@@ -1172,9 +1262,9 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1172
1262
|
runId,
|
|
1173
1263
|
index: childIndex,
|
|
1174
1264
|
sessionDir: sessionDirForIndex(childIndex),
|
|
1175
|
-
sessionFile: sessionFileForTask?.(seqStep.agent, childIndex)
|
|
1265
|
+
sessionFile: sessionFileForTask?.(seqStep.agent, childIndex, effectiveModel)
|
|
1176
1266
|
?? sessionFileForIndex?.(childIndex),
|
|
1177
|
-
thinkingOverride: thinkingOverrideForTask?.(seqStep.agent, childIndex),
|
|
1267
|
+
thinkingOverride: thinkingOverrideForTask?.(seqStep.agent, childIndex, effectiveModel),
|
|
1178
1268
|
share: shareEnabled,
|
|
1179
1269
|
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
1180
1270
|
artifactConfig,
|
|
@@ -1192,6 +1282,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1192
1282
|
modelScope,
|
|
1193
1283
|
skills: behavior.skills === false ? [] : behavior.skills,
|
|
1194
1284
|
structuredOutput: structuredRuntime,
|
|
1285
|
+
agentContract,
|
|
1195
1286
|
acceptance: seqStep.acceptance,
|
|
1196
1287
|
acceptanceContext: { mode: "chain" },
|
|
1197
1288
|
timeoutMs: params.timeoutMs,
|
|
@@ -1206,18 +1297,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1206
1297
|
const stepResults = p.details?.results || [];
|
|
1207
1298
|
const stepProgress = p.details?.progress || [];
|
|
1208
1299
|
if (foregroundControl && stepProgress.length > 0) {
|
|
1209
|
-
|
|
1210
|
-
foregroundControl.currentAgent = seqStep.agent;
|
|
1211
|
-
foregroundControl.currentIndex = childIndex;
|
|
1212
|
-
foregroundControl.currentActivityState = current?.activityState;
|
|
1213
|
-
foregroundControl.lastActivityAt = current?.lastActivityAt;
|
|
1214
|
-
foregroundControl.currentTool = current?.currentTool;
|
|
1215
|
-
foregroundControl.currentToolStartedAt = current?.currentToolStartedAt;
|
|
1216
|
-
foregroundControl.currentPath = current?.currentPath;
|
|
1217
|
-
foregroundControl.turnCount = current?.turnCount;
|
|
1218
|
-
foregroundControl.tokens = current?.tokens;
|
|
1219
|
-
foregroundControl.toolCount = current?.toolCount;
|
|
1220
|
-
foregroundControl.updatedAt = Date.now();
|
|
1300
|
+
updateForegroundChild(foregroundControl, childIndex, stepProgress[0]);
|
|
1221
1301
|
}
|
|
1222
1302
|
onUpdate({
|
|
1223
1303
|
...p,
|
|
@@ -1245,10 +1325,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1245
1325
|
}
|
|
1246
1326
|
: undefined,
|
|
1247
1327
|
});
|
|
1248
|
-
if (foregroundControl
|
|
1249
|
-
foregroundControl.interrupt = undefined;
|
|
1250
|
-
foregroundControl.updatedAt = Date.now();
|
|
1251
|
-
}
|
|
1328
|
+
if (foregroundControl) finishForegroundChild(foregroundControl, childIndex);
|
|
1252
1329
|
recordRun(seqStep.agent, cleanTask, r.exitCode, r.progressSummary?.durationMs ?? 0);
|
|
1253
1330
|
|
|
1254
1331
|
globalTaskIndex++;
|
|
@@ -1264,7 +1341,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1264
1341
|
}
|
|
1265
1342
|
if (r.detached) {
|
|
1266
1343
|
return {
|
|
1267
|
-
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${r.agent}). Reply to the supervisor request first.
|
|
1344
|
+
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${r.agent}). Reply to the supervisor request first, then wait with subagent_wait({ id: "${runId}" }). Use subagent({ action: "status", id: "${runId}" }) to recover the result; do not resume or launch a replacement while it remains detached.` }],
|
|
1268
1345
|
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: childIndex })),
|
|
1269
1346
|
};
|
|
1270
1347
|
}
|
|
@@ -1280,6 +1357,17 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1280
1357
|
isError: true,
|
|
1281
1358
|
};
|
|
1282
1359
|
}
|
|
1360
|
+
if (isAgentContractV1(agentContract) && seqStep.gateOn === "acceptance" && r.acceptance?.status === "rejected") {
|
|
1361
|
+
const summary = buildChainSummary(chainSteps, results, chainDir, "failed", {
|
|
1362
|
+
index: stepIndex,
|
|
1363
|
+
error: acceptanceFailureMessage(r.acceptance) ?? "Chain acceptance gate rejected the step.",
|
|
1364
|
+
});
|
|
1365
|
+
return {
|
|
1366
|
+
content: [{ type: "text", text: summary }],
|
|
1367
|
+
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: childIndex })),
|
|
1368
|
+
isError: true,
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1283
1371
|
|
|
1284
1372
|
if (behavior.output) {
|
|
1285
1373
|
try {
|