@selesai/code 0.13.15 → 0.13.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +2 -14
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.js +3 -9
- package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
- package/dist/bun/sandbox-env-setup.d.ts +1 -0
- package/dist/bun/sandbox-env-setup.js +3 -0
- package/dist/cli/auth-command.d.ts +23 -0
- package/dist/cli/auth-command.js +102 -0
- package/dist/cli/config-selector.js +2 -1
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.js +11 -0
- package/dist/cli.js +2 -14
- package/dist/config.d.ts +3 -2
- package/dist/config.js +9 -4
- package/dist/core/agent-session-runtime.js +15 -7
- package/dist/core/agent-session.d.ts +2 -6
- package/dist/core/agent-session.js +15 -4
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -1
- package/dist/core/extensions/loader.js +3 -0
- package/dist/core/extensions/types.d.ts +16 -2
- package/dist/core/http-dispatcher.js +2 -0
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.js +4 -0
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/model-config.d.ts +15 -0
- package/dist/core/model-config.js +3 -0
- package/dist/core/model-runtime.d.ts +1 -0
- package/dist/core/model-runtime.js +5 -2
- package/dist/core/provider-composer.js +8 -2
- package/dist/core/session-export.d.ts +3 -0
- package/dist/core/session-export.js +31 -0
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.js +40 -13
- package/dist/core/skills.d.ts +1 -1
- package/dist/core/skills.js +4 -2
- package/dist/core/system-prompt.js +10 -10
- package/dist/core/tools/bash.js +3 -117
- package/dist/core/tools/edit.d.ts +1 -12
- package/dist/core/tools/edit.js +5 -163
- package/dist/core/tools/find.js +4 -55
- package/dist/core/tools/grep.js +4 -60
- package/dist/core/tools/ls.js +4 -49
- package/dist/core/tools/read.d.ts +4 -0
- package/dist/core/tools/read.js +10 -122
- package/dist/core/tools/renderers/bash.d.ts +11 -0
- package/dist/core/tools/renderers/bash.js +129 -0
- package/dist/core/tools/renderers/edit.d.ts +22 -0
- package/dist/core/tools/renderers/edit.js +166 -0
- package/dist/core/tools/renderers/find.d.ts +9 -0
- package/dist/core/tools/renderers/find.js +63 -0
- package/dist/core/tools/renderers/grep.d.ts +9 -0
- package/dist/core/tools/renderers/grep.js +68 -0
- package/dist/core/tools/renderers/index.d.ts +27 -0
- package/dist/core/tools/renderers/index.js +46 -0
- package/dist/core/tools/renderers/ls.d.ts +9 -0
- package/dist/core/tools/renderers/ls.js +57 -0
- package/dist/core/tools/renderers/read.d.ts +10 -0
- package/dist/core/tools/renderers/read.js +128 -0
- package/dist/core/tools/renderers/write.d.ts +9 -0
- package/dist/core/tools/renderers/write.js +152 -0
- package/dist/core/tools/write.js +5 -146
- package/dist/extensions/capability-gateway/index.ts +12 -1
- package/dist/extensions/capability-gateway/integration.test.ts +23 -0
- package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
- package/dist/extensions/pi-hermes-memory/README.md +16 -12
- package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
- package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
- package/dist/extensions/pi-hermes-memory/package.json +4 -4
- package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
- package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
- package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
- package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
- package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
- package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
- package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
- package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
- package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
- package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
- package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
- package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
- package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
- package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
- package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
- package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
- package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
- package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
- package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
- package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
- package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
- package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
- package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
- package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
- package/dist/extensions/pi-intercom/README.md +16 -2
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
- package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
- package/dist/extensions/pi-intercom/index.ts +1 -1
- package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
- package/dist/extensions/pi-intercom/package.json +1 -1
- package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
- package/dist/extensions/pi-intercom/project-agent.ts +1 -6
- package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
- package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
- package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
- package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
- package/dist/extensions/pi-subagents/README.md +3 -3
- package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
- package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
- package/dist/extensions/pi-subagents/agents/scout.md +1 -1
- package/dist/extensions/pi-subagents/docs/agents.md +32 -16
- package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
- package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
- package/dist/extensions/pi-subagents/docs/missions.md +2 -0
- package/dist/extensions/pi-subagents/docs/models.md +58 -1
- package/dist/extensions/pi-subagents/docs/observability.md +50 -12
- package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
- package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
- package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
- package/dist/extensions/pi-subagents/package-lock.json +747 -177
- package/dist/extensions/pi-subagents/package.json +6 -4
- package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
- package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
- package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
- package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
- package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
- package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
- package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
- package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
- package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
- package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
- package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
- package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
- package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
- package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
- package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
- package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
- package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
- package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
- package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
- package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
- package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
- package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
- package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
- package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
- package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
- package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
- package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
- package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
- package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
- package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
- package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
- package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
- package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
- package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
- package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
- package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
- package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
- package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
- package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
- package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
- package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
- package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
- package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
- package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
- package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
- package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
- package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
- package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
- package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
- package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
- package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
- package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
- package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
- package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
- package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
- package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
- package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
- package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
- package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
- package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
- package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
- package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
- package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
- package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
- package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
- package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
- package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
- package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
- package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
- package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
- package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
- package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
- package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
- package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
- package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
- package/dist/extensions/pi-web-agent/src/backends/config.ts +1 -0
- package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
- package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
- package/dist/extensions/pi-web-agent/src/types.ts +1 -1
- package/dist/extensions/pi-zentui/README.md +17 -0
- package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
- package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
- package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
- package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
- package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
- package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
- package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
- package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
- package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
- package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
- package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
- package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
- package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
- package/dist/extensions/pi-zentui/package-lock.json +277 -517
- package/dist/extensions/pi-zentui/package.json +7 -4
- package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
- package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
- package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
- package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
- package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
- package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
- package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
- package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
- package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
- package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
- package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
- package/dist/index.d.ts +1 -1
- package/dist/main.js +4 -1
- package/dist/modes/interactive/chat-viewport.d.ts +19 -0
- package/dist/modes/interactive/chat-viewport.js +27 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
- package/dist/modes/interactive/components/assistant-message.js +30 -13
- package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
- package/dist/modes/interactive/components/custom-editor.js +39 -1
- package/dist/modes/interactive/components/first-time-setup.js +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
- package/dist/modes/interactive/components/markdown-transform.js +18 -0
- package/dist/modes/interactive/components/model-selector.js +19 -17
- package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
- package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
- package/dist/modes/interactive/components/settings-selector.js +128 -20
- package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
- package/dist/modes/interactive/components/settings-submenu.js +164 -0
- package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
- package/dist/modes/interactive/components/status-indicator.js +10 -3
- package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
- package/dist/modes/interactive/components/thinking-selector.js +75 -18
- package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
- package/dist/modes/interactive/components/tool-execution.js +35 -33
- package/dist/modes/interactive/components/trust-selector.js +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts +13 -15
- package/dist/modes/interactive/interactive-mode.js +144 -80
- package/dist/modes/interactive/session-share.d.ts +15 -0
- package/dist/modes/interactive/session-share.js +183 -0
- package/dist/modes/interactive/theme/dark.json +2 -1
- package/dist/modes/interactive/theme/light.json +2 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-controller.js +5 -0
- package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
- package/dist/modes/interactive/theme/theme-json.js +129 -0
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive/theme/theme.d.ts +14 -5
- package/dist/modes/interactive/theme/theme.js +18 -119
- package/dist/modes/interactive/tui-renderer.d.ts +20 -0
- package/dist/modes/interactive/tui-renderer.js +65 -0
- package/dist/utils/exif-orientation.js +2 -3
- package/dist/utils/management-http.d.ts +24 -0
- package/dist/utils/management-http.js +53 -0
- package/dist/utils/text.d.ts +7 -0
- package/dist/utils/text.js +8 -0
- package/dist/utils/tools-manager.d.ts +1 -0
- package/dist/utils/tools-manager.js +43 -21
- package/docs/docs.json +0 -4
- package/package.json +4 -4
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
- package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
- package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
- package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
- package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
- package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
- package/dist/skills/implanger/SKILL.md +0 -70
- package/dist/skills/output/SKILL.md +0 -49
- package/dist/skills/planger/SKILL.md +0 -167
- package/dist/skills/workflow/SKILL.md +0 -95
- package/docs/workflows.md +0 -18
- /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* Core execution logic for running subagents
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { existsSync } from "node:fs";
|
|
5
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
7
6
|
import * as path from "node:path";
|
|
8
7
|
import type { Message } from "@earendil-works/pi-ai";
|
|
9
8
|
import { discoverAgents, formatUnknownAgentError, unknownAgentDiagnosticContext, type AgentConfig } from "../../agents/agents.ts";
|
|
@@ -31,7 +30,6 @@ import {
|
|
|
31
30
|
type AcceptanceLedger,
|
|
32
31
|
type ResolvedAcceptanceConfig,
|
|
33
32
|
truncateOutput,
|
|
34
|
-
getSubagentDepthEnv,
|
|
35
33
|
} from "../../shared/types.ts";
|
|
36
34
|
import {
|
|
37
35
|
DEFAULT_CONTROL_CONFIG,
|
|
@@ -60,22 +58,22 @@ import { effectiveToolTimeoutMs, formatToolTimeoutMessage, resolveToolTimeoutMs,
|
|
|
60
58
|
import { evaluateCompletionMutationGuard, expectsImplementationMutation, hasMutationToolCapability, validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
61
59
|
import { planCompletionEvidence } from "../shared/completion-evidence.ts";
|
|
62
60
|
import { planAbortRecovery } from "../shared/abort-recovery.ts";
|
|
61
|
+
import { planReadonlyModelContinuation, type LogicalRecoveryState } from "../shared/readonly-model-continuation.ts";
|
|
62
|
+
import { getReadonlySessionEvidence, requestReadonlySessionEvidence, type SettledReadonlyEvidence } from "../shared/readonly-session-evidence.ts";
|
|
63
|
+
import { getReadonlyChildModels } from "../shared/child-session.ts";
|
|
63
64
|
import { arbitrateCompletionGuardRescue } from "../shared/llm-intent-arbiter.ts";
|
|
64
|
-
import { getPiSpawnCommand } from "../shared/pi-spawn.ts";
|
|
65
65
|
import { preflightLaunchCwd } from "../shared/launch-cwd.ts";
|
|
66
66
|
import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
|
|
67
67
|
import { createOrcaProgressTab, type OrcaProgressTab } from "../shared/orca-progress-tabs.ts";
|
|
68
|
-
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
69
68
|
import { resolvePermissionRules } from "../shared/permissions.ts";
|
|
70
|
-
import { applyThinkingSuffix,
|
|
69
|
+
import { applyThinkingSuffix, deriveForkPromptCacheKey } from "../shared/child-tool-plan.ts";
|
|
71
70
|
import { deriveChildSessionName } from "../../shared/child-session-name.ts";
|
|
72
|
-
import {
|
|
73
|
-
import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV } from "../shared/capability-ceiling.ts";
|
|
71
|
+
import { assertAgentAllowedByCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
74
72
|
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
75
|
-
import { assertThinkingWithinCeiling,
|
|
76
|
-
import {
|
|
77
|
-
import { formatMidToolExitError,
|
|
78
|
-
import {
|
|
73
|
+
import { assertThinkingWithinCeiling, intersectThinkingCeilings } from "../../shared/thinking-ceiling.ts";
|
|
74
|
+
import { MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR, MISSING_STRUCTURED_OUTPUT_CALL_ERROR } from "../shared/structured-output.ts";
|
|
75
|
+
import { formatMidToolExitError, isOrdinaryToolForMidToolExit } from "../shared/process-signal.ts";
|
|
76
|
+
import { formatChildToolDiagnostic } from "../shared/tool-availability.ts";
|
|
79
77
|
import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.ts";
|
|
80
78
|
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, hasSingleOutputChangedSinceSnapshot, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
81
79
|
import {
|
|
@@ -86,14 +84,6 @@ import {
|
|
|
86
84
|
isRetryableModelFailureAttempt,
|
|
87
85
|
recordRetryableModelFailure,
|
|
88
86
|
} from "../shared/model-fallback.ts";
|
|
89
|
-
import {
|
|
90
|
-
SUBAGENT_STARTUP_RETRY_DELAYS_MS,
|
|
91
|
-
formatSubagentExtensionConflictError,
|
|
92
|
-
formatSubagentStartupRetryExhaustedError,
|
|
93
|
-
formatSubagentStartupRetryNote,
|
|
94
|
-
isRetryableSubagentStartupFailure,
|
|
95
|
-
waitForSubagentStartupRetry,
|
|
96
|
-
} from "../shared/subagent-startup-retry.ts";
|
|
97
87
|
import {
|
|
98
88
|
createMutatingFailureState,
|
|
99
89
|
didMutatingToolFail,
|
|
@@ -107,12 +97,12 @@ import {
|
|
|
107
97
|
} from "../shared/long-running-guard.ts";
|
|
108
98
|
import { acceptanceFailureMessage, buildSkippedAcceptanceLedger, evaluateAcceptance, formatAcceptancePrompt, resolveEffectiveAcceptance, stripAcceptanceReport, validateAcceptanceInput } from "../shared/acceptance.ts";
|
|
109
99
|
import { PROMPT_REDACTED } from "../../shared/utils.ts";
|
|
110
|
-
import { attachContractProjections,
|
|
100
|
+
import { attachContractProjections, isAgentContract } from "../shared/agent-contract.ts";
|
|
111
101
|
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
|
|
112
102
|
import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
|
|
113
103
|
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
114
104
|
import { consumeWorkflowChildPermit } from "../../shared/workflow-child-permit.ts";
|
|
115
|
-
import {
|
|
105
|
+
import { projectChildLifecycle, type ChildLifecycleAction, type ChildLifecycleState } from "../shared/child-lifecycle.ts";
|
|
116
106
|
import {
|
|
117
107
|
acceptChildWatchdogEvent,
|
|
118
108
|
applyChildWatchdogMessage,
|
|
@@ -120,7 +110,10 @@ import {
|
|
|
120
110
|
isChildWatchdogStatusEvent,
|
|
121
111
|
resolveChildWatchdogConfig,
|
|
122
112
|
type ChildWatchdogStateSnapshot,
|
|
113
|
+
type ChildWatchdogStatusEvent,
|
|
123
114
|
} from "../../watchdog/child-status.ts";
|
|
115
|
+
import { buildInProcessChildLaunch, createReportedChildSessionInput } from "../shared/child-launch.ts";
|
|
116
|
+
import { childSessionFactory, projectChildSessionEventForJson, type ChildSession, type ChildSessionEvent } from "../shared/child-session.ts";
|
|
124
117
|
|
|
125
118
|
const artifactOutputByResult = new WeakMap<SingleResult, string>();
|
|
126
119
|
const acceptanceOutputByResult = new WeakMap<SingleResult, string>();
|
|
@@ -288,8 +281,8 @@ function snapshotResult(result: SingleResult, progress: AgentProgress): SingleRe
|
|
|
288
281
|
/**
|
|
289
282
|
* Streaming variant of snapshotResult for `onUpdate` progress events: it drops the
|
|
290
283
|
* unbounded `messages` transcript in favour of compact tool-call summaries so a
|
|
291
|
-
* single `tool_execution_update`
|
|
292
|
-
*
|
|
284
|
+
* single `tool_execution_update` event stays small; the parent records every
|
|
285
|
+
* one in its transcript and `events.jsonl`. Non-streaming consumers such as
|
|
293
286
|
* foreground detach receipts and terminal consumers use snapshotResult directly.
|
|
294
287
|
*/
|
|
295
288
|
function snapshotStreamResult(result: SingleResult, progress: AgentProgress): SingleResult {
|
|
@@ -350,6 +343,10 @@ function structuredDelegationProgressChanged(
|
|
|
350
343
|
|
|
351
344
|
const AFTER_COMPACTION_SETTLEMENT = Symbol("afterCompactionSettlement");
|
|
352
345
|
type AbortRecoverySingleResult = SingleResult & { [AFTER_COMPACTION_SETTLEMENT]?: true };
|
|
346
|
+
const settledReadonlySource = new WeakMap<SingleResult, ChildSession>();
|
|
347
|
+
|
|
348
|
+
const STOPPED_BEFORE_COMPLETION_ERROR = "Subagent stopped before completion.";
|
|
349
|
+
|
|
353
350
|
|
|
354
351
|
async function runSingleAttempt(
|
|
355
352
|
runtimeCwd: string,
|
|
@@ -360,6 +357,7 @@ async function runSingleAttempt(
|
|
|
360
357
|
shared: {
|
|
361
358
|
sessionEnabled: boolean;
|
|
362
359
|
systemPrompt: string;
|
|
360
|
+
acceptancePrompt: string;
|
|
363
361
|
resolvedSkillNames?: string[];
|
|
364
362
|
modelCandidates?: string[];
|
|
365
363
|
skillsWarning?: string;
|
|
@@ -369,10 +367,12 @@ async function runSingleAttempt(
|
|
|
369
367
|
attemptNotes: string[];
|
|
370
368
|
outputSnapshot?: SingleOutputSnapshot;
|
|
371
369
|
originalTask?: string;
|
|
372
|
-
taskDelivery?: SubagentTaskDelivery;
|
|
373
370
|
orcaProgressTab?: OrcaProgressTab;
|
|
374
371
|
launchWarnings: { emitted: boolean };
|
|
375
372
|
verifyModel: boolean;
|
|
373
|
+
readonlyExpected?: SettledReadonlyEvidence;
|
|
374
|
+
readonlyModel?: string;
|
|
375
|
+
readonlyHandoffAllowed?: () => boolean;
|
|
376
376
|
},
|
|
377
377
|
): Promise<SingleResult> {
|
|
378
378
|
const effectiveThinking = options.thinkingOverride ?? agent.thinking;
|
|
@@ -380,9 +380,9 @@ async function runSingleAttempt(
|
|
|
380
380
|
assertThinkingWithinCeiling({ model: modelArg, configThinking: effectiveThinking, ceiling: options.thinkingCeiling, agent: agent.name, runId: options.runId });
|
|
381
381
|
const expectedModelForVerification = shared.verifyModel ? modelArg : undefined;
|
|
382
382
|
const resolvedThinking = resolveEffectiveThinking(modelArg, effectiveThinking);
|
|
383
|
-
// Display name for the child session: applied inside the child
|
|
384
|
-
//
|
|
385
|
-
//
|
|
383
|
+
// Display name for the child session: applied inside the child through its
|
|
384
|
+
// runtime config and echoed back on the result payload so hosts can label
|
|
385
|
+
// this run without reading the child's session file.
|
|
386
386
|
const childSessionName = deriveChildSessionName({ agent: agent.name, task: shared.originalTask ?? task });
|
|
387
387
|
const watchdogConfig = resolveWatchdogConfig(options.cwd ?? runtimeCwd);
|
|
388
388
|
const childWatchdog = watchdogConfig.ok
|
|
@@ -397,15 +397,12 @@ async function runSingleAttempt(
|
|
|
397
397
|
const permissionAuditPath = permissionRules && options.artifactsDir
|
|
398
398
|
? path.join(options.artifactsDir, "permission-audit", `${options.runId}-${options.index ?? 0}.jsonl`)
|
|
399
399
|
: undefined;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
task,
|
|
403
|
-
taskDelivery: shared.taskDelivery,
|
|
400
|
+
let onWatchdogStatus: ((event: ChildWatchdogStatusEvent) => void) | undefined;
|
|
401
|
+
const launch = buildInProcessChildLaunch({
|
|
404
402
|
sessionEnabled: shared.sessionEnabled,
|
|
405
403
|
sessionDir: options.sessionDir,
|
|
406
404
|
sessionFile: options.sessionFile,
|
|
407
405
|
model: modelArg,
|
|
408
|
-
thinking: effectiveThinking,
|
|
409
406
|
systemPromptMode: agent.systemPromptMode,
|
|
410
407
|
inheritProjectContext: agent.inheritProjectContext,
|
|
411
408
|
inheritGlobalContext: agent.inheritGlobalContext,
|
|
@@ -416,66 +413,45 @@ async function runSingleAttempt(
|
|
|
416
413
|
allowNestedSubagents: agent.allowNestedSubagents,
|
|
417
414
|
extensions: agent.extensions,
|
|
418
415
|
subagentOnlyExtensions: agent.subagentOnlyExtensions,
|
|
419
|
-
|
|
416
|
+
// Exact terminal protocol belongs to session resources, not compactable history.
|
|
417
|
+
systemPrompt: shared.acceptancePrompt ? `${shared.systemPrompt}\n${shared.acceptancePrompt}` : shared.systemPrompt,
|
|
420
418
|
mcpDirectTools: agent.mcpDirectTools,
|
|
421
419
|
cwd: options.cwd ?? runtimeCwd,
|
|
422
|
-
promptFileStem: agent.name,
|
|
423
420
|
intercomSessionName: options.intercomSessionName,
|
|
424
421
|
sessionName: childSessionName,
|
|
425
422
|
orchestratorIntercomTarget: options.orchestratorIntercomTarget,
|
|
426
423
|
runId: options.runId,
|
|
427
424
|
childAgentName: agent.name,
|
|
428
425
|
childIndex: options.index ?? 0,
|
|
429
|
-
|
|
430
|
-
parentControlInbox: options.nestedRoute?.controlInbox,
|
|
431
|
-
parentRootRunId: options.nestedRoute?.rootRunId,
|
|
432
|
-
parentCapabilityToken: options.nestedRoute?.capabilityToken,
|
|
426
|
+
nestedRoute: options.nestedRoute,
|
|
433
427
|
runFanoutBudget: options.runFanoutBudget,
|
|
434
428
|
parentSessionId: options.parentSessionId,
|
|
435
429
|
forkCacheKey: options.context === "fork" ? deriveForkPromptCacheKey(options.parentSessionId) : undefined,
|
|
436
|
-
steerInboxDir: options.steerInboxDir,
|
|
437
|
-
steerCapabilityPath: options.steerCapabilityPath,
|
|
438
|
-
steerAckDir: options.steerAckDir,
|
|
439
430
|
structuredOutput: options.structuredOutput,
|
|
440
431
|
fast: options.fast ?? agent.fast,
|
|
441
432
|
modelCandidates: shared.modelCandidates,
|
|
442
433
|
toolBudget: options.toolBudget,
|
|
443
|
-
allowZeroToolBudget: options.allowZeroToolBudget,
|
|
444
434
|
permissionRules,
|
|
445
435
|
permissionAuditPath,
|
|
446
436
|
childWatchdog,
|
|
437
|
+
// registerChildWatchdog returns before reading the sink when no watchdog exists.
|
|
438
|
+
watchdogStatus: childWatchdog ? (event) => onWatchdogStatus?.(event) : undefined,
|
|
447
439
|
waitToolEnabled: options.waitToolEnabled,
|
|
448
440
|
waitToolDefaultTimeoutMs: options.waitToolDefaultTimeoutMs,
|
|
449
441
|
capabilityCeiling: options.capabilityCeiling,
|
|
450
442
|
thinkingCeiling: options.thinkingCeiling,
|
|
451
|
-
|
|
443
|
+
maxSubagentDepth: options.maxSubagentDepth,
|
|
452
444
|
runtimeSnapshotHost: options.runtimeSnapshotHost,
|
|
445
|
+
inherited: options.childRuntime,
|
|
446
|
+
host: "parent",
|
|
453
447
|
});
|
|
448
|
+
const { toolPlan, capabilityAudit, warnings, launchResolvedExtensions, capture } = launch;
|
|
454
449
|
if (!shared.launchWarnings.emitted && warnings.length > 0) {
|
|
455
450
|
for (const warning of warnings) console.warn(`[pi-subagents] ${warning}`);
|
|
456
451
|
shared.launchWarnings.emitted = true;
|
|
457
452
|
}
|
|
458
453
|
|
|
459
454
|
const effectiveSystemPrompt = shared.systemPrompt;
|
|
460
|
-
const toolPlan = resolvePiLaunchToolPlan({
|
|
461
|
-
tools: agent.tools,
|
|
462
|
-
allowNestedSubagents: agent.allowNestedSubagents,
|
|
463
|
-
extensions: agent.extensions,
|
|
464
|
-
subagentOnlyExtensions: agent.subagentOnlyExtensions,
|
|
465
|
-
mcpDirectTools: agent.mcpDirectTools,
|
|
466
|
-
cwd: options.cwd ?? runtimeCwd,
|
|
467
|
-
requireReadTool: Boolean(shared.resolvedSkillNames?.length),
|
|
468
|
-
structuredOutput: Boolean(options.structuredOutput),
|
|
469
|
-
excludeTools: agent.excludeTools,
|
|
470
|
-
fast: options.fast ?? agent.fast,
|
|
471
|
-
model: modelArg,
|
|
472
|
-
modelCandidates: shared.modelCandidates,
|
|
473
|
-
capabilityCeiling: options.capabilityCeiling,
|
|
474
|
-
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
475
|
-
agentName: agent.name,
|
|
476
|
-
permissionRules,
|
|
477
|
-
runtimeSnapshotHost: options.runtimeSnapshotHost,
|
|
478
|
-
});
|
|
479
455
|
const contractTools = toolPlan.explicitToolAllowlist ? toolPlan.effectiveToolAllowlist : undefined;
|
|
480
456
|
const contractError = validateImplementationToolContract({
|
|
481
457
|
agent: agent.name,
|
|
@@ -488,7 +464,6 @@ async function runSingleAttempt(
|
|
|
488
464
|
completionGuard: agent.completionGuard,
|
|
489
465
|
});
|
|
490
466
|
if (contractError) {
|
|
491
|
-
cleanupTempDir(tempDir);
|
|
492
467
|
return {
|
|
493
468
|
index: options.index ?? 0,
|
|
494
469
|
agent: agent.name,
|
|
@@ -507,7 +482,6 @@ async function runSingleAttempt(
|
|
|
507
482
|
...(toolPlan.capabilityAudit ? { capabilityAudit: toolPlan.capabilityAudit } : {}),
|
|
508
483
|
};
|
|
509
484
|
}
|
|
510
|
-
const launchResolvedExtensions = projectLaunchResolvedChildExtensions(toolPlan);
|
|
511
485
|
const launchContractDigest = launchBindingDigest({
|
|
512
486
|
definitionDigest: agentDefinitionDigest(agent),
|
|
513
487
|
task: shared.originalTask ?? task,
|
|
@@ -554,17 +528,6 @@ async function runSingleAttempt(
|
|
|
554
528
|
...(capabilityAudit ? { capabilityAudit } : {}),
|
|
555
529
|
}, options.context);
|
|
556
530
|
const startTime = Date.now();
|
|
557
|
-
if (options.structuredOutput) {
|
|
558
|
-
const cleanupError = clearStructuredOutputCaptures(options.structuredOutput);
|
|
559
|
-
if (cleanupError) {
|
|
560
|
-
cleanupTempDir(tempDir);
|
|
561
|
-
result.exitCode = 1;
|
|
562
|
-
result.error = cleanupError;
|
|
563
|
-
result.finalOutput = cleanupError;
|
|
564
|
-
result.progressSummary = { toolCount: 0, tokens: 0, durationMs: Date.now() - startTime };
|
|
565
|
-
return result;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
531
|
const controlConfig = options.controlConfig ?? DEFAULT_CONTROL_CONFIG;
|
|
569
532
|
let interruptedByControl = false;
|
|
570
533
|
const allControlEvents: ControlEvent[] = [];
|
|
@@ -599,7 +562,6 @@ async function runSingleAttempt(
|
|
|
599
562
|
result.progress = progress;
|
|
600
563
|
const attemptTimeout = resolveAttemptTimeout(options);
|
|
601
564
|
if (attemptTimeout?.remainingMs === 0) {
|
|
602
|
-
cleanupTempDir(tempDir);
|
|
603
565
|
result.exitCode = 1;
|
|
604
566
|
result.timedOut = true;
|
|
605
567
|
result.error = attemptTimeout.message;
|
|
@@ -613,7 +575,6 @@ async function runSingleAttempt(
|
|
|
613
575
|
};
|
|
614
576
|
return result;
|
|
615
577
|
}
|
|
616
|
-
const spawnEnv = { ...process.env, ...sharedEnv, ...getSubagentDepthEnv(options.maxSubagentDepth) };
|
|
617
578
|
const mutationSnapshot = snapshotTrackedMutations(options.cwd ?? runtimeCwd);
|
|
618
579
|
let observedMutationAttempt = false;
|
|
619
580
|
let structuredOutputToolInvoked = false;
|
|
@@ -621,7 +582,6 @@ async function runSingleAttempt(
|
|
|
621
582
|
let toolAvailabilityError: string | undefined;
|
|
622
583
|
let abortedBySignal = options.signal?.aborted === true;
|
|
623
584
|
|
|
624
|
-
const spawnSpec = getPiSpawnCommand(args);
|
|
625
585
|
if (options.workflowChildPermitLaunch) {
|
|
626
586
|
const permitError = consumeWorkflowChildPermit(options.workflowChildPermitLaunch.permit, {
|
|
627
587
|
workflowRunId: options.workflowChildPermitLaunch.workflowRunId,
|
|
@@ -632,7 +592,6 @@ async function runSingleAttempt(
|
|
|
632
592
|
runner: "pi",
|
|
633
593
|
});
|
|
634
594
|
if (permitError) {
|
|
635
|
-
cleanupTempDir(tempDir);
|
|
636
595
|
result.exitCode = 1;
|
|
637
596
|
result.error = permitError;
|
|
638
597
|
result.finalOutput = permitError;
|
|
@@ -641,16 +600,13 @@ async function runSingleAttempt(
|
|
|
641
600
|
return result;
|
|
642
601
|
}
|
|
643
602
|
}
|
|
603
|
+
const childSessions = options.childSessionFactory ?? childSessionFactory();
|
|
644
604
|
let afterCompactionSettlement = false;
|
|
645
605
|
const exitCode = await new Promise<number>((resolve) => {
|
|
646
|
-
const
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
windowsHide: true,
|
|
651
|
-
});
|
|
652
|
-
const jsonlWriter = createJsonlWriter(shared.jsonlPath, proc.stdout);
|
|
653
|
-
let processClosed = false;
|
|
606
|
+
const jsonlWriter = createJsonlWriter(shared.jsonlPath, { pause() {}, resume() {} });
|
|
607
|
+
let session: ChildSession | undefined;
|
|
608
|
+
let unsubscribe: (() => void) | undefined;
|
|
609
|
+
let sessionSettled = false;
|
|
654
610
|
let lifecycleFinished = false;
|
|
655
611
|
let detached = false;
|
|
656
612
|
let intercomStarted = false;
|
|
@@ -659,26 +615,26 @@ async function runSingleAttempt(
|
|
|
659
615
|
let removeInterruptListener: (() => void) | undefined;
|
|
660
616
|
let activityTimer: NodeJS.Timeout | undefined;
|
|
661
617
|
let timeoutTimer: NodeJS.Timeout | undefined;
|
|
662
|
-
let
|
|
663
|
-
let timeoutHardKillTimer: NodeJS.Timeout | undefined;
|
|
664
|
-
let protocolHardKillTimer: NodeJS.Timeout | undefined;
|
|
618
|
+
let timeoutHardFinishTimer: NodeJS.Timeout | undefined;
|
|
665
619
|
const clearTimeoutTimers = () => {
|
|
666
620
|
if (timeoutTimer) {
|
|
667
621
|
clearTimeout(timeoutTimer);
|
|
668
622
|
timeoutTimer = undefined;
|
|
669
623
|
}
|
|
670
|
-
if (
|
|
671
|
-
clearTimeout(
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
if (timeoutHardKillTimer) {
|
|
675
|
-
clearTimeout(timeoutHardKillTimer);
|
|
676
|
-
timeoutHardKillTimer = undefined;
|
|
624
|
+
if (timeoutHardFinishTimer) {
|
|
625
|
+
clearTimeout(timeoutHardFinishTimer);
|
|
626
|
+
timeoutHardFinishTimer = undefined;
|
|
677
627
|
}
|
|
678
628
|
};
|
|
629
|
+
const abortChild = (): void => {
|
|
630
|
+
if (!session || sessionSettled || lifecycleFinished) return;
|
|
631
|
+
void session.abort().catch(() => {
|
|
632
|
+
// The session settles through its prompt promise; abort failures are not separately actionable.
|
|
633
|
+
});
|
|
634
|
+
};
|
|
679
635
|
|
|
680
636
|
const detachForeground = (reason: string): boolean => {
|
|
681
|
-
if (detached ||
|
|
637
|
+
if (detached || sessionSettled || lifecycleFinished || options.signal?.aborted) return false;
|
|
682
638
|
const receiptProgress = snapshotProgress(progress);
|
|
683
639
|
receiptProgress.status = "detached";
|
|
684
640
|
receiptProgress.durationMs = Date.now() - startTime;
|
|
@@ -713,20 +669,21 @@ async function runSingleAttempt(
|
|
|
713
669
|
}
|
|
714
670
|
if (!accepted) return false;
|
|
715
671
|
detached = true;
|
|
672
|
+
if (session) session.detached = true;
|
|
716
673
|
return true;
|
|
717
674
|
};
|
|
718
675
|
|
|
719
|
-
// If the child emits a terminal assistant stop but never
|
|
720
|
-
//
|
|
676
|
+
// If the child emits a terminal assistant stop but its run never settles
|
|
677
|
+
// (a hook is stuck), abort it after a short grace period and then finish
|
|
678
|
+
// without it.
|
|
721
679
|
const FINAL_STOP_GRACE_MS = 1000;
|
|
722
|
-
const
|
|
723
|
-
let
|
|
724
|
-
let forcedTerminationSignal = false;
|
|
680
|
+
const HARD_FINISH_MS = 3000;
|
|
681
|
+
let forcedTermination = false;
|
|
725
682
|
let cleanTerminalAssistantStopReceived = false;
|
|
726
683
|
let agentSettledReceived = false;
|
|
727
684
|
let compactionStartedReceived = false;
|
|
728
685
|
let finalDrainTimer: NodeJS.Timeout | undefined;
|
|
729
|
-
let
|
|
686
|
+
let finalHardFinishTimer: NodeJS.Timeout | undefined;
|
|
730
687
|
let watchdogTailTimer: NodeJS.Timeout | undefined;
|
|
731
688
|
let childWatchdogState: ChildWatchdogStateSnapshot | undefined;
|
|
732
689
|
const updateChildWatchdogState = (snapshot: ChildWatchdogStateSnapshot): void => {
|
|
@@ -745,9 +702,9 @@ async function runSingleAttempt(
|
|
|
745
702
|
clearTimeout(finalDrainTimer);
|
|
746
703
|
finalDrainTimer = undefined;
|
|
747
704
|
}
|
|
748
|
-
if (
|
|
749
|
-
clearTimeout(
|
|
750
|
-
|
|
705
|
+
if (finalHardFinishTimer) {
|
|
706
|
+
clearTimeout(finalHardFinishTimer);
|
|
707
|
+
finalHardFinishTimer = undefined;
|
|
751
708
|
}
|
|
752
709
|
};
|
|
753
710
|
const startFinalDrain = () => {
|
|
@@ -755,25 +712,24 @@ async function runSingleAttempt(
|
|
|
755
712
|
armWatchdogTail();
|
|
756
713
|
return;
|
|
757
714
|
}
|
|
758
|
-
if (
|
|
715
|
+
if (sessionSettled || finalDrainTimer || lifecycleFinished) return;
|
|
759
716
|
finalDrainTimer = setTimeout(() => {
|
|
760
|
-
if (lifecycleFinished ||
|
|
761
|
-
|
|
762
|
-
if (!termSent) return;
|
|
763
|
-
forcedTerminationSignal = true;
|
|
717
|
+
if (lifecycleFinished || sessionSettled) return;
|
|
718
|
+
forcedTermination = true;
|
|
764
719
|
if (!cleanTerminalAssistantStopReceived && !agentSettledReceived && !assistantError) {
|
|
765
|
-
result.error = result.error ?? `Subagent
|
|
720
|
+
result.error = result.error ?? `Subagent session did not settle within ${FINAL_STOP_GRACE_MS}ms after its terminal event. Aborting it.`;
|
|
766
721
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
722
|
+
abortChild();
|
|
723
|
+
finalHardFinishTimer = setTimeout(() => {
|
|
724
|
+
if (lifecycleFinished || sessionSettled) return;
|
|
725
|
+
settle(undefined, true);
|
|
726
|
+
}, HARD_FINISH_MS);
|
|
727
|
+
finalHardFinishTimer.unref?.();
|
|
772
728
|
}, FINAL_STOP_GRACE_MS);
|
|
773
729
|
finalDrainTimer.unref?.();
|
|
774
730
|
};
|
|
775
731
|
function armWatchdogTail(): void {
|
|
776
|
-
if ((!cleanTerminalAssistantStopReceived && !agentSettledReceived) || watchdogTailTimer || lifecycleFinished ||
|
|
732
|
+
if ((!cleanTerminalAssistantStopReceived && !agentSettledReceived) || watchdogTailTimer || lifecycleFinished || sessionSettled) return;
|
|
777
733
|
watchdogTailTimer = setTimeout(() => {
|
|
778
734
|
watchdogTailTimer = undefined;
|
|
779
735
|
updateChildWatchdogState({
|
|
@@ -799,7 +755,7 @@ async function runSingleAttempt(
|
|
|
799
755
|
const childLifecycleState: ChildLifecycleState = { compactionRetryActive: false };
|
|
800
756
|
|
|
801
757
|
const unsubscribeIntercomDetach = options.intercomEvents?.on?.(INTERCOM_DETACH_REQUEST_EVENT, (payload) => {
|
|
802
|
-
if (!options.allowIntercomDetach ||
|
|
758
|
+
if (!options.allowIntercomDetach || sessionSettled) return;
|
|
803
759
|
if (!payload || typeof payload !== "object") return;
|
|
804
760
|
const event = payload as { requestId?: unknown; runId?: unknown; agent?: unknown; childIndex?: unknown };
|
|
805
761
|
const requestId = event.requestId;
|
|
@@ -819,13 +775,8 @@ async function runSingleAttempt(
|
|
|
819
775
|
lifecycleFinished = true;
|
|
820
776
|
clearFinalDrainTimers();
|
|
821
777
|
clearWatchdogTailTimer();
|
|
822
|
-
clearStdioGuard();
|
|
823
778
|
clearTimeoutTimers();
|
|
824
779
|
clearAllToolTimeouts();
|
|
825
|
-
if (protocolHardKillTimer) {
|
|
826
|
-
clearTimeout(protocolHardKillTimer);
|
|
827
|
-
protocolHardKillTimer = undefined;
|
|
828
|
-
}
|
|
829
780
|
if (activityTimer) {
|
|
830
781
|
clearInterval(activityTimer);
|
|
831
782
|
activityTimer = undefined;
|
|
@@ -833,7 +784,16 @@ async function runSingleAttempt(
|
|
|
833
784
|
unsubscribeIntercomDetach?.();
|
|
834
785
|
removeAbortListener?.();
|
|
835
786
|
removeInterruptListener?.();
|
|
836
|
-
|
|
787
|
+
unsubscribe?.();
|
|
788
|
+
onWatchdogStatus = undefined;
|
|
789
|
+
void jsonlWriter.close().catch(() => {
|
|
790
|
+
// JSONL artifact flush is best effort.
|
|
791
|
+
});
|
|
792
|
+
// Report the run only after the child's extensions have shut down.
|
|
793
|
+
void Promise.resolve().then(() => session?.dispose()).catch(() => undefined).then(() => {
|
|
794
|
+
if (session && getReadonlySessionEvidence(session)) settledReadonlySource.set(result, session);
|
|
795
|
+
resolve(code);
|
|
796
|
+
});
|
|
837
797
|
};
|
|
838
798
|
|
|
839
799
|
const drainPendingControlEvents = (): ControlEvent[] | undefined => {
|
|
@@ -996,7 +956,7 @@ async function runSingleAttempt(
|
|
|
996
956
|
|
|
997
957
|
let lastStructuredDelegationProgressState: StructuredDelegationProgressState | undefined;
|
|
998
958
|
const emitUpdateSnapshot = (text: string) => {
|
|
999
|
-
if (!options.onUpdate ||
|
|
959
|
+
if (!options.onUpdate || sessionSettled) return;
|
|
1000
960
|
const progressSnapshot = snapshotProgress(progress);
|
|
1001
961
|
const resultSnapshot = snapshotStreamResult(result, progressSnapshot);
|
|
1002
962
|
const controlEvents = drainPendingControlEvents();
|
|
@@ -1012,7 +972,7 @@ async function runSingleAttempt(
|
|
|
1012
972
|
};
|
|
1013
973
|
|
|
1014
974
|
const fireUpdate = () => {
|
|
1015
|
-
if (!options.onUpdate ||
|
|
975
|
+
if (!options.onUpdate || sessionSettled) return;
|
|
1016
976
|
progress.durationMs = Date.now() - startTime;
|
|
1017
977
|
if (options.suppressUnchangedDelegationUpdates) {
|
|
1018
978
|
if (lastStructuredDelegationProgressState && !structuredDelegationProgressChanged(lastStructuredDelegationProgressState, progress, result)) return;
|
|
@@ -1022,20 +982,9 @@ async function runSingleAttempt(
|
|
|
1022
982
|
emitUpdateSnapshot(output || "(running...)");
|
|
1023
983
|
};
|
|
1024
984
|
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
jsonlWriter.writeLine(line);
|
|
1029
|
-
let evt: { type?: string; message?: Message; toolName?: string; toolCallId?: string; args?: unknown; willRetry?: unknown };
|
|
1030
|
-
try {
|
|
1031
|
-
evt = JSON.parse(line) as { type?: string; message?: Message; toolName?: string; toolCallId?: string; args?: unknown; willRetry?: unknown };
|
|
1032
|
-
} catch {
|
|
1033
|
-
rawStdoutTail.push(`${line}\n`);
|
|
1034
|
-
shared.transcriptWriter?.writeStdoutLine(line);
|
|
1035
|
-
shared.orcaProgressTab?.append(`${line}\n`);
|
|
1036
|
-
// Non-JSON stdout lines are expected; only structured events are parsed.
|
|
1037
|
-
return;
|
|
1038
|
-
}
|
|
985
|
+
const processEvent = (evt: ChildSessionEvent & { message?: Message; toolName?: string; toolCallId?: string; args?: unknown; willRetry?: unknown }) => {
|
|
986
|
+
if (lifecycleFinished) return;
|
|
987
|
+
jsonlWriter.writeLine(JSON.stringify(projectChildSessionEventForJson(evt)));
|
|
1039
988
|
shared.transcriptWriter?.writeChildEvent(evt);
|
|
1040
989
|
shared.orcaProgressTab?.event(evt);
|
|
1041
990
|
if (evt.type === "compaction_start") compactionStartedReceived = true;
|
|
@@ -1047,6 +996,20 @@ async function runSingleAttempt(
|
|
|
1047
996
|
compactionStartedReceived = false;
|
|
1048
997
|
afterCompactionSettlement = false;
|
|
1049
998
|
}
|
|
999
|
+
if (evt.type === "agent_start") {
|
|
1000
|
+
const diagnostic = capture.toolDiagnostic();
|
|
1001
|
+
if (diagnostic) {
|
|
1002
|
+
const message = formatChildToolDiagnostic(diagnostic, { host: "parent" });
|
|
1003
|
+
toolAvailabilityError = message;
|
|
1004
|
+
result.error = message;
|
|
1005
|
+
result.finalOutput = message;
|
|
1006
|
+
progress.status = "failed";
|
|
1007
|
+
progress.error = message;
|
|
1008
|
+
fireUpdate();
|
|
1009
|
+
abortChild();
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1050
1013
|
const lifecycleAction = projectChildLifecycle(evt, false, childLifecycleState);
|
|
1051
1014
|
if (evt.type === "agent_settled" && lifecycleAction === "start-drain") {
|
|
1052
1015
|
agentSettledReceived = true;
|
|
@@ -1150,14 +1113,18 @@ async function runSingleAttempt(
|
|
|
1150
1113
|
progress.model = evt.message.model;
|
|
1151
1114
|
if (!result.model) result.model = evt.message.model;
|
|
1152
1115
|
if (expectedModelForVerification && !hasToolCall) {
|
|
1153
|
-
const modelVerificationError = formatSubagentModelVerificationError(expectedModelForVerification, evt.message.model, options.availableModels);
|
|
1116
|
+
const modelVerificationError = formatSubagentModelVerificationError(expectedModelForVerification, evt.message.model, options.availableModels, options.modelResponseAliases);
|
|
1154
1117
|
if (modelVerificationError && !result.error) result.error = modelVerificationError;
|
|
1155
1118
|
}
|
|
1156
1119
|
}
|
|
1157
1120
|
if (evt.message.errorMessage) assistantError = evt.message.errorMessage;
|
|
1121
|
+
else if (hasToolCall && evt.message.stopReason === "toolUse") {
|
|
1122
|
+
// A recovered request can finish via a terminating tool, without a text stop.
|
|
1123
|
+
assistantError = undefined;
|
|
1124
|
+
}
|
|
1158
1125
|
const assistantText = extractTextFromContent(evt.message.content);
|
|
1159
1126
|
appendRecentOutput(progress, assistantText.split("\n").slice(-10));
|
|
1160
|
-
// Final assistant message: start the
|
|
1127
|
+
// Final assistant message: start the settle drain window.
|
|
1161
1128
|
if (terminalAssistantStop) {
|
|
1162
1129
|
if (!evt.message.errorMessage && assistantText.trim()) assistantError = undefined;
|
|
1163
1130
|
cleanTerminalAssistantStopReceived ||= !evt.message.errorMessage;
|
|
@@ -1219,11 +1186,12 @@ async function runSingleAttempt(
|
|
|
1219
1186
|
fireUpdate();
|
|
1220
1187
|
}
|
|
1221
1188
|
};
|
|
1189
|
+
onWatchdogStatus = (event) => processEvent(event as unknown as Parameters<typeof processEvent>[0]);
|
|
1222
1190
|
|
|
1223
1191
|
fireUpdate();
|
|
1224
1192
|
if (controlConfig.enabled || options.onUpdate) {
|
|
1225
1193
|
activityTimer = setInterval(() => {
|
|
1226
|
-
if (
|
|
1194
|
+
if (sessionSettled || lifecycleFinished) {
|
|
1227
1195
|
return;
|
|
1228
1196
|
}
|
|
1229
1197
|
updateActivityState(Date.now());
|
|
@@ -1234,7 +1202,7 @@ async function runSingleAttempt(
|
|
|
1234
1202
|
|
|
1235
1203
|
if (attemptTimeout) {
|
|
1236
1204
|
timeoutTimer = setTimeout(() => {
|
|
1237
|
-
if (
|
|
1205
|
+
if (sessionSettled || lifecycleFinished || interruptedByControl) return;
|
|
1238
1206
|
result.timedOut = true;
|
|
1239
1207
|
clearAllToolTimeouts();
|
|
1240
1208
|
result.error = attemptTimeout.message;
|
|
@@ -1243,17 +1211,12 @@ async function runSingleAttempt(
|
|
|
1243
1211
|
progress.error = attemptTimeout.message;
|
|
1244
1212
|
progress.durationMs = Date.now() - startTime;
|
|
1245
1213
|
fireUpdate();
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
if (
|
|
1249
|
-
|
|
1250
|
-
}, 1000);
|
|
1251
|
-
timeoutTerminationTimer.unref?.();
|
|
1252
|
-
timeoutHardKillTimer = setTimeout(() => {
|
|
1253
|
-
if (processClosed || lifecycleFinished) return;
|
|
1254
|
-
trySignalChild(proc, "SIGKILL");
|
|
1214
|
+
abortChild();
|
|
1215
|
+
timeoutHardFinishTimer = setTimeout(() => {
|
|
1216
|
+
if (sessionSettled || lifecycleFinished) return;
|
|
1217
|
+
settle(undefined, true);
|
|
1255
1218
|
}, 4000);
|
|
1256
|
-
|
|
1219
|
+
timeoutHardFinishTimer.unref?.();
|
|
1257
1220
|
}, attemptTimeout.remainingMs);
|
|
1258
1221
|
timeoutTimer.unref?.();
|
|
1259
1222
|
}
|
|
@@ -1261,8 +1224,7 @@ async function runSingleAttempt(
|
|
|
1261
1224
|
let toolTimeoutSequence = 0;
|
|
1262
1225
|
const activeToolTimeouts = new Map<string, { toolName: string; timer: ReturnType<typeof setTimeout> }>();
|
|
1263
1226
|
const activeToolTimeoutKeysByName = new Map<string, string[]>();
|
|
1264
|
-
let
|
|
1265
|
-
let toolTimeoutHardKillTimer: ReturnType<typeof setTimeout> | undefined;
|
|
1227
|
+
let toolTimeoutHardFinishTimer: ReturnType<typeof setTimeout> | undefined;
|
|
1266
1228
|
const removeToolTimeoutKey = (key: string): void => {
|
|
1267
1229
|
const active = activeToolTimeouts.get(key);
|
|
1268
1230
|
if (!active) return;
|
|
@@ -1284,17 +1246,13 @@ async function runSingleAttempt(
|
|
|
1284
1246
|
};
|
|
1285
1247
|
const clearAllToolTimeouts = (): void => {
|
|
1286
1248
|
for (const key of [...activeToolTimeouts.keys()]) removeToolTimeoutKey(key);
|
|
1287
|
-
if (
|
|
1288
|
-
clearTimeout(
|
|
1289
|
-
|
|
1290
|
-
}
|
|
1291
|
-
if (toolTimeoutHardKillTimer) {
|
|
1292
|
-
clearTimeout(toolTimeoutHardKillTimer);
|
|
1293
|
-
toolTimeoutHardKillTimer = undefined;
|
|
1249
|
+
if (toolTimeoutHardFinishTimer) {
|
|
1250
|
+
clearTimeout(toolTimeoutHardFinishTimer);
|
|
1251
|
+
toolTimeoutHardFinishTimer = undefined;
|
|
1294
1252
|
}
|
|
1295
1253
|
};
|
|
1296
1254
|
const terminateForToolTimeout = (message: string): void => {
|
|
1297
|
-
if (
|
|
1255
|
+
if (sessionSettled || lifecycleFinished || interruptedByControl) return;
|
|
1298
1256
|
result.timedOut = true;
|
|
1299
1257
|
result.error = message;
|
|
1300
1258
|
result.finalOutput = message;
|
|
@@ -1302,17 +1260,12 @@ async function runSingleAttempt(
|
|
|
1302
1260
|
progress.error = message;
|
|
1303
1261
|
progress.durationMs = Date.now() - startTime;
|
|
1304
1262
|
fireUpdate();
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
if (
|
|
1308
|
-
|
|
1309
|
-
}, 1000);
|
|
1310
|
-
toolTimeoutTerminationTimer.unref?.();
|
|
1311
|
-
toolTimeoutHardKillTimer = setTimeout(() => {
|
|
1312
|
-
if (processClosed || lifecycleFinished) return;
|
|
1313
|
-
trySignalChild(proc, "SIGKILL");
|
|
1263
|
+
abortChild();
|
|
1264
|
+
toolTimeoutHardFinishTimer = setTimeout(() => {
|
|
1265
|
+
if (sessionSettled || lifecycleFinished) return;
|
|
1266
|
+
settle(undefined, true);
|
|
1314
1267
|
}, 4000);
|
|
1315
|
-
|
|
1268
|
+
toolTimeoutHardFinishTimer.unref?.();
|
|
1316
1269
|
};
|
|
1317
1270
|
const armToolTimeout = (event: { toolCallId?: unknown; toolName: string }): void => {
|
|
1318
1271
|
const timeoutForTool = effectiveToolTimeoutMs(event.toolName, options.toolTimeoutMs);
|
|
@@ -1333,111 +1286,42 @@ async function runSingleAttempt(
|
|
|
1333
1286
|
activeToolTimeoutKeysByName.set(toolName, keys);
|
|
1334
1287
|
};
|
|
1335
1288
|
|
|
1336
|
-
|
|
1337
|
-
const
|
|
1338
|
-
if (
|
|
1339
|
-
|
|
1340
|
-
result.error = formatProtocolOutputLimit(limit);
|
|
1341
|
-
progress.status = "failed";
|
|
1342
|
-
progress.error = result.error;
|
|
1343
|
-
progress.durationMs = Date.now() - startTime;
|
|
1344
|
-
fireUpdate();
|
|
1345
|
-
if (!childExited) {
|
|
1346
|
-
trySignalChild(proc, "SIGTERM");
|
|
1347
|
-
protocolHardKillTimer = setTimeout(() => {
|
|
1348
|
-
if (!childExited) trySignalChild(proc, "SIGKILL");
|
|
1349
|
-
}, 3000);
|
|
1350
|
-
protocolHardKillTimer.unref?.();
|
|
1351
|
-
}
|
|
1352
|
-
};
|
|
1353
|
-
const stdoutReader = createBoundedLineReader({
|
|
1354
|
-
oversizedLineProjector: PI_AGGREGATE_EVENT_PROJECTOR,
|
|
1355
|
-
onLine: processLine,
|
|
1356
|
-
onLimit: failProtocol,
|
|
1357
|
-
});
|
|
1358
|
-
const stderrReader = createBoundedLineReader({
|
|
1359
|
-
stream: "stderr",
|
|
1360
|
-
maxPendingLineBytes: MAX_CHILD_STDERR_BYTES,
|
|
1361
|
-
onLine: (line) => shared.transcriptWriter?.writeStderrLine(line),
|
|
1362
|
-
onLimit: (limit) => shared.transcriptWriter?.writeStderrLine(formatProtocolOutputLimit(limit)),
|
|
1363
|
-
});
|
|
1364
|
-
|
|
1365
|
-
const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
|
|
1366
|
-
proc.stdout.on("data", (chunk: Buffer) => stdoutReader.push(chunk));
|
|
1367
|
-
proc.stderr.on("data", (chunk: Buffer) => {
|
|
1368
|
-
stderrTail.push(chunk);
|
|
1369
|
-
stderrReader.push(chunk);
|
|
1370
|
-
shared.orcaProgressTab?.append(chunk.toString("utf-8"));
|
|
1371
|
-
});
|
|
1372
|
-
proc.on("exit", () => {
|
|
1373
|
-
childExited = true;
|
|
1289
|
+
/** The child run ended (or was forced to end); fold in the captures and finish. */
|
|
1290
|
+
const settle = (promptError: unknown, forced = false): void => {
|
|
1291
|
+
if (lifecycleFinished || sessionSettled) return;
|
|
1292
|
+
sessionSettled = true;
|
|
1374
1293
|
clearFinalDrainTimers();
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
if (lifecycleFinished) return;
|
|
1378
|
-
processClosed = true;
|
|
1379
|
-
clearFinalDrainTimers();
|
|
1380
|
-
clearStdioGuard();
|
|
1381
|
-
void jsonlWriter.close().catch(() => {
|
|
1382
|
-
// JSONL artifact flush is best effort.
|
|
1383
|
-
});
|
|
1384
|
-
const toolDiagnosticError = readChildToolDiagnosticError(toolDiagnosticPath);
|
|
1294
|
+
const diagnostic = capture.toolDiagnostic();
|
|
1295
|
+
const toolDiagnosticError = diagnostic ? formatChildToolDiagnostic(diagnostic, { host: "parent" }) : undefined;
|
|
1385
1296
|
toolAvailabilityError = toolDiagnosticError;
|
|
1386
|
-
result.runtimeAcknowledgedExtensions =
|
|
1387
|
-
cleanupTempDir(tempDir);
|
|
1388
|
-
stdoutReader.end();
|
|
1389
|
-
stderrReader.end();
|
|
1390
|
-
const stderr = stderrTail.text();
|
|
1391
|
-
const rawStdout = rawStdoutTail.text();
|
|
1297
|
+
result.runtimeAcknowledgedExtensions = capture.runtimeAcknowledgedExtensions();
|
|
1392
1298
|
let closeError = result.error ?? toolDiagnosticError ?? assistantError;
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
if (signal) result.processSignal = signal;
|
|
1396
|
-
if (!closeError && forcedDrainAfterEmptyTerminal && stderr.trim()) {
|
|
1397
|
-
closeError = stderr.trim();
|
|
1398
|
-
}
|
|
1399
|
-
if (!closeError && isUnexplainedProcessSignal({
|
|
1400
|
-
processSignal: signal,
|
|
1401
|
-
interrupted: result.interrupted,
|
|
1402
|
-
timedOut: result.timedOut,
|
|
1403
|
-
stopped: result.stopped,
|
|
1404
|
-
forcedDrainAfterFinalSuccess: forcedDrainAfterFinalSuccess && !forcedDrainAfterEmptyTerminal,
|
|
1405
|
-
})) {
|
|
1406
|
-
closeError = formatProcessSignalError(signal!);
|
|
1299
|
+
if (!closeError && promptError !== undefined) {
|
|
1300
|
+
closeError = promptError instanceof Error ? promptError.message : String(promptError);
|
|
1407
1301
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1302
|
+
const forcedDrainAfterFinalSuccess = (forced || forcedTermination) && (cleanTerminalAssistantStopReceived || agentSettledReceived) && !closeError;
|
|
1303
|
+
const forcedDrainAfterEmptyTerminal = forcedDrainAfterFinalSuccess && hasEmptyTerminalAssistantResponse(result.messages ?? []);
|
|
1304
|
+
if (!closeError && (abortedBySignal || session?.shutDown) && !result.interrupted && !result.timedOut) {
|
|
1305
|
+
closeError = session?.shutDown ? "Subagent stopped because the parent session shut down." : STOPPED_BEFORE_COMPLETION_ERROR;
|
|
1410
1306
|
}
|
|
1411
|
-
if (
|
|
1412
|
-
closeError =
|
|
1307
|
+
if (!closeError && forced && !forcedDrainAfterFinalSuccess) {
|
|
1308
|
+
closeError = "Subagent session did not settle after it was aborted.";
|
|
1413
1309
|
}
|
|
1414
|
-
const finalCode = forcedDrainAfterFinalSuccess && !forcedDrainAfterEmptyTerminal ? 0 :
|
|
1310
|
+
const finalCode = forcedDrainAfterFinalSuccess && !forcedDrainAfterEmptyTerminal ? 0 : closeError || promptError !== undefined ? 1 : 0;
|
|
1415
1311
|
if (!result.error && closeError) result.error = closeError;
|
|
1416
1312
|
finish(finalCode);
|
|
1417
|
-
}
|
|
1418
|
-
proc.on("error", (error) => {
|
|
1419
|
-
if (lifecycleFinished) return;
|
|
1420
|
-
processClosed = true;
|
|
1421
|
-
clearFinalDrainTimers();
|
|
1422
|
-
clearStdioGuard();
|
|
1423
|
-
void jsonlWriter.close().catch(() => {
|
|
1424
|
-
// JSONL artifact flush is best effort.
|
|
1425
|
-
});
|
|
1426
|
-
cleanupTempDir(tempDir);
|
|
1427
|
-
stdoutReader.end();
|
|
1428
|
-
stderrReader.end();
|
|
1429
|
-
if (!result.error) {
|
|
1430
|
-
result.error = error instanceof Error ? error.message : String(error);
|
|
1431
|
-
}
|
|
1432
|
-
finish(1);
|
|
1433
|
-
});
|
|
1313
|
+
};
|
|
1434
1314
|
|
|
1435
1315
|
if (options.signal) {
|
|
1436
1316
|
const kill = () => {
|
|
1437
|
-
if (
|
|
1317
|
+
if (sessionSettled || lifecycleFinished) return;
|
|
1438
1318
|
abortedBySignal = true;
|
|
1439
|
-
|
|
1440
|
-
setTimeout(() =>
|
|
1319
|
+
abortChild();
|
|
1320
|
+
const hardTimer = setTimeout(() => {
|
|
1321
|
+
if (sessionSettled || lifecycleFinished) return;
|
|
1322
|
+
settle(undefined, true);
|
|
1323
|
+
}, 3000);
|
|
1324
|
+
hardTimer.unref?.();
|
|
1441
1325
|
};
|
|
1442
1326
|
if (options.signal.aborted) kill();
|
|
1443
1327
|
else {
|
|
@@ -1448,7 +1332,7 @@ async function runSingleAttempt(
|
|
|
1448
1332
|
|
|
1449
1333
|
if (options.interruptSignal) {
|
|
1450
1334
|
const interrupt = () => {
|
|
1451
|
-
if (
|
|
1335
|
+
if (sessionSettled || lifecycleFinished) return;
|
|
1452
1336
|
if (result.timedOut) return;
|
|
1453
1337
|
interruptedByControl = true;
|
|
1454
1338
|
clearTimeoutTimers();
|
|
@@ -1459,11 +1343,12 @@ async function runSingleAttempt(
|
|
|
1459
1343
|
result.finalOutput = "Interrupted. Waiting for explicit next action.";
|
|
1460
1344
|
progress.activityState = undefined;
|
|
1461
1345
|
fireUpdate();
|
|
1462
|
-
|
|
1463
|
-
setTimeout(() => {
|
|
1464
|
-
if (
|
|
1465
|
-
|
|
1466
|
-
},
|
|
1346
|
+
abortChild();
|
|
1347
|
+
const hardTimer = setTimeout(() => {
|
|
1348
|
+
if (sessionSettled || lifecycleFinished) return;
|
|
1349
|
+
settle(undefined, true);
|
|
1350
|
+
}, 3000);
|
|
1351
|
+
hardTimer.unref?.();
|
|
1467
1352
|
};
|
|
1468
1353
|
if (options.interruptSignal.aborted) interrupt();
|
|
1469
1354
|
else {
|
|
@@ -1478,9 +1363,37 @@ async function runSingleAttempt(
|
|
|
1478
1363
|
options.onDetachReady?.((reason = "user request") => detachForeground(reason));
|
|
1479
1364
|
} catch (error) {
|
|
1480
1365
|
// A consumer callback is advisory. Keep the child attached and observable
|
|
1481
|
-
// rather than rejecting this attempt and orphaning its live
|
|
1366
|
+
// rather than rejecting this attempt and orphaning its live session.
|
|
1482
1367
|
appendRecentOutput(progress, [`Foreground detach callback failed: ${error instanceof Error ? error.message : String(error)}`]);
|
|
1483
1368
|
}
|
|
1369
|
+
|
|
1370
|
+
void (async () => {
|
|
1371
|
+
try {
|
|
1372
|
+
const input = createReportedChildSessionInput(launch, shared.transcriptWriter);
|
|
1373
|
+
requestReadonlySessionEvidence(input, shared.readonlyExpected);
|
|
1374
|
+
if (shared.readonlyHandoffAllowed && !shared.readonlyHandoffAllowed()) throw new Error("Read-only continuation handoff vetoed.");
|
|
1375
|
+
const created = await childSessions.create(input);
|
|
1376
|
+
if (lifecycleFinished) {
|
|
1377
|
+
void created.dispose();
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
session = created;
|
|
1381
|
+
created.detached = detached;
|
|
1382
|
+
unsubscribe = created.subscribe((event) => processEvent(event as Parameters<typeof processEvent>[0]));
|
|
1383
|
+
if (abortedBySignal || interruptedByControl || result.timedOut) {
|
|
1384
|
+
abortChild();
|
|
1385
|
+
}
|
|
1386
|
+
options.onChildSession?.({ steer: (text) => created.steer(text), followUp: (text) => created.followUp(text) });
|
|
1387
|
+
const actualReadonlyModel = shared.readonlyExpected && getReadonlyChildModels(created)?.current;
|
|
1388
|
+
if (shared.readonlyExpected && (!actualReadonlyModel || actualReadonlyModel.fullId !== shared.readonlyModel
|
|
1389
|
+
|| actualReadonlyModel.api !== shared.readonlyExpected.api || created.modelId !== shared.readonlyModel || abortedBySignal || interruptedByControl || result.timedOut
|
|
1390
|
+
|| !shared.readonlyHandoffAllowed?.())) throw new Error("Read-only continuation handoff vetoed.");
|
|
1391
|
+
await created.prompt(`Task: ${task}`);
|
|
1392
|
+
settle(undefined);
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
settle(error ?? new Error("Child session failed."));
|
|
1395
|
+
}
|
|
1396
|
+
})();
|
|
1484
1397
|
});
|
|
1485
1398
|
result.exitCode = exitCode;
|
|
1486
1399
|
if (afterCompactionSettlement) {
|
|
@@ -1506,20 +1419,10 @@ async function runSingleAttempt(
|
|
|
1506
1419
|
&& !abortedBySignal
|
|
1507
1420
|
&& !result.timedOut
|
|
1508
1421
|
&& !result.stopped
|
|
1509
|
-
&& !result.protocolError
|
|
1510
1422
|
&& !toolAvailabilityError) {
|
|
1511
|
-
const processExitCode = result.exitCode;
|
|
1512
1423
|
result.exitCode = 1;
|
|
1513
|
-
result.error = formatMidToolExitError({
|
|
1514
|
-
toolName: progress.currentTool,
|
|
1515
|
-
exitCode: processExitCode,
|
|
1516
|
-
processSignal: result.processSignal,
|
|
1517
|
-
});
|
|
1424
|
+
result.error = formatMidToolExitError({ toolName: progress.currentTool });
|
|
1518
1425
|
}
|
|
1519
|
-
result.error = formatSubagentExtensionConflictError(result.error, {
|
|
1520
|
-
agent: agent.name,
|
|
1521
|
-
ambientExtensionsEnabled: !launchResolvedExtensions.disableAmbientExtensions,
|
|
1522
|
-
});
|
|
1523
1426
|
if (result.error && result.exitCode === 0) {
|
|
1524
1427
|
result.exitCode = 1;
|
|
1525
1428
|
}
|
|
@@ -1527,27 +1430,23 @@ async function runSingleAttempt(
|
|
|
1527
1430
|
if (options.structuredOutput && result.exitCode === 0 && !result.error) {
|
|
1528
1431
|
result.structuredOutputSchemaPath = options.structuredOutput.schemaPath;
|
|
1529
1432
|
result.structuredOutputPath = options.structuredOutput.outputPath;
|
|
1530
|
-
|
|
1433
|
+
const structured = capture.structuredOutput();
|
|
1434
|
+
if (!structuredOutputToolInvoked || !structured.called) {
|
|
1531
1435
|
result.exitCode = 1;
|
|
1532
1436
|
result.error = MISSING_STRUCTURED_OUTPUT_CALL_ERROR;
|
|
1533
1437
|
result.structuredOutputFailed = true;
|
|
1534
1438
|
} else {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
const acceptanceReport = readStructuredOutputAcceptanceReport(options.structuredOutput);
|
|
1547
|
-
(result as SingleResult & { structuredAcceptanceReport?: unknown; structuredAcceptanceReportError?: string }).structuredAcceptanceReport = acceptanceReport.value;
|
|
1548
|
-
(result as SingleResult & { structuredAcceptanceReport?: unknown; structuredAcceptanceReportError?: string }).structuredAcceptanceReportError = acceptanceReport.error;
|
|
1549
|
-
validatedStructuredOutput = true;
|
|
1550
|
-
}
|
|
1439
|
+
result.structuredOutput = structured.value;
|
|
1440
|
+
const acceptanceMode = options.structuredOutput.acceptanceReportPath
|
|
1441
|
+
? options.structuredOutput.acceptanceReportRequired ? "required" : "optional"
|
|
1442
|
+
: undefined;
|
|
1443
|
+
const acceptanceReportError = acceptanceMode === "required" && !structured.acceptanceReportProvided
|
|
1444
|
+
? MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR
|
|
1445
|
+
: undefined;
|
|
1446
|
+
(result as SingleResult & { structuredAcceptanceReport?: unknown; structuredAcceptanceReportError?: string }).structuredAcceptanceReport = acceptanceMode ? structured.acceptanceReport : undefined;
|
|
1447
|
+
(result as SingleResult & { structuredAcceptanceReport?: unknown; structuredAcceptanceReportError?: string }).structuredAcceptanceReportError = acceptanceReportError;
|
|
1448
|
+
writeStructuredOutputArtifacts(options.structuredOutput, structured.value, acceptanceMode ? structured.acceptanceReport : undefined);
|
|
1449
|
+
validatedStructuredOutput = true;
|
|
1551
1450
|
}
|
|
1552
1451
|
}
|
|
1553
1452
|
if (result.exitCode === 0 && !result.error) {
|
|
@@ -1600,7 +1499,7 @@ async function runSingleAttempt(
|
|
|
1600
1499
|
const outputChanged = hasSingleOutputChangedSinceSnapshot(options.outputPath, shared.outputSnapshot);
|
|
1601
1500
|
requiredOutputMissing = outputChanged === undefined ? undefined : !outputChanged;
|
|
1602
1501
|
} else if (options.structuredOutput) {
|
|
1603
|
-
requiredOutputMissing = !
|
|
1502
|
+
requiredOutputMissing = !capture.structuredOutput().called;
|
|
1604
1503
|
}
|
|
1605
1504
|
result.timeoutRecovery = buildTimeoutRecoverySummary({
|
|
1606
1505
|
termination: "timed-out",
|
|
@@ -1617,7 +1516,7 @@ async function runSingleAttempt(
|
|
|
1617
1516
|
? `${timeoutMessage}\n\n${result.timeoutRecovery.message}\n\nPartial output before timeout:\n${fullOutput}`
|
|
1618
1517
|
: `${timeoutMessage}\n\n${result.timeoutRecovery.message}`;
|
|
1619
1518
|
}
|
|
1620
|
-
const completionGuardEnabled =
|
|
1519
|
+
const completionGuardEnabled = isAgentContract(options.agentContract) ? agent.completionGuard === true : agent.completionGuard !== false;
|
|
1621
1520
|
const completionGuard = ((result.exitCode === 0 && !result.error) || toolAvailabilityError) && completionGuardEnabled
|
|
1622
1521
|
? evaluateCompletionMutationGuard({
|
|
1623
1522
|
agent: agent.name,
|
|
@@ -1657,7 +1556,7 @@ async function runSingleAttempt(
|
|
|
1657
1556
|
mutationAttemptObserved,
|
|
1658
1557
|
mutationEvidence,
|
|
1659
1558
|
arbiterRescued,
|
|
1660
|
-
|
|
1559
|
+
agentContractEnabled: isAgentContract(options.agentContract),
|
|
1661
1560
|
});
|
|
1662
1561
|
if (completionEvidence.fileMutation) {
|
|
1663
1562
|
result.effects = {
|
|
@@ -1719,6 +1618,20 @@ async function runSingleAttempt(
|
|
|
1719
1618
|
return result;
|
|
1720
1619
|
}
|
|
1721
1620
|
|
|
1621
|
+
/** Keep the structured output artifact files other consumers read by path. */
|
|
1622
|
+
function writeStructuredOutputArtifacts(runtime: NonNullable<RunSyncOptions["structuredOutput"]>, value: unknown, acceptanceReport: unknown): void {
|
|
1623
|
+
try {
|
|
1624
|
+
mkdirSync(path.dirname(runtime.outputPath), { recursive: true });
|
|
1625
|
+
writeFileSync(runtime.outputPath, JSON.stringify(value), { mode: 0o600 });
|
|
1626
|
+
if (runtime.acceptanceReportPath) {
|
|
1627
|
+
if (acceptanceReport !== undefined) writeFileSync(runtime.acceptanceReportPath, JSON.stringify(acceptanceReport), { mode: 0o600 });
|
|
1628
|
+
else rmSync(runtime.acceptanceReportPath, { force: true });
|
|
1629
|
+
}
|
|
1630
|
+
} catch {
|
|
1631
|
+
// The captured value is already on the result; the file is observability only.
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1722
1635
|
/**
|
|
1723
1636
|
* Run a subagent synchronously (blocking until complete)
|
|
1724
1637
|
*/
|
|
@@ -1744,7 +1657,7 @@ async function runSyncCompletionInner(
|
|
|
1744
1657
|
}
|
|
1745
1658
|
options = {
|
|
1746
1659
|
...options,
|
|
1747
|
-
capabilityCeiling: intersectSubagentCapabilityCeilings(options.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(options.parentSessionId),
|
|
1660
|
+
capabilityCeiling: intersectSubagentCapabilityCeilings(options.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(options.parentSessionId), options.childRuntime?.capabilityCeiling),
|
|
1748
1661
|
};
|
|
1749
1662
|
const childSessionName = deriveChildSessionName({ agent: agentName, task });
|
|
1750
1663
|
const agent = agents.find((a) => a.name === agentName);
|
|
@@ -1766,7 +1679,7 @@ async function runSyncCompletionInner(
|
|
|
1766
1679
|
thinkingCeiling: intersectThinkingCeilings(
|
|
1767
1680
|
options.thinkingCeiling,
|
|
1768
1681
|
agent.maxThinking,
|
|
1769
|
-
|
|
1682
|
+
options.childRuntime?.thinkingCeiling,
|
|
1770
1683
|
),
|
|
1771
1684
|
};
|
|
1772
1685
|
try {
|
|
@@ -1839,7 +1752,7 @@ async function runSyncCompletionInner(
|
|
|
1839
1752
|
dynamicGroup: options.acceptanceContext?.dynamicGroup,
|
|
1840
1753
|
agentContract: options.agentContract,
|
|
1841
1754
|
});
|
|
1842
|
-
const acceptancePrompt = formatAcceptancePrompt(effectiveAcceptance, { reportOptional:
|
|
1755
|
+
const acceptancePrompt = formatAcceptancePrompt(effectiveAcceptance, { reportOptional: isAgentContract(options.agentContract), structuredOutput: Boolean(options.structuredOutput?.acceptanceReportPath) });
|
|
1843
1756
|
const taskWithAcceptance = acceptancePrompt ? `${task}\n${acceptancePrompt}` : task;
|
|
1844
1757
|
options.onEffectivePrompt?.(taskWithAcceptance);
|
|
1845
1758
|
const sessionEnabled = Boolean(options.sessionFile || options.sessionDir) || shareEnabled;
|
|
@@ -1990,21 +1903,33 @@ async function runSyncCompletionInner(
|
|
|
1990
1903
|
};
|
|
1991
1904
|
let lastResult: SingleResult | undefined;
|
|
1992
1905
|
const modelsToTry = candidates.length > 0 ? candidates : [undefined];
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
let
|
|
1996
|
-
let
|
|
1997
|
-
|
|
1906
|
+
let recoveryState: LogicalRecoveryState = "unused";
|
|
1907
|
+
let readonlyExpected: SettledReadonlyEvidence | undefined;
|
|
1908
|
+
let readonlyModel: string | undefined;
|
|
1909
|
+
let readonlySource: ChildSession | undefined;
|
|
1910
|
+
// Ordinary startup retries retain their per-attempt timeout. Only retained
|
|
1911
|
+
// continuation uses the original logical deadline, never a renewed allowance.
|
|
1912
|
+
const continuationDeadline = options.deadlineAt ?? (options.timeoutMs === undefined ? undefined : Date.now() + options.timeoutMs);
|
|
1913
|
+
const readonlyHandoffAllowed = () => !options.signal?.aborted && !options.interruptSignal?.aborted
|
|
1914
|
+
&& !intercomDetached && !detachedReason && !options.workflowChildPermitLaunch
|
|
1915
|
+
&& options.usageBudget === undefined && options.toolBudget === undefined
|
|
1916
|
+
&& (continuationDeadline === undefined || Date.now() < continuationDeadline)
|
|
1917
|
+
&& (!readonlySource || getReadonlySessionEvidence(readonlySource) === readonlyExpected)
|
|
1918
|
+
&& !readonlySource?.detached && !readonlySource?.shutDown;
|
|
1919
|
+
let nextAttemptTask = task;
|
|
1998
1920
|
modelAttemptsLoop: for (let modelIndex = 0; modelIndex < modelsToTry.length; modelIndex++) {
|
|
1999
1921
|
const candidate = modelsToTry[modelIndex];
|
|
2000
|
-
|
|
2001
|
-
|
|
1922
|
+
// The inner loop re-runs the same candidate at most once, for abort recovery.
|
|
1923
|
+
for (;;) {
|
|
1924
|
+
const recoveringAbort = recoveryState === "abort-recovery";
|
|
2002
1925
|
const attemptTask = nextAttemptTask;
|
|
2003
1926
|
const verifyModel = Boolean(candidate) && !(options.modelOverrideFromParent && modelIndex === 0);
|
|
2004
1927
|
const outputSnapshot = captureSingleOutputSnapshot(options.outputPath);
|
|
1928
|
+
if (recoveryState === "readonly-continuation") attemptOptions.deadlineAt = continuationDeadline;
|
|
2005
1929
|
const result = await runSingleAttempt(runtimeCwd, agent, attemptTask, candidate, attemptOptions, {
|
|
2006
1930
|
sessionEnabled,
|
|
2007
1931
|
systemPrompt,
|
|
1932
|
+
acceptancePrompt,
|
|
2008
1933
|
resolvedSkillNames: resolvedSkills.length > 0 ? resolvedSkills.map((skill) => skill.name) : undefined,
|
|
2009
1934
|
skillsWarning: missingSkills.length > 0 ? `Skills not found: ${missingSkills.join(", ")}` : undefined,
|
|
2010
1935
|
jsonlPath,
|
|
@@ -2016,13 +1941,15 @@ async function runSyncCompletionInner(
|
|
|
2016
1941
|
.filter((modelCandidate): modelCandidate is string => Boolean(modelCandidate)),
|
|
2017
1942
|
outputSnapshot,
|
|
2018
1943
|
originalTask: task,
|
|
2019
|
-
taskDelivery: taskDeliveryOverride,
|
|
2020
1944
|
orcaProgressTab,
|
|
2021
1945
|
launchWarnings,
|
|
2022
1946
|
verifyModel,
|
|
1947
|
+
readonlyExpected,
|
|
1948
|
+
readonlyModel,
|
|
1949
|
+
readonlyHandoffAllowed: readonlyExpected ? readonlyHandoffAllowed : undefined,
|
|
2023
1950
|
});
|
|
2024
1951
|
lastResult = result;
|
|
2025
|
-
if (!recoveringAbort
|
|
1952
|
+
if (!recoveringAbort) {
|
|
2026
1953
|
if (result.model) attemptedModels.push(result.model);
|
|
2027
1954
|
else if (candidate) attemptedModels.push(candidate);
|
|
2028
1955
|
}
|
|
@@ -2038,6 +1965,46 @@ async function runSyncCompletionInner(
|
|
|
2038
1965
|
usage: { ...result.usage },
|
|
2039
1966
|
};
|
|
2040
1967
|
modelAttempts.push(attempt);
|
|
1968
|
+
// A consumed retained continuation is terminal even on a startup error or abort.
|
|
1969
|
+
if (recoveryState === "readonly-continuation") break modelAttemptsLoop;
|
|
1970
|
+
const source = settledReadonlySource.get(result);
|
|
1971
|
+
const evidence = source && getReadonlySessionEvidence(source);
|
|
1972
|
+
const models = source && getReadonlyChildModels(source);
|
|
1973
|
+
// Deny non-text retained inputs, including unknown blocks. Count bytes once,
|
|
1974
|
+
// not restored usage (the latter belongs to earlier attempts/runs).
|
|
1975
|
+
const textOnly = evidence && (JSON.parse(evidence.contextJson) as Array<{ role: string; content: unknown }>).every((message) =>
|
|
1976
|
+
typeof message.content === "string" || Array.isArray(message.content) && message.content.every((block) =>
|
|
1977
|
+
block?.type === "text" || message.role === "assistant" && block?.type === "toolCall"));
|
|
1978
|
+
const retainedBytes = evidence && models ? Buffer.byteLength(evidence.contextJson) + models.requestBytes : Infinity;
|
|
1979
|
+
const resolvedCandidates = modelsToTry.map((reference, index) => index === modelIndex ? models?.current : reference ? models?.resolve(reference) : undefined);
|
|
1980
|
+
const continuation = planReadonlyModelContinuation({
|
|
1981
|
+
source, recoveryState, currentIndex: modelIndex,
|
|
1982
|
+
candidates: resolvedCandidates.map((resolved, index) => {
|
|
1983
|
+
// A conservative byte ceiling includes serialized history, actual system
|
|
1984
|
+
// prompt/tools, framing/continuation headroom and full output allowance.
|
|
1985
|
+
const required = resolved?.maxTokens ? retainedBytes + 4096 + resolved.maxTokens : Infinity;
|
|
1986
|
+
return {
|
|
1987
|
+
resolved: resolved?.api ? { provider: resolved.provider, model: resolved.id, api: resolved.api } : undefined,
|
|
1988
|
+
tried: index <= modelIndex,
|
|
1989
|
+
compatibility: textOnly && resolved?.input?.includes("text") && (resolved.contextWindow ?? 0) >= required ? "compatible" as const : "unknown" as const,
|
|
1990
|
+
};
|
|
1991
|
+
}),
|
|
1992
|
+
lifecycleAllowsContinuation: !attemptSucceeded && readonlyHandoffAllowed() && !result.stopped && !result.detached && !result.interrupted && !result.timedOut,
|
|
1993
|
+
effectsAllowContinuation: !result.structuredOutputFailed && !result.toolBudgetBlocked && !result.progress?.currentTool
|
|
1994
|
+
&& !result.outputSaveError && (!result.effects?.fileMutation || result.effects.fileMutation.status === "not-applicable"),
|
|
1995
|
+
budget: options.toolBudget ? "tool-budget-configured" : options.usageBudget ? "unknown" : "unconfigured",
|
|
1996
|
+
knownContextOverflow: Boolean(result.contextOverflow || isContextOverflow(result.error)),
|
|
1997
|
+
});
|
|
1998
|
+
if (continuation.kind === "continue") {
|
|
1999
|
+
recoveryState = continuation.recoveryState; // consume BEFORE any sibling creation
|
|
2000
|
+
readonlyExpected = continuation.expected;
|
|
2001
|
+
readonlySource = source;
|
|
2002
|
+
readonlyModel = resolvedCandidates[continuation.candidateIndex]?.fullId;
|
|
2003
|
+
nextAttemptTask = continuation.prompt;
|
|
2004
|
+
attemptNotes.push(`[readonly-continuation] ${attempt.model} failed with HTTP 429 after read-only progress; continuing retained session once with ${readonlyModel}.`);
|
|
2005
|
+
modelIndex = continuation.candidateIndex - 1;
|
|
2006
|
+
continue modelAttemptsLoop;
|
|
2007
|
+
}
|
|
2041
2008
|
if (!attemptSucceeded) {
|
|
2042
2009
|
const afterCompactionSettlement = (result as AbortRecoverySingleResult)[AFTER_COMPACTION_SETTLEMENT];
|
|
2043
2010
|
const abortRecovery = planAbortRecovery({
|
|
@@ -2045,7 +2012,7 @@ async function runSyncCompletionInner(
|
|
|
2045
2012
|
error: result.error,
|
|
2046
2013
|
processSignal: result.processSignal,
|
|
2047
2014
|
sessionAvailable: Boolean(options.sessionFile && existsSync(options.sessionFile)),
|
|
2048
|
-
alreadyResumed:
|
|
2015
|
+
alreadyResumed: recoveryState !== "unused",
|
|
2049
2016
|
stopped: result.stopped || result.detached || options.signal?.aborted,
|
|
2050
2017
|
interrupted: result.interrupted || intercomDetached || options.interruptSignal?.aborted,
|
|
2051
2018
|
timedOut: result.timedOut,
|
|
@@ -2057,7 +2024,7 @@ async function runSyncCompletionInner(
|
|
|
2057
2024
|
afterCompactionSettlement,
|
|
2058
2025
|
});
|
|
2059
2026
|
if (abortRecovery.action === "resume") {
|
|
2060
|
-
|
|
2027
|
+
recoveryState = "abort-recovery";
|
|
2061
2028
|
nextAttemptTask = abortRecovery.prompt;
|
|
2062
2029
|
attemptNotes.push("[abort-recovery] provider/transport abort after useful progress; resuming the retained child session once.");
|
|
2063
2030
|
continue;
|
|
@@ -2072,75 +2039,10 @@ async function runSyncCompletionInner(
|
|
|
2072
2039
|
if (options.workflowChildPermitLaunch && !attemptSucceeded) break modelAttemptsLoop;
|
|
2073
2040
|
// Preserve the legacy intercom handoff contract: once this logical run has
|
|
2074
2041
|
// been handed to a supervisor, terminating that attempt must not launch a
|
|
2075
|
-
//
|
|
2042
|
+
// model fallback. Explicit user detach retains fallback.
|
|
2076
2043
|
if (intercomDetached || result.timedOut) break modelAttemptsLoop;
|
|
2077
2044
|
if (attemptSucceeded) break modelAttemptsLoop;
|
|
2078
2045
|
|
|
2079
|
-
const startupFailure = isRetryableSubagentStartupFailure({
|
|
2080
|
-
exitCode: result.exitCode,
|
|
2081
|
-
error: result.error,
|
|
2082
|
-
finalOutput: result.finalOutput,
|
|
2083
|
-
messageCount: result.messages?.length ?? 0,
|
|
2084
|
-
toolCount: result.progressSummary?.toolCount ?? 0,
|
|
2085
|
-
usage: result.usage,
|
|
2086
|
-
durationMs: result.progressSummary?.durationMs ?? Number.POSITIVE_INFINITY,
|
|
2087
|
-
protocolError: result.protocolError,
|
|
2088
|
-
processSignal: result.processSignal,
|
|
2089
|
-
detached: result.detached,
|
|
2090
|
-
interrupted: result.interrupted,
|
|
2091
|
-
timedOut: result.timedOut,
|
|
2092
|
-
stopped: result.stopped,
|
|
2093
|
-
});
|
|
2094
|
-
const retryDelayMs = SUBAGENT_STARTUP_RETRY_DELAYS_MS[startupAttemptIndex];
|
|
2095
|
-
if (startupFailure && retryDelayMs !== undefined) {
|
|
2096
|
-
const retryNote = formatSubagentStartupRetryNote({
|
|
2097
|
-
model: attempt.model,
|
|
2098
|
-
attempt: startupAttemptIndex + 1,
|
|
2099
|
-
maxAttempts: SUBAGENT_STARTUP_RETRY_DELAYS_MS.length + 1,
|
|
2100
|
-
delayMs: retryDelayMs,
|
|
2101
|
-
});
|
|
2102
|
-
const shouldRetry = await waitForSubagentStartupRetry(retryDelayMs, [options.signal, options.interruptSignal]);
|
|
2103
|
-
if (!shouldRetry) {
|
|
2104
|
-
if (options.interruptSignal?.aborted) {
|
|
2105
|
-
result.exitCode = 0;
|
|
2106
|
-
result.interrupted = true;
|
|
2107
|
-
result.error = undefined;
|
|
2108
|
-
result.finalOutput = "Interrupted. Waiting for explicit next action.";
|
|
2109
|
-
if (result.progress) {
|
|
2110
|
-
result.progress.status = "running";
|
|
2111
|
-
result.progress.error = undefined;
|
|
2112
|
-
}
|
|
2113
|
-
} else {
|
|
2114
|
-
const cancellationError = "Subagent startup retry cancelled before relaunch.";
|
|
2115
|
-
result.error = cancellationError;
|
|
2116
|
-
result.finalOutput = cancellationError;
|
|
2117
|
-
attempt.error = cancellationError;
|
|
2118
|
-
if (result.progress) result.progress.error = cancellationError;
|
|
2119
|
-
}
|
|
2120
|
-
break modelAttemptsLoop;
|
|
2121
|
-
}
|
|
2122
|
-
if (!taskDeliveryOverride && result.processSignal === "SIGKILL") {
|
|
2123
|
-
taskDeliveryOverride = "file";
|
|
2124
|
-
attemptNotes.push("[startup-retry] retrying with file task delivery to keep the task text out of the child process argv.");
|
|
2125
|
-
}
|
|
2126
|
-
attempt.error = retryNote;
|
|
2127
|
-
attemptNotes.push(retryNote);
|
|
2128
|
-
continue;
|
|
2129
|
-
}
|
|
2130
|
-
if (startupFailure) {
|
|
2131
|
-
const startupError = formatSubagentStartupRetryExhaustedError({
|
|
2132
|
-
model: attempt.model,
|
|
2133
|
-
attempts: startupAttemptIndex + 1,
|
|
2134
|
-
});
|
|
2135
|
-
result.error = startupError;
|
|
2136
|
-
result.finalOutput = startupError;
|
|
2137
|
-
if (result.progress) {
|
|
2138
|
-
result.progress.error = startupError;
|
|
2139
|
-
result.progress.status = "failed";
|
|
2140
|
-
}
|
|
2141
|
-
attempt.error = startupError;
|
|
2142
|
-
break modelAttemptsLoop;
|
|
2143
|
-
}
|
|
2144
2046
|
const retryableModelFailure = isRetryableModelFailureAttempt({ error: result.error, messages: result.messages, toolCount: result.progressSummary?.toolCount });
|
|
2145
2047
|
if (retryableModelFailure) recordRetryableModelFailure(result.model ?? candidate, result.error);
|
|
2146
2048
|
if (isContextOverflow(result.error)) {
|
|
@@ -2233,7 +2135,7 @@ async function runSyncCompletionInner(
|
|
|
2233
2135
|
? { content: childWrittenOutput, path: options.outputPath, authoritative: options.outputMode === "file-only", durable: result.savedOutputPath !== undefined }
|
|
2234
2136
|
: undefined,
|
|
2235
2137
|
cwd: options.cwd ?? runtimeCwd,
|
|
2236
|
-
reportOptional:
|
|
2138
|
+
reportOptional: isAgentContract(options.agentContract),
|
|
2237
2139
|
artifactsDir: options.artifactsDir,
|
|
2238
2140
|
runId: options.runId,
|
|
2239
2141
|
watchdog: result.watchdog,
|
|
@@ -2245,7 +2147,7 @@ async function runSyncCompletionInner(
|
|
|
2245
2147
|
}
|
|
2246
2148
|
const acceptanceFailure = acceptanceFailureMessage(result.acceptance);
|
|
2247
2149
|
stripAcceptanceReportsFromMessages(result.messages);
|
|
2248
|
-
if (acceptanceFailure && result.acceptance.explicit && result.exitCode === 0 && !result.interrupted && !result.timedOut && !
|
|
2150
|
+
if (acceptanceFailure && result.acceptance.explicit && result.exitCode === 0 && !result.interrupted && !result.timedOut && !isAgentContract(options.agentContract)) {
|
|
2249
2151
|
result.exitCode = 1;
|
|
2250
2152
|
if (result.savedOutputPath) {
|
|
2251
2153
|
result.finalOutput = finalizeSingleOutput({
|
|
@@ -2278,7 +2180,7 @@ async function runSyncCompletionInner(
|
|
|
2278
2180
|
result.progress.error = result.error;
|
|
2279
2181
|
}
|
|
2280
2182
|
}
|
|
2281
|
-
if (
|
|
2183
|
+
if (isAgentContract(options.agentContract)) attachContractProjections(result);
|
|
2282
2184
|
redactResultPrompt(result);
|
|
2283
2185
|
try {
|
|
2284
2186
|
persistResultMetadata(result);
|
|
@@ -2323,7 +2225,7 @@ export async function runSync(
|
|
|
2323
2225
|
): Promise<SingleResult> {
|
|
2324
2226
|
// Capture the strict contract before consumer-owned objects can be mutated
|
|
2325
2227
|
// after a detached receipt is published.
|
|
2326
|
-
const strictContract =
|
|
2228
|
+
const strictContract = isAgentContract(options.agentContract);
|
|
2327
2229
|
let detachedReason: string | undefined;
|
|
2328
2230
|
let publishedReceipt: SingleResult | undefined;
|
|
2329
2231
|
let activeDetachAttempt: ((reason?: string) => boolean) | undefined;
|
|
@@ -2421,13 +2323,13 @@ export async function runSync(
|
|
|
2421
2323
|
});
|
|
2422
2324
|
|
|
2423
2325
|
let terminalCallbackInvoked = false;
|
|
2424
|
-
void authoritativeCompletion.then((terminalResult) => {
|
|
2326
|
+
void authoritativeCompletion.then(async (terminalResult) => {
|
|
2425
2327
|
if (!detachedReason || terminalCallbackInvoked) return;
|
|
2426
2328
|
terminalCallbackInvoked = true;
|
|
2427
2329
|
terminalResult.detached = undefined;
|
|
2428
2330
|
terminalResult.detachedReason = detachedReason;
|
|
2429
2331
|
try {
|
|
2430
|
-
options.onDetachedExit?.(terminalResult);
|
|
2332
|
+
await options.onDetachedExit?.(terminalResult);
|
|
2431
2333
|
} catch {
|
|
2432
2334
|
// The authoritative result has settled. Consumer callback failures are
|
|
2433
2335
|
// contained here; each consumer owns cleanup through its own finally block.
|