@selesai/code 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/README.md +5 -3
- package/dist/bun/cli.d.ts +0 -1
- package/dist/bun/cli.js +0 -1
- package/dist/bun/register-bedrock.d.ts +0 -1
- package/dist/bun/register-bedrock.js +0 -1
- package/dist/bun/restore-sandbox-env.d.ts +0 -1
- package/dist/bun/restore-sandbox-env.js +0 -1
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.js +0 -1
- package/dist/cli/config-selector.d.ts +0 -1
- package/dist/cli/config-selector.js +0 -1
- package/dist/cli/credential-print.d.ts +0 -1
- package/dist/cli/credential-print.js +0 -1
- package/dist/cli/file-processor.d.ts +0 -1
- package/dist/cli/file-processor.js +0 -1
- package/dist/cli/initial-message.d.ts +0 -1
- package/dist/cli/initial-message.js +0 -1
- package/dist/cli/list-models.d.ts +0 -1
- package/dist/cli/list-models.js +0 -1
- package/dist/cli/project-trust.d.ts +0 -1
- package/dist/cli/project-trust.js +0 -1
- package/dist/cli/session-picker.d.ts +0 -1
- package/dist/cli/session-picker.js +0 -1
- package/dist/cli/startup-ui.d.ts +0 -1
- package/dist/cli/startup-ui.js +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/core/agent-session-auto-handoff.test.d.ts +0 -1
- package/dist/core/agent-session-auto-handoff.test.js +0 -1
- package/dist/core/agent-session-runtime.d.ts +0 -1
- package/dist/core/agent-session-runtime.js +0 -1
- package/dist/core/agent-session-services.d.ts +0 -1
- package/dist/core/agent-session-services.js +0 -1
- package/dist/core/agent-session-skill-block.test.d.ts +0 -1
- package/dist/core/agent-session-skill-block.test.js +0 -1
- package/dist/core/agent-session.d.ts +0 -1
- package/dist/core/agent-session.js +0 -1
- package/dist/core/agents.d.ts +0 -1
- package/dist/core/agents.js +0 -1
- package/dist/core/auth-guidance.d.ts +0 -1
- package/dist/core/auth-guidance.js +0 -1
- package/dist/core/auth-storage.d.ts +0 -1
- package/dist/core/auth-storage.js +0 -1
- package/dist/core/bash-executor.d.ts +0 -1
- package/dist/core/bash-executor.js +0 -1
- package/dist/core/built-in-extensions.d.ts +0 -1
- package/dist/core/built-in-extensions.js +0 -1
- package/dist/core/cache-stats.d.ts +0 -1
- package/dist/core/cache-stats.js +0 -1
- package/dist/core/compaction/branch-summarization.d.ts +0 -1
- package/dist/core/compaction/branch-summarization.js +0 -1
- package/dist/core/compaction/compaction.d.ts +0 -1
- package/dist/core/compaction/compaction.js +0 -1
- package/dist/core/compaction/index.d.ts +0 -1
- package/dist/core/compaction/index.js +0 -1
- package/dist/core/compaction/utils.d.ts +0 -1
- package/dist/core/compaction/utils.js +0 -1
- package/dist/core/defaults.d.ts +0 -1
- package/dist/core/defaults.js +0 -1
- package/dist/core/diagnostics.d.ts +0 -1
- package/dist/core/diagnostics.js +0 -1
- package/dist/core/event-bus.d.ts +0 -1
- package/dist/core/event-bus.js +0 -1
- package/dist/core/exec.d.ts +0 -1
- package/dist/core/exec.js +0 -1
- package/dist/core/experimental.d.ts +0 -1
- package/dist/core/experimental.js +0 -1
- package/dist/core/export-html/ansi-to-html.d.ts +0 -1
- package/dist/core/export-html/ansi-to-html.js +0 -1
- package/dist/core/export-html/index.d.ts +0 -1
- package/dist/core/export-html/index.js +0 -1
- package/dist/core/export-html/tool-renderer.d.ts +0 -1
- package/dist/core/export-html/tool-renderer.js +0 -1
- package/dist/core/extensions/index.d.ts +0 -1
- package/dist/core/extensions/index.js +0 -1
- package/dist/core/extensions/loader.d.ts +0 -1
- package/dist/core/extensions/loader.js +0 -1
- package/dist/core/extensions/runner.d.ts +0 -1
- package/dist/core/extensions/runner.js +0 -1
- package/dist/core/extensions/types.d.ts +0 -1
- package/dist/core/extensions/types.js +0 -1
- package/dist/core/extensions/wrapper.d.ts +0 -1
- package/dist/core/extensions/wrapper.js +0 -1
- package/dist/core/footer-data-provider.d.ts +0 -1
- package/dist/core/footer-data-provider.js +0 -1
- package/dist/core/git-command.d.ts +0 -1
- package/dist/core/git-command.js +0 -1
- package/dist/core/http-dispatcher.d.ts +0 -1
- package/dist/core/http-dispatcher.js +0 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +0 -1
- package/dist/core/keybindings.d.ts +0 -1
- package/dist/core/keybindings.js +0 -1
- package/dist/core/llama/client.d.ts +0 -1
- package/dist/core/llama/client.js +0 -1
- package/dist/core/llama/huggingface.d.ts +0 -1
- package/dist/core/llama/huggingface.js +0 -1
- package/dist/core/llama/index.d.ts +0 -1
- package/dist/core/llama/index.js +0 -1
- package/dist/core/llama/provider.d.ts +0 -1
- package/dist/core/llama/provider.js +0 -1
- package/dist/core/llama/ui.d.ts +0 -1
- package/dist/core/llama/ui.js +0 -1
- package/dist/core/messages.d.ts +0 -1
- package/dist/core/messages.js +0 -1
- package/dist/core/model-config.d.ts +0 -1
- package/dist/core/model-config.js +0 -1
- package/dist/core/model-registry.d.ts +0 -1
- package/dist/core/model-registry.js +0 -1
- package/dist/core/model-resolver.d.ts +0 -1
- package/dist/core/model-resolver.js +0 -1
- package/dist/core/model-runtime.d.ts +0 -1
- package/dist/core/model-runtime.js +0 -1
- package/dist/core/models-store.d.ts +0 -1
- package/dist/core/models-store.js +0 -1
- package/dist/core/output-guard.d.ts +0 -1
- package/dist/core/output-guard.js +0 -1
- package/dist/core/package-manager.d.ts +0 -1
- package/dist/core/package-manager.js +0 -1
- package/dist/core/package-manager.test.d.ts +0 -1
- package/dist/core/package-manager.test.js +0 -1
- package/dist/core/project-trust.d.ts +0 -1
- package/dist/core/project-trust.js +0 -1
- package/dist/core/prompt-templates.d.ts +0 -1
- package/dist/core/prompt-templates.js +0 -1
- package/dist/core/provider-attribution.d.ts +0 -1
- package/dist/core/provider-attribution.js +0 -1
- package/dist/core/provider-composer.d.ts +0 -1
- package/dist/core/provider-composer.js +0 -1
- package/dist/core/radius.d.ts +0 -1
- package/dist/core/radius.js +0 -1
- package/dist/core/remote-catalog-provider.d.ts +0 -1
- package/dist/core/remote-catalog-provider.js +0 -1
- package/dist/core/resolve-config-value.d.ts +0 -1
- package/dist/core/resolve-config-value.js +0 -1
- package/dist/core/resource-loader.d.ts +0 -1
- package/dist/core/resource-loader.js +0 -1
- package/dist/core/runtime-credentials.d.ts +0 -1
- package/dist/core/runtime-credentials.js +0 -1
- package/dist/core/sdk.d.ts +0 -1
- package/dist/core/sdk.js +0 -1
- package/dist/core/session-cwd.d.ts +0 -1
- package/dist/core/session-cwd.js +0 -1
- package/dist/core/session-manager.d.ts +0 -1
- package/dist/core/session-manager.js +0 -1
- package/dist/core/settings-manager-auto-handoff.test.d.ts +0 -1
- package/dist/core/settings-manager-auto-handoff.test.js +0 -1
- package/dist/core/settings-manager.d.ts +0 -4
- package/dist/core/settings-manager.js +0 -12
- package/dist/core/skills.d.ts +0 -1
- package/dist/core/skills.js +0 -1
- package/dist/core/slash-commands.d.ts +0 -1
- package/dist/core/slash-commands.js +0 -1
- package/dist/core/source-info.d.ts +0 -1
- package/dist/core/source-info.js +0 -1
- package/dist/core/system-prompt.d.ts +0 -1
- package/dist/core/system-prompt.js +0 -1
- package/dist/core/system-prompt.test.d.ts +0 -1
- package/dist/core/system-prompt.test.js +0 -1
- package/dist/core/telemetry.d.ts +0 -1
- package/dist/core/telemetry.js +0 -1
- package/dist/core/timings.d.ts +0 -1
- package/dist/core/timings.js +0 -1
- package/dist/core/tools/bash.d.ts +0 -1
- package/dist/core/tools/bash.js +0 -1
- package/dist/core/tools/edit-diff.d.ts +0 -1
- package/dist/core/tools/edit-diff.js +0 -1
- package/dist/core/tools/edit.d.ts +0 -1
- package/dist/core/tools/edit.js +0 -1
- package/dist/core/tools/file-mutation-queue.d.ts +0 -1
- package/dist/core/tools/file-mutation-queue.js +0 -1
- package/dist/core/tools/find.d.ts +0 -1
- package/dist/core/tools/find.js +0 -1
- package/dist/core/tools/grep.d.ts +0 -1
- package/dist/core/tools/grep.js +0 -1
- package/dist/core/tools/index.d.ts +0 -1
- package/dist/core/tools/index.js +0 -1
- package/dist/core/tools/ls.d.ts +0 -1
- package/dist/core/tools/ls.js +0 -1
- package/dist/core/tools/output-accumulator.d.ts +0 -1
- package/dist/core/tools/output-accumulator.js +0 -1
- package/dist/core/tools/path-utils.d.ts +0 -1
- package/dist/core/tools/path-utils.js +0 -1
- package/dist/core/tools/read.d.ts +0 -1
- package/dist/core/tools/read.js +0 -1
- package/dist/core/tools/render-utils.d.ts +0 -1
- package/dist/core/tools/render-utils.js +0 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +0 -1
- package/dist/core/tools/tool-definition-wrapper.js +0 -1
- package/dist/core/tools/truncate.d.ts +0 -1
- package/dist/core/tools/truncate.js +0 -1
- package/dist/core/tools/write.d.ts +0 -1
- package/dist/core/tools/write.js +0 -1
- package/dist/core/trust-manager.d.ts +0 -1
- package/dist/core/trust-manager.js +0 -1
- package/dist/core/usage-totals.d.ts +0 -1
- package/dist/core/usage-totals.js +0 -1
- package/dist/defaults/models.json +8 -0
- package/dist/defaults/settings.json +6 -7
- package/dist/extensions/agent-browser.test.ts +195 -0
- package/dist/extensions/agent-browser.ts +158 -0
- package/dist/extensions/inline-skills.test.ts +27 -13
- package/dist/extensions/inline-skills.ts +18 -11
- package/dist/extensions/package.json +2 -1
- package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +27 -0
- package/dist/extensions/pi-powerline-footer/CHANGELOG.md +153 -0
- package/dist/extensions/pi-powerline-footer/CONTRIBUTING.md +16 -0
- package/dist/extensions/pi-powerline-footer/README.md +192 -44
- package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +19 -4
- package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +80 -25
- package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +81 -29
- package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +1 -1
- package/dist/extensions/pi-powerline-footer/cd-command.ts +190 -0
- package/dist/extensions/pi-powerline-footer/colors.ts +2 -1
- package/dist/extensions/pi-powerline-footer/context-usage.ts +121 -6
- package/dist/extensions/pi-powerline-footer/currency-rates.ts +142 -0
- package/dist/extensions/pi-powerline-footer/editor-composition.ts +32 -0
- package/dist/extensions/pi-powerline-footer/git-status.ts +108 -6
- package/dist/extensions/pi-powerline-footer/icons.ts +11 -2
- package/dist/extensions/pi-powerline-footer/index.ts +1056 -324
- package/dist/extensions/pi-powerline-footer/lifecycle.ts +10 -0
- package/dist/extensions/pi-powerline-footer/package.json +10 -6
- package/dist/extensions/pi-powerline-footer/paths.ts +22 -0
- package/dist/extensions/pi-powerline-footer/powerline-config.ts +297 -15
- package/dist/extensions/pi-powerline-footer/presets.ts +6 -25
- package/dist/extensions/pi-powerline-footer/queue/store.ts +361 -0
- package/dist/extensions/pi-powerline-footer/queue/types.ts +54 -0
- package/dist/extensions/pi-powerline-footer/render-scheduler.ts +12 -7
- package/dist/extensions/pi-powerline-footer/segments.ts +114 -107
- package/dist/extensions/pi-powerline-footer/session-usage.ts +1 -1
- package/dist/extensions/pi-powerline-footer/shortcuts.ts +17 -3
- package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +189 -17
- package/dist/extensions/pi-powerline-footer/tests/cd-command.test.ts +144 -0
- package/dist/extensions/pi-powerline-footer/tests/context-usage.test.ts +120 -2
- package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +245 -22
- package/dist/extensions/pi-powerline-footer/tests/editor-composition.test.ts +48 -0
- package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +34 -0
- package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +39 -0
- package/dist/extensions/pi-powerline-footer/tests/git-status.test.ts +92 -0
- package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +4 -1
- package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +33 -197
- package/dist/extensions/pi-powerline-footer/tests/mode-aware-trigger.test.ts +79 -0
- package/dist/extensions/pi-powerline-footer/tests/paths.test.ts +63 -0
- package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +195 -0
- package/dist/extensions/pi-powerline-footer/tests/quit-cursor.test.ts +14 -0
- package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +167 -0
- package/dist/extensions/pi-powerline-footer/tests/stash-shortcut.test.ts +23 -18
- package/dist/extensions/pi-powerline-footer/tests/thinking-segment.test.ts +16 -1
- package/dist/extensions/pi-powerline-footer/tests/token-stats.test.ts +249 -0
- package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +237 -0
- package/dist/extensions/pi-powerline-footer/tests/welcome.test.ts +199 -0
- package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +191 -100
- package/dist/extensions/pi-powerline-footer/theme.ts +32 -18
- package/dist/extensions/pi-powerline-footer/token-stats.ts +304 -0
- package/dist/extensions/pi-powerline-footer/tsconfig.json +13 -0
- package/dist/extensions/pi-powerline-footer/types.ts +74 -29
- package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +34 -0
- package/dist/extensions/pi-powerline-footer/welcome.ts +65 -10
- package/dist/extensions/pi-powerline-footer/working-vibes.ts +44 -11
- package/dist/extensions/pi-subagents/CHANGELOG.md +89 -12
- package/dist/extensions/pi-subagents/README.md +339 -604
- package/dist/extensions/pi-subagents/package-lock.json +190 -2079
- package/dist/extensions/pi-subagents/package.json +13 -5
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +1 -1
- package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +10 -10
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +32 -43
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +106 -105
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +3 -3
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +28 -35
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +167 -124
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +163 -75
- package/dist/extensions/pi-subagents/src/agents/chain-serializer.ts +10 -7
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +5 -3
- package/dist/extensions/pi-subagents/src/agents/identity.ts +1 -1
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +14 -11
- package/dist/extensions/pi-subagents/src/agents/skills.ts +23 -6
- package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +8 -1
- package/dist/extensions/pi-subagents/src/api/control-channel.ts +4 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +26 -194
- package/dist/extensions/pi-subagents/src/api/external-runs.ts +129 -0
- package/dist/extensions/pi-subagents/src/api/intercom-bridge.ts +3 -0
- package/dist/extensions/pi-subagents/src/api/pi-args.ts +5 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +4 -4
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +19 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +10 -0
- package/dist/extensions/pi-subagents/src/extension/control-notices.ts +5 -39
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +10 -9
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +7 -4
- package/dist/extensions/pi-subagents/src/extension/index.ts +243 -77
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +18 -6
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +50 -39
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +36 -103
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +229 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/client.ts +130 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +141 -0
- package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +154 -0
- package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +330 -0
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +3 -2
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +5 -1
- package/dist/extensions/pi-subagents/src/missions/actions.ts +372 -0
- package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +314 -0
- package/dist/extensions/pi-subagents/src/missions/store.ts +442 -0
- package/dist/extensions/pi-subagents/src/missions/types.ts +135 -0
- package/dist/extensions/pi-subagents/src/policy/authority.ts +46 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +103 -72
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +10 -2
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +6 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +29 -1
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +3 -2
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +9 -7
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +3 -4
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +3 -28
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +5 -5
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +18 -68
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +35 -8
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +602 -375
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +612 -464
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +50 -9
- package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +253 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +12 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +8 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +74 -102
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +21 -22
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1050 -396
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +44 -18
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +0 -1
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +302 -22
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +130 -0
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +42 -1
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +59 -5
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -4
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +86 -2
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +11 -2
- package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +95 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +11 -1
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +15 -6
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +9 -63
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +37 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +2 -23
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +6 -6
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +124 -13
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +29 -7
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +18 -1
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +3 -2
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +1 -0
- package/dist/extensions/pi-subagents/src/shared/settings.ts +10 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +158 -55
- package/dist/extensions/pi-subagents/src/shared/utils.ts +16 -66
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +33 -199
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +43 -126
- package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +136 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +158 -205
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +22 -58
- package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +14 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +44 -642
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +18 -14
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +156 -21
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +110 -5
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +60 -24
- package/dist/extensions/pi-subagents/src/tui/render.ts +296 -140
- package/dist/extensions/pi-subagents/src/types/pi-runtime-compat.d.ts +14 -0
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +13 -7
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +2 -2
- package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +145 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +1 -1
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -1
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +3 -2
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +140 -0
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +415 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +41 -144
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +16 -16
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +415 -298
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +149 -82
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +40 -40
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +193 -133
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +1 -49
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +56 -58
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +81 -68
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +20 -25
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +425 -317
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +73 -73
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +123 -98
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +653 -240
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +20 -1661
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +8 -5
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +6 -6
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +4 -20
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +280 -295
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +47 -207
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +26 -26
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +89 -89
- package/dist/extensions/pi-subagents/test/unit/agent-selection.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +33 -9
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +24 -2
- package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +11 -9
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +40 -40
- package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +5 -39
- package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +19 -19
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/chain-serializer.test.ts +20 -20
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +99 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +41 -0
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +35 -5
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +16 -82
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +162 -620
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +25 -25
- package/dist/extensions/pi-subagents/test/unit/ensure-accessible-dir.test.ts +125 -0
- package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +66 -0
- package/dist/extensions/pi-subagents/test/unit/extra-agent-dirs.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +242 -52
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +197 -36
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +245 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +494 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +261 -31
- package/dist/extensions/pi-subagents/test/unit/inline-subagents.test.ts +127 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +6 -6
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +217 -0
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +182 -0
- package/dist/extensions/pi-subagents/test/unit/mock-pi.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +10 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +47 -5
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +49 -55
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +20 -3
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +37 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +10 -10
- package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +46 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +31 -10
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +40 -16
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +42 -44
- package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +13 -13
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +4 -4
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +75 -9
- package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +20 -84
- package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +15 -16
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +28 -28
- package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +19 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +37 -21
- package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +50 -50
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +396 -433
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +76 -153
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +411 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +1 -91
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +139 -0
- package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +29 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +13 -13
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +35 -35
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +53 -18
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +13 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +44 -11
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +2 -26
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +24 -148
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +11 -9
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +13 -13
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +8 -8
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +45 -9
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +197 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-graph.test.ts +8 -8
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +142 -12
- package/dist/extensions/pi-subagents/tsconfig.json +15 -0
- package/dist/extensions/ponytail/index.js +1 -31
- package/dist/extensions/ponytail/test/extension.test.js +5 -22
- package/dist/extensions/rtk.test.ts +141 -0
- package/dist/extensions/rtk.ts +78 -36
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.d.ts +0 -1
- package/dist/main.js +0 -1
- package/dist/migrations.d.ts +0 -1
- package/dist/migrations.js +0 -1
- package/dist/modes/index.d.ts +0 -1
- package/dist/modes/index.js +0 -1
- package/dist/modes/interactive/components/armin.d.ts +0 -1
- package/dist/modes/interactive/components/armin.js +0 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +0 -1
- package/dist/modes/interactive/components/assistant-message.js +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
- package/dist/modes/interactive/components/bash-execution.js +0 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +0 -1
- package/dist/modes/interactive/components/bordered-loader.js +0 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -1
- package/dist/modes/interactive/components/branch-summary-message.js +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +0 -1
- package/dist/modes/interactive/components/config-selector.d.ts +0 -1
- package/dist/modes/interactive/components/config-selector.js +0 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts +0 -1
- package/dist/modes/interactive/components/countdown-timer.js +0 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +0 -1
- package/dist/modes/interactive/components/custom-editor.js +0 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +0 -1
- package/dist/modes/interactive/components/custom-entry.js +0 -1
- package/dist/modes/interactive/components/custom-message.d.ts +0 -1
- package/dist/modes/interactive/components/custom-message.js +0 -1
- package/dist/modes/interactive/components/daxnuts.d.ts +0 -1
- package/dist/modes/interactive/components/daxnuts.js +0 -1
- package/dist/modes/interactive/components/diff.d.ts +0 -1
- package/dist/modes/interactive/components/diff.js +0 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts +0 -1
- package/dist/modes/interactive/components/dynamic-border.js +0 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -1
- package/dist/modes/interactive/components/earendil-announcement.js +0 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +0 -1
- package/dist/modes/interactive/components/extension-editor.js +0 -1
- package/dist/modes/interactive/components/extension-input.d.ts +0 -1
- package/dist/modes/interactive/components/extension-input.js +0 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +0 -1
- package/dist/modes/interactive/components/extension-selector.js +0 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +0 -1
- package/dist/modes/interactive/components/first-time-setup.js +0 -1
- package/dist/modes/interactive/components/footer.d.ts +0 -1
- package/dist/modes/interactive/components/footer.js +0 -1
- package/dist/modes/interactive/components/index.d.ts +0 -1
- package/dist/modes/interactive/components/index.js +0 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -1
- package/dist/modes/interactive/components/keybinding-hints.js +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
- package/dist/modes/interactive/components/login-dialog.js +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts +0 -1
- package/dist/modes/interactive/components/model-selector.js +0 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +0 -1
- package/dist/modes/interactive/components/oauth-selector.js +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +0 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +0 -1
- package/dist/modes/interactive/components/session-selector-search.js +0 -1
- package/dist/modes/interactive/components/session-selector.d.ts +0 -1
- package/dist/modes/interactive/components/session-selector.js +0 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +0 -3
- package/dist/modes/interactive/components/settings-selector.js +1 -14
- package/dist/modes/interactive/components/show-images-selector.d.ts +0 -1
- package/dist/modes/interactive/components/show-images-selector.js +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +0 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +0 -1
- package/dist/modes/interactive/components/status-indicator.js +0 -1
- package/dist/modes/interactive/components/theme-selector.d.ts +0 -1
- package/dist/modes/interactive/components/theme-selector.js +0 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts +0 -1
- package/dist/modes/interactive/components/thinking-selector.js +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/dist/modes/interactive/components/tool-execution.js +0 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +0 -1
- package/dist/modes/interactive/components/tree-selector.js +0 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +0 -1
- package/dist/modes/interactive/components/trust-selector.js +0 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts +0 -1
- package/dist/modes/interactive/components/user-message-selector.js +0 -1
- package/dist/modes/interactive/components/user-message.d.ts +0 -1
- package/dist/modes/interactive/components/user-message.js +0 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +0 -1
- package/dist/modes/interactive/components/visual-truncate.js +0 -1
- package/dist/modes/interactive/external-editor.d.ts +0 -1
- package/dist/modes/interactive/external-editor.js +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -2
- package/dist/modes/interactive/interactive-mode.js +1 -22
- package/dist/modes/interactive/model-search.d.ts +0 -1
- package/dist/modes/interactive/model-search.js +0 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +0 -1
- package/dist/modes/interactive/theme/theme-controller.js +0 -1
- package/dist/modes/interactive/theme/theme.d.ts +0 -1
- package/dist/modes/interactive/theme/theme.js +0 -1
- package/dist/modes/print-mode.d.ts +0 -1
- package/dist/modes/print-mode.js +0 -1
- package/dist/modes/rpc/jsonl.d.ts +0 -1
- package/dist/modes/rpc/jsonl.js +0 -1
- package/dist/modes/rpc/rpc-client.d.ts +1 -2
- package/dist/modes/rpc/rpc-client.js +1 -2
- package/dist/modes/rpc/rpc-mode.d.ts +0 -1
- package/dist/modes/rpc/rpc-mode.js +0 -9
- package/dist/modes/rpc/rpc-types.d.ts +0 -1
- package/dist/modes/rpc/rpc-types.js +0 -1
- package/dist/package-manager-cli.d.ts +0 -1
- package/dist/package-manager-cli.js +0 -1
- package/dist/rpc-entry.d.ts +0 -1
- package/dist/rpc-entry.js +0 -1
- package/dist/utils/ansi.d.ts +0 -1
- package/dist/utils/ansi.js +0 -1
- package/dist/utils/changelog.d.ts +0 -1
- package/dist/utils/changelog.js +0 -1
- package/dist/utils/child-process.d.ts +0 -1
- package/dist/utils/child-process.js +0 -1
- package/dist/utils/clipboard-image.d.ts +0 -1
- package/dist/utils/clipboard-image.js +0 -1
- package/dist/utils/clipboard-native.d.ts +0 -1
- package/dist/utils/clipboard-native.js +0 -1
- package/dist/utils/clipboard.d.ts +0 -1
- package/dist/utils/clipboard.js +0 -1
- package/dist/utils/deprecation.d.ts +0 -1
- package/dist/utils/deprecation.js +0 -1
- package/dist/utils/exif-orientation.d.ts +0 -1
- package/dist/utils/exif-orientation.js +0 -1
- package/dist/utils/frontmatter.d.ts +0 -1
- package/dist/utils/frontmatter.js +0 -1
- package/dist/utils/fs-watch.d.ts +0 -1
- package/dist/utils/fs-watch.js +0 -1
- package/dist/utils/git.d.ts +0 -1
- package/dist/utils/git.js +0 -1
- package/dist/utils/html.d.ts +0 -1
- package/dist/utils/html.js +0 -1
- package/dist/utils/image-convert.d.ts +0 -1
- package/dist/utils/image-convert.js +0 -1
- package/dist/utils/image-process.d.ts +0 -1
- package/dist/utils/image-process.js +0 -1
- package/dist/utils/image-resize-core.d.ts +0 -1
- package/dist/utils/image-resize-core.js +0 -1
- package/dist/utils/image-resize-worker.d.ts +0 -1
- package/dist/utils/image-resize-worker.js +0 -1
- package/dist/utils/image-resize.d.ts +0 -1
- package/dist/utils/image-resize.js +0 -1
- package/dist/utils/json.d.ts +0 -1
- package/dist/utils/json.js +0 -1
- package/dist/utils/mime.d.ts +0 -1
- package/dist/utils/mime.js +0 -1
- package/dist/utils/open-browser.d.ts +0 -1
- package/dist/utils/open-browser.js +0 -1
- package/dist/utils/paths.d.ts +0 -1
- package/dist/utils/paths.js +0 -1
- package/dist/utils/photon.d.ts +0 -1
- package/dist/utils/photon.js +0 -1
- package/dist/utils/pi-user-agent.d.ts +0 -1
- package/dist/utils/pi-user-agent.js +0 -1
- package/dist/utils/shell.d.ts +0 -1
- package/dist/utils/shell.js +0 -1
- package/dist/utils/sleep.d.ts +0 -1
- package/dist/utils/sleep.js +0 -1
- package/dist/utils/syntax-highlight.d.ts +0 -1
- package/dist/utils/syntax-highlight.js +0 -1
- package/dist/utils/thinking-tags.d.ts +0 -1
- package/dist/utils/thinking-tags.js +0 -1
- package/dist/utils/tools-manager.d.ts +3 -3
- package/dist/utils/tools-manager.js +125 -42
- package/dist/utils/version-check.d.ts +0 -1
- package/dist/utils/version-check.js +0 -1
- package/dist/utils/windows-self-update.d.ts +0 -1
- package/dist/utils/windows-self-update.js +0 -1
- package/docs/rpc.md +1 -2
- package/docs/settings.md +0 -1
- package/docs/skills.md +10 -18
- package/package.json +3 -2
- package/dist/bun/cli.d.ts.map +0 -1
- package/dist/bun/cli.js.map +0 -1
- package/dist/bun/register-bedrock.d.ts.map +0 -1
- package/dist/bun/register-bedrock.js.map +0 -1
- package/dist/bun/restore-sandbox-env.d.ts.map +0 -1
- package/dist/bun/restore-sandbox-env.js.map +0 -1
- package/dist/cli/args.d.ts.map +0 -1
- package/dist/cli/args.js.map +0 -1
- package/dist/cli/config-selector.d.ts.map +0 -1
- package/dist/cli/config-selector.js.map +0 -1
- package/dist/cli/credential-print.d.ts.map +0 -1
- package/dist/cli/credential-print.js.map +0 -1
- package/dist/cli/file-processor.d.ts.map +0 -1
- package/dist/cli/file-processor.js.map +0 -1
- package/dist/cli/initial-message.d.ts.map +0 -1
- package/dist/cli/initial-message.js.map +0 -1
- package/dist/cli/list-models.d.ts.map +0 -1
- package/dist/cli/list-models.js.map +0 -1
- package/dist/cli/project-trust.d.ts.map +0 -1
- package/dist/cli/project-trust.js.map +0 -1
- package/dist/cli/session-picker.d.ts.map +0 -1
- package/dist/cli/session-picker.js.map +0 -1
- package/dist/cli/startup-ui.d.ts.map +0 -1
- package/dist/cli/startup-ui.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/core/agent-session-auto-handoff.test.d.ts.map +0 -1
- package/dist/core/agent-session-auto-handoff.test.js.map +0 -1
- package/dist/core/agent-session-runtime.d.ts.map +0 -1
- package/dist/core/agent-session-runtime.js.map +0 -1
- package/dist/core/agent-session-services.d.ts.map +0 -1
- package/dist/core/agent-session-services.js.map +0 -1
- package/dist/core/agent-session-skill-block.test.d.ts.map +0 -1
- package/dist/core/agent-session-skill-block.test.js.map +0 -1
- package/dist/core/agent-session.d.ts.map +0 -1
- package/dist/core/agent-session.js.map +0 -1
- package/dist/core/agents.d.ts.map +0 -1
- package/dist/core/agents.js.map +0 -1
- package/dist/core/auth-guidance.d.ts.map +0 -1
- package/dist/core/auth-guidance.js.map +0 -1
- package/dist/core/auth-storage.d.ts.map +0 -1
- package/dist/core/auth-storage.js.map +0 -1
- package/dist/core/bash-executor.d.ts.map +0 -1
- package/dist/core/bash-executor.js.map +0 -1
- package/dist/core/built-in-extensions.d.ts.map +0 -1
- package/dist/core/built-in-extensions.js.map +0 -1
- package/dist/core/cache-stats.d.ts.map +0 -1
- package/dist/core/cache-stats.js.map +0 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
- package/dist/core/compaction/branch-summarization.js.map +0 -1
- package/dist/core/compaction/compaction.d.ts.map +0 -1
- package/dist/core/compaction/compaction.js.map +0 -1
- package/dist/core/compaction/index.d.ts.map +0 -1
- package/dist/core/compaction/index.js.map +0 -1
- package/dist/core/compaction/utils.d.ts.map +0 -1
- package/dist/core/compaction/utils.js.map +0 -1
- package/dist/core/defaults.d.ts.map +0 -1
- package/dist/core/defaults.js.map +0 -1
- package/dist/core/diagnostics.d.ts.map +0 -1
- package/dist/core/diagnostics.js.map +0 -1
- package/dist/core/event-bus.d.ts.map +0 -1
- package/dist/core/event-bus.js.map +0 -1
- package/dist/core/exec.d.ts.map +0 -1
- package/dist/core/exec.js.map +0 -1
- package/dist/core/experimental.d.ts.map +0 -1
- package/dist/core/experimental.js.map +0 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
- package/dist/core/export-html/ansi-to-html.js.map +0 -1
- package/dist/core/export-html/index.d.ts.map +0 -1
- package/dist/core/export-html/index.js.map +0 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
- package/dist/core/export-html/tool-renderer.js.map +0 -1
- package/dist/core/extensions/index.d.ts.map +0 -1
- package/dist/core/extensions/index.js.map +0 -1
- package/dist/core/extensions/loader.d.ts.map +0 -1
- package/dist/core/extensions/loader.js.map +0 -1
- package/dist/core/extensions/runner.d.ts.map +0 -1
- package/dist/core/extensions/runner.js.map +0 -1
- package/dist/core/extensions/types.d.ts.map +0 -1
- package/dist/core/extensions/types.js.map +0 -1
- package/dist/core/extensions/wrapper.d.ts.map +0 -1
- package/dist/core/extensions/wrapper.js.map +0 -1
- package/dist/core/footer-data-provider.d.ts.map +0 -1
- package/dist/core/footer-data-provider.js.map +0 -1
- package/dist/core/git-command.d.ts.map +0 -1
- package/dist/core/git-command.js.map +0 -1
- package/dist/core/http-dispatcher.d.ts.map +0 -1
- package/dist/core/http-dispatcher.js.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -1
- package/dist/core/keybindings.d.ts.map +0 -1
- package/dist/core/keybindings.js.map +0 -1
- package/dist/core/llama/client.d.ts.map +0 -1
- package/dist/core/llama/client.js.map +0 -1
- package/dist/core/llama/huggingface.d.ts.map +0 -1
- package/dist/core/llama/huggingface.js.map +0 -1
- package/dist/core/llama/index.d.ts.map +0 -1
- package/dist/core/llama/index.js.map +0 -1
- package/dist/core/llama/provider.d.ts.map +0 -1
- package/dist/core/llama/provider.js.map +0 -1
- package/dist/core/llama/ui.d.ts.map +0 -1
- package/dist/core/llama/ui.js.map +0 -1
- package/dist/core/messages.d.ts.map +0 -1
- package/dist/core/messages.js.map +0 -1
- package/dist/core/model-config.d.ts.map +0 -1
- package/dist/core/model-config.js.map +0 -1
- package/dist/core/model-registry.d.ts.map +0 -1
- package/dist/core/model-registry.js.map +0 -1
- package/dist/core/model-resolver.d.ts.map +0 -1
- package/dist/core/model-resolver.js.map +0 -1
- package/dist/core/model-runtime.d.ts.map +0 -1
- package/dist/core/model-runtime.js.map +0 -1
- package/dist/core/models-store.d.ts.map +0 -1
- package/dist/core/models-store.js.map +0 -1
- package/dist/core/output-guard.d.ts.map +0 -1
- package/dist/core/output-guard.js.map +0 -1
- package/dist/core/package-manager.d.ts.map +0 -1
- package/dist/core/package-manager.js.map +0 -1
- package/dist/core/package-manager.test.d.ts.map +0 -1
- package/dist/core/package-manager.test.js.map +0 -1
- package/dist/core/project-trust.d.ts.map +0 -1
- package/dist/core/project-trust.js.map +0 -1
- package/dist/core/prompt-templates.d.ts.map +0 -1
- package/dist/core/prompt-templates.js.map +0 -1
- package/dist/core/provider-attribution.d.ts.map +0 -1
- package/dist/core/provider-attribution.js.map +0 -1
- package/dist/core/provider-composer.d.ts.map +0 -1
- package/dist/core/provider-composer.js.map +0 -1
- package/dist/core/radius.d.ts.map +0 -1
- package/dist/core/radius.js.map +0 -1
- package/dist/core/remote-catalog-provider.d.ts.map +0 -1
- package/dist/core/remote-catalog-provider.js.map +0 -1
- package/dist/core/resolve-config-value.d.ts.map +0 -1
- package/dist/core/resolve-config-value.js.map +0 -1
- package/dist/core/resource-loader.d.ts.map +0 -1
- package/dist/core/resource-loader.js.map +0 -1
- package/dist/core/runtime-credentials.d.ts.map +0 -1
- package/dist/core/runtime-credentials.js.map +0 -1
- package/dist/core/sdk.d.ts.map +0 -1
- package/dist/core/sdk.js.map +0 -1
- package/dist/core/session-cwd.d.ts.map +0 -1
- package/dist/core/session-cwd.js.map +0 -1
- package/dist/core/session-manager.d.ts.map +0 -1
- package/dist/core/session-manager.js.map +0 -1
- package/dist/core/settings-manager-auto-handoff.test.d.ts.map +0 -1
- package/dist/core/settings-manager-auto-handoff.test.js.map +0 -1
- package/dist/core/settings-manager.d.ts.map +0 -1
- package/dist/core/settings-manager.js.map +0 -1
- package/dist/core/skills.d.ts.map +0 -1
- package/dist/core/skills.js.map +0 -1
- package/dist/core/slash-commands.d.ts.map +0 -1
- package/dist/core/slash-commands.js.map +0 -1
- package/dist/core/source-info.d.ts.map +0 -1
- package/dist/core/source-info.js.map +0 -1
- package/dist/core/system-prompt.d.ts.map +0 -1
- package/dist/core/system-prompt.js.map +0 -1
- package/dist/core/system-prompt.test.d.ts.map +0 -1
- package/dist/core/system-prompt.test.js.map +0 -1
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js.map +0 -1
- package/dist/core/timings.d.ts.map +0 -1
- package/dist/core/timings.js.map +0 -1
- package/dist/core/tools/bash.d.ts.map +0 -1
- package/dist/core/tools/bash.js.map +0 -1
- package/dist/core/tools/edit-diff.d.ts.map +0 -1
- package/dist/core/tools/edit-diff.js.map +0 -1
- package/dist/core/tools/edit.d.ts.map +0 -1
- package/dist/core/tools/edit.js.map +0 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
- package/dist/core/tools/file-mutation-queue.js.map +0 -1
- package/dist/core/tools/find.d.ts.map +0 -1
- package/dist/core/tools/find.js.map +0 -1
- package/dist/core/tools/grep.d.ts.map +0 -1
- package/dist/core/tools/grep.js.map +0 -1
- package/dist/core/tools/index.d.ts.map +0 -1
- package/dist/core/tools/index.js.map +0 -1
- package/dist/core/tools/ls.d.ts.map +0 -1
- package/dist/core/tools/ls.js.map +0 -1
- package/dist/core/tools/output-accumulator.d.ts.map +0 -1
- package/dist/core/tools/output-accumulator.js.map +0 -1
- package/dist/core/tools/path-utils.d.ts.map +0 -1
- package/dist/core/tools/path-utils.js.map +0 -1
- package/dist/core/tools/read.d.ts.map +0 -1
- package/dist/core/tools/read.js.map +0 -1
- package/dist/core/tools/render-utils.d.ts.map +0 -1
- package/dist/core/tools/render-utils.js.map +0 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
- package/dist/core/tools/truncate.d.ts.map +0 -1
- package/dist/core/tools/truncate.js.map +0 -1
- package/dist/core/tools/write.d.ts.map +0 -1
- package/dist/core/tools/write.js.map +0 -1
- package/dist/core/trust-manager.d.ts.map +0 -1
- package/dist/core/trust-manager.js.map +0 -1
- package/dist/core/usage-totals.d.ts.map +0 -1
- package/dist/core/usage-totals.js.map +0 -1
- package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/dist/extensions/pi-subagents/test/unit/slash-chain-groups.test.ts +0 -464
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/migrations.d.ts.map +0 -1
- package/dist/migrations.js.map +0 -1
- package/dist/modes/index.d.ts.map +0 -1
- package/dist/modes/index.js.map +0 -1
- package/dist/modes/interactive/components/armin.d.ts.map +0 -1
- package/dist/modes/interactive/components/armin.js.map +0 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/assistant-message.js.map +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
- package/dist/modes/interactive/components/bash-execution.js.map +0 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/config-selector.js.map +0 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
- package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-editor.js.map +0 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-entry.js.map +0 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-message.js.map +0 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
- package/dist/modes/interactive/components/daxnuts.js.map +0 -1
- package/dist/modes/interactive/components/diff.d.ts.map +0 -1
- package/dist/modes/interactive/components/diff.js.map +0 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-editor.js.map +0 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-input.js.map +0 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-selector.js.map +0 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +0 -1
- package/dist/modes/interactive/components/first-time-setup.js.map +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +0 -1
- package/dist/modes/interactive/components/footer.js.map +0 -1
- package/dist/modes/interactive/components/index.d.ts.map +0 -1
- package/dist/modes/interactive/components/index.js.map +0 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
- package/dist/modes/interactive/components/login-dialog.js.map +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/model-selector.js.map +0 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/session-selector.js.map +0 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/settings-selector.js.map +0 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +0 -1
- package/dist/modes/interactive/components/status-indicator.js.map +0 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/theme-selector.js.map +0 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-execution.js.map +0 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/tree-selector.js.map +0 -1
- package/dist/modes/interactive/components/trust-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/trust-selector.js.map +0 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/user-message.js.map +0 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
- package/dist/modes/interactive/external-editor.d.ts.map +0 -1
- package/dist/modes/interactive/external-editor.js.map +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
- package/dist/modes/interactive/interactive-mode.js.map +0 -1
- package/dist/modes/interactive/model-search.d.ts.map +0 -1
- package/dist/modes/interactive/model-search.js.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme.js.map +0 -1
- package/dist/modes/print-mode.d.ts.map +0 -1
- package/dist/modes/print-mode.js.map +0 -1
- package/dist/modes/rpc/jsonl.d.ts.map +0 -1
- package/dist/modes/rpc/jsonl.js.map +0 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-client.js.map +0 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-mode.js.map +0 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-types.js.map +0 -1
- package/dist/package-manager-cli.d.ts.map +0 -1
- package/dist/package-manager-cli.js.map +0 -1
- package/dist/rpc-entry.d.ts.map +0 -1
- package/dist/rpc-entry.js.map +0 -1
- package/dist/utils/ansi.d.ts.map +0 -1
- package/dist/utils/ansi.js.map +0 -1
- package/dist/utils/changelog.d.ts.map +0 -1
- package/dist/utils/changelog.js.map +0 -1
- package/dist/utils/child-process.d.ts.map +0 -1
- package/dist/utils/child-process.js.map +0 -1
- package/dist/utils/clipboard-image.d.ts.map +0 -1
- package/dist/utils/clipboard-image.js.map +0 -1
- package/dist/utils/clipboard-native.d.ts.map +0 -1
- package/dist/utils/clipboard-native.js.map +0 -1
- package/dist/utils/clipboard.d.ts.map +0 -1
- package/dist/utils/clipboard.js.map +0 -1
- package/dist/utils/deprecation.d.ts.map +0 -1
- package/dist/utils/deprecation.js.map +0 -1
- package/dist/utils/exif-orientation.d.ts.map +0 -1
- package/dist/utils/exif-orientation.js.map +0 -1
- package/dist/utils/frontmatter.d.ts.map +0 -1
- package/dist/utils/frontmatter.js.map +0 -1
- package/dist/utils/fs-watch.d.ts.map +0 -1
- package/dist/utils/fs-watch.js.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/html.d.ts.map +0 -1
- package/dist/utils/html.js.map +0 -1
- package/dist/utils/image-convert.d.ts.map +0 -1
- package/dist/utils/image-convert.js.map +0 -1
- package/dist/utils/image-process.d.ts.map +0 -1
- package/dist/utils/image-process.js.map +0 -1
- package/dist/utils/image-resize-core.d.ts.map +0 -1
- package/dist/utils/image-resize-core.js.map +0 -1
- package/dist/utils/image-resize-worker.d.ts.map +0 -1
- package/dist/utils/image-resize-worker.js.map +0 -1
- package/dist/utils/image-resize.d.ts.map +0 -1
- package/dist/utils/image-resize.js.map +0 -1
- package/dist/utils/json.d.ts.map +0 -1
- package/dist/utils/json.js.map +0 -1
- package/dist/utils/mime.d.ts.map +0 -1
- package/dist/utils/mime.js.map +0 -1
- package/dist/utils/open-browser.d.ts.map +0 -1
- package/dist/utils/open-browser.js.map +0 -1
- package/dist/utils/paths.d.ts.map +0 -1
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/photon.d.ts.map +0 -1
- package/dist/utils/photon.js.map +0 -1
- package/dist/utils/pi-user-agent.d.ts.map +0 -1
- package/dist/utils/pi-user-agent.js.map +0 -1
- package/dist/utils/shell.d.ts.map +0 -1
- package/dist/utils/shell.js.map +0 -1
- package/dist/utils/sleep.d.ts.map +0 -1
- package/dist/utils/sleep.js.map +0 -1
- package/dist/utils/syntax-highlight.d.ts.map +0 -1
- package/dist/utils/syntax-highlight.js.map +0 -1
- package/dist/utils/thinking-tags.d.ts.map +0 -1
- package/dist/utils/thinking-tags.js.map +0 -1
- package/dist/utils/tools-manager.d.ts.map +0 -1
- package/dist/utils/tools-manager.js.map +0 -1
- package/dist/utils/version-check.d.ts.map +0 -1
- package/dist/utils/version-check.js.map +0 -1
- package/dist/utils/windows-self-update.d.ts.map +0 -1
- package/dist/utils/windows-self-update.js.map +0 -1
|
@@ -80,7 +80,7 @@ interface AsyncResultPayload {
|
|
|
80
80
|
totalCost?: { inputTokens: number; outputTokens: number; costUsd: number };
|
|
81
81
|
usageBudget?: UsageBudgetState;
|
|
82
82
|
checkpoint?: { name?: string; status?: string };
|
|
83
|
-
results: Array<{ agent?: string; launchContractDigest?: string; launchResolvedExtensions?: LaunchResolvedExtensions; runtimeAcknowledgedExtensions?: RuntimeAcknowledgedExtensions; output?: string;
|
|
83
|
+
results: Array<{ agent?: string; launchContractDigest?: string; launchResolvedExtensions?: LaunchResolvedExtensions; runtimeAcknowledgedExtensions?: RuntimeAcknowledgedExtensions; output?: string; outputState?: "present" | "absent" | "unknown"; success?: boolean; error?: string; protocolError?: { code?: string; stream?: string; limitBytes?: number; observedBytes?: number }; timedOut?: boolean; stopped?: boolean; turnBudget?: { maxTurns: number; graceTurns: number; outcome: string; turnCount: number; wrapUpRequestedAtTurn?: number; terminationDeferredAtTurn?: number; exceededAtTurn?: number }; turnBudgetExceeded?: boolean; wrapUpRequested?: boolean; model?: string; attemptedModels?: string[]; modelAttempts?: Array<{ success?: boolean; error?: string }>; totalCost?: { inputTokens: number; outputTokens: number; costUsd: number }; structuredOutput?: unknown; agentContract?: { version: 1 }; execution?: { status?: string; success?: boolean; exitCode?: number }; effects?: { fileMutation?: { status?: string; expected?: boolean; attempted?: boolean } }; intercomTarget?: string; acceptance?: { status?: string; effectiveAcceptance?: { level?: string }; childReport?: unknown; runtimeChecks?: Array<{ id?: string; status?: string; message?: string }> }; artifactPaths?: { outputPath?: string; inputPath?: string; metadataPath?: string }; outputSaveError?: string; metadataSaveError?: string; capabilityCeiling?: { version?: number; allowedTools?: string[]; denyExtensions?: boolean; sources?: string[] }; capabilityAudit?: { effectiveTools?: string[]; removedTools?: string[]; extensionsDenied?: boolean } }>;
|
|
84
84
|
outputs?: Record<string, { text?: string; structured?: unknown }>;
|
|
85
85
|
workflowGraph?: { nodes?: Array<{ kind?: string; label?: string; phase?: string; status?: string; acceptanceStatus?: string; error?: string; outputName?: string; structured?: boolean; children?: Array<{ label?: string; outputName?: string; itemKey?: string; status?: string; acceptanceStatus?: string; error?: string }> }> };
|
|
86
86
|
parallelHandoff?: { version?: number; path?: string; groupCount?: number; childCount?: number; changedPatches?: number; cleanupState?: string };
|
|
@@ -191,7 +191,7 @@ function childWatchdogStatus(runId: string, phase: "idle" | "reviewing" | "autof
|
|
|
191
191
|
return {
|
|
192
192
|
type: CHILD_WATCHDOG_STATUS_EVENT,
|
|
193
193
|
runId,
|
|
194
|
-
agent: "
|
|
194
|
+
agent: "builder",
|
|
195
195
|
childIndex: 0,
|
|
196
196
|
stepIndex: 0,
|
|
197
197
|
seq,
|
|
@@ -453,23 +453,11 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
453
453
|
return JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
-
/**
|
|
457
|
-
* Reference-first async child assertion: the result payload carries the
|
|
458
|
-
* saved-output reference; the full text is read from the durable output path.
|
|
459
|
-
*/
|
|
460
|
-
function assertAsyncChildOutput(payload: AsyncResultPayload, index: number, expected: string): void {
|
|
461
|
-
const child = payload.results[index];
|
|
462
|
-
assert.ok(child, `expected async child ${index}`);
|
|
463
|
-
assert.match(child.output ?? "", /Output saved to: /);
|
|
464
|
-
assert.ok(child.outputPath, `expected a durable output path for child ${index}`);
|
|
465
|
-
assert.equal(fs.readFileSync(child.outputPath, "utf-8"), expected);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
456
|
function launchProtocolTest(id: string): void {
|
|
469
457
|
executeAsyncSingle(id, {
|
|
470
|
-
agent: "
|
|
458
|
+
agent: "builder",
|
|
471
459
|
task: "Exercise child protocol",
|
|
472
|
-
agentConfig: makeAgent("
|
|
460
|
+
agentConfig: makeAgent("builder", { completionGuard: false }),
|
|
473
461
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
474
462
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
475
463
|
shareEnabled: false,
|
|
@@ -492,7 +480,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
492
480
|
launchProtocolTest(id);
|
|
493
481
|
const payload = await readAsyncPayload(id);
|
|
494
482
|
assert.equal(payload.success, true);
|
|
495
|
-
|
|
483
|
+
assert.equal(payload.results[0]?.output, "你好 from fragmented async JSON");
|
|
496
484
|
});
|
|
497
485
|
|
|
498
486
|
it("persists absent output provenance when async lifecycle text is synthetic", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -512,26 +500,23 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
512
500
|
const payload = await readAsyncPayload(id);
|
|
513
501
|
assert.equal(payload.success, false);
|
|
514
502
|
assert.equal(payload.results[0]?.outputState, "present");
|
|
515
|
-
|
|
503
|
+
assert.equal(payload.results[0]?.output, "usable partial answer");
|
|
516
504
|
});
|
|
517
505
|
|
|
518
506
|
it("matches preflight launch digest in equivalent foreground and async execution", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
519
|
-
const agentName = `contract-
|
|
507
|
+
const agentName = `contract-builder-${Date.now().toString(36)}`;
|
|
520
508
|
const task = "Compare the resolved launch inputs.";
|
|
521
509
|
const turnBudget = { maxTurns: 2, graceTurns: 1 } as const;
|
|
522
510
|
const agentPath = path.join(tempDir, ".selesai", "agents", `${agentName}.md`);
|
|
523
511
|
fs.mkdirSync(path.dirname(agentPath), { recursive: true });
|
|
524
|
-
fs.writeFileSync(agentPath, `---\nname: ${agentName}\ndescription: Contract comparison
|
|
512
|
+
fs.writeFileSync(agentPath, `---\nname: ${agentName}\ndescription: Contract comparison builder\n---\n`, "utf-8");
|
|
525
513
|
const discovered = discoverAgents(tempDir).agents.find((agent) => agent.name === agentName);
|
|
526
514
|
assert.ok(discovered, "expected temporary agent definition to be discovered");
|
|
527
|
-
|
|
528
|
-
// both execution paths (generated per-run paths would differ by design).
|
|
529
|
-
const contractOutputPath = path.join(tempDir, "contract-output.md");
|
|
530
|
-
const preflight = await resolveSubagentLaunchContract({ agent: agentName, cwd: tempDir, task, turnBudget, runId: "contract-preflight", output: contractOutputPath });
|
|
515
|
+
const preflight = await resolveSubagentLaunchContract({ agent: agentName, cwd: tempDir, task, turnBudget, runId: "contract-preflight" });
|
|
531
516
|
assert.equal(preflight.ok, true);
|
|
532
517
|
|
|
533
518
|
mockPi.onCall({ output: "foreground contract comparison" });
|
|
534
|
-
const foreground = await runSync(tempDir, [discovered], agentName, task, { runId: "contract-foreground", acceptance: false, turnBudget
|
|
519
|
+
const foreground = await runSync(tempDir, [discovered], agentName, task, { runId: "contract-foreground", acceptance: false, turnBudget });
|
|
535
520
|
assert.equal(foreground.exitCode, 0);
|
|
536
521
|
assert.equal(foreground.launchContractDigest, preflight.contract.launchContractDigest);
|
|
537
522
|
|
|
@@ -540,8 +525,6 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
540
525
|
const launch = executeAsyncSingle(asyncId, {
|
|
541
526
|
agent: agentName,
|
|
542
527
|
task,
|
|
543
|
-
output: contractOutputPath,
|
|
544
|
-
outputMode: "inline",
|
|
545
528
|
agentConfig: discovered,
|
|
546
529
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
547
530
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
@@ -565,9 +548,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
565
548
|
const id = `async-launch-digest-${Date.now().toString(36)}`;
|
|
566
549
|
const privateExtension = path.join(tempDir, "extensions", "private-extension.ts");
|
|
567
550
|
const launch = executeAsyncSingle(id, {
|
|
568
|
-
agent: "
|
|
551
|
+
agent: "builder",
|
|
569
552
|
task: "Exercise launch digest reporting",
|
|
570
|
-
agentConfig: makeAgent("
|
|
553
|
+
agentConfig: makeAgent("builder", { completionGuard: false, extensions: [privateExtension] }),
|
|
571
554
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
572
555
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
573
556
|
shareEnabled: false,
|
|
@@ -629,7 +612,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
629
612
|
|
|
630
613
|
it("foreground checkpoint decisions use current-session control actions", { skip: !createSubagentExecutor ? "executor not available" : undefined }, async () => {
|
|
631
614
|
mockPi.onCall({ output: "analysis done" });
|
|
632
|
-
const executor = makeAsyncExecutor([makeAgent("analyst"), makeAgent("
|
|
615
|
+
const executor = makeAsyncExecutor([makeAgent("analyst"), makeAgent("builder")]);
|
|
633
616
|
const ctx = makeMinimalCtx(tempDir);
|
|
634
617
|
ctx.sessionManager.getSessionId = () => "session-foreground-checkpoint";
|
|
635
618
|
const id = `foreground-checkpoint-${Date.now().toString(36)}`;
|
|
@@ -638,7 +621,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
638
621
|
chain: [
|
|
639
622
|
{ agent: "analyst", task: "Analyze" },
|
|
640
623
|
{ checkpoint: "review", message: "Approve implementation?" },
|
|
641
|
-
{ agent: "
|
|
624
|
+
{ agent: "builder", task: "Implement" },
|
|
642
625
|
],
|
|
643
626
|
}, new AbortController().signal, undefined, ctx) as AsyncExecutionResult;
|
|
644
627
|
|
|
@@ -663,9 +646,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
663
646
|
chain: [
|
|
664
647
|
{ agent: "analyst", task: "Analyze" },
|
|
665
648
|
{ checkpoint: "review" },
|
|
666
|
-
{ agent: "
|
|
649
|
+
{ agent: "builder", task: "Implement" },
|
|
667
650
|
],
|
|
668
|
-
agents: [makeAgent("analyst"), makeAgent("
|
|
651
|
+
agents: [makeAgent("analyst"), makeAgent("builder")],
|
|
669
652
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
670
653
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
671
654
|
shareEnabled: false,
|
|
@@ -734,11 +717,11 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
734
717
|
const sessionFile = path.join(tempDir, "sessions", "parent-session", "session.jsonl");
|
|
735
718
|
const ctx = makeMinimalCtx(tempDir);
|
|
736
719
|
ctx.sessionManager.getSessionFile = () => sessionFile;
|
|
737
|
-
const executor = makeAsyncExecutor([makeAgent("
|
|
720
|
+
const executor = makeAsyncExecutor([makeAgent("builder", { completionGuard: false })], { artifactDir: "session" });
|
|
738
721
|
|
|
739
722
|
const launch = await executor.execute(
|
|
740
723
|
"async-session-artifact-dir",
|
|
741
|
-
{ agent: "
|
|
724
|
+
{ agent: "builder", task: "Write async session artifacts", async: true, runId: "async-session-artifacts", acceptance: false },
|
|
742
725
|
new AbortController().signal,
|
|
743
726
|
undefined,
|
|
744
727
|
ctx,
|
|
@@ -763,13 +746,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
763
746
|
const sessionId = `session-capability-${Date.now().toString(36)}`;
|
|
764
747
|
const handle = registerSubagentCapabilityCeiling({ sessionId, ceiling: { allowedTools: ["read"], denyExtensions: true }, source: "test" });
|
|
765
748
|
try {
|
|
766
|
-
const executor = makeAsyncExecutor([makeAgent("
|
|
749
|
+
const executor = makeAsyncExecutor([makeAgent("builder", { tools: ["read", "write"], completionGuard: false })]);
|
|
767
750
|
const id = `async-capability-${Date.now().toString(36)}`;
|
|
768
751
|
const ctx = makeMinimalCtx(tempDir);
|
|
769
752
|
ctx.sessionManager.getSessionId = () => sessionId;
|
|
770
753
|
const launch = await executor.execute(
|
|
771
754
|
id,
|
|
772
|
-
{ agent: "
|
|
755
|
+
{ agent: "builder", task: "Run with a restricted capability ceiling", async: true, runId: id, acceptance: false, artifacts: true },
|
|
773
756
|
new AbortController().signal,
|
|
774
757
|
undefined,
|
|
775
758
|
ctx,
|
|
@@ -804,9 +787,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
804
787
|
mockPi.onCall({ output: "", stderr: "model unavailable", exitCode: 1 });
|
|
805
788
|
const id = `async-empty-failure-artifact-${Date.now().toString(36)}`;
|
|
806
789
|
executeAsyncSingle(id, {
|
|
807
|
-
agent: "
|
|
790
|
+
agent: "builder",
|
|
808
791
|
task: "Fail before output",
|
|
809
|
-
agentConfig: makeAgent("
|
|
792
|
+
agentConfig: makeAgent("builder", { completionGuard: false }),
|
|
810
793
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
811
794
|
artifactConfig: { enabled: true, includeInput: true, includeOutput: true, includeJsonl: false, includeMetadata: true, cleanupDays: 7 },
|
|
812
795
|
artifactsDir: path.join(tempDir, ".pi-subagents", "artifacts"),
|
|
@@ -826,6 +809,37 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
826
809
|
assert.match(artifact, /Metadata:/);
|
|
827
810
|
});
|
|
828
811
|
|
|
812
|
+
it("recreates project-local artifact directories removed before async completion", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
813
|
+
mockPi.onCall({ delay: 800, output: "completed after artifact cleanup" });
|
|
814
|
+
const id = `async-artifact-dir-recovery-${Date.now().toString(36)}`;
|
|
815
|
+
const artifactsDir = path.join(tempDir, ".pi-subagents", "artifacts");
|
|
816
|
+
executeAsyncSingle(id, {
|
|
817
|
+
agent: "builder",
|
|
818
|
+
task: "Complete after generated artifacts are cleaned",
|
|
819
|
+
agentConfig: makeAgent("builder", { completionGuard: false }),
|
|
820
|
+
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
821
|
+
artifactConfig: { enabled: true, includeInput: true, includeOutput: true, includeJsonl: false, includeMetadata: true, cleanupDays: 7 },
|
|
822
|
+
artifactsDir,
|
|
823
|
+
shareEnabled: false,
|
|
824
|
+
maxSubagentDepth: 2,
|
|
825
|
+
acceptance: false,
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
await waitForMockPiCall(mockPi, 0);
|
|
829
|
+
assert.equal(fs.existsSync(artifactsDir), true);
|
|
830
|
+
fs.rmSync(path.join(tempDir, ".pi-subagents"), { recursive: true, force: true });
|
|
831
|
+
|
|
832
|
+
const payload = await readAsyncPayload(id);
|
|
833
|
+
assert.equal(payload.success, true);
|
|
834
|
+
assert.equal(payload.results[0]?.outputSaveError, undefined);
|
|
835
|
+
assert.equal(payload.results[0]?.metadataSaveError, undefined);
|
|
836
|
+
const outputPath = payload.results[0]?.artifactPaths?.outputPath;
|
|
837
|
+
const metadataPath = payload.results[0]?.artifactPaths?.metadataPath;
|
|
838
|
+
assert.ok(outputPath && metadataPath);
|
|
839
|
+
assert.equal(fs.readFileSync(outputPath, "utf-8"), "completed after artifact cleanup");
|
|
840
|
+
assert.equal((JSON.parse(fs.readFileSync(metadataPath, "utf-8")) as { exitCode?: number }).exitCode, 0);
|
|
841
|
+
});
|
|
842
|
+
|
|
829
843
|
it("background keeps only a bounded UTF-8 stderr tail", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
830
844
|
mockPi.onCall({ output: "failed", stderr: `${"x".repeat(MAX_CHILD_STDERR_BYTES + 1024)}终`, exitCode: 1 });
|
|
831
845
|
const id = `async-stderr-tail-${Date.now().toString(36)}`;
|
|
@@ -836,6 +850,24 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
836
850
|
assert.match(payload.results[0]?.error ?? "", /终$/);
|
|
837
851
|
});
|
|
838
852
|
|
|
853
|
+
it("background preserves retry lifecycle from an oversized agent_end aggregate", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
854
|
+
mockPi.onCall({ steps: [
|
|
855
|
+
{ jsonl: [
|
|
856
|
+
events.assistantMessage("retrying oversized async response"),
|
|
857
|
+
{ type: "agent_end", messages: ["x".repeat(MAX_CHILD_PENDING_LINE_BYTES)], willRetry: true },
|
|
858
|
+
] },
|
|
859
|
+
{ delay: 1400, jsonl: [events.assistantMessage("settled after oversized aggregate"), { type: "agent_end", willRetry: false }, { type: "agent_settled" }] },
|
|
860
|
+
] });
|
|
861
|
+
const id = `async-lifecycle-oversized-retry-${Date.now().toString(36)}`;
|
|
862
|
+
const startedAt = Date.now();
|
|
863
|
+
launchProtocolTest(id);
|
|
864
|
+
const payload = await readAsyncPayload(id);
|
|
865
|
+
assert.equal(payload.success, true);
|
|
866
|
+
assert.equal(payload.results[0]?.protocolError, undefined);
|
|
867
|
+
assert.equal(payload.results[0]?.output, "settled after oversized aggregate");
|
|
868
|
+
assert.ok(Date.now() - startedAt >= 1200, "projected agent_end must cancel the retry drain");
|
|
869
|
+
});
|
|
870
|
+
|
|
839
871
|
it("background cancels final drain while agent_end reports a retry and waits for agent_settled", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
840
872
|
mockPi.onCall({ steps: [
|
|
841
873
|
{ jsonl: [events.assistantMessage("retrying async response"), { type: "agent_end", willRetry: true }] },
|
|
@@ -846,7 +878,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
846
878
|
launchProtocolTest(id);
|
|
847
879
|
const payload = await readAsyncPayload(id);
|
|
848
880
|
assert.equal(payload.success, true);
|
|
849
|
-
|
|
881
|
+
assert.equal(payload.results[0]?.output, "settled async response");
|
|
850
882
|
assert.ok(Date.now() - startedAt >= 1200, "background runner must not terminate during the retry delay");
|
|
851
883
|
});
|
|
852
884
|
|
|
@@ -858,7 +890,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
858
890
|
const payload = await readAsyncPayload(id);
|
|
859
891
|
assert.equal(payload.success, true);
|
|
860
892
|
assert.equal(payload.results[0]?.error, undefined);
|
|
861
|
-
|
|
893
|
+
assert.equal(payload.results[0]?.output, "settled async without a terminal assistant stop");
|
|
862
894
|
assert.ok(Date.now() - startedAt < 4000, "agent_settled should trigger bounded child cleanup");
|
|
863
895
|
});
|
|
864
896
|
|
|
@@ -867,9 +899,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
867
899
|
mockPi.onCall({ output: "OK" });
|
|
868
900
|
const id = `async-single-literal-output-ref-${Date.now().toString(36)}`;
|
|
869
901
|
const result = executeAsyncSingle(id, {
|
|
870
|
-
agent: "
|
|
902
|
+
agent: "builder",
|
|
871
903
|
task,
|
|
872
|
-
agentConfig: makeAgent("
|
|
904
|
+
agentConfig: makeAgent("builder"),
|
|
873
905
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
874
906
|
artifactConfig: {
|
|
875
907
|
enabled: false,
|
|
@@ -889,7 +921,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
889
921
|
assert.match(call.args.at(-1) ?? "", /\{outputs\.name\}/);
|
|
890
922
|
const payload = await readAsyncPayload(id);
|
|
891
923
|
assert.equal(payload.success, true);
|
|
892
|
-
|
|
924
|
+
assert.equal(payload.results[0]?.output, "OK");
|
|
893
925
|
});
|
|
894
926
|
|
|
895
927
|
it("spawns the async runner with node when process.execPath is not node", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -899,9 +931,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
899
931
|
mockPi.onCall({ output: "non-node exec async done" });
|
|
900
932
|
const id = `async-non-node-exec-${Date.now().toString(36)}`;
|
|
901
933
|
const result = executeAsyncSingle(id, {
|
|
902
|
-
agent: "
|
|
934
|
+
agent: "builder",
|
|
903
935
|
task: "Say non-node exec async done. Do not edit files.",
|
|
904
|
-
agentConfig: makeAgent("
|
|
936
|
+
agentConfig: makeAgent("builder"),
|
|
905
937
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
906
938
|
artifactConfig: {
|
|
907
939
|
enabled: false,
|
|
@@ -920,7 +952,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
920
952
|
const resultPath = await waitForAsyncResultFile(id, 30_000);
|
|
921
953
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
922
954
|
assert.equal(payload.success, true);
|
|
923
|
-
|
|
955
|
+
assert.equal(payload.results[0]?.output, "non-node exec async done");
|
|
924
956
|
} finally {
|
|
925
957
|
process.execPath = originalExecPath;
|
|
926
958
|
}
|
|
@@ -933,9 +965,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
933
965
|
mockPi.onCall({ output: "stale node exec async done" });
|
|
934
966
|
const id = `async-stale-node-exec-${Date.now().toString(36)}`;
|
|
935
967
|
const result = executeAsyncSingle(id, {
|
|
936
|
-
agent: "
|
|
968
|
+
agent: "builder",
|
|
937
969
|
task: "Say stale node exec async done. Do not edit files.",
|
|
938
|
-
agentConfig: makeAgent("
|
|
970
|
+
agentConfig: makeAgent("builder"),
|
|
939
971
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
940
972
|
artifactConfig: {
|
|
941
973
|
enabled: false,
|
|
@@ -954,7 +986,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
954
986
|
const resultPath = await waitForAsyncResultFile(id, 10_000);
|
|
955
987
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
956
988
|
assert.equal(payload.success, true);
|
|
957
|
-
|
|
989
|
+
assert.equal(payload.results[0]?.output, "stale node exec async done");
|
|
958
990
|
} finally {
|
|
959
991
|
process.execPath = originalExecPath;
|
|
960
992
|
}
|
|
@@ -1125,9 +1157,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1125
1157
|
const timeoutMs = 1_000;
|
|
1126
1158
|
const startedAt = Date.now();
|
|
1127
1159
|
executeAsyncSingle(id, {
|
|
1128
|
-
agent: "
|
|
1160
|
+
agent: "builder",
|
|
1129
1161
|
task: "Implement with verified acceptance",
|
|
1130
|
-
agentConfig: makeAgent("
|
|
1162
|
+
agentConfig: makeAgent("builder"),
|
|
1131
1163
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
1132
1164
|
artifactConfig: {
|
|
1133
1165
|
enabled: true,
|
|
@@ -1174,9 +1206,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1174
1206
|
});
|
|
1175
1207
|
const id = `async-turn-budget-soft-${Date.now().toString(36)}`;
|
|
1176
1208
|
executeAsyncSingle(id, {
|
|
1177
|
-
agent: "
|
|
1209
|
+
agent: "builder",
|
|
1178
1210
|
task: "Use the final grace turn to wrap up.",
|
|
1179
|
-
agentConfig: makeAgent("
|
|
1211
|
+
agentConfig: makeAgent("builder"),
|
|
1180
1212
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
1181
1213
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1182
1214
|
shareEnabled: false,
|
|
@@ -1195,18 +1227,15 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1195
1227
|
assert.equal(payload.turnBudget?.turnCount, 2);
|
|
1196
1228
|
assert.equal(payload.results[0]?.wrapUpRequested, true);
|
|
1197
1229
|
assert.equal(payload.results[0]?.turnBudget?.turnCount, 2);
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
// and the persisted result file.
|
|
1201
|
-
assert.match(payload.results[0]?.output ?? "", /Output saved to: /);
|
|
1202
|
-
assertAsyncChildOutput(payload, 0, "final wrapped output");
|
|
1230
|
+
assert.match(payload.results[0]?.output ?? "", /Turn budget wrap-up was requested after 1 assistant turn/);
|
|
1231
|
+
assert.match(payload.results[0]?.output ?? "", /final wrapped output/);
|
|
1203
1232
|
assert.equal(status.wrapUpRequested, true);
|
|
1204
1233
|
assert.equal(status.turnBudgetExceeded, undefined);
|
|
1205
1234
|
assert.equal(status.steps?.[0]?.wrapUpRequested, true);
|
|
1206
1235
|
assert.equal(status.steps?.[0]?.turnBudget?.turnCount, 2);
|
|
1207
1236
|
});
|
|
1208
1237
|
|
|
1209
|
-
it("async turn budget
|
|
1238
|
+
it("async turn budget preserves a clean terminal response beyond the final grace turn", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
1210
1239
|
mockPi.onCall({
|
|
1211
1240
|
jsonl: [
|
|
1212
1241
|
mockAssistantMessage("working before wrap-up", "tool_use"),
|
|
@@ -1216,9 +1245,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1216
1245
|
});
|
|
1217
1246
|
const id = `async-turn-budget-hard-${Date.now().toString(36)}`;
|
|
1218
1247
|
executeAsyncSingle(id, {
|
|
1219
|
-
agent: "
|
|
1248
|
+
agent: "builder",
|
|
1220
1249
|
task: "Exceed the turn budget.",
|
|
1221
|
-
agentConfig: makeAgent("
|
|
1250
|
+
agentConfig: makeAgent("builder"),
|
|
1222
1251
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
1223
1252
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1224
1253
|
shareEnabled: false,
|
|
@@ -1229,25 +1258,24 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1229
1258
|
const resultPath = await waitForAsyncResultFile(id, 10_000);
|
|
1230
1259
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
1231
1260
|
const status = JSON.parse(fs.readFileSync(path.join(ASYNC_DIR, id, "status.json"), "utf-8")) as AsyncStatusPayload;
|
|
1232
|
-
assert.equal(payload.success,
|
|
1233
|
-
assert.equal(payload.state, "
|
|
1234
|
-
assert.equal(payload.exitCode,
|
|
1235
|
-
assert.equal(payload.turnBudgetExceeded,
|
|
1261
|
+
assert.equal(payload.success, true);
|
|
1262
|
+
assert.equal(payload.state, "complete");
|
|
1263
|
+
assert.equal(payload.exitCode, 0);
|
|
1264
|
+
assert.equal(payload.turnBudgetExceeded, undefined);
|
|
1236
1265
|
assert.equal(payload.wrapUpRequested, true);
|
|
1237
|
-
assert.equal(payload.turnBudget?.outcome, "
|
|
1266
|
+
assert.equal(payload.turnBudget?.outcome, "wrap-up-requested");
|
|
1238
1267
|
assert.equal(payload.turnBudget?.turnCount, 3);
|
|
1239
|
-
assert.equal(payload.
|
|
1240
|
-
assert.
|
|
1241
|
-
assert.
|
|
1242
|
-
assert.
|
|
1243
|
-
|
|
1244
|
-
assert.equal(status.
|
|
1245
|
-
assert.equal(status.turnBudgetExceeded, true);
|
|
1246
|
-
assert.equal(status.steps?.[0]?.turnBudgetExceeded, true);
|
|
1247
|
-
assert.equal(status.steps?.[0]?.turnBudget?.outcome, "exceeded");
|
|
1268
|
+
assert.equal(payload.results[0]?.turnBudgetExceeded, undefined);
|
|
1269
|
+
assert.match(payload.results[0]?.output ?? "", /safe assistant boundary after tool work/);
|
|
1270
|
+
assert.equal(status.state, "complete");
|
|
1271
|
+
assert.equal(status.turnBudgetExceeded, undefined);
|
|
1272
|
+
assert.equal(status.steps?.[0]?.turnBudgetExceeded, undefined);
|
|
1273
|
+
assert.equal(status.steps?.[0]?.turnBudget?.outcome, "wrap-up-requested");
|
|
1248
1274
|
});
|
|
1249
1275
|
|
|
1250
|
-
it("
|
|
1276
|
+
it("preserves an async clean completion after turn-budget work defers", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
1277
|
+
const id = `async-turn-budget-deferred-${Date.now().toString(36)}`;
|
|
1278
|
+
const releasePath = path.join(tempDir, `${id}.release`);
|
|
1251
1279
|
mockPi.onCall({
|
|
1252
1280
|
steps: [
|
|
1253
1281
|
{
|
|
@@ -1257,7 +1285,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1257
1285
|
],
|
|
1258
1286
|
},
|
|
1259
1287
|
{
|
|
1260
|
-
|
|
1288
|
+
waitForPath: releasePath,
|
|
1261
1289
|
jsonl: [
|
|
1262
1290
|
events.toolResult("bash", "build completed"),
|
|
1263
1291
|
events.toolEnd("bash"),
|
|
@@ -1266,11 +1294,10 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1266
1294
|
},
|
|
1267
1295
|
],
|
|
1268
1296
|
});
|
|
1269
|
-
const id = `async-turn-budget-deferred-${Date.now().toString(36)}`;
|
|
1270
1297
|
executeAsyncSingle(id, {
|
|
1271
|
-
agent: "
|
|
1298
|
+
agent: "builder",
|
|
1272
1299
|
task: "Finish active tool work before enforcing the hard limit.",
|
|
1273
|
-
agentConfig: makeAgent("
|
|
1300
|
+
agentConfig: makeAgent("builder"),
|
|
1274
1301
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
1275
1302
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1276
1303
|
shareEnabled: false,
|
|
@@ -1278,7 +1305,12 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1278
1305
|
turnBudget: { maxTurns: 1, graceTurns: 0 },
|
|
1279
1306
|
});
|
|
1280
1307
|
|
|
1281
|
-
|
|
1308
|
+
let pending: AsyncStatusPayload;
|
|
1309
|
+
try {
|
|
1310
|
+
pending = await waitForDeferredTurnBudget(id);
|
|
1311
|
+
} finally {
|
|
1312
|
+
fs.writeFileSync(releasePath, "release", "utf-8");
|
|
1313
|
+
}
|
|
1282
1314
|
assert.equal(pending.error, undefined);
|
|
1283
1315
|
assert.equal(pending.turnBudgetExceeded, undefined);
|
|
1284
1316
|
assert.equal(pending.turnBudget?.terminationDeferredAtTurn, 1);
|
|
@@ -1288,16 +1320,15 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1288
1320
|
const resultPath = await waitForAsyncResultFile(id, 10_000);
|
|
1289
1321
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
1290
1322
|
const status = JSON.parse(fs.readFileSync(path.join(ASYNC_DIR, id, "status.json"), "utf-8")) as AsyncStatusPayload;
|
|
1291
|
-
assert.equal(payload.state, "
|
|
1292
|
-
assert.equal(payload.turnBudgetExceeded,
|
|
1293
|
-
assert.equal(payload.turnBudget?.outcome, "
|
|
1323
|
+
assert.equal(payload.state, "complete");
|
|
1324
|
+
assert.equal(payload.turnBudgetExceeded, undefined);
|
|
1325
|
+
assert.equal(payload.turnBudget?.outcome, "wrap-up-requested");
|
|
1294
1326
|
assert.equal(payload.turnBudget?.turnCount, 2);
|
|
1295
|
-
assert.equal(payload.results[0]?.turnBudgetExceeded,
|
|
1296
|
-
assert.match(payload.results[0]?.output ?? "", /
|
|
1297
|
-
|
|
1298
|
-
assert.equal(status.
|
|
1299
|
-
assert.equal(status.
|
|
1300
|
-
assert.equal(status.steps?.[0]?.turnBudget?.outcome, "exceeded");
|
|
1327
|
+
assert.equal(payload.results[0]?.turnBudgetExceeded, undefined);
|
|
1328
|
+
assert.match(payload.results[0]?.output ?? "", /safe assistant boundary reached/);
|
|
1329
|
+
assert.equal(status.state, "complete");
|
|
1330
|
+
assert.equal(status.turnBudgetExceeded, undefined);
|
|
1331
|
+
assert.equal(status.steps?.[0]?.turnBudget?.outcome, "wrap-up-requested");
|
|
1301
1332
|
});
|
|
1302
1333
|
|
|
1303
1334
|
it("lets timeout delivery preempt deferred turn-budget termination", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -1314,9 +1345,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1314
1345
|
});
|
|
1315
1346
|
const id = `async-turn-budget-timeout-${Date.now().toString(36)}`;
|
|
1316
1347
|
executeAsyncSingle(id, {
|
|
1317
|
-
agent: "
|
|
1348
|
+
agent: "builder",
|
|
1318
1349
|
task: "Timeout while hard termination is deferred.",
|
|
1319
|
-
agentConfig: makeAgent("
|
|
1350
|
+
agentConfig: makeAgent("builder"),
|
|
1320
1351
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
1321
1352
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1322
1353
|
shareEnabled: false,
|
|
@@ -1356,9 +1387,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1356
1387
|
});
|
|
1357
1388
|
const id = `async-turn-budget-stop-${Date.now().toString(36)}`;
|
|
1358
1389
|
executeAsyncSingle(id, {
|
|
1359
|
-
agent: "
|
|
1390
|
+
agent: "builder",
|
|
1360
1391
|
task: "Stop while hard termination is deferred.",
|
|
1361
|
-
agentConfig: makeAgent("
|
|
1392
|
+
agentConfig: makeAgent("builder"),
|
|
1362
1393
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
1363
1394
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1364
1395
|
shareEnabled: false,
|
|
@@ -1414,13 +1445,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1414
1445
|
const wrappedTask = `Fork preamble: ${"execution ".repeat(20)}`;
|
|
1415
1446
|
const rawGoal = `Caller-facing goal: ${"raw ".repeat(40)}`;
|
|
1416
1447
|
const singleResult = executeAsyncSingle(singleId, {
|
|
1417
|
-
agent: "
|
|
1448
|
+
agent: "builder",
|
|
1418
1449
|
task: wrappedTask,
|
|
1419
1450
|
goal: rawGoal,
|
|
1420
|
-
agentConfig: makeAgent("
|
|
1451
|
+
agentConfig: makeAgent("builder"),
|
|
1421
1452
|
...commonParams,
|
|
1422
1453
|
});
|
|
1423
|
-
assert.match(singleResult.content[0]?.text ?? "", /Async:
|
|
1454
|
+
assert.match(singleResult.content[0]?.text ?? "", /Async: builder \[/);
|
|
1424
1455
|
assert.match(singleResult.content[0]?.text ?? "", /Do not run sleep timers or polling loops/);
|
|
1425
1456
|
assert.match(singleResult.content[0]?.text ?? "", /call subagent_wait\(\)/i);
|
|
1426
1457
|
assert.match(singleResult.content[0]?.text ?? "", /non-interactive run: Pi auto-drains current-session background work at agent_end/);
|
|
@@ -1431,9 +1462,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1431
1462
|
mockPi.onCall({ output: "interactive done" });
|
|
1432
1463
|
const interactiveId = `async-handoff-interactive-${Date.now().toString(36)}`;
|
|
1433
1464
|
const interactiveResult = executeAsyncSingle(interactiveId, {
|
|
1434
|
-
agent: "
|
|
1465
|
+
agent: "builder",
|
|
1435
1466
|
task: "Interactive handoff",
|
|
1436
|
-
agentConfig: makeAgent("
|
|
1467
|
+
agentConfig: makeAgent("builder"),
|
|
1437
1468
|
...commonParams,
|
|
1438
1469
|
ctx: { ...commonParams.ctx, interactive: true },
|
|
1439
1470
|
});
|
|
@@ -1447,9 +1478,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1447
1478
|
mockPi.onCall({ output: "parallel two done" });
|
|
1448
1479
|
const parallelId = `async-handoff-parallel-${Date.now().toString(36)}`;
|
|
1449
1480
|
const parallelResult = executeAsyncChain(parallelId, {
|
|
1450
|
-
chain: [{ parallel: [{ agent: "
|
|
1481
|
+
chain: [{ parallel: [{ agent: "builder", task: "Do one" }, { agent: "commentator", task: "Do two" }] }],
|
|
1451
1482
|
resultMode: "parallel",
|
|
1452
|
-
agents: [makeAgent("
|
|
1483
|
+
agents: [makeAgent("builder"), makeAgent("commentator")],
|
|
1453
1484
|
...commonParams,
|
|
1454
1485
|
});
|
|
1455
1486
|
assert.match(parallelResult.content[0]?.text ?? "", /Async parallel:/);
|
|
@@ -1459,7 +1490,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1459
1490
|
const parallelResultPath = await waitForAsyncResultFile(parallelId, 10_000);
|
|
1460
1491
|
const parallelPayload = JSON.parse(fs.readFileSync(parallelResultPath, "utf-8")) as { agent?: string; mode?: string };
|
|
1461
1492
|
assert.equal(parallelPayload.mode, "parallel");
|
|
1462
|
-
assert.equal(parallelPayload.agent, "parallel:
|
|
1493
|
+
assert.equal(parallelPayload.agent, "parallel:builder+commentator");
|
|
1463
1494
|
|
|
1464
1495
|
mockPi.onCall({ output: "chain done" });
|
|
1465
1496
|
const chainId = `async-handoff-chain-${Date.now().toString(36)}`;
|
|
@@ -1467,8 +1498,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1467
1498
|
const chainChildTask = `Do chained work ${"child ".repeat(15)}`;
|
|
1468
1499
|
const chainResult = executeAsyncChain(chainId, {
|
|
1469
1500
|
task: chainGoal,
|
|
1470
|
-
chain: [{ agent: "
|
|
1471
|
-
agents: [makeAgent("
|
|
1501
|
+
chain: [{ agent: "builder", task: chainChildTask }],
|
|
1502
|
+
agents: [makeAgent("builder")],
|
|
1472
1503
|
...commonParams,
|
|
1473
1504
|
});
|
|
1474
1505
|
assert.match(chainResult.content[0]?.text ?? "", /Async chain:/);
|
|
@@ -1484,8 +1515,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1484
1515
|
const id = `async-missing-extension-tool-${Date.now().toString(36)}`;
|
|
1485
1516
|
|
|
1486
1517
|
executeAsyncChain(id, {
|
|
1487
|
-
chain: [{ agent: "extension-
|
|
1488
|
-
agents: [makeAgent("extension-
|
|
1518
|
+
chain: [{ agent: "extension-builder", task: "Use fixture search" }],
|
|
1519
|
+
agents: [makeAgent("extension-builder", { tools: ["read", "fixture_search"] })],
|
|
1489
1520
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
1490
1521
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1491
1522
|
shareEnabled: false,
|
|
@@ -1502,11 +1533,11 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1502
1533
|
|
|
1503
1534
|
it("applies agent acceptance roles to inferred async acceptance", { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
1504
1535
|
mockPi.onCall({ output: "exploration complete" });
|
|
1505
|
-
const executor = makeAsyncExecutor([makeAgent("
|
|
1536
|
+
const executor = makeAsyncExecutor([makeAgent("builder", { acceptanceRole: "read-only" })]);
|
|
1506
1537
|
|
|
1507
1538
|
const result = await executor.execute(
|
|
1508
1539
|
"async-agent-acceptance-role",
|
|
1509
|
-
{ agent: "
|
|
1540
|
+
{ agent: "builder", task: "Explore the authentication flow", async: true, clarify: false },
|
|
1510
1541
|
new AbortController().signal,
|
|
1511
1542
|
undefined,
|
|
1512
1543
|
makeMinimalCtx(tempDir),
|
|
@@ -1520,11 +1551,11 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1520
1551
|
|
|
1521
1552
|
it("applies agent acceptance roles to inferred async parallel acceptance", { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
1522
1553
|
mockPi.onCall({ output: "parallel exploration complete" });
|
|
1523
|
-
const executor = makeAsyncExecutor([makeAgent("
|
|
1554
|
+
const executor = makeAsyncExecutor([makeAgent("builder", { acceptanceRole: "read-only" })]);
|
|
1524
1555
|
|
|
1525
1556
|
const result = await executor.execute(
|
|
1526
1557
|
"async-parallel-agent-acceptance-role",
|
|
1527
|
-
{ tasks: [{ agent: "
|
|
1558
|
+
{ tasks: [{ agent: "builder", task: "Explore the authentication flow" }], async: true, clarify: false },
|
|
1528
1559
|
new AbortController().signal,
|
|
1529
1560
|
undefined,
|
|
1530
1561
|
makeMinimalCtx(tempDir),
|
|
@@ -1586,7 +1617,6 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1586
1617
|
tasks: [{ agent: "builder", task: "Do async work", output: "async-top-output.md", reads: ["input.md"] }],
|
|
1587
1618
|
async: true,
|
|
1588
1619
|
clarify: false,
|
|
1589
|
-
artifacts: true,
|
|
1590
1620
|
},
|
|
1591
1621
|
new AbortController().signal,
|
|
1592
1622
|
undefined,
|
|
@@ -1637,15 +1667,15 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1637
1667
|
it(`async top-level parallel isolates inherited output (${outputOverride === true ? "output:true" : "omitted output"})`, { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
1638
1668
|
mockPi.onCall({ matchArgIncludes: "Write the first report", output: "first async report" });
|
|
1639
1669
|
mockPi.onCall({ matchArgIncludes: "Write the second report", output: "second async report" });
|
|
1640
|
-
const agent = makeAgent("
|
|
1670
|
+
const agent = makeAgent("builder", { output: "context.md", tools: ["read", "grep", "find", "ls"] });
|
|
1641
1671
|
const executor = makeAsyncExecutor([agent]);
|
|
1642
1672
|
const tasks = [
|
|
1643
|
-
{ agent: "
|
|
1644
|
-
{ agent: "
|
|
1673
|
+
{ agent: "builder", task: "Write the first report", ...(outputOverride !== undefined ? { output: outputOverride } : {}) },
|
|
1674
|
+
{ agent: "builder", task: "Write the second report", ...(outputOverride !== undefined ? { output: outputOverride } : {}) },
|
|
1645
1675
|
];
|
|
1646
1676
|
const launch = await executor.execute(
|
|
1647
1677
|
`async-inherited-output-${outputOverride === true ? "true" : "omitted"}`,
|
|
1648
|
-
{ tasks, async: true, clarify: false
|
|
1678
|
+
{ tasks, async: true, clarify: false },
|
|
1649
1679
|
new AbortController().signal,
|
|
1650
1680
|
undefined,
|
|
1651
1681
|
makeMinimalCtx(tempDir),
|
|
@@ -1654,12 +1684,12 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1654
1684
|
assert.equal(launch.isError, undefined);
|
|
1655
1685
|
const payload = await readAsyncPayload(launch.details?.asyncId as string);
|
|
1656
1686
|
assert.equal(payload.success, true);
|
|
1657
|
-
|
|
1658
|
-
|
|
1687
|
+
assert.equal(payload.results[0]?.output?.split("\n\nOutput saved to:")[0], "first async report");
|
|
1688
|
+
assert.equal(payload.results[1]?.output?.split("\n\nOutput saved to:")[0], "second async report");
|
|
1659
1689
|
const outputDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs", launch.details?.asyncId as string);
|
|
1660
1690
|
const authoritativePaths = [
|
|
1661
|
-
path.join(outputDir, "parallel-0", "0-
|
|
1662
|
-
path.join(outputDir, "parallel-0", "1-
|
|
1691
|
+
path.join(outputDir, "parallel-0", "0-builder", "context.md"),
|
|
1692
|
+
path.join(outputDir, "parallel-0", "1-builder", "context.md"),
|
|
1663
1693
|
];
|
|
1664
1694
|
assert.equal(fs.readFileSync(authoritativePaths[0]!, "utf-8"), "first async report");
|
|
1665
1695
|
assert.equal(fs.readFileSync(authoritativePaths[1]!, "utf-8"), "second async report");
|
|
@@ -1672,8 +1702,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1672
1702
|
const taskArgs = calls.map((name) => (JSON.parse(fs.readFileSync(path.join(mockPi.dir, name), "utf-8")) as MockPiCallRecord).args?.at(-1) ?? "");
|
|
1673
1703
|
const firstTask = taskArgs.find((task) => task.includes("Write the first report")) ?? "";
|
|
1674
1704
|
const secondTask = taskArgs.find((task) => task.includes("Write the second report")) ?? "";
|
|
1675
|
-
assert.ok(firstTask.includes(path.join("parallel-0", "0-
|
|
1676
|
-
assert.ok(secondTask.includes(path.join("parallel-0", "1-
|
|
1705
|
+
assert.ok(firstTask.includes(path.join("parallel-0", "0-builder", "context.md")));
|
|
1706
|
+
assert.ok(secondTask.includes(path.join("parallel-0", "1-builder", "context.md")));
|
|
1677
1707
|
for (const taskArg of [firstTask, secondTask]) {
|
|
1678
1708
|
assert.match(taskArg, /Return the complete artifact in your final response\./);
|
|
1679
1709
|
assert.match(taskArg, /Do not call contact_supervisor merely because no write-capable tool is available\./);
|
|
@@ -1683,13 +1713,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1683
1713
|
}
|
|
1684
1714
|
|
|
1685
1715
|
it("async top-level parallel rejects duplicate explicit output paths before spawning", { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
1686
|
-
const executor = makeAsyncExecutor([makeAgent("
|
|
1716
|
+
const executor = makeAsyncExecutor([makeAgent("builder")]);
|
|
1687
1717
|
const result = await executor.execute(
|
|
1688
1718
|
"async-duplicate-output",
|
|
1689
1719
|
{
|
|
1690
1720
|
tasks: [
|
|
1691
|
-
{ agent: "
|
|
1692
|
-
{ agent: "
|
|
1721
|
+
{ agent: "builder", task: "Write A", output: "same.md" },
|
|
1722
|
+
{ agent: "builder", task: "Write B", output: "same.md" },
|
|
1693
1723
|
],
|
|
1694
1724
|
async: true,
|
|
1695
1725
|
clarify: false,
|
|
@@ -1700,24 +1730,23 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1700
1730
|
);
|
|
1701
1731
|
|
|
1702
1732
|
assert.equal(result.isError, true);
|
|
1703
|
-
assert.match(result.content[0]?.text ?? "", /Parallel tasks 1 \(
|
|
1733
|
+
assert.match(result.content[0]?.text ?? "", /Parallel tasks 1 \(builder\) and 2 \(builder\).*same\.md/);
|
|
1704
1734
|
assert.equal(mockPi.callCount(), 0);
|
|
1705
1735
|
});
|
|
1706
1736
|
|
|
1707
1737
|
it("async top-level parallel preserves distinct explicit output destinations", { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
1708
1738
|
mockPi.onCall({ matchArgIncludes: "first.md", output: "first explicit report" });
|
|
1709
1739
|
mockPi.onCall({ matchArgIncludes: "second.md", output: "second explicit report" });
|
|
1710
|
-
const executor = makeAsyncExecutor([makeAgent("
|
|
1740
|
+
const executor = makeAsyncExecutor([makeAgent("builder", { output: "context.md" })]);
|
|
1711
1741
|
const launch = await executor.execute(
|
|
1712
1742
|
"async-distinct-explicit-output",
|
|
1713
1743
|
{
|
|
1714
1744
|
tasks: [
|
|
1715
|
-
{ agent: "
|
|
1716
|
-
{ agent: "
|
|
1745
|
+
{ agent: "builder", task: "Write A", output: "first.md" },
|
|
1746
|
+
{ agent: "builder", task: "Write B", output: "second.md" },
|
|
1717
1747
|
],
|
|
1718
1748
|
async: true,
|
|
1719
1749
|
clarify: false,
|
|
1720
|
-
artifacts: true,
|
|
1721
1750
|
},
|
|
1722
1751
|
new AbortController().signal,
|
|
1723
1752
|
undefined,
|
|
@@ -1729,8 +1758,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1729
1758
|
const outputDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs", launch.details?.asyncId as string);
|
|
1730
1759
|
assert.equal(fs.readFileSync(path.join(outputDir, "first.md"), "utf-8"), "first explicit report");
|
|
1731
1760
|
assert.equal(fs.readFileSync(path.join(outputDir, "second.md"), "utf-8"), "second explicit report");
|
|
1732
|
-
assert.ok(payload.results[0]?.artifactPaths?.outputPath?.endsWith("
|
|
1733
|
-
assert.ok(payload.results[1]?.artifactPaths?.outputPath?.endsWith("
|
|
1761
|
+
assert.ok(payload.results[0]?.artifactPaths?.outputPath?.endsWith("_builder_0_output.md"));
|
|
1762
|
+
assert.ok(payload.results[1]?.artifactPaths?.outputPath?.endsWith("_builder_1_output.md"));
|
|
1734
1763
|
});
|
|
1735
1764
|
|
|
1736
1765
|
it("async chain static parallel namespaces inherited default outputs", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -1738,8 +1767,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1738
1767
|
mockPi.onCall({ matchArgIncludes: "Write second", output: "chain second report" });
|
|
1739
1768
|
const id = `async-chain-parallel-output-${Date.now().toString(36)}`;
|
|
1740
1769
|
const launch = executeAsyncChain(id, {
|
|
1741
|
-
chain: [{ parallel: [{ agent: "
|
|
1742
|
-
agents: [makeAgent("
|
|
1770
|
+
chain: [{ parallel: [{ agent: "builder", task: "Write first" }, { agent: "builder", task: "Write second" }] }],
|
|
1771
|
+
agents: [makeAgent("builder", { output: "context.md" })],
|
|
1743
1772
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-chain-output" },
|
|
1744
1773
|
artifactConfig: { enabled: true, includeInput: false, includeOutput: true, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1745
1774
|
artifactsDir: path.join(tempDir, ".pi-subagents", "artifacts"),
|
|
@@ -1752,8 +1781,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1752
1781
|
assert.equal(payload.success, true);
|
|
1753
1782
|
const outputDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs", id);
|
|
1754
1783
|
const authoritativePaths = [
|
|
1755
|
-
path.join(outputDir, "parallel-0", "0-
|
|
1756
|
-
path.join(outputDir, "parallel-0", "1-
|
|
1784
|
+
path.join(outputDir, "parallel-0", "0-builder", "context.md"),
|
|
1785
|
+
path.join(outputDir, "parallel-0", "1-builder", "context.md"),
|
|
1757
1786
|
];
|
|
1758
1787
|
assert.equal(fs.readFileSync(authoritativePaths[0]!, "utf-8"), "chain first report");
|
|
1759
1788
|
assert.equal(fs.readFileSync(authoritativePaths[1]!, "utf-8"), "chain second report");
|
|
@@ -1764,8 +1793,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1764
1793
|
assert.equal(fs.readFileSync(artifactPaths[1], "utf-8"), "chain second report");
|
|
1765
1794
|
const calls = fs.readdirSync(mockPi.dir).filter((name) => name.startsWith("call-")).sort();
|
|
1766
1795
|
const taskArgs = calls.map((name) => (JSON.parse(fs.readFileSync(path.join(mockPi.dir, name), "utf-8")) as MockPiCallRecord).args?.at(-1) ?? "");
|
|
1767
|
-
assert.ok(taskArgs.find((task) => task.includes("Write first"))?.includes(path.join("parallel-0", "0-
|
|
1768
|
-
assert.ok(taskArgs.find((task) => task.includes("Write second"))?.includes(path.join("parallel-0", "1-
|
|
1796
|
+
assert.ok(taskArgs.find((task) => task.includes("Write first"))?.includes(path.join("parallel-0", "0-builder", "context.md")));
|
|
1797
|
+
assert.ok(taskArgs.find((task) => task.includes("Write second"))?.includes(path.join("parallel-0", "1-builder", "context.md")));
|
|
1769
1798
|
});
|
|
1770
1799
|
|
|
1771
1800
|
it("async single preserves checked evidence while independent review is pending", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -1796,14 +1825,14 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1796
1825
|
};
|
|
1797
1826
|
const id = `async-acceptance-${Date.now().toString(36)}`;
|
|
1798
1827
|
executeAsyncSingle(id, {
|
|
1799
|
-
agent: "
|
|
1828
|
+
agent: "builder",
|
|
1800
1829
|
task: "Implement acceptance-covered fix",
|
|
1801
|
-
agentConfig: makeAgent("
|
|
1830
|
+
agentConfig: makeAgent("builder", { completionGuard: false }),
|
|
1802
1831
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-acceptance" },
|
|
1803
1832
|
artifactConfig,
|
|
1804
1833
|
shareEnabled: false,
|
|
1805
1834
|
maxSubagentDepth: 2,
|
|
1806
|
-
acceptance: { level: "checked", criteria: ["Patch bug"], review: { agent: "
|
|
1835
|
+
acceptance: { level: "checked", criteria: ["Patch bug"], review: { agent: "commentator", required: true } },
|
|
1807
1836
|
});
|
|
1808
1837
|
const resultPath = await waitForAsyncResultFile(id, 10_000);
|
|
1809
1838
|
const result = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
@@ -1827,13 +1856,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1827
1856
|
tempArtifactsDir: tempDir,
|
|
1828
1857
|
getSubagentSessionRoot: () => tempDir,
|
|
1829
1858
|
expandTilde: (p: string) => p,
|
|
1830
|
-
discoverAgents: () => ({ agents: [makeAgent("
|
|
1859
|
+
discoverAgents: () => ({ agents: [makeAgent("commentator", { defaultProgress: true })] }),
|
|
1831
1860
|
});
|
|
1832
1861
|
|
|
1833
1862
|
const result = await executor.execute(
|
|
1834
1863
|
"async-chain-read-only-progress",
|
|
1835
1864
|
{
|
|
1836
|
-
chain: [{ agent: "
|
|
1865
|
+
chain: [{ agent: "commentator" }],
|
|
1837
1866
|
task: "Review-only. Do not edit files. Return findings.",
|
|
1838
1867
|
async: true,
|
|
1839
1868
|
clarify: false,
|
|
@@ -1923,15 +1952,15 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1923
1952
|
mockPi.onCall({ matchArgIncludes: "Scout API", output: "Scout A async findings" });
|
|
1924
1953
|
mockPi.onCall({ matchArgIncludes: "Scout UI", output: "Scout B async findings" });
|
|
1925
1954
|
mockPi.onCall({ matchArgIncludes: "Synthesize:", output: "Async funnel synthesis" });
|
|
1926
|
-
mockPi.onCall({ matchArgIncludes: "Review funnel A:", output: "Async
|
|
1927
|
-
mockPi.onCall({ matchArgIncludes: "Review funnel B:", output: "Async
|
|
1955
|
+
mockPi.onCall({ matchArgIncludes: "Review funnel A:", output: "Async commentator A done" });
|
|
1956
|
+
mockPi.onCall({ matchArgIncludes: "Review funnel B:", output: "Async commentator B done" });
|
|
1928
1957
|
const id = `async-parallel-funnel-fanout-${Date.now().toString(36)}`;
|
|
1929
1958
|
const result = executeAsyncChain(id, {
|
|
1930
1959
|
chain: [
|
|
1931
1960
|
{
|
|
1932
1961
|
parallel: [
|
|
1933
|
-
{ agent: "
|
|
1934
|
-
{ agent: "
|
|
1962
|
+
{ agent: "explorer-a", task: "Scout API" },
|
|
1963
|
+
{ agent: "explorer-b", task: "Scout UI" },
|
|
1935
1964
|
],
|
|
1936
1965
|
concurrency: 2,
|
|
1937
1966
|
},
|
|
@@ -1944,7 +1973,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1944
1973
|
concurrency: 2,
|
|
1945
1974
|
},
|
|
1946
1975
|
],
|
|
1947
|
-
agents: [makeAgent("
|
|
1976
|
+
agents: [makeAgent("explorer-a"), makeAgent("explorer-b"), makeAgent("synthesizer"), makeAgent("review-a"), makeAgent("review-b")],
|
|
1948
1977
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-parallel-funnel-fanout" },
|
|
1949
1978
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
1950
1979
|
shareEnabled: false,
|
|
@@ -1956,28 +1985,25 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1956
1985
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
1957
1986
|
const status = JSON.parse(fs.readFileSync(path.join(ASYNC_DIR, id, "status.json"), "utf-8")) as AsyncStatusPayload;
|
|
1958
1987
|
assert.equal(payload.success, true);
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1988
|
+
assert.deepEqual(payload.results.map((entry) => entry.output), [
|
|
1989
|
+
"Scout A async findings",
|
|
1990
|
+
"Scout B async findings",
|
|
1991
|
+
"Async funnel synthesis",
|
|
1992
|
+
"Async commentator A done",
|
|
1993
|
+
"Async commentator B done",
|
|
1994
|
+
]);
|
|
1966
1995
|
assert.deepEqual(status.steps?.map((step) => step.status), ["complete", "complete", "complete", "complete", "complete"]);
|
|
1967
1996
|
assert.deepEqual(status.parallelGroups, [
|
|
1968
1997
|
{ start: 0, count: 2, stepIndex: 0 },
|
|
1969
1998
|
{ start: 3, count: 2, stepIndex: 2 },
|
|
1970
1999
|
]);
|
|
1971
2000
|
const funnelTask = readMockPiArgsMatching(mockPi, "Synthesize:").at(-1) ?? "";
|
|
1972
|
-
assert.match(funnelTask, /=== Parallel Task 1 \(
|
|
1973
|
-
assert.match(funnelTask,
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
assert.match(
|
|
1977
|
-
assert.
|
|
1978
|
-
assert.doesNotMatch(funnelTask, /Scout B async findings/);
|
|
1979
|
-
assert.match(readMockPiArgsMatching(mockPi, "Review funnel A:").at(-1) ?? "", /Review funnel A:\nOutput saved to: /);
|
|
1980
|
-
assert.match(readMockPiArgsMatching(mockPi, "Review funnel B:").at(-1) ?? "", /Review funnel B:\nOutput saved to: /);
|
|
2001
|
+
assert.match(funnelTask, /=== Parallel Task 1 \(explorer-a\) ===/);
|
|
2002
|
+
assert.match(funnelTask, /Scout A async findings/);
|
|
2003
|
+
assert.match(funnelTask, /=== Parallel Task 2 \(explorer-b\) ===/);
|
|
2004
|
+
assert.match(funnelTask, /Scout B async findings/);
|
|
2005
|
+
assert.match(readMockPiArgsMatching(mockPi, "Review funnel A:").at(-1) ?? "", /Review funnel A:\nAsync funnel synthesis/);
|
|
2006
|
+
assert.match(readMockPiArgsMatching(mockPi, "Review funnel B:").at(-1) ?? "", /Review funnel B:\nAsync funnel synthesis/);
|
|
1981
2007
|
assert.equal(payload.workflowGraph?.nodes?.[0]?.kind, "parallel-group");
|
|
1982
2008
|
assert.equal(payload.workflowGraph?.nodes?.[0]?.status, "completed");
|
|
1983
2009
|
assert.equal(payload.workflowGraph?.nodes?.[1]?.kind, "step");
|
|
@@ -1997,13 +2023,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
1997
2023
|
{ agent: "producer", task: "Produce targets", as: "targets", outputSchema: { type: "object" } },
|
|
1998
2024
|
{
|
|
1999
2025
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 },
|
|
2000
|
-
parallel: { agent: "
|
|
2026
|
+
parallel: { agent: "commentator", task: "Review {target.path}", label: "Review {target.path}", outputSchema: { type: "object" } },
|
|
2001
2027
|
collect: { as: "reviews" },
|
|
2002
2028
|
concurrency: 1,
|
|
2003
2029
|
},
|
|
2004
2030
|
{ agent: "consumer", task: "Use {outputs.reviews}" },
|
|
2005
2031
|
],
|
|
2006
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2032
|
+
agents: [makeAgent("producer"), makeAgent("commentator"), makeAgent("consumer")],
|
|
2007
2033
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic-placeholder" },
|
|
2008
2034
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2009
2035
|
shareEnabled: false,
|
|
@@ -2019,7 +2045,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2019
2045
|
if (fs.existsSync(statusPath)) status = JSON.parse(fs.readFileSync(statusPath, "utf-8")) as AsyncStatusPayload;
|
|
2020
2046
|
else await new Promise((resolve) => setTimeout(resolve, 50));
|
|
2021
2047
|
}
|
|
2022
|
-
assert.deepEqual(status.steps?.map((step) => step.agent), ["producer", "expand:
|
|
2048
|
+
assert.deepEqual(status.steps?.map((step) => step.agent), ["producer", "expand:commentator", "consumer"]);
|
|
2023
2049
|
assert.equal(status.steps?.[1]?.label, "Review {target.path}");
|
|
2024
2050
|
assert.equal(status.steps?.[1]?.outputName, "reviews");
|
|
2025
2051
|
assert.deepEqual(status.parallelGroups, [{ start: 1, count: 1, stepIndex: 1 }]);
|
|
@@ -2028,7 +2054,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2028
2054
|
const finalStatus = JSON.parse(fs.readFileSync(statusPath, "utf-8")) as AsyncStatusPayload;
|
|
2029
2055
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
2030
2056
|
assert.equal(payload.success, true);
|
|
2031
|
-
assert.deepEqual(finalStatus.steps?.map((step) => step.agent), ["producer", "
|
|
2057
|
+
assert.deepEqual(finalStatus.steps?.map((step) => step.agent), ["producer", "commentator", "commentator", "consumer"]);
|
|
2032
2058
|
assert.deepEqual(finalStatus.parallelGroups, [{ start: 1, count: 2, stepIndex: 1 }]);
|
|
2033
2059
|
});
|
|
2034
2060
|
|
|
@@ -2044,7 +2070,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2044
2070
|
{
|
|
2045
2071
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 },
|
|
2046
2072
|
parallel: {
|
|
2047
|
-
agent: "
|
|
2073
|
+
agent: "commentator",
|
|
2048
2074
|
task: "Review {target.path}",
|
|
2049
2075
|
label: "Review {target.path}",
|
|
2050
2076
|
outputSchema: { type: "object" },
|
|
@@ -2054,7 +2080,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2054
2080
|
},
|
|
2055
2081
|
{ agent: "consumer", task: "Use {outputs.reviews}" },
|
|
2056
2082
|
],
|
|
2057
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2083
|
+
agents: [makeAgent("producer"), makeAgent("commentator", { output: "context.md" }), makeAgent("consumer")],
|
|
2058
2084
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic" },
|
|
2059
2085
|
artifactConfig: { enabled: true, includeInput: false, includeOutput: true, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2060
2086
|
artifactsDir: path.join(tempDir, ".pi-subagents", "artifacts"),
|
|
@@ -2076,8 +2102,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2076
2102
|
assert.deepEqual(collected.map((item) => item.structured), [{ ok: "a" }, { ok: "b" }]);
|
|
2077
2103
|
const outputDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs", id);
|
|
2078
2104
|
const dynamicOutputPaths = [
|
|
2079
|
-
path.join(outputDir, "dynamic-1", "0-
|
|
2080
|
-
path.join(outputDir, "dynamic-1", "1-
|
|
2105
|
+
path.join(outputDir, "dynamic-1", "0-commentator", "context.md"),
|
|
2106
|
+
path.join(outputDir, "dynamic-1", "1-commentator", "context.md"),
|
|
2081
2107
|
];
|
|
2082
2108
|
assert.equal(fs.readFileSync(dynamicOutputPaths[0]!, "utf-8"), "review-a");
|
|
2083
2109
|
assert.equal(fs.readFileSync(dynamicOutputPaths[1]!, "utf-8"), "review-b");
|
|
@@ -2104,13 +2130,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2104
2130
|
{ agent: "producer", task: "Produce targets", as: "targets", outputSchema: { type: "object" } },
|
|
2105
2131
|
{
|
|
2106
2132
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 },
|
|
2107
|
-
parallel: { agent: "
|
|
2133
|
+
parallel: { agent: "commentator", task: "Review {target.path}", outputSchema: { type: "object" } },
|
|
2108
2134
|
collect: { as: "reviews" },
|
|
2109
2135
|
concurrency: 1,
|
|
2110
2136
|
},
|
|
2111
2137
|
],
|
|
2112
2138
|
usageBudget: { tokens: { hard: 200 } },
|
|
2113
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2139
|
+
agents: [makeAgent("producer"), makeAgent("commentator")],
|
|
2114
2140
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic-budget" },
|
|
2115
2141
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2116
2142
|
shareEnabled: false,
|
|
@@ -2125,7 +2151,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2125
2151
|
assert.equal(status.steps?.[1]?.status, "complete");
|
|
2126
2152
|
assert.equal(status.steps?.[2]?.status, "failed");
|
|
2127
2153
|
assert.match(status.steps?.[2]?.error ?? "", /Usage budget exhausted/);
|
|
2128
|
-
assert.equal(payload.results.find((result) => result.agent === "
|
|
2154
|
+
assert.equal(payload.results.find((result) => result.agent === "commentator" && result.skipped)?.skipped, true);
|
|
2129
2155
|
});
|
|
2130
2156
|
|
|
2131
2157
|
it("rejects a shared explicit output before dynamic fanout children start", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -2136,12 +2162,12 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2136
2162
|
{ agent: "producer", task: "Produce targets", as: "targets", outputSchema: { type: "object" } },
|
|
2137
2163
|
{
|
|
2138
2164
|
expand: { from: { output: "targets", path: "/items" }, item: "target", maxItems: 2 },
|
|
2139
|
-
parallel: { agent: "
|
|
2165
|
+
parallel: { agent: "commentator", task: "Review {target.path}", output: "shared.md" },
|
|
2140
2166
|
collect: { as: "reviews" },
|
|
2141
2167
|
concurrency: 2,
|
|
2142
2168
|
},
|
|
2143
2169
|
],
|
|
2144
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2170
|
+
agents: [makeAgent("producer"), makeAgent("commentator")],
|
|
2145
2171
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic-explicit-output" },
|
|
2146
2172
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2147
2173
|
shareEnabled: false,
|
|
@@ -2170,7 +2196,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2170
2196
|
{
|
|
2171
2197
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 2 },
|
|
2172
2198
|
parallel: {
|
|
2173
|
-
agent: "
|
|
2199
|
+
agent: "commentator",
|
|
2174
2200
|
task: "Review {target.path}",
|
|
2175
2201
|
label: "Review {target.path}",
|
|
2176
2202
|
outputSchema: { type: "object" },
|
|
@@ -2179,7 +2205,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2179
2205
|
concurrency: 1,
|
|
2180
2206
|
},
|
|
2181
2207
|
],
|
|
2182
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2208
|
+
agents: [makeAgent("producer"), makeAgent("commentator", { model: "anthropic/claude-sonnet-4-5:high", thinking: "high" })],
|
|
2183
2209
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic" },
|
|
2184
2210
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2185
2211
|
shareEnabled: false,
|
|
@@ -2304,7 +2330,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2304
2330
|
{ agent: "producer", task: "Produce targets", as: "targets", outputSchema: { type: "object" } },
|
|
2305
2331
|
{
|
|
2306
2332
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 },
|
|
2307
|
-
parallel: { agent: "
|
|
2333
|
+
parallel: { agent: "commentator", task: "Review {target.path}", outputSchema: { type: "object" }, acceptance: { level: "checked" } },
|
|
2308
2334
|
collect: { as: "reviews" },
|
|
2309
2335
|
acceptance: {
|
|
2310
2336
|
level: "verified",
|
|
@@ -2312,7 +2338,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2312
2338
|
},
|
|
2313
2339
|
},
|
|
2314
2340
|
],
|
|
2315
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2341
|
+
agents: [makeAgent("producer"), makeAgent("commentator")],
|
|
2316
2342
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic-acceptance-timeout" },
|
|
2317
2343
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2318
2344
|
shareEnabled: false,
|
|
@@ -2347,13 +2373,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2347
2373
|
{ agent: "producer", task: "Produce targets", as: "targets", outputSchema: { type: "object" } },
|
|
2348
2374
|
{
|
|
2349
2375
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 },
|
|
2350
|
-
parallel: { agent: "
|
|
2376
|
+
parallel: { agent: "commentator", task: "Review {target.path}", outputSchema: { type: "object" } },
|
|
2351
2377
|
collect: { as: "reviews" },
|
|
2352
2378
|
concurrency: 1,
|
|
2353
2379
|
},
|
|
2354
2380
|
{ agent: "consumer", task: "Use {outputs.reviews}" },
|
|
2355
2381
|
],
|
|
2356
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2382
|
+
agents: [makeAgent("producer"), makeAgent("commentator"), makeAgent("consumer")],
|
|
2357
2383
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic-targets" },
|
|
2358
2384
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2359
2385
|
shareEnabled: false,
|
|
@@ -2368,10 +2394,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2368
2394
|
const expectedConsumerTarget = `subagent-consumer-${id}-4`;
|
|
2369
2395
|
assert.equal(payload.success, true);
|
|
2370
2396
|
assert.equal(payload.results[3]?.intercomTarget, expectedConsumerTarget);
|
|
2371
|
-
|
|
2372
|
-
assert.ok(consumerChild?.outputPath, "expected a durable output path for the consumer child");
|
|
2373
|
-
assert.match(consumerChild.output ?? "", /Output saved to: /);
|
|
2374
|
-
assert.deepEqual(JSON.parse(fs.readFileSync(consumerChild.outputPath, "utf-8")), { SELESAI_SUBAGENT_INTERCOM_SESSION_NAME: expectedConsumerTarget });
|
|
2397
|
+
assert.deepEqual(JSON.parse(payload.results[3]?.output ?? "{}"), { SELESAI_SUBAGENT_INTERCOM_SESSION_NAME: expectedConsumerTarget });
|
|
2375
2398
|
});
|
|
2376
2399
|
|
|
2377
2400
|
it("async dynamic pre-spawn failures persist failed graph status and error", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -2382,11 +2405,11 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2382
2405
|
{ agent: "producer", task: "Produce targets", as: "targets", outputSchema: { type: "object" } },
|
|
2383
2406
|
{
|
|
2384
2407
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 1 },
|
|
2385
|
-
parallel: { agent: "
|
|
2408
|
+
parallel: { agent: "commentator", task: "Review {target.path}" },
|
|
2386
2409
|
collect: { as: "reviews" },
|
|
2387
2410
|
},
|
|
2388
2411
|
],
|
|
2389
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2412
|
+
agents: [makeAgent("producer"), makeAgent("commentator")],
|
|
2390
2413
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic-fail" },
|
|
2391
2414
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2392
2415
|
shareEnabled: false,
|
|
@@ -2415,11 +2438,11 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2415
2438
|
{ agent: "producer", task: "Produce targets", as: "targets", outputSchema: { type: "object" } },
|
|
2416
2439
|
{
|
|
2417
2440
|
expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 },
|
|
2418
|
-
parallel: { agent: "
|
|
2441
|
+
parallel: { agent: "commentator", task: "Review {target.path}", outputSchema: { type: "object" } },
|
|
2419
2442
|
collect: { as: "reviews", outputSchema: { type: "object" } },
|
|
2420
2443
|
},
|
|
2421
2444
|
],
|
|
2422
|
-
agents: [makeAgent("producer"), makeAgent("
|
|
2445
|
+
agents: [makeAgent("producer"), makeAgent("commentator")],
|
|
2423
2446
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-dynamic-collect-fail" },
|
|
2424
2447
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
2425
2448
|
shareEnabled: false,
|
|
@@ -2448,17 +2471,16 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2448
2471
|
tempArtifactsDir: repoDir,
|
|
2449
2472
|
getSubagentSessionRoot: () => repoDir,
|
|
2450
2473
|
expandTilde: (p: string) => p,
|
|
2451
|
-
discoverAgents: () => ({ agents: [makeAgent("
|
|
2474
|
+
discoverAgents: () => ({ agents: [makeAgent("builder")] }),
|
|
2452
2475
|
});
|
|
2453
2476
|
|
|
2454
2477
|
const result = await executor.execute(
|
|
2455
2478
|
"async-parallel-worktree-fields",
|
|
2456
2479
|
{
|
|
2457
|
-
tasks: [{ agent: "
|
|
2480
|
+
tasks: [{ agent: "builder", task: "Do worktree work", output: "report.md", reads: ["input.md"] }],
|
|
2458
2481
|
async: true,
|
|
2459
2482
|
clarify: false,
|
|
2460
2483
|
worktree: true,
|
|
2461
|
-
artifacts: true,
|
|
2462
2484
|
},
|
|
2463
2485
|
new AbortController().signal,
|
|
2464
2486
|
undefined,
|
|
@@ -2487,7 +2509,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2487
2509
|
groups: Array<{ children: Array<{ agent: string; status: string; patch: { path: string } }>; cleanup: { state: string } }>;
|
|
2488
2510
|
};
|
|
2489
2511
|
assert.equal(handoff.version, 1);
|
|
2490
|
-
assert.equal(handoff.groups[0]!.children[0]!.agent, "
|
|
2512
|
+
assert.equal(handoff.groups[0]!.children[0]!.agent, "builder");
|
|
2491
2513
|
assert.equal(handoff.groups[0]!.children[0]!.status, "completed");
|
|
2492
2514
|
assert.equal(handoff.groups[0]!.cleanup.state, "complete");
|
|
2493
2515
|
assert.equal(fs.existsSync(handoff.groups[0]!.children[0]!.patch.path), true, "patch artifact should outlive cleanup");
|
|
@@ -2556,10 +2578,10 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2556
2578
|
const asyncDir = path.join(ASYNC_DIR, id);
|
|
2557
2579
|
const resultPath = path.join(RESULTS_DIR, `${id}.json`);
|
|
2558
2580
|
const run = executeAsyncSingle(id, {
|
|
2559
|
-
agent: "
|
|
2581
|
+
agent: "builder",
|
|
2560
2582
|
task: "Do work",
|
|
2561
2583
|
acceptance: { level: "none", reason: "descriptor persistence coverage" },
|
|
2562
|
-
agentConfig: makeAgent("
|
|
2584
|
+
agentConfig: makeAgent("builder", {
|
|
2563
2585
|
model: "openai/gpt-5-mini:high",
|
|
2564
2586
|
fallbackModels: ["anthropic/claude-sonnet-4:low"],
|
|
2565
2587
|
}),
|
|
@@ -2594,7 +2616,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2594
2616
|
const descriptorPath = path.join(asyncDir, "recovery-descriptor.json");
|
|
2595
2617
|
const descriptor = JSON.parse(fs.readFileSync(descriptorPath, "utf-8"));
|
|
2596
2618
|
assert.equal(descriptor.sourceRunId, id);
|
|
2597
|
-
assert.equal(descriptor.agent, "
|
|
2619
|
+
assert.equal(descriptor.agent, "builder");
|
|
2598
2620
|
assert.equal(descriptor.model, "openai/gpt-5-mini:high");
|
|
2599
2621
|
assert.deepEqual(descriptor.fallbackModels, ["anthropic/claude-sonnet-4:low"]);
|
|
2600
2622
|
assert.equal(descriptor.cwd, tempDir);
|
|
@@ -2635,9 +2657,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2635
2657
|
mockPi.onCall({ output: "Recovered asynchronously after startup race" });
|
|
2636
2658
|
const id = `async-startup-retry-${Date.now().toString(36)}`;
|
|
2637
2659
|
executeAsyncSingle(id, {
|
|
2638
|
-
agent: "
|
|
2660
|
+
agent: "builder",
|
|
2639
2661
|
task: "Do work",
|
|
2640
|
-
agentConfig: makeAgent("
|
|
2662
|
+
agentConfig: makeAgent("builder", {
|
|
2641
2663
|
model: "openai/gpt-5-mini:high",
|
|
2642
2664
|
fallbackModels: ["anthropic/claude-sonnet-4:low"],
|
|
2643
2665
|
}),
|
|
@@ -2663,7 +2685,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2663
2685
|
assert.equal(payload.results[0]?.model, "openai/gpt-5-mini:high");
|
|
2664
2686
|
assert.deepEqual(payload.results[0]?.attemptedModels, ["openai/gpt-5-mini:high"]);
|
|
2665
2687
|
assert.deepEqual(payload.results[0]?.modelAttempts?.map((attempt) => attempt.success), [false, true]);
|
|
2666
|
-
|
|
2688
|
+
assert.match(payload.results[0]?.output ?? "", /\[startup-retry\].*Recovered asynchronously after startup race/s);
|
|
2667
2689
|
assert.equal(mockPi.callCount(), 2);
|
|
2668
2690
|
});
|
|
2669
2691
|
|
|
@@ -2684,9 +2706,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2684
2706
|
mockPi.onCall({ output: "Recovered after stream failure" });
|
|
2685
2707
|
const id = `async-fallback-stream-${Date.now().toString(36)}`;
|
|
2686
2708
|
executeAsyncSingle(id, {
|
|
2687
|
-
agent: "
|
|
2709
|
+
agent: "builder",
|
|
2688
2710
|
task: "Do work",
|
|
2689
|
-
agentConfig: makeAgent("
|
|
2711
|
+
agentConfig: makeAgent("builder", {
|
|
2690
2712
|
model: "openai/gpt-5-mini:high",
|
|
2691
2713
|
fallbackModels: ["anthropic/claude-sonnet-4:low"],
|
|
2692
2714
|
}),
|
|
@@ -2710,7 +2732,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2710
2732
|
const payload = JSON.parse(fs.readFileSync(await waitForAsyncResultFile(id), "utf-8"));
|
|
2711
2733
|
assert.equal(payload.success, true);
|
|
2712
2734
|
assert.deepEqual(payload.results[0].attemptedModels, ["openai/gpt-5-mini:high", "anthropic/claude-sonnet-4:low"]);
|
|
2713
|
-
|
|
2735
|
+
assert.match(payload.results[0].output ?? "", /Recovered after stream failure/);
|
|
2714
2736
|
assert.equal(mockPi.callCount(), 2);
|
|
2715
2737
|
});
|
|
2716
2738
|
|
|
@@ -2725,9 +2747,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2725
2747
|
mockPi.onCall({ output: "fallback must not run" });
|
|
2726
2748
|
const id = `async-fallback-toolfail-${Date.now().toString(36)}`;
|
|
2727
2749
|
executeAsyncSingle(id, {
|
|
2728
|
-
agent: "
|
|
2750
|
+
agent: "builder",
|
|
2729
2751
|
task: "Do work",
|
|
2730
|
-
agentConfig: makeAgent("
|
|
2752
|
+
agentConfig: makeAgent("builder", {
|
|
2731
2753
|
model: "openai/gpt-5-mini:high",
|
|
2732
2754
|
fallbackModels: ["anthropic/claude-sonnet-4:low"],
|
|
2733
2755
|
}),
|
|
@@ -2773,9 +2795,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2773
2795
|
mockPi.onCall({ output: "Recovered asynchronously" });
|
|
2774
2796
|
const id = `async-fallback-thinking-off-${Date.now().toString(36)}`;
|
|
2775
2797
|
const run = executeAsyncSingle(id, {
|
|
2776
|
-
agent: "
|
|
2798
|
+
agent: "builder",
|
|
2777
2799
|
task: "Do work",
|
|
2778
|
-
agentConfig: makeAgent("
|
|
2800
|
+
agentConfig: makeAgent("builder", {
|
|
2779
2801
|
model: "openai/gpt-5-mini:high",
|
|
2780
2802
|
fallbackModels: ["anthropic/claude-sonnet-4:low"],
|
|
2781
2803
|
thinking: "high",
|
|
@@ -2828,9 +2850,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2828
2850
|
mockPi.onCall({ output: "Recovered asynchronously from empty output" });
|
|
2829
2851
|
const id = `async-empty-output-fallback-${Date.now().toString(36)}`;
|
|
2830
2852
|
executeAsyncSingle(id, {
|
|
2831
|
-
agent: "
|
|
2853
|
+
agent: "builder",
|
|
2832
2854
|
task: "Do work",
|
|
2833
|
-
agentConfig: makeAgent("
|
|
2855
|
+
agentConfig: makeAgent("builder", {
|
|
2834
2856
|
model: "openai/gpt-5-mini",
|
|
2835
2857
|
fallbackModels: ["anthropic/claude-sonnet-4"],
|
|
2836
2858
|
}),
|
|
@@ -2851,7 +2873,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2851
2873
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
2852
2874
|
assert.equal(payload.success, true);
|
|
2853
2875
|
assert.equal(payload.results[0]?.model, "anthropic/claude-sonnet-4");
|
|
2854
|
-
|
|
2876
|
+
assert.match(payload.results[0]?.output ?? "", /Recovered asynchronously from empty output/);
|
|
2855
2877
|
assert.match(payload.results[0]?.modelAttempts?.[0]?.error ?? "", /no output/i);
|
|
2856
2878
|
assert.deepEqual(payload.results[0]?.modelAttempts?.map((attempt) => attempt.success), [false, true]);
|
|
2857
2879
|
assert.equal(mockPi.callCount(), 2);
|
|
@@ -2878,9 +2900,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2878
2900
|
mockPi.onCall({ output: "Recovered asynchronously on fallback" });
|
|
2879
2901
|
const id = `async-empty-output-after-tool-error-${Date.now().toString(36)}`;
|
|
2880
2902
|
executeAsyncSingle(id, {
|
|
2881
|
-
agent: "
|
|
2903
|
+
agent: "builder",
|
|
2882
2904
|
task: "Do work",
|
|
2883
|
-
agentConfig: makeAgent("
|
|
2905
|
+
agentConfig: makeAgent("builder", {
|
|
2884
2906
|
model: "openai/gpt-5-mini",
|
|
2885
2907
|
fallbackModels: ["anthropic/claude-sonnet-4"],
|
|
2886
2908
|
}),
|
|
@@ -2922,9 +2944,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2922
2944
|
const id = `async-zero-exit-provider-error-${Date.now().toString(36)}`;
|
|
2923
2945
|
const asyncDir = path.join(ASYNC_DIR, id);
|
|
2924
2946
|
executeAsyncSingle(id, {
|
|
2925
|
-
agent: "
|
|
2947
|
+
agent: "builder",
|
|
2926
2948
|
task: "Do work",
|
|
2927
|
-
agentConfig: makeAgent("
|
|
2949
|
+
agentConfig: makeAgent("builder", { model: "openai/gpt-5-mini" }),
|
|
2928
2950
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
2929
2951
|
artifactConfig: {
|
|
2930
2952
|
enabled: false,
|
|
@@ -2968,9 +2990,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2968
2990
|
const id = `async-recovered-child-error-${Date.now().toString(36)}`;
|
|
2969
2991
|
const asyncDir = path.join(ASYNC_DIR, id);
|
|
2970
2992
|
executeAsyncSingle(id, {
|
|
2971
|
-
agent: "
|
|
2993
|
+
agent: "builder",
|
|
2972
2994
|
task: "Do work",
|
|
2973
|
-
agentConfig: makeAgent("
|
|
2995
|
+
agentConfig: makeAgent("builder", { model: "openai/gpt-5-mini" }),
|
|
2974
2996
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
2975
2997
|
artifactConfig: {
|
|
2976
2998
|
enabled: false,
|
|
@@ -2991,7 +3013,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
2991
3013
|
assert.equal(payload.exitCode, 0);
|
|
2992
3014
|
assert.equal(payload.results[0]?.success, true);
|
|
2993
3015
|
assert.equal(payload.results[0]?.error, undefined);
|
|
2994
|
-
|
|
3016
|
+
assert.equal(payload.results[0]?.output, "Recovered asynchronously");
|
|
2995
3017
|
const statusPayload = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8")) as AsyncStatusPayload;
|
|
2996
3018
|
assert.equal(statusPayload.state, "complete");
|
|
2997
3019
|
assert.equal(statusPayload.steps?.[0]?.status, "complete");
|
|
@@ -3018,9 +3040,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3018
3040
|
const id = `async-provider-error-empty-stop-${Date.now().toString(36)}`;
|
|
3019
3041
|
const asyncDir = path.join(ASYNC_DIR, id);
|
|
3020
3042
|
executeAsyncSingle(id, {
|
|
3021
|
-
agent: "
|
|
3043
|
+
agent: "builder",
|
|
3022
3044
|
task: "Do work",
|
|
3023
|
-
agentConfig: makeAgent("
|
|
3045
|
+
agentConfig: makeAgent("builder", { model: "openai/gpt-5-mini" }),
|
|
3024
3046
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3025
3047
|
artifactConfig: {
|
|
3026
3048
|
enabled: false,
|
|
@@ -3177,9 +3199,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3177
3199
|
mockPi.onCall({ output: "async inline report" });
|
|
3178
3200
|
const id = `async-string-false-output-${Date.now().toString(36)}`;
|
|
3179
3201
|
const run = executeAsyncSingle(id, {
|
|
3180
|
-
agent: "
|
|
3202
|
+
agent: "builder",
|
|
3181
3203
|
task: "Do work",
|
|
3182
|
-
agentConfig: makeAgent("
|
|
3204
|
+
agentConfig: makeAgent("builder", { output: "default-report.md" }),
|
|
3183
3205
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3184
3206
|
artifactConfig: {
|
|
3185
3207
|
enabled: false,
|
|
@@ -3216,9 +3238,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3216
3238
|
const sessionRoot = path.join(tempDir, "sessions");
|
|
3217
3239
|
|
|
3218
3240
|
executeAsyncSingle(id, {
|
|
3219
|
-
agent: "
|
|
3241
|
+
agent: "builder",
|
|
3220
3242
|
task: "Deploy app",
|
|
3221
|
-
agentConfig: makeAgent("
|
|
3243
|
+
agentConfig: makeAgent("builder"),
|
|
3222
3244
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3223
3245
|
artifactConfig: {
|
|
3224
3246
|
enabled: false,
|
|
@@ -3255,9 +3277,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3255
3277
|
const sessionRoot = path.join(tempDir, "sessions");
|
|
3256
3278
|
|
|
3257
3279
|
executeAsyncSingle(id, {
|
|
3258
|
-
agent: "
|
|
3280
|
+
agent: "builder",
|
|
3259
3281
|
task: "Implement the approved fixes",
|
|
3260
|
-
agentConfig: makeAgent("
|
|
3282
|
+
agentConfig: makeAgent("builder"),
|
|
3261
3283
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3262
3284
|
artifactConfig: {
|
|
3263
3285
|
enabled: false,
|
|
@@ -3290,7 +3312,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3290
3312
|
const eventsPath = path.join(ASYNC_DIR, id, "events.jsonl");
|
|
3291
3313
|
const eventsText = fs.readFileSync(eventsPath, "utf-8");
|
|
3292
3314
|
assert.match(eventsText, /"reason":"completion_guard"/);
|
|
3293
|
-
assert.match(eventsText, /Subagent failed:
|
|
3315
|
+
assert.match(eventsText, /Subagent failed: builder/);
|
|
3294
3316
|
assert.doesNotMatch(eventsText, /Status:/);
|
|
3295
3317
|
assert.doesNotMatch(eventsText, /Interrupt:/);
|
|
3296
3318
|
});
|
|
@@ -3300,9 +3322,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3300
3322
|
const id = `async-v1-separate-${Date.now().toString(36)}`;
|
|
3301
3323
|
|
|
3302
3324
|
executeAsyncSingle(id, {
|
|
3303
|
-
agent: "
|
|
3325
|
+
agent: "builder",
|
|
3304
3326
|
task: "Implement the approved fixes",
|
|
3305
|
-
agentConfig: makeAgent("
|
|
3327
|
+
agentConfig: makeAgent("builder", { completionGuard: true }),
|
|
3306
3328
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3307
3329
|
artifactConfig: {
|
|
3308
3330
|
enabled: false,
|
|
@@ -3342,9 +3364,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3342
3364
|
const id = `async-single-schema-${Date.now().toString(36)}`;
|
|
3343
3365
|
|
|
3344
3366
|
executeAsyncSingle(id, {
|
|
3345
|
-
agent: "
|
|
3367
|
+
agent: "builder",
|
|
3346
3368
|
task: "Return structured data",
|
|
3347
|
-
agentConfig: makeAgent("
|
|
3369
|
+
agentConfig: makeAgent("builder", { completionGuard: false }),
|
|
3348
3370
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3349
3371
|
artifactConfig: {
|
|
3350
3372
|
enabled: false,
|
|
@@ -3395,7 +3417,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3395
3417
|
assert.equal(payload.success, true);
|
|
3396
3418
|
assert.equal(payload.exitCode, 0);
|
|
3397
3419
|
assert.equal(payload.results[0].success, true);
|
|
3398
|
-
|
|
3420
|
+
assert.equal(payload.results[0].output, "cold start test after patch");
|
|
3399
3421
|
|
|
3400
3422
|
const eventsPath = path.join(ASYNC_DIR, id, "events.jsonl");
|
|
3401
3423
|
const eventsText = fs.readFileSync(eventsPath, "utf-8");
|
|
@@ -3410,9 +3432,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3410
3432
|
const sessionRoot = path.join(tempDir, "sessions");
|
|
3411
3433
|
|
|
3412
3434
|
executeAsyncSingle(id, {
|
|
3413
|
-
agent: "
|
|
3435
|
+
agent: "builder",
|
|
3414
3436
|
task: "Do work",
|
|
3415
|
-
agentConfig: makeAgent("
|
|
3437
|
+
agentConfig: makeAgent("builder", { model: "gpt-5-mini" }),
|
|
3416
3438
|
ctx: {
|
|
3417
3439
|
pi: { events: { emit() {} } },
|
|
3418
3440
|
cwd: tempDir,
|
|
@@ -3450,6 +3472,101 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3450
3472
|
assert.deepEqual(payload.results[0].attemptedModels, ["github-copilot/gpt-5-mini"]);
|
|
3451
3473
|
});
|
|
3452
3474
|
|
|
3475
|
+
it("scheduled executor launches retain the live active session ownership", { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
3476
|
+
mockPi.onCall({ output: "Scheduled work completed" });
|
|
3477
|
+
const liveCwd = path.join(tempDir, "live-project");
|
|
3478
|
+
fs.mkdirSync(liveCwd);
|
|
3479
|
+
const state = {
|
|
3480
|
+
baseCwd: liveCwd,
|
|
3481
|
+
currentSessionId: "session-b",
|
|
3482
|
+
lastParentModel: { provider: "deepseek", id: "live-model" },
|
|
3483
|
+
subagentSpawns: { sessionId: "session-b", count: 1, configuredLimit: 1, granted: 1, grantHistory: [] },
|
|
3484
|
+
asyncJobs: new Map(),
|
|
3485
|
+
fleetJobs: new Map(),
|
|
3486
|
+
foregroundControls: new Map(),
|
|
3487
|
+
lastForegroundControlId: null,
|
|
3488
|
+
};
|
|
3489
|
+
const executor = createSubagentExecutor!({
|
|
3490
|
+
pi: { events: createEventBus(), getSessionName: () => undefined },
|
|
3491
|
+
state,
|
|
3492
|
+
config: { maxSubagentSpawnsPerSession: 1 },
|
|
3493
|
+
asyncByDefault: false,
|
|
3494
|
+
tempArtifactsDir: tempDir,
|
|
3495
|
+
getSubagentSessionRoot: () => path.join(tempDir, "sessions"),
|
|
3496
|
+
expandTilde: (p: string) => p,
|
|
3497
|
+
discoverAgents: () => ({ agents: [makeAgent("builder")] }),
|
|
3498
|
+
});
|
|
3499
|
+
const retainedCtx = makeMinimalCtx(tempDir);
|
|
3500
|
+
retainedCtx.sessionManager.getSessionId = () => "session-a";
|
|
3501
|
+
retainedCtx.model = { provider: "deepseek", id: "scheduled-model" };
|
|
3502
|
+
const launch = await executor.executeScheduled(
|
|
3503
|
+
`scheduled-owner-${Date.now().toString(36)}`,
|
|
3504
|
+
{ agent: "builder", task: "Run retained project timer", async: true, acceptance: false },
|
|
3505
|
+
new AbortController().signal,
|
|
3506
|
+
retainedCtx,
|
|
3507
|
+
) as AsyncExecutionResult;
|
|
3508
|
+
|
|
3509
|
+
assert.equal(launch.isError, undefined);
|
|
3510
|
+
assert.ok(launch.details.asyncId);
|
|
3511
|
+
assert.equal(state.currentSessionId, "session-b");
|
|
3512
|
+
assert.equal(state.baseCwd, liveCwd);
|
|
3513
|
+
assert.deepEqual(state.lastParentModel, { provider: "deepseek", id: "live-model" });
|
|
3514
|
+
assert.deepEqual(state.subagentSpawns, { sessionId: "session-b", count: 1, configuredLimit: 1, granted: 1, grantHistory: [] });
|
|
3515
|
+
const blocked = await executor.executeScheduled(
|
|
3516
|
+
`scheduled-owner-blocked-${Date.now().toString(36)}`,
|
|
3517
|
+
{ agent: "builder", task: "Exceed the retained owner budget", async: true, acceptance: false },
|
|
3518
|
+
new AbortController().signal,
|
|
3519
|
+
retainedCtx,
|
|
3520
|
+
);
|
|
3521
|
+
assert.equal(blocked.isError, true);
|
|
3522
|
+
assert.match(blocked.content[0]?.type === "text" ? blocked.content[0].text : "", /1\/1 used/);
|
|
3523
|
+
assert.deepEqual(state.subagentSpawns, { sessionId: "session-b", count: 1, configuredLimit: 1, granted: 1, grantHistory: [] });
|
|
3524
|
+
await readAsyncPayload(launch.details.asyncId);
|
|
3525
|
+
});
|
|
3526
|
+
|
|
3527
|
+
it("scheduled workflows keep owner status and registries isolated from the live session", { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
3528
|
+
const liveCwd = path.join(tempDir, "live-workflow-project");
|
|
3529
|
+
fs.mkdirSync(liveCwd);
|
|
3530
|
+
const state = {
|
|
3531
|
+
baseCwd: liveCwd,
|
|
3532
|
+
currentSessionId: "session-b",
|
|
3533
|
+
subagentSpawns: { sessionId: "session-b", count: 4, configuredLimit: 5, granted: 0, grantHistory: [] },
|
|
3534
|
+
asyncJobs: new Map(),
|
|
3535
|
+
fleetJobs: new Map(),
|
|
3536
|
+
foregroundControls: new Map(),
|
|
3537
|
+
lastForegroundControlId: null,
|
|
3538
|
+
};
|
|
3539
|
+
const executor = createSubagentExecutor!({
|
|
3540
|
+
pi: { events: createEventBus(), getSessionName: () => undefined },
|
|
3541
|
+
state,
|
|
3542
|
+
config: { maxSubagentSpawnsPerSession: 5 },
|
|
3543
|
+
asyncByDefault: false,
|
|
3544
|
+
tempArtifactsDir: tempDir,
|
|
3545
|
+
getSubagentSessionRoot: () => path.join(tempDir, "sessions"),
|
|
3546
|
+
expandTilde: (p: string) => p,
|
|
3547
|
+
discoverAgents: () => ({ agents: [makeAgent("builder")] }),
|
|
3548
|
+
});
|
|
3549
|
+
const retainedCtx = makeMinimalCtx(tempDir);
|
|
3550
|
+
retainedCtx.sessionManager.getSessionId = () => "session-a";
|
|
3551
|
+
const workflowId = `scheduled-workflow-${Date.now().toString(36)}`;
|
|
3552
|
+
const launch = await executor.executeScheduled(
|
|
3553
|
+
workflowId,
|
|
3554
|
+
{ workflowScript: `return await runs.status("${workflowId}")`, async: true },
|
|
3555
|
+
new AbortController().signal,
|
|
3556
|
+
retainedCtx,
|
|
3557
|
+
) as AsyncExecutionResult;
|
|
3558
|
+
|
|
3559
|
+
assert.equal(launch.isError, undefined);
|
|
3560
|
+
assert.equal(state.asyncJobs.size, 0);
|
|
3561
|
+
assert.equal(state.fleetJobs.size, 0);
|
|
3562
|
+
assert.deepEqual(state.subagentSpawns, { sessionId: "session-b", count: 4, configuredLimit: 5, granted: 0, grantHistory: [] });
|
|
3563
|
+
const payload = await readAsyncPayload(launch.details.asyncId);
|
|
3564
|
+
assert.equal(state.asyncJobs.size, 0);
|
|
3565
|
+
assert.equal(state.fleetJobs.size, 0);
|
|
3566
|
+
assert.match(payload.workflow.value.output, /Spawn budget: 0\/5 used/);
|
|
3567
|
+
assert.match(payload.workflow.value.output, new RegExp(workflowId));
|
|
3568
|
+
});
|
|
3569
|
+
|
|
3453
3570
|
it("async executor keeps the last parent session model after continuation drops ctx.model", { skip: !isAsyncAvailable() || !createSubagentExecutor ? "jiti or executor not available" : undefined }, async () => {
|
|
3454
3571
|
mockPi.onCall({ output: "Done asynchronously" });
|
|
3455
3572
|
const state = {
|
|
@@ -3467,7 +3584,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3467
3584
|
tempArtifactsDir: tempDir,
|
|
3468
3585
|
getSubagentSessionRoot: () => path.join(tempDir, "sessions"),
|
|
3469
3586
|
expandTilde: (p: string) => p,
|
|
3470
|
-
discoverAgents: () => ({ agents: [makeAgent("
|
|
3587
|
+
discoverAgents: () => ({ agents: [makeAgent("builder")] }),
|
|
3471
3588
|
});
|
|
3472
3589
|
const initialCtx = makeMinimalCtx(tempDir);
|
|
3473
3590
|
initialCtx.sessionManager.getSessionId = () => "session-continued";
|
|
@@ -3478,7 +3595,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3478
3595
|
continuedCtx.sessionManager.getSessionId = () => "session-continued";
|
|
3479
3596
|
const launch = await executor.execute(
|
|
3480
3597
|
"continued-async-child",
|
|
3481
|
-
{ agent: "
|
|
3598
|
+
{ agent: "builder", task: "Do work", async: true, acceptance: false },
|
|
3482
3599
|
new AbortController().signal,
|
|
3483
3600
|
undefined,
|
|
3484
3601
|
continuedCtx,
|
|
@@ -3495,7 +3612,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3495
3612
|
|
|
3496
3613
|
it("foreground chains keep the last parent session model after continuation drops ctx.model", { skip: !createSubagentExecutor ? "executor not available" : undefined }, async () => {
|
|
3497
3614
|
mockPi.onCall({ output: "Done foreground" });
|
|
3498
|
-
const executor = makeAsyncExecutor([makeAgent("
|
|
3615
|
+
const executor = makeAsyncExecutor([makeAgent("builder", { completionGuard: false })]);
|
|
3499
3616
|
const initialCtx = makeMinimalCtx(tempDir);
|
|
3500
3617
|
initialCtx.sessionManager.getSessionId = () => "session-continued";
|
|
3501
3618
|
initialCtx.model = { provider: "deepseek", id: "deepseek-v4-flash" };
|
|
@@ -3505,7 +3622,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3505
3622
|
continuedCtx.sessionManager.getSessionId = () => "session-continued";
|
|
3506
3623
|
const result = await executor.execute(
|
|
3507
3624
|
"continued-foreground-chain",
|
|
3508
|
-
{ chain: [{ agent: "
|
|
3625
|
+
{ chain: [{ agent: "builder", task: "Do work" }], acceptance: false },
|
|
3509
3626
|
new AbortController().signal,
|
|
3510
3627
|
undefined,
|
|
3511
3628
|
continuedCtx,
|
|
@@ -3520,9 +3637,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3520
3637
|
|
|
3521
3638
|
const id = `async-single-parent-model-${Date.now().toString(36)}`;
|
|
3522
3639
|
executeAsyncSingle(id, {
|
|
3523
|
-
agent: "
|
|
3640
|
+
agent: "builder",
|
|
3524
3641
|
task: "Do work",
|
|
3525
|
-
agentConfig: makeAgent("
|
|
3642
|
+
agentConfig: makeAgent("builder"),
|
|
3526
3643
|
ctx: {
|
|
3527
3644
|
pi: { events: { emit() {} } },
|
|
3528
3645
|
cwd: tempDir,
|
|
@@ -3557,8 +3674,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3557
3674
|
|
|
3558
3675
|
const id = `async-chain-parent-model-${Date.now().toString(36)}`;
|
|
3559
3676
|
executeAsyncChain(id, {
|
|
3560
|
-
chain: [{ agent: "
|
|
3561
|
-
agents: [makeAgent("
|
|
3677
|
+
chain: [{ agent: "builder", task: "Do work" }],
|
|
3678
|
+
agents: [makeAgent("builder")],
|
|
3562
3679
|
ctx: {
|
|
3563
3680
|
pi: { events: { emit() {} } },
|
|
3564
3681
|
cwd: tempDir,
|
|
@@ -3593,8 +3710,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3593
3710
|
|
|
3594
3711
|
const id = `async-chain-empty-model-${Date.now().toString(36)}`;
|
|
3595
3712
|
executeAsyncChain(id, {
|
|
3596
|
-
chain: [{ agent: "
|
|
3597
|
-
agents: [makeAgent("
|
|
3713
|
+
chain: [{ agent: "builder", task: "Do work", model: "" }],
|
|
3714
|
+
agents: [makeAgent("builder", { model: "anthropic/claude-sonnet-4-5", thinking: "high" })],
|
|
3598
3715
|
ctx: {
|
|
3599
3716
|
pi: { events: { emit() {} } },
|
|
3600
3717
|
cwd: tempDir,
|
|
@@ -3637,8 +3754,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3637
3754
|
for (const [index, requestedModel] of [undefined, "", "inherit"].entries()) {
|
|
3638
3755
|
const id = `async-chain-no-parent-${index}-${Date.now().toString(36)}`;
|
|
3639
3756
|
executeAsyncChain(id, {
|
|
3640
|
-
chain: [{ agent: "
|
|
3641
|
-
agents: [makeAgent("
|
|
3757
|
+
chain: [{ agent: "builder", task: "Do work", ...(requestedModel !== undefined ? { model: requestedModel } : {}) }],
|
|
3758
|
+
agents: [makeAgent("builder", { model: "openai/gpt-5-mini", thinking: "high" })],
|
|
3642
3759
|
ctx: {
|
|
3643
3760
|
pi: { events: { emit() {} } },
|
|
3644
3761
|
cwd: tempDir,
|
|
@@ -3687,9 +3804,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3687
3804
|
try {
|
|
3688
3805
|
writePackageSkill(taskCwd, "async-task-cwd-skill");
|
|
3689
3806
|
executeAsyncSingle(id, {
|
|
3690
|
-
agent: "
|
|
3807
|
+
agent: "builder",
|
|
3691
3808
|
task: "Do work",
|
|
3692
|
-
agentConfig: makeAgent("
|
|
3809
|
+
agentConfig: makeAgent("builder", { skills: ["async-task-cwd-skill"] }),
|
|
3693
3810
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3694
3811
|
cwd: taskCwd,
|
|
3695
3812
|
artifactConfig: {
|
|
@@ -3725,15 +3842,15 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3725
3842
|
it("injects agent-file-relative local skills into background single child prompts", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
3726
3843
|
mockPi.onCall({ output: "Done asynchronously" });
|
|
3727
3844
|
const id = `async-local-skill-${Date.now().toString(36)}`;
|
|
3728
|
-
const agentFile = path.join(tempDir, "agents", "
|
|
3845
|
+
const agentFile = path.join(tempDir, "agents", "builder", "builder.md");
|
|
3729
3846
|
const skillFile = path.join(path.dirname(agentFile), "skills", "local", "SKILL.md");
|
|
3730
3847
|
fs.mkdirSync(path.dirname(skillFile), { recursive: true });
|
|
3731
3848
|
fs.writeFileSync(skillFile, "---\ndescription: async local skill\n---\nLocal skill body\n", "utf-8");
|
|
3732
3849
|
|
|
3733
3850
|
executeAsyncSingle(id, {
|
|
3734
|
-
agent: "
|
|
3851
|
+
agent: "builder",
|
|
3735
3852
|
task: "Do work",
|
|
3736
|
-
agentConfig: makeAgent("
|
|
3853
|
+
agentConfig: makeAgent("builder", { filePath: agentFile, skills: ["local"], skillPath: ["./skills"] }),
|
|
3737
3854
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3738
3855
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
3739
3856
|
shareEnabled: false,
|
|
@@ -3779,9 +3896,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3779
3896
|
it("background single runs report unavailable pi-subagents skill requests", () => {
|
|
3780
3897
|
const id = `async-pi-subagents-skill-${Date.now().toString(36)}`;
|
|
3781
3898
|
const result = executeAsyncSingle(id, {
|
|
3782
|
-
agent: "
|
|
3899
|
+
agent: "builder",
|
|
3783
3900
|
task: "Do work",
|
|
3784
|
-
agentConfig: makeAgent("
|
|
3901
|
+
agentConfig: makeAgent("builder"),
|
|
3785
3902
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3786
3903
|
cwd: tempDir,
|
|
3787
3904
|
artifactConfig: {
|
|
@@ -3805,8 +3922,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3805
3922
|
it("background chains report unavailable pi-subagents skill requests", () => {
|
|
3806
3923
|
const id = `async-chain-pi-subagents-skill-${Date.now().toString(36)}`;
|
|
3807
3924
|
const result = executeAsyncChain(id, {
|
|
3808
|
-
chain: [{ agent: "
|
|
3809
|
-
agents: [makeAgent("
|
|
3925
|
+
chain: [{ agent: "builder", task: "Do work", skill: ["pi-subagents"] }],
|
|
3926
|
+
agents: [makeAgent("builder")],
|
|
3810
3927
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3811
3928
|
cwd: tempDir,
|
|
3812
3929
|
artifactConfig: {
|
|
@@ -3837,8 +3954,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3837
3954
|
try {
|
|
3838
3955
|
writePackageSkill(path.join(chainCwd, "packages", "app"), "async-chain-step-skill");
|
|
3839
3956
|
executeAsyncChain(id, {
|
|
3840
|
-
chain: [{ agent: "
|
|
3841
|
-
agents: [makeAgent("
|
|
3957
|
+
chain: [{ agent: "builder", task: "Do work", cwd: "packages/app", skill: ["async-chain-step-skill"] }],
|
|
3958
|
+
agents: [makeAgent("builder")],
|
|
3842
3959
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3843
3960
|
cwd: chainCwd,
|
|
3844
3961
|
artifactConfig: {
|
|
@@ -3936,9 +4053,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3936
4053
|
fs.mkdirSync(path.join(TEMP_ROOT_DIR, `async-cfg-${id}.json`), { recursive: true });
|
|
3937
4054
|
|
|
3938
4055
|
const result = executeAsyncSingle(id, {
|
|
3939
|
-
agent: "
|
|
4056
|
+
agent: "builder",
|
|
3940
4057
|
task: "Do work",
|
|
3941
|
-
agentConfig: makeAgent("
|
|
4058
|
+
agentConfig: makeAgent("builder"),
|
|
3942
4059
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3943
4060
|
artifactConfig: {
|
|
3944
4061
|
enabled: false,
|
|
@@ -3963,9 +4080,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3963
4080
|
const missingCwd = path.join(tempDir, "missing-cwd");
|
|
3964
4081
|
|
|
3965
4082
|
const singleResult = executeAsyncSingle(id, {
|
|
3966
|
-
agent: "
|
|
4083
|
+
agent: "builder",
|
|
3967
4084
|
task: "Do work",
|
|
3968
|
-
agentConfig: makeAgent("
|
|
4085
|
+
agentConfig: makeAgent("builder"),
|
|
3969
4086
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3970
4087
|
cwd: missingCwd,
|
|
3971
4088
|
artifactConfig: {
|
|
@@ -3987,8 +4104,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
3987
4104
|
|
|
3988
4105
|
const chainId = `async-missing-cwd-chain-${Date.now().toString(36)}`;
|
|
3989
4106
|
const chainResult = executeAsyncChain(chainId, {
|
|
3990
|
-
chain: [{ agent: "
|
|
3991
|
-
agents: [makeAgent("
|
|
4107
|
+
chain: [{ agent: "builder", task: "Do work" }],
|
|
4108
|
+
agents: [makeAgent("builder")],
|
|
3992
4109
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
3993
4110
|
cwd: missingCwd,
|
|
3994
4111
|
artifactConfig: {
|
|
@@ -4018,9 +4135,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4018
4135
|
try {
|
|
4019
4136
|
const id = `async-spawn-fail-${Date.now().toString(36)}`;
|
|
4020
4137
|
const result = executeAsyncSingle(id, {
|
|
4021
|
-
agent: "
|
|
4138
|
+
agent: "builder",
|
|
4022
4139
|
task: "Do work",
|
|
4023
|
-
agentConfig: makeAgent("
|
|
4140
|
+
agentConfig: makeAgent("builder"),
|
|
4024
4141
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4025
4142
|
artifactConfig: {
|
|
4026
4143
|
enabled: false,
|
|
@@ -4055,8 +4172,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4055
4172
|
fs.mkdirSync(path.join(TEMP_ROOT_DIR, `async-cfg-${id}.json`), { recursive: true });
|
|
4056
4173
|
|
|
4057
4174
|
const result = executeAsyncChain(id, {
|
|
4058
|
-
chain: [{ agent: "
|
|
4059
|
-
agents: [makeAgent("
|
|
4175
|
+
chain: [{ agent: "builder", task: "Do work" }],
|
|
4176
|
+
agents: [makeAgent("builder")],
|
|
4060
4177
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4061
4178
|
artifactConfig: {
|
|
4062
4179
|
enabled: false,
|
|
@@ -4086,9 +4203,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4086
4203
|
|
|
4087
4204
|
const start = Date.now();
|
|
4088
4205
|
executeAsyncSingle(id, {
|
|
4089
|
-
agent: "
|
|
4206
|
+
agent: "builder",
|
|
4090
4207
|
task: "Do work",
|
|
4091
|
-
agentConfig: makeAgent("
|
|
4208
|
+
agentConfig: makeAgent("builder"),
|
|
4092
4209
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4093
4210
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4094
4211
|
shareEnabled: false,
|
|
@@ -4101,7 +4218,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4101
4218
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
4102
4219
|
assert.ok(elapsed < 6000, `unconfigured watchdog status should not delay async final drain, took ${elapsed}ms`);
|
|
4103
4220
|
assert.equal(payload.success, true);
|
|
4104
|
-
|
|
4221
|
+
assert.equal(payload.results[0]?.output, "async-done-without-watchdog-config");
|
|
4105
4222
|
assert.equal((payload.results[0] as { watchdog?: unknown }).watchdog, undefined);
|
|
4106
4223
|
});
|
|
4107
4224
|
});
|
|
@@ -4120,9 +4237,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4120
4237
|
|
|
4121
4238
|
const start = Date.now();
|
|
4122
4239
|
executeAsyncSingle(id, {
|
|
4123
|
-
agent: "
|
|
4240
|
+
agent: "builder",
|
|
4124
4241
|
task: "Do work",
|
|
4125
|
-
agentConfig: makeAgent("
|
|
4242
|
+
agentConfig: makeAgent("builder"),
|
|
4126
4243
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4127
4244
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4128
4245
|
shareEnabled: false,
|
|
@@ -4136,7 +4253,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4136
4253
|
assert.ok(elapsed >= 1200, `watchdog settlement should delay async final drain, took ${elapsed}ms`);
|
|
4137
4254
|
assert.ok(elapsed < 9000, `settled watchdog should still allow async cleanup, took ${elapsed}ms`);
|
|
4138
4255
|
assert.equal(payload.success, true);
|
|
4139
|
-
|
|
4256
|
+
assert.equal(payload.results[0]?.output, "async-done-before-watchdog");
|
|
4140
4257
|
assert.equal((payload.results[0] as { watchdog?: { phase?: string } }).watchdog?.phase, "idle");
|
|
4141
4258
|
});
|
|
4142
4259
|
});
|
|
@@ -4152,9 +4269,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4152
4269
|
|
|
4153
4270
|
const start = Date.now();
|
|
4154
4271
|
executeAsyncSingle(id, {
|
|
4155
|
-
agent: "
|
|
4272
|
+
agent: "builder",
|
|
4156
4273
|
task: "Do work",
|
|
4157
|
-
agentConfig: makeAgent("
|
|
4274
|
+
agentConfig: makeAgent("builder"),
|
|
4158
4275
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4159
4276
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4160
4277
|
shareEnabled: false,
|
|
@@ -4167,7 +4284,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4167
4284
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
4168
4285
|
assert.ok(elapsed < 6000, `watchdog tail fallback should not hang async final drain, took ${elapsed}ms`);
|
|
4169
4286
|
assert.equal(payload.success, true);
|
|
4170
|
-
|
|
4287
|
+
assert.equal(payload.results[0]?.output, "async-done-before-watchdog-timeout");
|
|
4171
4288
|
const watchdog = (payload.results[0] as { watchdog?: { phase?: string; timedOut?: boolean } }).watchdog;
|
|
4172
4289
|
assert.equal(watchdog?.phase, "stale");
|
|
4173
4290
|
assert.equal(watchdog?.timedOut, true);
|
|
@@ -4187,9 +4304,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4187
4304
|
|
|
4188
4305
|
const start = Date.now();
|
|
4189
4306
|
executeAsyncSingle(id, {
|
|
4190
|
-
agent: "
|
|
4307
|
+
agent: "builder",
|
|
4191
4308
|
task: "Do work",
|
|
4192
|
-
agentConfig: makeAgent("
|
|
4309
|
+
agentConfig: makeAgent("builder"),
|
|
4193
4310
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4194
4311
|
artifactConfig: {
|
|
4195
4312
|
enabled: false,
|
|
@@ -4218,7 +4335,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4218
4335
|
assert.equal(payload.success, true);
|
|
4219
4336
|
assert.equal(payload.exitCode, 0);
|
|
4220
4337
|
assert.equal(payload.results[0].success, true);
|
|
4221
|
-
|
|
4338
|
+
assert.equal(payload.results[0].output, "async-done-before-drain");
|
|
4222
4339
|
});
|
|
4223
4340
|
|
|
4224
4341
|
it("background forced drain after empty terminal assistant output is cleanup success", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -4232,9 +4349,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4232
4349
|
|
|
4233
4350
|
const start = Date.now();
|
|
4234
4351
|
executeAsyncSingle(id, {
|
|
4235
|
-
agent: "
|
|
4352
|
+
agent: "explorer",
|
|
4236
4353
|
task: "Inspect something",
|
|
4237
|
-
agentConfig: makeAgent("
|
|
4354
|
+
agentConfig: makeAgent("explorer"),
|
|
4238
4355
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4239
4356
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4240
4357
|
shareEnabled: false,
|
|
@@ -4254,7 +4371,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4254
4371
|
assert.equal(payload.success, true);
|
|
4255
4372
|
assert.equal(payload.exitCode, 0);
|
|
4256
4373
|
assert.equal(payload.results[0].success, true);
|
|
4257
|
-
assert.
|
|
4374
|
+
assert.equal(payload.results[0].output, "");
|
|
4258
4375
|
});
|
|
4259
4376
|
|
|
4260
4377
|
it("background final-drain cleanup preserves explicit assistant errors", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
|
|
@@ -4277,9 +4394,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4277
4394
|
const resultPath = path.join(RESULTS_DIR, `${id}.json`);
|
|
4278
4395
|
|
|
4279
4396
|
executeAsyncSingle(id, {
|
|
4280
|
-
agent: "
|
|
4397
|
+
agent: "builder",
|
|
4281
4398
|
task: "Do work",
|
|
4282
|
-
agentConfig: makeAgent("
|
|
4399
|
+
agentConfig: makeAgent("builder"),
|
|
4283
4400
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4284
4401
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4285
4402
|
shareEnabled: false,
|
|
@@ -4314,9 +4431,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4314
4431
|
const resultPath = path.join(RESULTS_DIR, `${id}.json`);
|
|
4315
4432
|
|
|
4316
4433
|
executeAsyncSingle(id, {
|
|
4317
|
-
agent: "
|
|
4434
|
+
agent: "explorer",
|
|
4318
4435
|
task: "Investigate behavior",
|
|
4319
|
-
agentConfig: makeAgent("
|
|
4436
|
+
agentConfig: makeAgent("explorer"),
|
|
4320
4437
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4321
4438
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4322
4439
|
shareEnabled: false,
|
|
@@ -4382,9 +4499,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4382
4499
|
const eventsPath = path.join(asyncDir, "events.jsonl");
|
|
4383
4500
|
const resultPath = path.join(RESULTS_DIR, `${id}.json`);
|
|
4384
4501
|
executeAsyncSingle(id, {
|
|
4385
|
-
agent: "
|
|
4502
|
+
agent: "builder",
|
|
4386
4503
|
task: "Run the command",
|
|
4387
|
-
agentConfig: makeAgent("
|
|
4504
|
+
agentConfig: makeAgent("builder"),
|
|
4388
4505
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4389
4506
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4390
4507
|
shareEnabled: false,
|
|
@@ -4438,9 +4555,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4438
4555
|
const resultPath = path.join(RESULTS_DIR, `${id}.json`);
|
|
4439
4556
|
const statusPath = path.join(asyncDir, "status.json");
|
|
4440
4557
|
executeAsyncSingle(id, {
|
|
4441
|
-
agent: "
|
|
4558
|
+
agent: "builder",
|
|
4442
4559
|
task: "Ask the supervisor for a blocking decision",
|
|
4443
|
-
agentConfig: makeAgent("
|
|
4560
|
+
agentConfig: makeAgent("builder"),
|
|
4444
4561
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4445
4562
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4446
4563
|
shareEnabled: false,
|
|
@@ -4523,9 +4640,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4523
4640
|
const resultPath = path.join(RESULTS_DIR, `${id}.json`);
|
|
4524
4641
|
|
|
4525
4642
|
executeAsyncSingle(id, {
|
|
4526
|
-
agent: "
|
|
4643
|
+
agent: "builder",
|
|
4527
4644
|
task: "Implement the approved fixes",
|
|
4528
|
-
agentConfig: makeAgent("
|
|
4645
|
+
agentConfig: makeAgent("builder"),
|
|
4529
4646
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4530
4647
|
artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
|
|
4531
4648
|
shareEnabled: false,
|
|
@@ -4607,9 +4724,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4607
4724
|
const sessionRoot = path.join(tempDir, "sessions");
|
|
4608
4725
|
|
|
4609
4726
|
executeAsyncSingle(id, {
|
|
4610
|
-
agent: "
|
|
4727
|
+
agent: "builder",
|
|
4611
4728
|
task: "Stream noisy diagnostics",
|
|
4612
|
-
agentConfig: makeAgent("
|
|
4729
|
+
agentConfig: makeAgent("builder"),
|
|
4613
4730
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4614
4731
|
artifactConfig: {
|
|
4615
4732
|
enabled: false,
|
|
@@ -4627,7 +4744,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4627
4744
|
const resultPath = await waitForAsyncResultFile(id, 10_000);
|
|
4628
4745
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
|
|
4629
4746
|
assert.equal(payload.success, true);
|
|
4630
|
-
|
|
4747
|
+
assert.equal(payload.results[0]?.output, "Done after noisy stream");
|
|
4631
4748
|
|
|
4632
4749
|
const eventsText = fs.readFileSync(path.join(asyncDir, "events.jsonl"), "utf-8");
|
|
4633
4750
|
assert.doesNotMatch(eventsText, /"type":"message_update"/);
|
|
@@ -4658,9 +4775,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4658
4775
|
const sessionRoot = path.join(tempDir, "sessions");
|
|
4659
4776
|
|
|
4660
4777
|
executeAsyncSingle(id, {
|
|
4661
|
-
agent: "
|
|
4778
|
+
agent: "builder",
|
|
4662
4779
|
task: "Stream detailed progress",
|
|
4663
|
-
agentConfig: makeAgent("
|
|
4780
|
+
agentConfig: makeAgent("builder"),
|
|
4664
4781
|
ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
|
|
4665
4782
|
artifactConfig: {
|
|
4666
4783
|
enabled: false,
|
|
@@ -4706,7 +4823,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
|
|
|
4706
4823
|
|
|
4707
4824
|
const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8"));
|
|
4708
4825
|
assert.equal(payload.success, true);
|
|
4709
|
-
|
|
4826
|
+
assert.equal(payload.results[0].output, "Done streaming");
|
|
4710
4827
|
|
|
4711
4828
|
const status = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8"));
|
|
4712
4829
|
assert.deepEqual(status.steps[0].recentTools.map((tool: { tool: string; args: string }) => ({ tool: tool.tool, args: tool.args })), [{ tool: "bash", args: "ls" }]);
|