@selesai/code 0.5.28 → 0.5.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +23 -0
- package/dist/cli/credential-print.d.ts.map +1 -0
- package/dist/cli/credential-print.js +117 -0
- package/dist/cli/credential-print.js.map +1 -0
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +3 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +12 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +20 -14
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +11 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +11 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +14 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +10 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/llama/provider.d.ts.map +1 -1
- package/dist/core/llama/provider.js +8 -3
- package/dist/core/llama/provider.js.map +1 -1
- package/dist/core/model-config.d.ts +30 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +6 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -2
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +20 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +5 -4
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +13 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +24 -11
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts +15 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +66 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +34 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
- package/dist/extensions/pi-intercom/README.md +102 -39
- package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
- package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
- package/dist/extensions/pi-intercom/broker/client.ts +315 -12
- package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
- package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
- package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
- package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
- package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
- package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
- package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
- package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
- package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
- package/dist/extensions/pi-intercom/config.test.ts +93 -0
- package/dist/extensions/pi-intercom/config.ts +55 -6
- package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
- package/dist/extensions/pi-intercom/cwd.ts +31 -0
- package/dist/extensions/pi-intercom/extension-api.ts +44 -0
- package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
- package/dist/extensions/pi-intercom/format-context.ts +32 -0
- package/dist/extensions/pi-intercom/index.ts +742 -145
- package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
- package/dist/extensions/pi-intercom/package.json +15 -5
- package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
- package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
- package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
- package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
- package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
- package/dist/extensions/pi-intercom/types.ts +94 -4
- package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
- package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
- package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +85 -0
- package/dist/extensions/pi-subagents/LICENSE +21 -0
- package/dist/extensions/pi-subagents/README.md +146 -52
- package/dist/extensions/pi-subagents/agents/architect.md +1 -0
- package/dist/extensions/pi-subagents/agents/builder.md +1 -0
- package/dist/extensions/pi-subagents/package-lock.json +2 -2
- package/dist/extensions/pi-subagents/package.json +3 -3
- package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +21 -989
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +282 -0
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
- package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
- package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +63 -16
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +29 -4
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
- package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +143 -43
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
- package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
- package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
- package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
- package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +155 -10
- package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
- package/dist/extensions/pi-subagents/src/tui/render.ts +27 -28
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
- package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +26 -1
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +118 -12
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
- package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +102 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +4 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +11 -11
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +10 -2
- package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +46 -0
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
- package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
- package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +34 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +3 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +43 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +3 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +10 -2
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +16 -46
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +72 -64
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +14 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +19 -8
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +14 -5
- package/docs/environment-variables.md +86 -0
- package/docs/extensions.md +15 -5
- package/docs/index.md +1 -0
- package/docs/models.md +9 -2
- package/docs/providers.md +21 -2
- package/docs/rpc.md +23 -6
- package/docs/session-format.md +2 -0
- package/docs/settings.md +1 -1
- package/docs/usage.md +0 -13
- package/examples/extensions/custom-compaction.ts +5 -2
- package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +11 -3
- package/examples/extensions/message-renderer.ts +3 -3
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +5 -2
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +3 -1
- package/package.json +15 -6
- package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
|
@@ -6,8 +6,11 @@ import { resolveAsyncRunLocation } from "../runs/background/async-resume.ts";
|
|
|
6
6
|
import { deliverStopRequest } from "../runs/background/control-channel.ts";
|
|
7
7
|
import { reconcileAsyncRun } from "../runs/background/stale-run-reconciler.ts";
|
|
8
8
|
import type { SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
9
|
+
import { resolveCurrentSessionId } from "../shared/session-identity.ts";
|
|
9
10
|
import {
|
|
11
|
+
type AsyncJobStep,
|
|
10
12
|
type Details,
|
|
13
|
+
type SubagentState,
|
|
11
14
|
ASYNC_DIR,
|
|
12
15
|
RESULTS_DIR,
|
|
13
16
|
SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
@@ -23,7 +26,7 @@ export const SUBAGENT_RPC_REQUEST_EVENT = "subagents:rpc:v1:request";
|
|
|
23
26
|
export const SUBAGENT_RPC_READY_EVENT = "subagents:rpc:v1:ready";
|
|
24
27
|
export const SUBAGENT_RPC_REPLY_EVENT_PREFIX = "subagents:rpc:v1:reply:";
|
|
25
28
|
|
|
26
|
-
export const SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "steer", "interrupt", "stop"] as const;
|
|
29
|
+
export const SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "steer", "interrupt", "stop", "resume"] as const;
|
|
27
30
|
export type SubagentRpcMethod = typeof SUBAGENT_RPC_METHODS[number];
|
|
28
31
|
|
|
29
32
|
export interface SubagentRpcRequestEnvelope {
|
|
@@ -69,6 +72,200 @@ interface EventBus {
|
|
|
69
72
|
emit(event: string, data: unknown): void;
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
export interface SubagentRpcFleetEntry {
|
|
76
|
+
/** Opaque key for client-side reconciliation; never a run or async identifier. */
|
|
77
|
+
key: string;
|
|
78
|
+
/** Resolved child agent/role name. */
|
|
79
|
+
agent: string;
|
|
80
|
+
role?: string;
|
|
81
|
+
model?: string;
|
|
82
|
+
effort?: string;
|
|
83
|
+
startedAt: number;
|
|
84
|
+
tokens: { input: number; output: number; total: number };
|
|
85
|
+
goal?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface SubagentRpcFleetStatus {
|
|
89
|
+
version: 1;
|
|
90
|
+
entries: SubagentRpcFleetEntry[];
|
|
91
|
+
/** Total active children before the bounded entries window. */
|
|
92
|
+
totalActive: number;
|
|
93
|
+
omitted: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const MAX_FLEET_ENTRIES = 16;
|
|
97
|
+
const MAX_FLEET_CANDIDATES = 256;
|
|
98
|
+
const MAX_AGENT_LENGTH = 96;
|
|
99
|
+
const MAX_GOAL_LENGTH = 512;
|
|
100
|
+
const MAX_METADATA_LENGTH = 128;
|
|
101
|
+
|
|
102
|
+
function displayText(value: unknown, maxLength: number): string | undefined {
|
|
103
|
+
if (typeof value !== "string") return undefined;
|
|
104
|
+
// Strip complete CSI/OSC/DCS/APC/PM strings and C1 controls before collapsing
|
|
105
|
+
// whitespace; never leave CSI parameters behind after removing ESC.
|
|
106
|
+
const normalized = value.slice(0, 4_096)
|
|
107
|
+
.replace(/\x1b\[[0-?]*[ -/]*[@-~]|\x9b[0-?]*[ -/]*[@-~]|\x1b][\s\S]*?(?:\x07|\x1b\\)|\x1b[PX^_][\s\S]*?\x1b\\|[\u0000-\u001f\u007f-\u009f]/g, " ")
|
|
108
|
+
.replace(/\s+/g, " ").trim();
|
|
109
|
+
return normalized ? normalized.slice(0, maxLength) : undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function publicTokens(value: unknown): { input: number; output: number; total: number } {
|
|
113
|
+
const record = isRecord(value) ? value : {};
|
|
114
|
+
const count = (field: "input" | "output" | "total") => {
|
|
115
|
+
const raw = record[field];
|
|
116
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0
|
|
117
|
+
? Math.min(Number.MAX_SAFE_INTEGER, Math.floor(raw))
|
|
118
|
+
: 0;
|
|
119
|
+
};
|
|
120
|
+
const input = count("input");
|
|
121
|
+
const output = count("output");
|
|
122
|
+
const sum = Math.min(Number.MAX_SAFE_INTEGER, input + output);
|
|
123
|
+
return { input, output, total: Math.max(sum, count("total")) };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function activeState(value: unknown): boolean {
|
|
127
|
+
return value === "running" || value === "queued" || value === "pending";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface FleetKeyState {
|
|
131
|
+
sessionId: string | null;
|
|
132
|
+
next: number;
|
|
133
|
+
keys: Map<string, string>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface FleetCandidate {
|
|
137
|
+
internalKey: string;
|
|
138
|
+
agent: unknown;
|
|
139
|
+
role?: unknown;
|
|
140
|
+
model?: unknown;
|
|
141
|
+
effort?: unknown;
|
|
142
|
+
startedAt: unknown;
|
|
143
|
+
tokens?: unknown;
|
|
144
|
+
goal?: unknown;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function buildFleetStatus(
|
|
148
|
+
state: SubagentState | undefined,
|
|
149
|
+
keyState: FleetKeyState,
|
|
150
|
+
sessionId: string | null | undefined,
|
|
151
|
+
): SubagentRpcFleetStatus {
|
|
152
|
+
const authoritativeSessionId = sessionId ?? null;
|
|
153
|
+
if (keyState.sessionId !== authoritativeSessionId) {
|
|
154
|
+
keyState.sessionId = authoritativeSessionId;
|
|
155
|
+
keyState.next = 0;
|
|
156
|
+
keyState.keys.clear();
|
|
157
|
+
}
|
|
158
|
+
if (!state || !authoritativeSessionId || state.currentSessionId !== authoritativeSessionId) {
|
|
159
|
+
keyState.keys.clear();
|
|
160
|
+
return { version: 1, entries: [], totalActive: 0, omitted: 0 };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let totalActive = 0;
|
|
164
|
+
const candidates: FleetCandidate[] = [];
|
|
165
|
+
const addCandidate = (candidate: FleetCandidate) => {
|
|
166
|
+
totalActive += 1;
|
|
167
|
+
if (candidates.length < MAX_FLEET_CANDIDATES) candidates.push(candidate);
|
|
168
|
+
};
|
|
169
|
+
for (const control of state.foregroundControls.values()) {
|
|
170
|
+
if (control.sessionId !== authoritativeSessionId) continue;
|
|
171
|
+
if (control.activeChildren?.size) {
|
|
172
|
+
for (const child of control.activeChildren.values()) addCandidate({
|
|
173
|
+
internalKey: `foreground:${control.runId}:${child.index}`,
|
|
174
|
+
agent: child.agent,
|
|
175
|
+
model: child.model,
|
|
176
|
+
effort: child.thinking,
|
|
177
|
+
startedAt: child.startedAt,
|
|
178
|
+
tokens: { input: child.inputTokens ?? 0, output: child.outputTokens ?? 0, total: child.tokens ?? 0 },
|
|
179
|
+
goal: child.description ?? control.description,
|
|
180
|
+
});
|
|
181
|
+
} else {
|
|
182
|
+
addCandidate({
|
|
183
|
+
internalKey: `foreground:${control.runId}:${control.currentIndex ?? 0}`,
|
|
184
|
+
agent: control.currentAgent ?? control.mode,
|
|
185
|
+
model: control.model,
|
|
186
|
+
effort: control.thinking,
|
|
187
|
+
startedAt: control.startedAt,
|
|
188
|
+
tokens: { input: control.inputTokens ?? 0, output: control.outputTokens ?? 0, total: control.tokens ?? 0 },
|
|
189
|
+
goal: control.description,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
for (const job of state.asyncJobs.values()) {
|
|
194
|
+
if (job.sessionId !== authoritativeSessionId || !activeState(job.status)) continue;
|
|
195
|
+
const startedAt = job.startedAt ?? job.updatedAt;
|
|
196
|
+
const steps: AsyncJobStep[] | undefined = job.steps?.length
|
|
197
|
+
? job.steps
|
|
198
|
+
: job.agents?.map((agent, index) => ({
|
|
199
|
+
agent,
|
|
200
|
+
index,
|
|
201
|
+
status: job.status === "queued" ? "pending" : "running",
|
|
202
|
+
}));
|
|
203
|
+
if (!steps?.length) {
|
|
204
|
+
addCandidate({
|
|
205
|
+
internalKey: `async:${job.asyncId}`,
|
|
206
|
+
agent: job.mode ?? "subagent",
|
|
207
|
+
startedAt,
|
|
208
|
+
tokens: job.totalTokens,
|
|
209
|
+
goal: job.description,
|
|
210
|
+
});
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
for (const [offset, step] of steps.entries()) {
|
|
214
|
+
if (!activeState(step.status)) continue;
|
|
215
|
+
const index = step.index ?? offset;
|
|
216
|
+
if (step.status === "pending" && job.mode === "chain" && !job.activeParallelGroup && index !== (job.currentStep ?? 0)) continue;
|
|
217
|
+
addCandidate({
|
|
218
|
+
internalKey: `async:${job.asyncId}:${index}`,
|
|
219
|
+
agent: step.agent,
|
|
220
|
+
role: step.label,
|
|
221
|
+
model: step.model,
|
|
222
|
+
effort: step.thinking,
|
|
223
|
+
startedAt: step.startedAt ?? startedAt,
|
|
224
|
+
tokens: step.tokens ?? (steps.length === 1 ? job.totalTokens : undefined),
|
|
225
|
+
goal: job.description,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
candidates.sort((left, right) => {
|
|
231
|
+
const leftStarted = typeof left.startedAt === "number" ? left.startedAt : Number.MAX_SAFE_INTEGER;
|
|
232
|
+
const rightStarted = typeof right.startedAt === "number" ? right.startedAt : Number.MAX_SAFE_INTEGER;
|
|
233
|
+
return leftStarted - rightStarted || left.internalKey.localeCompare(right.internalKey);
|
|
234
|
+
});
|
|
235
|
+
const activeKeys = new Set(candidates.map((candidate) => candidate.internalKey));
|
|
236
|
+
const entries: SubagentRpcFleetEntry[] = [];
|
|
237
|
+
for (const candidate of candidates) {
|
|
238
|
+
if (entries.length >= MAX_FLEET_ENTRIES) break;
|
|
239
|
+
const agent = displayText(candidate.agent, MAX_AGENT_LENGTH);
|
|
240
|
+
const startedAt = candidate.startedAt;
|
|
241
|
+
if (!agent || typeof startedAt !== "number" || !Number.isSafeInteger(startedAt) || startedAt < 0) continue;
|
|
242
|
+
let key = keyState.keys.get(candidate.internalKey);
|
|
243
|
+
if (!key) {
|
|
244
|
+
key = `fleet-${++keyState.next}`;
|
|
245
|
+
keyState.keys.set(candidate.internalKey, key);
|
|
246
|
+
}
|
|
247
|
+
const role = displayText(candidate.role, MAX_AGENT_LENGTH);
|
|
248
|
+
const model = displayText(candidate.model, MAX_METADATA_LENGTH);
|
|
249
|
+
const effort = displayText(candidate.effort, MAX_METADATA_LENGTH);
|
|
250
|
+
const goal = displayText(candidate.goal, MAX_GOAL_LENGTH);
|
|
251
|
+
entries.push({
|
|
252
|
+
key,
|
|
253
|
+
agent,
|
|
254
|
+
...(role ? { role } : {}),
|
|
255
|
+
...(model ? { model } : {}),
|
|
256
|
+
...(effort ? { effort } : {}),
|
|
257
|
+
startedAt,
|
|
258
|
+
tokens: publicTokens(candidate.tokens),
|
|
259
|
+
...(goal ? { goal } : {}),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
for (const internalKey of keyState.keys.keys()) {
|
|
263
|
+
if (!activeKeys.has(internalKey)) keyState.keys.delete(internalKey);
|
|
264
|
+
}
|
|
265
|
+
const omitted = Math.max(0, totalActive - entries.length);
|
|
266
|
+
return { version: 1, entries, totalActive, omitted };
|
|
267
|
+
}
|
|
268
|
+
|
|
72
269
|
interface RegisterSubagentRpcBridgeOptions {
|
|
73
270
|
events: EventBus;
|
|
74
271
|
getContext: () => ExtensionContext | null;
|
|
@@ -83,6 +280,8 @@ interface RegisterSubagentRpcBridgeOptions {
|
|
|
83
280
|
resultsDir?: string;
|
|
84
281
|
kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;
|
|
85
282
|
now?: () => number;
|
|
283
|
+
/** Native live state, projected into the optional public fleet-status capability. */
|
|
284
|
+
state?: SubagentState;
|
|
86
285
|
}
|
|
87
286
|
|
|
88
287
|
class SubagentRpcError extends Error {
|
|
@@ -140,7 +339,9 @@ function textFromToolResult(result: AgentToolResult<Details>): string {
|
|
|
140
339
|
.join("\n");
|
|
141
340
|
}
|
|
142
341
|
|
|
143
|
-
|
|
342
|
+
type ToolResultWithError = AgentToolResult<Details> & { isError?: boolean };
|
|
343
|
+
|
|
344
|
+
function dataFromToolResult(result: ToolResultWithError): { text: string; details?: Details; isError?: boolean } {
|
|
144
345
|
return {
|
|
145
346
|
text: textFromToolResult(result),
|
|
146
347
|
...(result.details ? { details: result.details } : {}),
|
|
@@ -148,7 +349,7 @@ function dataFromToolResult(result: AgentToolResult<Details>): { text: string; d
|
|
|
148
349
|
};
|
|
149
350
|
}
|
|
150
351
|
|
|
151
|
-
function failIfToolError(result:
|
|
352
|
+
function failIfToolError(result: ToolResultWithError): void {
|
|
152
353
|
if (!result.isError) return;
|
|
153
354
|
throw new SubagentRpcError("execution_failed", textFromToolResult(result) || "Subagent RPC execution failed.");
|
|
154
355
|
}
|
|
@@ -178,11 +379,15 @@ function pingData(ctx: ExtensionContext | null) {
|
|
|
178
379
|
methods: [...SUBAGENT_RPC_METHODS],
|
|
179
380
|
capabilities: {
|
|
180
381
|
status: true,
|
|
382
|
+
fleetStatus: { version: 1 },
|
|
181
383
|
asyncSpawn: true,
|
|
182
384
|
steer: true,
|
|
183
385
|
nonRecoveringSteer: true,
|
|
184
386
|
interrupt: true,
|
|
185
387
|
stop: true,
|
|
388
|
+
resume: true,
|
|
389
|
+
launchResolvedExtensions: { version: 1, source: "launch-resolved" },
|
|
390
|
+
runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", event: "subagent:acknowledge-extension" },
|
|
186
391
|
processTerminalProof: { version: 1, lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION },
|
|
187
392
|
},
|
|
188
393
|
events: {
|
|
@@ -238,6 +443,24 @@ function steerParams(params: unknown): SubagentParamsLike {
|
|
|
238
443
|
};
|
|
239
444
|
}
|
|
240
445
|
|
|
446
|
+
function resumeParams(params: unknown): SubagentParamsLike {
|
|
447
|
+
const input = assertRecordParams(params, "resume");
|
|
448
|
+
if (typeof input.message !== "string" || !input.message.trim())
|
|
449
|
+
throw new SubagentRpcError("invalid_params", "RPC resume requires a non-empty message.");
|
|
450
|
+
const target = normalizeTargetParams(input, "resume");
|
|
451
|
+
if (!target.id && !target.runId && !target.dir) throw new SubagentRpcError("invalid_params", "RPC resume requires id, runId, or dir.");
|
|
452
|
+
if (input.output !== undefined && (typeof input.output !== "string" || !input.output.trim()))
|
|
453
|
+
throw new SubagentRpcError("invalid_params", "RPC resume output must be a non-empty path.");
|
|
454
|
+
if (input.outputMode !== undefined && input.outputMode !== "file-only")
|
|
455
|
+
throw new SubagentRpcError("invalid_params", "RPC resume supports only file-only output mode.");
|
|
456
|
+
return {
|
|
457
|
+
action: "resume",
|
|
458
|
+
...target,
|
|
459
|
+
message: input.message.trim(),
|
|
460
|
+
...(typeof input.output === "string" ? { output: input.output.trim(), outputMode: "file-only" } : {}),
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
241
464
|
function stopAsyncRun(
|
|
242
465
|
params: unknown,
|
|
243
466
|
options: RegisterSubagentRpcBridgeOptions,
|
|
@@ -257,7 +480,7 @@ function stopAsyncRun(
|
|
|
257
480
|
throw new SubagentRpcError("not_found", "Async run not found or already completed; stop requires a live async run directory.");
|
|
258
481
|
}
|
|
259
482
|
|
|
260
|
-
const currentSessionId = ctx.sessionManager
|
|
483
|
+
const currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
261
484
|
const initialStatus = readStatus(location.asyncDir);
|
|
262
485
|
const initialRunId = initialStatus?.runId ?? location.resolvedId ?? path.basename(location.asyncDir);
|
|
263
486
|
if (!initialStatus) throw new SubagentRpcError("not_found", `Status file not found for async run '${initialRunId}'.`);
|
|
@@ -304,6 +527,7 @@ function stopAsyncRun(
|
|
|
304
527
|
async function handleRequest(
|
|
305
528
|
request: SubagentRpcRequestEnvelope,
|
|
306
529
|
options: RegisterSubagentRpcBridgeOptions,
|
|
530
|
+
fleetKeys: FleetKeyState,
|
|
307
531
|
): Promise<unknown> {
|
|
308
532
|
const ctx = options.getContext();
|
|
309
533
|
if (request.method === "ping") return pingData(ctx);
|
|
@@ -313,7 +537,21 @@ async function handleRequest(
|
|
|
313
537
|
return executeChecked(options, ctx, request.requestId, request.method, spawnParams(request.params));
|
|
314
538
|
}
|
|
315
539
|
if (request.method === "status") {
|
|
316
|
-
|
|
540
|
+
const status = await executeChecked(
|
|
541
|
+
options,
|
|
542
|
+
ctx,
|
|
543
|
+
request.requestId,
|
|
544
|
+
request.method,
|
|
545
|
+
{ action: "status", ...normalizeTargetParams(request.params, "status") },
|
|
546
|
+
);
|
|
547
|
+
return {
|
|
548
|
+
...status,
|
|
549
|
+
fleet: buildFleetStatus(
|
|
550
|
+
options.state,
|
|
551
|
+
fleetKeys,
|
|
552
|
+
resolveCurrentSessionId(ctx.sessionManager),
|
|
553
|
+
),
|
|
554
|
+
};
|
|
317
555
|
}
|
|
318
556
|
if (request.method === "steer") {
|
|
319
557
|
return executeChecked(options, ctx, request.requestId, request.method, steerParams(request.params));
|
|
@@ -324,6 +562,9 @@ async function handleRequest(
|
|
|
324
562
|
if (request.method === "stop") {
|
|
325
563
|
return stopAsyncRun(request.params, options, ctx);
|
|
326
564
|
}
|
|
565
|
+
if (request.method === "resume") {
|
|
566
|
+
return executeChecked(options, ctx, request.requestId, request.method, resumeParams(request.params));
|
|
567
|
+
}
|
|
327
568
|
throw new SubagentRpcError("unsupported_method", `Unsupported subagent RPC method: ${String(request.method)}`);
|
|
328
569
|
}
|
|
329
570
|
|
|
@@ -377,11 +618,12 @@ export function registerSubagentRpcBridge(options: RegisterSubagentRpcBridgeOpti
|
|
|
377
618
|
emitReady: (ctx?: ExtensionContext | null) => void;
|
|
378
619
|
dispose: () => void;
|
|
379
620
|
} {
|
|
621
|
+
const fleetKeys: FleetKeyState = { sessionId: null, next: 0, keys: new Map() };
|
|
380
622
|
const unsubscribe = options.events.on(SUBAGENT_RPC_REQUEST_EVENT, async (raw) => {
|
|
381
623
|
let request: SubagentRpcRequestEnvelope | undefined;
|
|
382
624
|
try {
|
|
383
625
|
request = parseRequest(raw);
|
|
384
|
-
const data = await handleRequest(request, options);
|
|
626
|
+
const data = await handleRequest(request, options, fleetKeys);
|
|
385
627
|
options.events.emit(subagentRpcReplyEvent(request.requestId), {
|
|
386
628
|
version: SUBAGENT_RPC_PROTOCOL_VERSION,
|
|
387
629
|
requestId: request.requestId,
|
|
@@ -65,6 +65,18 @@ const JsonSchemaObject = Type.Unsafe({
|
|
|
65
65
|
description: "JSON Schema object for strict structured output. Non-object roots are rejected.",
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
const AcceptanceEvidenceKinds = [
|
|
69
|
+
"changed-files",
|
|
70
|
+
"tests-added",
|
|
71
|
+
"commands-run",
|
|
72
|
+
"validation-output",
|
|
73
|
+
"residual-risks",
|
|
74
|
+
"no-staged-files",
|
|
75
|
+
"diff-summary",
|
|
76
|
+
"review-findings",
|
|
77
|
+
"manual-notes",
|
|
78
|
+
];
|
|
79
|
+
|
|
68
80
|
const AcceptanceOverride = Type.Unsafe({
|
|
69
81
|
anyOf: [
|
|
70
82
|
{ type: "string", enum: ["auto", "attested", "checked", "verified"] },
|
|
@@ -77,7 +89,7 @@ const AcceptanceOverride = Type.Unsafe({
|
|
|
77
89
|
{ type: "boolean", enum: [false] },
|
|
78
90
|
{ type: "object", additionalProperties: true },
|
|
79
91
|
],
|
|
80
|
-
description:
|
|
92
|
+
description: `Optional acceptance policy. For reviewer/read-only calls, omit acceptance. Example: { level: "checked", evidence: ["commands-run", "changed-files"] }. Supported evidence kinds: ${AcceptanceEvidenceKinds.join(", ")}. Evidence levels end at verified; use acceptance.review.required for review. Omitted means auto-inferred unless agentContract.version=1.`,
|
|
81
93
|
});
|
|
82
94
|
|
|
83
95
|
const AgentContractOverride = Type.Object({
|
|
@@ -107,6 +119,16 @@ const ToolBudgetOverride = Type.Object({
|
|
|
107
119
|
block: Type.Optional(ToolBudgetBlock),
|
|
108
120
|
}, { additionalProperties: false, description: "Optional child tool-call budget. soft nudges the child; after hard, block tools (default read/grep/find/ls, or '*' for all tools) are blocked so the child can finalize." });
|
|
109
121
|
|
|
122
|
+
const UsageBudgetLimitOverride = Type.Object({
|
|
123
|
+
soft: Type.Optional(Type.Number({ exclusiveMinimum: 0 })),
|
|
124
|
+
hard: Type.Number({ exclusiveMinimum: 0 }),
|
|
125
|
+
}, { additionalProperties: false });
|
|
126
|
+
|
|
127
|
+
const UsageBudgetOverride = Type.Object({
|
|
128
|
+
tokens: Type.Optional(UsageBudgetLimitOverride),
|
|
129
|
+
costUsd: Type.Optional(UsageBudgetLimitOverride),
|
|
130
|
+
}, { additionalProperties: false, description: "Optional root-only reported-usage budget. Hard limits prevent future child launches; running children are not stopped." });
|
|
131
|
+
|
|
110
132
|
const TaskItem = Type.Object({
|
|
111
133
|
agent: Type.String(),
|
|
112
134
|
task: Type.String(),
|
|
@@ -183,6 +205,8 @@ export const DynamicCollectSchema = Type.Object({
|
|
|
183
205
|
|
|
184
206
|
// Flattened so chain steps do not need an object-shape anyOf/oneOf union.
|
|
185
207
|
export const ChainItem = Type.Object({
|
|
208
|
+
checkpoint: Type.Optional(Type.String({ description: "Approval checkpoint name. Pauses the chain without launching a child until approve-checkpoint or reject-checkpoint is called." })),
|
|
209
|
+
message: Type.Optional(Type.String({ description: "Optional approval message shown while the checkpoint is paused." })),
|
|
186
210
|
agent: Type.Optional(Type.String({ description: "Sequential step agent name" })),
|
|
187
211
|
task: Type.Optional(Type.String({
|
|
188
212
|
description: "Task template with variables: {task}=original request, {previous}=prior step's text response, {chain_dir}=shared folder, {outputs.name}=prior named output. Required for first step, defaults to '{previous}' for subsequent steps."
|
|
@@ -217,7 +241,7 @@ export const ChainItem = Type.Object({
|
|
|
217
241
|
description: "Create isolated git worktrees for each parallel task."
|
|
218
242
|
})),
|
|
219
243
|
}, {
|
|
220
|
-
description: "Chain step: use {agent, task?, ...} for sequential, {parallel: [...]} for static concurrent execution,
|
|
244
|
+
description: "Chain step: use {agent, task?, ...} for sequential, {parallel: [...]} for static concurrent execution, {expand, parallel: {...}, collect} for dynamic fanout, or {checkpoint: name, message?} for an approval pause.",
|
|
221
245
|
additionalProperties: false,
|
|
222
246
|
});
|
|
223
247
|
|
|
@@ -244,10 +268,10 @@ const SubagentParamsSchema = Type.Object({
|
|
|
244
268
|
description: "Optional management/control action. Omit this field entirely for execution/delegation ({agent, task}, {tasks}, or {chain}); use it only for management/control actions."
|
|
245
269
|
})),
|
|
246
270
|
id: Type.Optional(Type.String({
|
|
247
|
-
description: "Run id or prefix for action='status', action='interrupt', action='stop', action='resume', action='steer',
|
|
271
|
+
description: "Run id or prefix for action='status', action='interrupt', action='stop', action='resume', action='steer', action='append-step', action='approve-checkpoint', or action='reject-checkpoint'."
|
|
248
272
|
})),
|
|
249
273
|
runId: Type.Optional(Type.String({
|
|
250
|
-
description: "Target run ID for action='interrupt', action='stop', action='resume', action='steer',
|
|
274
|
+
description: "Target run ID for action='interrupt', action='stop', action='resume', action='steer', action='append-step', action='approve-checkpoint', or action='reject-checkpoint'. Prefer id for new calls."
|
|
251
275
|
})),
|
|
252
276
|
dir: Type.Optional(Type.String({
|
|
253
277
|
description: "Async run directory for action='status', action='stop', action='resume', or action='steer'."
|
|
@@ -290,10 +314,11 @@ const SubagentParamsSchema = Type.Object({
|
|
|
290
314
|
})),
|
|
291
315
|
chainDir: Type.Optional(Type.String({ description: "Persistent chain artifact directory; defaults to user-scoped temp storage." })),
|
|
292
316
|
async: Type.Optional(Type.Boolean({ description: "Run in background (default: false, or per config)" })),
|
|
293
|
-
timeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "
|
|
294
|
-
maxRuntimeMs: Type.Optional(Type.Integer({ minimum: 1, description: "Alias
|
|
317
|
+
timeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "Timeout for foreground and async/background runs; foreground defaults to 30m absent call/agent. Alias maxRuntimeMs." })),
|
|
318
|
+
maxRuntimeMs: Type.Optional(Type.Integer({ minimum: 1, description: "Alias timeoutMs for foreground and async/background runs; foreground defaults to 30m absent call/agent." })),
|
|
295
319
|
turnBudget: Type.Optional(TurnBudgetOverride),
|
|
296
320
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
321
|
+
usageBudget: Type.Optional(UsageBudgetOverride),
|
|
297
322
|
agentScope: Type.Optional(Type.String({ description: "Agent discovery scope: 'user', 'project', or 'both' (default: 'both'; project wins on name collisions)" })),
|
|
298
323
|
cwd: Type.Optional(Type.String()),
|
|
299
324
|
artifacts: Type.Optional(Type.Boolean({ description: "Write debug artifacts (default: true)" })),
|
|
@@ -8,7 +8,7 @@ const CUSTOM_TOOL_DESCRIPTION_MAX_BYTES = 50 * 1024;
|
|
|
8
8
|
|
|
9
9
|
export const SUBAGENT_SAFETY_GUIDANCE = `SAFETY-CRITICAL SUBAGENT GUIDANCE:
|
|
10
10
|
• Use { action: "list" } before execution and only run executable/non-disabled agents or chains.
|
|
11
|
-
• Keep execution and management separate: omit action for SINGLE/PARALLEL/CHAIN execution; use action only for list/get/models/create/update/delete/status/grant-spawn-budget/interrupt/stop/resume/append-step/doctor.
|
|
11
|
+
• Keep execution and management separate: omit action for SINGLE/PARALLEL/CHAIN execution; use action only for list/get/models/create/update/delete/status/grant-spawn-budget/interrupt/stop/resume/steer/append-step/approve-checkpoint/reject-checkpoint/doctor.
|
|
12
12
|
• Async/background runs: launch with async:true only when work can proceed independently. Do not sleep or poll status just to wait. In an interactive session, normally return control and let Pi wake you; do not call subagent_wait merely to wait. Override that default and call subagent_wait when the current request is run-to-completion — for example, the user asked you to report results back before continuing or a skill must finish in one turn. Headless sessions auto-drain current-session work at agent_end; use subagent_wait when this turn must receive results before it ends.
|
|
13
13
|
• Child-safety boundary: ordinary child subagents are not orchestrators and must not run subagents. Only explicitly configured fanout children may use the child-safe subagent tool, still bounded by depth/session limits.
|
|
14
14
|
• Writing/review safety: keep one writer for the same cwd/worktree. Use fresh-context read-only reviewers/validators for independent review, then have the parent synthesize and apply fixes as the sole writer unless an isolated worktree was intentionally requested.
|
|
@@ -19,11 +19,11 @@ export const FULL_SUBAGENT_TOOL_DESCRIPTION = `To delegate work, call with { age
|
|
|
19
19
|
EXECUTION (use exactly ONE mode):
|
|
20
20
|
• Before executing, use { action: "list" } to inspect configured agents/chains. Only execute agents listed as executable/non-disabled.
|
|
21
21
|
• SINGLE: { agent, task? } - one task; omit task for self-contained agents
|
|
22
|
-
• CHAIN: { chain: [{agent:"agent-a"}, {parallel:[{agent:"agent-b",count:3}]}] } - sequential pipeline with optional parallel fan-out
|
|
22
|
+
• CHAIN: { chain: [{agent:"agent-a"}, {checkpoint:"review"}, {parallel:[{agent:"agent-b",count:3}]}] } - sequential pipeline with optional approval checkpoints and parallel fan-out
|
|
23
23
|
• PARALLEL: { tasks: [{agent,task,count?,output?,reads?,progress?}, ...], concurrency?: number, worktree?: true } - concurrent execution (worktree: isolate each task in a git worktree)
|
|
24
24
|
• Optional context: { context: "fresh" | "fork" } (explicit value overrides every child; when omitted, each requested agent uses its own defaultContext, otherwise "fresh"; inspect agent defaults via { action: "list" })
|
|
25
25
|
• Fork thinking: model strings accept a thinking suffix (provider/model:off|minimal|low|medium|high|xhigh|max). Forking over a parent transcript that carries signed Anthropic thinking blocks forces thinking off only when a child's effective primary or fallback model resolves to the Anthropic provider or anthropic-messages API; unresolved models are treated conservatively. The result notes affected children, including on failures. Use fresh context when an Anthropic child needs thinking.
|
|
26
|
-
• Optional timeout: { timeoutMs } or { maxRuntimeMs } sets a run-level max runtime for foreground and async/background runs
|
|
26
|
+
• Optional timeout: { timeoutMs } or { maxRuntimeMs } sets a run-level max runtime for foreground and async/background runs; foreground defaults to 30 minutes only when neither value nor an agent timeout is provided
|
|
27
27
|
• Acceptance: omit acceptance for reviewer/read-only calls. Evidence levels end at verified. Use acceptance.review.required to require independent review of a writer result. Never request acceptance:"reviewed"; reviewed is achieved only after an independent reviewer result.
|
|
28
28
|
• If { action: "list" } shows proactive skill subagent suggestions, consider a small fresh-context fanout for broad tasks where one of those skills would materially help
|
|
29
29
|
|
|
@@ -35,7 +35,7 @@ CHAIN TEMPLATE VARIABLES (use in task strings):
|
|
|
35
35
|
CHAIN EXAMPLES (quick reference for the nested schema):
|
|
36
36
|
• Sequential: { chain: [{agent:"agent-a", task:"Analyze {task}"}, {agent:"agent-b", task:"Plan based on {previous}"}] }
|
|
37
37
|
• Parallel fan-out: { chain: [{parallel: [{agent:"agent-a", task:"Check part of {task}", count: 3}]}] }
|
|
38
|
-
• Mixed: { chain: [{agent:"agent-a", task:"Research {task}"}, {parallel: [{agent:"agent-b", task:"Review {previous}", count: 2}]}, {agent:"agent-c", task:"Summarize {previous}"}] }
|
|
38
|
+
• Mixed: { chain: [{agent:"agent-a", task:"Research {task}"}, {checkpoint:"review", message:"Approve implementation?"}, {parallel: [{agent:"agent-b", task:"Review {previous}", count: 2}]}, {agent:"agent-c", task:"Summarize {previous}"}] }
|
|
39
39
|
|
|
40
40
|
MANAGEMENT (use action field, omit agent/task/chain/tasks):
|
|
41
41
|
• { action: "list" } - discover executable agents/chains
|
|
@@ -63,6 +63,7 @@ CONTROL:
|
|
|
63
63
|
• { action: "resume", id: "...", message: "...", index?: 0 } - revive a paused, completed, or failed async/foreground child from its session; stopped runs are non-resumable; routed nested runs may accept live follow-ups; use steer for a live top-level async child
|
|
64
64
|
• { action: "steer", id: "...", message: "...", index?: 0 } - await correlated child-Pi input acceptance for up to 3 seconds; returns delivered, scheduled, pending, partial, recovered, or failed with a request id. Only top-level single runs may recover after a further 15-second pause/revival bound; chain, parallel, and nested runs never auto-interrupt.
|
|
65
65
|
• { action: "append-step", id: "...", chain: [{agent:"agent-c", task:"Use {previous}"}] } - append one step to the tail of a running async chain
|
|
66
|
+
• { action: "approve-checkpoint", id: "..." } / { action: "reject-checkpoint", id: "..." } - decide a paused current-session async chain checkpoint
|
|
66
67
|
|
|
67
68
|
SCHEDULE (opt-in; requires { "scheduledRuns": { "enabled": true } } in config.json):
|
|
68
69
|
• { action: "schedule", agent, task?, schedule: "+10m" | "2030-01-01T09:00:00Z", scheduleName? } - defer a subagent launch until a future time. Also accepts tasks[] or chain[]. Scheduled runs always launch async with fresh context; they become normal tracked async runs once they fire. Only schedule explicit delayed runs the user asked for.
|
|
@@ -79,8 +80,8 @@ export const COMPACT_SUBAGENT_TOOL_DESCRIPTION = `To delegate work, call with {
|
|
|
79
80
|
|
|
80
81
|
EXECUTE:
|
|
81
82
|
• Before execution, call { action: "list" }; run only executable/non-disabled configured agents/chains.
|
|
82
|
-
• SINGLE {agent, task?}; PARALLEL {tasks:[{agent,task,count?,output?,reads?,progress?}], concurrency?, worktree?}; CHAIN {chain:[{agent,task?},{parallel:[...]}]}.
|
|
83
|
-
• context can be "fresh" or "fork"; omitted uses each agent defaultContext, otherwise fresh. timeoutMs/maxRuntimeMs apply to foreground and async/background runs.
|
|
83
|
+
• SINGLE {agent, task?}; PARALLEL {tasks:[{agent,task,count?,output?,reads?,progress?}], concurrency?, worktree?}; CHAIN {chain:[{agent,task?},{checkpoint:"review"},{parallel:[...]}]}.
|
|
84
|
+
• context can be "fresh" or "fork"; omitted uses each agent defaultContext, otherwise fresh. timeoutMs/maxRuntimeMs apply to foreground and async/background runs; foreground defaults to 30 minutes only when neither value nor an agent timeout is provided.
|
|
84
85
|
• Omit acceptance for reviewer/read-only calls. Evidence levels end at verified; use acceptance.review.required for independent writer review. reviewed is an achieved status, never an explicit input.
|
|
85
86
|
• Chain templates may use {task}, {previous}, {chain_dir}, and named outputs. Parallel worktree isolation requires a clean git repo.
|
|
86
87
|
• Chain example: { chain: [{agent:"agent-a", task:"Analyze {task}"}, {parallel: [{agent:"agent-b", task:"Check {previous}", count: 3}]}] }
|
|
@@ -89,7 +90,7 @@ EXECUTE:
|
|
|
89
90
|
MANAGE / CONTROL:
|
|
90
91
|
• Use action without execution fields: list, get, models, create, update, delete, eject, disable, enable, reset, grant-spawn-budget, doctor, watchdog.status, watchdog.check, watchdog.recommend-model, watchdog.configure.
|
|
91
92
|
• Agent acceptanceRole (read-only or writer) affects inferred acceptance only, never tools. Explicit task intent wins; omission keeps name heuristics. Update with false or an empty string to clear it.
|
|
92
|
-
• Async control actions: status, interrupt, stop, resume, steer, append-step. Use stop with an id for current-session top-level async runs. Use status view:"fleet" for active-run overview, view:"transcript" to tail child output, steer for acknowledged top-level live async guidance, and resume for paused/completed/failed revival or a routed nested follow-up. Stopped runs are non-resumable. Steering delivery means Pi accepted the correlated user input, not model compliance; use index for a specific child.
|
|
93
|
+
• Async control actions: status, interrupt, stop, resume, steer, append-step, approve-checkpoint, reject-checkpoint. Use stop with an id for current-session top-level async runs. Use status view:"fleet" for active-run overview, view:"transcript" to tail child output, steer for acknowledged top-level live async guidance, and resume for paused/completed/failed revival or a routed nested follow-up. Stopped runs are non-resumable. Steering delivery means Pi accepted the correlated user input, not model compliance; use index for a specific child.
|
|
93
94
|
• Opt-in schedule actions: schedule, schedule-list, schedule-status, schedule-cancel. Schedule only explicit delayed runs the user asked for.
|
|
94
95
|
|
|
95
96
|
ASYNC / WAIT:
|
|
@@ -16,6 +16,7 @@ function defaultSubagentConfigDir(agentDir = defaultAgentDir()): string {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const DEFAULT_INTERCOM_TARGET_PREFIX = "subagent-chat";
|
|
19
|
+
export const PI_INTERCOM_SESSION_ID_ENV = "PI_INTERCOM_SESSION_ID";
|
|
19
20
|
export const INTERCOM_BRIDGE_MARKER = "Intercom orchestration channel:";
|
|
20
21
|
const DEFAULT_INTERCOM_BRIDGE_TEMPLATE = `The inherited thread is reference-only. Do not continue that conversation or send questions, status updates, or completion handoffs to the supervisor in normal assistant text.
|
|
21
22
|
|
|
@@ -32,6 +33,7 @@ Do not use contact_supervisor or intercom for routine completion handoffs. If no
|
|
|
32
33
|
export interface IntercomBridgeState {
|
|
33
34
|
active: boolean;
|
|
34
35
|
mode: IntercomBridgeMode;
|
|
36
|
+
resultDelivery: boolean;
|
|
35
37
|
orchestratorTarget?: string;
|
|
36
38
|
extensionDir: string;
|
|
37
39
|
instruction: string;
|
|
@@ -55,10 +57,11 @@ interface ResolveIntercomBridgeInput {
|
|
|
55
57
|
agentDir?: string;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
export function resolveIntercomSessionTarget(sessionName: string | undefined, sessionId: string): string {
|
|
60
|
+
export function resolveIntercomSessionTarget(sessionName: string | undefined, sessionId: string, intercomSessionId = process.env[PI_INTERCOM_SESSION_ID_ENV]): string {
|
|
59
61
|
const trimmedName = sessionName?.trim();
|
|
60
62
|
if (trimmedName) return trimmedName;
|
|
61
|
-
const
|
|
63
|
+
const fallbackSessionId = intercomSessionId?.trim() || sessionId;
|
|
64
|
+
const normalizedSessionId = fallbackSessionId.startsWith("session-") ? fallbackSessionId.slice("session-".length) : fallbackSessionId;
|
|
62
65
|
return `${DEFAULT_INTERCOM_TARGET_PREFIX}-${normalizedSessionId.slice(0, 8)}`;
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -78,11 +81,12 @@ export function resolveIntercomBridgeMode(value: unknown): IntercomBridgeMode {
|
|
|
78
81
|
|
|
79
82
|
function resolveIntercomBridgeConfig(value: ExtensionConfig["intercomBridge"]): Required<IntercomBridgeConfig> {
|
|
80
83
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
81
|
-
return { mode: "always", instructionFile: "" };
|
|
84
|
+
return { mode: "always", instructionFile: "", resultDelivery: true };
|
|
82
85
|
}
|
|
83
86
|
return {
|
|
84
87
|
mode: resolveIntercomBridgeMode(value.mode),
|
|
85
88
|
instructionFile: typeof value.instructionFile === "string" ? value.instructionFile : "",
|
|
89
|
+
resultDelivery: value.resultDelivery !== false,
|
|
86
90
|
};
|
|
87
91
|
}
|
|
88
92
|
|
|
@@ -146,11 +150,12 @@ export function resolveIntercomBridge(input: ResolveIntercomBridgeInput): Interc
|
|
|
146
150
|
);
|
|
147
151
|
const reason = inactiveReason(mode, input.context, orchestratorTarget);
|
|
148
152
|
if (reason || !orchestratorTarget) {
|
|
149
|
-
return { active: false, mode, extensionDir: NATIVE_INTERCOM_EXTENSION_DIR, instruction: defaultInstruction };
|
|
153
|
+
return { active: false, mode, resultDelivery: config.resultDelivery, extensionDir: NATIVE_INTERCOM_EXTENSION_DIR, instruction: defaultInstruction };
|
|
150
154
|
}
|
|
151
155
|
return {
|
|
152
156
|
active: true,
|
|
153
157
|
mode,
|
|
158
|
+
resultDelivery: config.resultDelivery,
|
|
154
159
|
orchestratorTarget,
|
|
155
160
|
extensionDir: NATIVE_INTERCOM_EXTENSION_DIR,
|
|
156
161
|
instruction: buildIntercomBridgeInstruction(orchestratorTarget, resolveInstructionTemplate(config.instructionFile, settingsDir)),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
+
import { isUnexplainedProcessSignal } from "../runs/shared/process-signal.ts";
|
|
3
4
|
import {
|
|
4
5
|
type Details,
|
|
5
6
|
type IntercomEventBus,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
type SubagentResultIntercomChild,
|
|
11
12
|
type SubagentResultIntercomPayload,
|
|
12
13
|
type SubagentResultStatus,
|
|
14
|
+
type SubagentOutputState,
|
|
13
15
|
type SubagentRunMode,
|
|
14
16
|
SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT,
|
|
15
17
|
SUBAGENT_RESULT_INTERCOM_EVENT,
|
|
@@ -21,11 +23,17 @@ export function resolveSubagentResultStatus(input: {
|
|
|
21
23
|
state?: string;
|
|
22
24
|
interrupted?: boolean;
|
|
23
25
|
detached?: boolean;
|
|
26
|
+
processSignal?: string | null;
|
|
27
|
+
timedOut?: boolean;
|
|
28
|
+
stopped?: boolean;
|
|
29
|
+
turnBudgetExceeded?: boolean;
|
|
24
30
|
}): SubagentResultStatus {
|
|
25
31
|
if (input.detached) return "detached";
|
|
26
|
-
if (input.state === "stopped") return "stopped";
|
|
32
|
+
if (input.stopped || input.state === "stopped") return "stopped";
|
|
27
33
|
if (input.interrupted || input.state === "paused") return "paused";
|
|
28
|
-
if (
|
|
34
|
+
if (input.success === true) return "completed";
|
|
35
|
+
if (isUnexplainedProcessSignal(input) && input.exitCode !== 0) return "stopped";
|
|
36
|
+
if (input.success === false) return "failed";
|
|
29
37
|
if (input.state === "complete") return "completed";
|
|
30
38
|
if (input.state === "failed") return "failed";
|
|
31
39
|
if (typeof input.exitCode === "number") return input.exitCode === 0 ? "completed" : "failed";
|
|
@@ -57,6 +65,21 @@ function formatStatusCounts(counts: Record<SubagentResultStatus, number>): strin
|
|
|
57
65
|
return parts.length ? parts.join(", ") : "0 results";
|
|
58
66
|
}
|
|
59
67
|
|
|
68
|
+
function countOutputStates(children: SubagentResultIntercomChild[]): Record<SubagentOutputState, number> {
|
|
69
|
+
const counts: Record<SubagentOutputState, number> = { present: 0, absent: 0, unknown: 0 };
|
|
70
|
+
for (const child of children) counts[child.outputState ?? "unknown"] += 1;
|
|
71
|
+
return counts;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function formatOutputCounts(counts: Record<SubagentOutputState, number>): string {
|
|
75
|
+
const parts = [
|
|
76
|
+
counts.present ? `${counts.present} present` : undefined,
|
|
77
|
+
counts.absent ? `${counts.absent} absent` : undefined,
|
|
78
|
+
counts.unknown ? `${counts.unknown} unknown` : undefined,
|
|
79
|
+
].filter((part): part is string => Boolean(part));
|
|
80
|
+
return parts.length ? parts.join(", ") : "0 outputs";
|
|
81
|
+
}
|
|
82
|
+
|
|
60
83
|
function resolveGroupedStatus(children: SubagentResultIntercomChild[]): SubagentResultStatus {
|
|
61
84
|
const counts = countStatuses(children);
|
|
62
85
|
if (counts.failed > 0) return "failed";
|
|
@@ -212,14 +235,19 @@ function formatSubagentResultIntercomMessage(input: {
|
|
|
212
235
|
parallelHandoff?: ParallelHandoffReference;
|
|
213
236
|
}): string {
|
|
214
237
|
const counts = countStatuses(input.children);
|
|
238
|
+
const outputCounts = countOutputStates(input.children);
|
|
215
239
|
const lines: string[] = [
|
|
216
240
|
"subagent results",
|
|
217
241
|
"",
|
|
218
242
|
`Run: ${input.runId}`,
|
|
219
243
|
`Mode: ${input.mode}`,
|
|
220
|
-
`
|
|
244
|
+
`Process status: ${input.status}`,
|
|
221
245
|
`Children: ${formatStatusCounts(counts)}`,
|
|
246
|
+
`Outputs: ${formatOutputCounts(outputCounts)} (semantic adequacy unassessed)`,
|
|
222
247
|
];
|
|
248
|
+
if (input.children.some((child) => child.status === "failed" && child.outputState === "present")) {
|
|
249
|
+
lines.push("Recovery: At least one failed process produced output. Inspect that output before retrying; output presence does not establish task completion.");
|
|
250
|
+
}
|
|
223
251
|
if (input.mode === "chain" && typeof input.chainSteps === "number") {
|
|
224
252
|
lines.push(`Chain steps: ${input.chainSteps}`);
|
|
225
253
|
}
|
|
@@ -238,7 +266,7 @@ function formatSubagentResultIntercomMessage(input: {
|
|
|
238
266
|
for (let index = 0; index < input.children.length; index++) {
|
|
239
267
|
const child = input.children[index]!;
|
|
240
268
|
lines.push("");
|
|
241
|
-
lines.push(`${index + 1}. ${child.agent} — ${child.status}`);
|
|
269
|
+
lines.push(`${index + 1}. ${child.agent} — process ${child.status} · output ${child.outputState ?? "unknown"}`);
|
|
242
270
|
if (child.intercomTarget) lines.push(`${input.source === "async" ? "Previous intercom target" : "Run intercom target"}: ${child.intercomTarget}`);
|
|
243
271
|
if (child.artifactPath) lines.push(`Output artifact: ${child.artifactPath}`);
|
|
244
272
|
if (child.sessionPath) lines.push(`Session: ${child.sessionPath}`);
|
|
@@ -253,6 +281,7 @@ function formatSubagentResultIntercomMessage(input: {
|
|
|
253
281
|
export function buildSubagentResultIntercomPayload(input: GroupedResultIntercomMessageInput): SubagentResultIntercomPayload {
|
|
254
282
|
const children = input.children.map((child) => ({
|
|
255
283
|
...child,
|
|
284
|
+
outputState: child.outputState ?? "unknown",
|
|
256
285
|
summary: child.summary.trim() || "(no output)",
|
|
257
286
|
children: compactNestedResultChildren(child.children),
|
|
258
287
|
}));
|