@selesai/code 0.5.19 → 0.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/handoff-new.test.ts +8 -9
- package/dist/extensions/handoff-new.ts +6 -8
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
- package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
- package/dist/extensions/pi-subagents/README.md +602 -220
- package/dist/extensions/pi-subagents/banner.png +0 -0
- package/dist/extensions/pi-subagents/index.ts +1 -0
- package/dist/extensions/pi-subagents/install.mjs +3 -3
- package/dist/extensions/pi-subagents/package-lock.json +3405 -0
- package/dist/extensions/pi-subagents/package.json +26 -14
- package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
- package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
- package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
- package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
- package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
- package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
- package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
- package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
- package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
- package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
- package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
- package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
- package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
- package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
- package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
- package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
- package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
- package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
- package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
- package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
- package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
- package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
- package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
- package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
- package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
- package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
- package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
- package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
- package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
- package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
- package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
- package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
- package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
- package/dist/extensions/question/batch.ts +39 -0
- package/dist/extensions/question/dialog-adapter.ts +23 -1
- package/dist/extensions/question/index.ts +237 -7
- package/dist/extensions/question/schemas.ts +28 -15
- package/dist/extensions/question/tests/batch.test.ts +26 -0
- package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
- package/dist/extensions/question/tui-adapter.ts +2 -3
- package/dist/extensions/question/types.ts +37 -0
- package/dist/extensions/question/ui-protocol.ts +3 -3
- package/dist/skills/batch-grill-me/SKILL.md +3 -1
- package/package.json +2 -1
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
SUBAGENT_RUN_ID_ENV,
|
|
13
13
|
SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV,
|
|
14
14
|
} from "../runs/shared/pi-args.ts";
|
|
15
|
-
import { POLL_INTERVAL_MS, TEMP_ROOT_DIR, type SubagentState } from "../shared/types.ts";
|
|
15
|
+
import { INTERCOM_DETACH_REQUEST_EVENT, POLL_INTERVAL_MS, TEMP_ROOT_DIR, type IntercomEventBus, type SubagentState } from "../shared/types.ts";
|
|
16
16
|
import { writeAtomicJson } from "../shared/atomic-json.ts";
|
|
17
17
|
|
|
18
18
|
const SUPERVISOR_CHANNEL_ROOT = path.join(TEMP_ROOT_DIR, "supervisor-channels");
|
|
@@ -22,6 +22,8 @@ export const NATIVE_SUPERVISOR_TOOL_NAME = "subagent_supervisor";
|
|
|
22
22
|
const MAX_MESSAGE_BYTES = 64 * 1024;
|
|
23
23
|
const DEFAULT_ASK_TIMEOUT_MS = 10 * 60 * 1000;
|
|
24
24
|
const CHANNEL_POLL_MS = Math.min(POLL_INTERVAL_MS, 500);
|
|
25
|
+
const STALE_EMPTY_CHANNEL_AGE_MS = 60 * 1000;
|
|
26
|
+
const STALE_EMPTY_CHANNEL_CLEANUP_INTERVAL_MS = 60 * 1000;
|
|
25
27
|
|
|
26
28
|
type SupervisorReason = "need_decision" | "interview_request" | "progress_update";
|
|
27
29
|
|
|
@@ -29,6 +31,7 @@ interface SupervisorRequest {
|
|
|
29
31
|
type: "subagent.supervisor.request";
|
|
30
32
|
id: string;
|
|
31
33
|
createdAt: number;
|
|
34
|
+
expiresAt?: number;
|
|
32
35
|
reason: SupervisorReason;
|
|
33
36
|
message: string;
|
|
34
37
|
expectsReply: boolean;
|
|
@@ -203,9 +206,8 @@ function delay(ms: number, signal?: AbortSignal): Promise<void> {
|
|
|
203
206
|
});
|
|
204
207
|
}
|
|
205
208
|
|
|
206
|
-
async function waitForReply(channelDir: string, requestId: string, signal?: AbortSignal): Promise<SupervisorReply> {
|
|
209
|
+
async function waitForReply(channelDir: string, requestId: string, deadline: number, signal?: AbortSignal): Promise<SupervisorReply> {
|
|
207
210
|
const file = replyPath(channelDir, requestId);
|
|
208
|
-
const deadline = Date.now() + askTimeoutMs();
|
|
209
211
|
while (Date.now() <= deadline) {
|
|
210
212
|
if (signal?.aborted) throw new Error("Supervisor request cancelled.");
|
|
211
213
|
if (fs.existsSync(file)) {
|
|
@@ -228,11 +230,15 @@ async function sendSupervisorRequest(params: ContactSupervisorParams, signal?: A
|
|
|
228
230
|
ensureSupervisorChannelDir(metadata.channelDir);
|
|
229
231
|
const requestId = randomUUID();
|
|
230
232
|
const expectsReply = params.reason !== "progress_update";
|
|
233
|
+
const createdAt = Date.now();
|
|
234
|
+
const replyDeadline = createdAt + askTimeoutMs();
|
|
235
|
+
const expiresAt = expectsReply ? replyDeadline : undefined;
|
|
231
236
|
const message = formatChildMessage({ ...metadata, reason: params.reason, message: params.message, interview: params.interview });
|
|
232
237
|
const request: SupervisorRequest = {
|
|
233
238
|
type: "subagent.supervisor.request",
|
|
234
239
|
id: requestId,
|
|
235
|
-
createdAt
|
|
240
|
+
createdAt,
|
|
241
|
+
...(expiresAt !== undefined ? { expiresAt } : {}),
|
|
236
242
|
reason: params.reason,
|
|
237
243
|
message,
|
|
238
244
|
expectsReply,
|
|
@@ -255,17 +261,22 @@ async function sendSupervisorRequest(params: ContactSupervisorParams, signal?: A
|
|
|
255
261
|
};
|
|
256
262
|
}
|
|
257
263
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
+
try {
|
|
265
|
+
const reply = await waitForReply(metadata.channelDir, requestId, replyDeadline, signal);
|
|
266
|
+
const details: Record<string, unknown> = { requestId, reason: params.reason };
|
|
267
|
+
if (params.reason === "interview_request") {
|
|
268
|
+
const structured = parseStructuredReply(reply.message);
|
|
269
|
+
if (structured.error) details.structuredReplyParseError = structured.error;
|
|
270
|
+
else details.structuredReply = structured.value;
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
content: [{ type: "text", text: `**Reply from supervisor:**\n${reply.message}` }],
|
|
274
|
+
details,
|
|
275
|
+
};
|
|
276
|
+
} catch (error) {
|
|
277
|
+
removeRequestFile(requestPath(metadata.channelDir, requestId));
|
|
278
|
+
throw error;
|
|
264
279
|
}
|
|
265
|
-
return {
|
|
266
|
-
content: [{ type: "text", text: `**Reply from supervisor:**\n${reply.message}` }],
|
|
267
|
-
details,
|
|
268
|
-
};
|
|
269
280
|
}
|
|
270
281
|
|
|
271
282
|
function hasTool(pi: ExtensionAPI, name: string): boolean {
|
|
@@ -350,6 +361,77 @@ function listRequestFiles(): Array<{ channelDir: string; file: string }> {
|
|
|
350
361
|
return files;
|
|
351
362
|
}
|
|
352
363
|
|
|
364
|
+
function readDirectoryEntries(dir: string): fs.Dirent[] | undefined {
|
|
365
|
+
try {
|
|
366
|
+
return fs.readdirSync(dir, { withFileTypes: true });
|
|
367
|
+
} catch (error) {
|
|
368
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return [];
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function directoryMtimeMs(dir: string): number {
|
|
374
|
+
try {
|
|
375
|
+
return fs.statSync(dir).mtimeMs;
|
|
376
|
+
} catch {
|
|
377
|
+
return 0;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function removeEmptyDirectory(dir: string): boolean {
|
|
382
|
+
try {
|
|
383
|
+
fs.rmdirSync(dir);
|
|
384
|
+
return true;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
387
|
+
if (code === "ENOENT") return true;
|
|
388
|
+
if (code === "ENOTEMPTY" || code === "EEXIST" || code === "EPERM" || code === "EBUSY") return false;
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function removeStaleEmptySupervisorChannel(channelDir: string, nowMs: number): boolean {
|
|
394
|
+
const requestsDir = path.join(channelDir, REQUESTS_DIR);
|
|
395
|
+
const repliesDir = path.join(channelDir, REPLIES_DIR);
|
|
396
|
+
const newestKnownMtimeMs = Math.max(
|
|
397
|
+
directoryMtimeMs(channelDir),
|
|
398
|
+
directoryMtimeMs(requestsDir),
|
|
399
|
+
directoryMtimeMs(repliesDir),
|
|
400
|
+
);
|
|
401
|
+
if (nowMs - newestKnownMtimeMs < STALE_EMPTY_CHANNEL_AGE_MS) return false;
|
|
402
|
+
|
|
403
|
+
const requestEntries = readDirectoryEntries(requestsDir);
|
|
404
|
+
if (!requestEntries || requestEntries.length > 0) return false;
|
|
405
|
+
const replyEntries = readDirectoryEntries(repliesDir);
|
|
406
|
+
if (!replyEntries || replyEntries.length > 0) return false;
|
|
407
|
+
|
|
408
|
+
if (!removeEmptyDirectory(requestsDir)) return false;
|
|
409
|
+
if (!removeEmptyDirectory(repliesDir)) return false;
|
|
410
|
+
if (!removeEmptyDirectory(channelDir)) return false;
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function cleanupStaleEmptySupervisorChannels(nowMs = Date.now()): number {
|
|
415
|
+
let channelEntries: fs.Dirent[];
|
|
416
|
+
try {
|
|
417
|
+
channelEntries = fs.readdirSync(SUPERVISOR_CHANNEL_ROOT, { withFileTypes: true });
|
|
418
|
+
} catch (error) {
|
|
419
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return 0;
|
|
420
|
+
throw error;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let removed = 0;
|
|
424
|
+
for (const entry of channelEntries) {
|
|
425
|
+
if (!entry.isDirectory()) continue;
|
|
426
|
+
try {
|
|
427
|
+
if (removeStaleEmptySupervisorChannel(path.join(SUPERVISOR_CHANNEL_ROOT, entry.name), nowMs)) removed++;
|
|
428
|
+
} catch {
|
|
429
|
+
// Cleanup is opportunistic; active writers can race with us and will be picked up by a later pass.
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return removed;
|
|
433
|
+
}
|
|
434
|
+
|
|
353
435
|
function currentContextSessionId(state: Pick<SubagentState, "currentSessionId">, ctx: ExtensionContext): string | undefined {
|
|
354
436
|
try {
|
|
355
437
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
@@ -365,6 +447,94 @@ function requestMatchesContext(request: SupervisorRequest, state: Pick<SubagentS
|
|
|
365
447
|
return Boolean(currentSessionId && request.orchestratorSessionId === currentSessionId);
|
|
366
448
|
}
|
|
367
449
|
|
|
450
|
+
function rememberedForegroundChild(request: SupervisorRequest, state: SubagentState) {
|
|
451
|
+
const run = state.foregroundRuns?.get(request.runId);
|
|
452
|
+
const child = run?.children.find((candidate) => candidate.index === request.childIndex && candidate.agent === request.agent)
|
|
453
|
+
?? run?.children[request.childIndex];
|
|
454
|
+
return run && child ? { run, child } : undefined;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function markForegroundSupervisorAttention(request: SupervisorRequest, state: SubagentState): void {
|
|
458
|
+
const remembered = rememberedForegroundChild(request, state);
|
|
459
|
+
if (!remembered || remembered.child.status !== "detached") return;
|
|
460
|
+
const updatedAt = Date.now();
|
|
461
|
+
remembered.run.updatedAt = updatedAt;
|
|
462
|
+
remembered.child.activityState = "needs_attention";
|
|
463
|
+
remembered.child.lastActivityAt = request.createdAt;
|
|
464
|
+
remembered.child.currentTool = "contact_supervisor";
|
|
465
|
+
remembered.child.currentToolStartedAt = request.createdAt;
|
|
466
|
+
remembered.child.updatedAt = updatedAt;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function clearForegroundSupervisorAttention(request: SupervisorRequest, pending: Map<string, PendingSupervisorRequest>, state: SubagentState): void {
|
|
470
|
+
if ([...pending.values()].some((candidate) =>
|
|
471
|
+
candidate.expectsReply
|
|
472
|
+
&& candidate.runId === request.runId
|
|
473
|
+
&& candidate.agent === request.agent
|
|
474
|
+
&& candidate.childIndex === request.childIndex
|
|
475
|
+
)) return;
|
|
476
|
+
const remembered = rememberedForegroundChild(request, state);
|
|
477
|
+
if (!remembered || remembered.child.status !== "detached" || remembered.child.currentTool !== "contact_supervisor") return;
|
|
478
|
+
const updatedAt = Date.now();
|
|
479
|
+
remembered.run.updatedAt = updatedAt;
|
|
480
|
+
remembered.child.activityState = undefined;
|
|
481
|
+
remembered.child.lastActivityAt = updatedAt;
|
|
482
|
+
remembered.child.currentTool = undefined;
|
|
483
|
+
remembered.child.currentToolStartedAt = undefined;
|
|
484
|
+
remembered.child.updatedAt = updatedAt;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function removeRequestFile(file: string): void {
|
|
488
|
+
try {
|
|
489
|
+
fs.rmSync(file, { force: true });
|
|
490
|
+
} catch {
|
|
491
|
+
// Request cleanup is best-effort; reply files and timeout errors remain authoritative.
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
type SupervisorRequestLifecycle = "pending" | "resolved" | "expired" | "inactive" | "missing" | "wrong-session";
|
|
496
|
+
|
|
497
|
+
function requestExpiresAt(request: SupervisorRequest, now: number): number {
|
|
498
|
+
const expiresAt = (request as { expiresAt?: unknown }).expiresAt;
|
|
499
|
+
if (typeof expiresAt === "number" && Number.isFinite(expiresAt)) return expiresAt;
|
|
500
|
+
return Number.isFinite(request.createdAt) ? request.createdAt + askTimeoutMs() : now;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function requestRunInactive(request: SupervisorRequest, state: SubagentState): boolean {
|
|
504
|
+
if (state.foregroundControls.has(request.runId)) return false;
|
|
505
|
+
const foreground = rememberedForegroundChild(request, state);
|
|
506
|
+
if (foreground) return foreground.child.status !== "detached";
|
|
507
|
+
|
|
508
|
+
const asyncJob = state.asyncJobs.get(request.runId);
|
|
509
|
+
if (!asyncJob) return false;
|
|
510
|
+
if (asyncJob.status === "complete" || asyncJob.status === "failed" || asyncJob.status === "paused") return true;
|
|
511
|
+
const stepStatus = asyncJob.steps?.[request.childIndex]?.status;
|
|
512
|
+
return stepStatus === "complete" || stepStatus === "completed" || stepStatus === "failed" || stepStatus === "paused";
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function requestLifecycle(request: PendingSupervisorRequest, state: SubagentState, ctx: ExtensionContext | undefined, now: number): SupervisorRequestLifecycle {
|
|
516
|
+
if (ctx && !requestMatchesContext(request, state, ctx)) return "wrong-session";
|
|
517
|
+
if (!fs.existsSync(request.requestFile)) return "missing";
|
|
518
|
+
if (request.expectsReply && fs.existsSync(replyPath(request.channelDir, request.id))) return "resolved";
|
|
519
|
+
if (request.expectsReply && now > requestExpiresAt(request, now)) return "expired";
|
|
520
|
+
if (request.expectsReply && requestRunInactive(request, state)) return "inactive";
|
|
521
|
+
return "pending";
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function cleanupRequestLifecycle(request: PendingSupervisorRequest, lifecycle: SupervisorRequestLifecycle): void {
|
|
525
|
+
if (lifecycle === "resolved" || lifecycle === "expired" || lifecycle === "inactive") removeRequestFile(request.requestFile);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function refreshPendingRequests(pending: Map<string, PendingSupervisorRequest>, state: SubagentState, ctx: ExtensionContext | undefined): void {
|
|
529
|
+
const now = Date.now();
|
|
530
|
+
for (const request of pending.values()) {
|
|
531
|
+
const lifecycle = requestLifecycle(request, state, ctx, now);
|
|
532
|
+
if (lifecycle === "pending") continue;
|
|
533
|
+
pending.delete(request.id);
|
|
534
|
+
cleanupRequestLifecycle(request, lifecycle);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
368
538
|
function formatPendingLine(request: PendingSupervisorRequest): string {
|
|
369
539
|
const replyHint = request.expectsReply ? ` Reply: ${NATIVE_SUPERVISOR_TOOL_NAME}({ action: "reply", replyTo: "${request.id}", message: "..." })` : "";
|
|
370
540
|
return `- ${request.id}: ${request.agent} [${request.runId}#${request.childIndex}] ${request.reason}.${replyHint}`;
|
|
@@ -387,11 +557,7 @@ function writeReply(request: PendingSupervisorRequest, message: string): void {
|
|
|
387
557
|
message: message.trim(),
|
|
388
558
|
};
|
|
389
559
|
writeAtomicJson(replyPath(request.channelDir, request.id), reply);
|
|
390
|
-
|
|
391
|
-
fs.rmSync(request.requestFile, { force: true });
|
|
392
|
-
} catch {
|
|
393
|
-
// Best effort: the reply file is authoritative for the child.
|
|
394
|
-
}
|
|
560
|
+
removeRequestFile(request.requestFile);
|
|
395
561
|
}
|
|
396
562
|
|
|
397
563
|
function resolvePendingRequest(pending: Map<string, PendingSupervisorRequest>, params: IntercomParams): PendingSupervisorRequest {
|
|
@@ -427,7 +593,7 @@ function publicPendingRequests(pending: Map<string, PendingSupervisorRequest>):
|
|
|
427
593
|
}));
|
|
428
594
|
}
|
|
429
595
|
|
|
430
|
-
function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>, name = "intercom"): ToolDefinition<typeof IntercomParamsSchema, Record<string, unknown>> {
|
|
596
|
+
function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>, state: SubagentState, name = "intercom"): ToolDefinition<typeof IntercomParamsSchema, Record<string, unknown>> {
|
|
431
597
|
return {
|
|
432
598
|
name,
|
|
433
599
|
label: name === "intercom" ? "Intercom" : "Subagent Supervisor",
|
|
@@ -436,6 +602,7 @@ function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>,
|
|
|
436
602
|
: "Native pi-subagents supervisor channel. Use reply/pending/status to answer child subagent requests without overriding pi-intercom.",
|
|
437
603
|
parameters: IntercomParamsSchema,
|
|
438
604
|
async execute(_id, params) {
|
|
605
|
+
refreshPendingRequests(pending, state, state.lastUiContext ?? undefined);
|
|
439
606
|
const input = params as IntercomParams;
|
|
440
607
|
if (input.action === "status") {
|
|
441
608
|
return { content: [{ type: "text", text: `Native supervisor channel active. Pending replies: ${pending.size}.` }], details: { active: true, pending: pending.size, root: SUPERVISOR_CHANNEL_ROOT } };
|
|
@@ -448,6 +615,7 @@ function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>,
|
|
|
448
615
|
const request = resolvePendingRequest(pending, input);
|
|
449
616
|
writeReply(request, input.message ?? "");
|
|
450
617
|
pending.delete(request.id);
|
|
618
|
+
clearForegroundSupervisorAttention(request, pending, state);
|
|
451
619
|
return { content: [{ type: "text", text: `Replied to supervisor request ${request.id}.` }], details: { replyTo: request.id, runId: request.runId, agent: request.agent } };
|
|
452
620
|
}
|
|
453
621
|
if (input.action === "send" || input.action === "ask") {
|
|
@@ -462,27 +630,47 @@ export function createNativeSupervisorChannel(pi: ExtensionAPI, state: SubagentS
|
|
|
462
630
|
const pending = new Map<string, PendingSupervisorRequest>();
|
|
463
631
|
const seenFiles = new Set<string>();
|
|
464
632
|
let poller: ReturnType<typeof setInterval> | undefined;
|
|
633
|
+
let lastStaleCleanupAt = 0;
|
|
465
634
|
|
|
466
635
|
const registerParentTools = (): void => {
|
|
467
|
-
if (!hasTool(pi, NATIVE_SUPERVISOR_TOOL_NAME)) pi.registerTool(buildParentIntercomTool(pending, NATIVE_SUPERVISOR_TOOL_NAME));
|
|
468
|
-
if (!hasTool(pi, "intercom")) pi.registerTool(buildParentIntercomTool(pending));
|
|
636
|
+
if (!hasTool(pi, NATIVE_SUPERVISOR_TOOL_NAME)) pi.registerTool(buildParentIntercomTool(pending, state, NATIVE_SUPERVISOR_TOOL_NAME));
|
|
637
|
+
if (!hasTool(pi, "intercom")) pi.registerTool(buildParentIntercomTool(pending, state));
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
const cleanupStaleChannelsIfDue = (): void => {
|
|
641
|
+
const nowMs = Date.now();
|
|
642
|
+
if (nowMs - lastStaleCleanupAt < STALE_EMPTY_CHANNEL_CLEANUP_INTERVAL_MS) return;
|
|
643
|
+
lastStaleCleanupAt = nowMs;
|
|
644
|
+
try {
|
|
645
|
+
cleanupStaleEmptySupervisorChannels(nowMs);
|
|
646
|
+
} catch {
|
|
647
|
+
// Supervisor delivery must not fail because best-effort temp cleanup failed.
|
|
648
|
+
}
|
|
469
649
|
};
|
|
470
650
|
|
|
471
651
|
const poll = (): void => {
|
|
652
|
+
cleanupStaleChannelsIfDue();
|
|
472
653
|
const ctx = state.lastUiContext;
|
|
473
654
|
if (!ctx) return;
|
|
655
|
+
refreshPendingRequests(pending, state, ctx);
|
|
656
|
+
const now = Date.now();
|
|
474
657
|
for (const { channelDir, file } of listRequestFiles()) {
|
|
475
658
|
if (seenFiles.has(file)) continue;
|
|
476
659
|
const request = parseRequestFile(file, channelDir);
|
|
477
660
|
if (!request || !requestMatchesContext(request, state, ctx)) continue;
|
|
661
|
+
const lifecycle = requestLifecycle(request, state, undefined, now);
|
|
662
|
+
if (lifecycle !== "pending") {
|
|
663
|
+
seenFiles.add(file);
|
|
664
|
+
cleanupRequestLifecycle(request, lifecycle);
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
478
667
|
seenFiles.add(file);
|
|
479
|
-
if (request.expectsReply)
|
|
668
|
+
if (request.expectsReply) {
|
|
669
|
+
pending.set(request.id, request);
|
|
670
|
+
markForegroundSupervisorAttention(request, state);
|
|
671
|
+
}
|
|
480
672
|
else {
|
|
481
|
-
|
|
482
|
-
fs.rmSync(request.requestFile, { force: true });
|
|
483
|
-
} catch {
|
|
484
|
-
// Non-blocking progress updates are already delivered to this session.
|
|
485
|
-
}
|
|
673
|
+
removeRequestFile(request.requestFile);
|
|
486
674
|
}
|
|
487
675
|
pi.sendMessage({
|
|
488
676
|
customType: "subagent_supervisor_request",
|
|
@@ -496,7 +684,15 @@ export function createNativeSupervisorChannel(pi: ExtensionAPI, state: SubagentS
|
|
|
496
684
|
agent: request.agent,
|
|
497
685
|
childIndex: request.childIndex,
|
|
498
686
|
},
|
|
499
|
-
});
|
|
687
|
+
}, { triggerTurn: true });
|
|
688
|
+
if (request.expectsReply) {
|
|
689
|
+
(pi as { events?: IntercomEventBus }).events?.emit(INTERCOM_DETACH_REQUEST_EVENT, {
|
|
690
|
+
requestId: request.id,
|
|
691
|
+
runId: request.runId,
|
|
692
|
+
agent: request.agent,
|
|
693
|
+
childIndex: request.childIndex,
|
|
694
|
+
});
|
|
695
|
+
}
|
|
500
696
|
}
|
|
501
697
|
};
|
|
502
698
|
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type IntercomEventBus,
|
|
6
6
|
type NestedRunSummary,
|
|
7
7
|
type PublicNestedRunSummary,
|
|
8
|
+
type ParallelHandoffReference,
|
|
8
9
|
type SingleResult,
|
|
9
10
|
type SubagentResultIntercomChild,
|
|
10
11
|
type SubagentResultIntercomPayload,
|
|
@@ -22,6 +23,7 @@ export function resolveSubagentResultStatus(input: {
|
|
|
22
23
|
detached?: boolean;
|
|
23
24
|
}): SubagentResultStatus {
|
|
24
25
|
if (input.detached) return "detached";
|
|
26
|
+
if (input.state === "stopped") return "stopped";
|
|
25
27
|
if (input.interrupted || input.state === "paused") return "paused";
|
|
26
28
|
if (typeof input.success === "boolean") return input.success ? "completed" : "failed";
|
|
27
29
|
if (input.state === "complete") return "completed";
|
|
@@ -35,6 +37,7 @@ function countStatuses(children: SubagentResultIntercomChild[]): Record<Subagent
|
|
|
35
37
|
completed: 0,
|
|
36
38
|
failed: 0,
|
|
37
39
|
paused: 0,
|
|
40
|
+
stopped: 0,
|
|
38
41
|
detached: 0,
|
|
39
42
|
};
|
|
40
43
|
for (const child of children) {
|
|
@@ -47,6 +50,7 @@ function formatStatusCounts(counts: Record<SubagentResultStatus, number>): strin
|
|
|
47
50
|
const parts = [
|
|
48
51
|
counts.completed ? `${counts.completed} completed` : undefined,
|
|
49
52
|
counts.failed ? `${counts.failed} failed` : undefined,
|
|
53
|
+
counts.stopped ? `${counts.stopped} stopped` : undefined,
|
|
50
54
|
counts.paused ? `${counts.paused} paused` : undefined,
|
|
51
55
|
counts.detached ? `${counts.detached} detached` : undefined,
|
|
52
56
|
].filter((part): part is string => Boolean(part));
|
|
@@ -56,6 +60,7 @@ function formatStatusCounts(counts: Record<SubagentResultStatus, number>): strin
|
|
|
56
60
|
function resolveGroupedStatus(children: SubagentResultIntercomChild[]): SubagentResultStatus {
|
|
57
61
|
const counts = countStatuses(children);
|
|
58
62
|
if (counts.failed > 0) return "failed";
|
|
63
|
+
if (counts.stopped > 0) return "stopped";
|
|
59
64
|
if (counts.paused > 0) return "paused";
|
|
60
65
|
if (counts.completed > 0) return "completed";
|
|
61
66
|
if (counts.detached > 0) return "detached";
|
|
@@ -175,6 +180,7 @@ interface GroupedResultIntercomMessageInput {
|
|
|
175
180
|
asyncId?: string;
|
|
176
181
|
asyncDir?: string;
|
|
177
182
|
chainSteps?: number;
|
|
183
|
+
parallelHandoff?: ParallelHandoffReference;
|
|
178
184
|
}
|
|
179
185
|
|
|
180
186
|
function asyncResumeGuidance(input: {
|
|
@@ -203,6 +209,7 @@ function formatSubagentResultIntercomMessage(input: {
|
|
|
203
209
|
asyncId?: string;
|
|
204
210
|
asyncDir?: string;
|
|
205
211
|
chainSteps?: number;
|
|
212
|
+
parallelHandoff?: ParallelHandoffReference;
|
|
206
213
|
}): string {
|
|
207
214
|
const counts = countStatuses(input.children);
|
|
208
215
|
const lines: string[] = [
|
|
@@ -218,6 +225,7 @@ function formatSubagentResultIntercomMessage(input: {
|
|
|
218
225
|
}
|
|
219
226
|
if (input.asyncId) lines.push(`Async id: ${input.asyncId}`);
|
|
220
227
|
if (input.asyncDir) lines.push(`Async dir: ${input.asyncDir}`);
|
|
228
|
+
if (input.parallelHandoff) lines.push(`Parallel handoff: ${input.parallelHandoff.path}`);
|
|
221
229
|
const resumeGuidance = asyncResumeGuidance(input);
|
|
222
230
|
if (resumeGuidance) lines.push(resumeGuidance);
|
|
223
231
|
if (input.children.some((child) => child.intercomTarget)) {
|
|
@@ -262,6 +270,7 @@ export function buildSubagentResultIntercomPayload(input: GroupedResultIntercomM
|
|
|
262
270
|
...(input.asyncId ? { asyncId: input.asyncId } : {}),
|
|
263
271
|
...(input.asyncDir ? { asyncDir: input.asyncDir } : {}),
|
|
264
272
|
...(typeof input.chainSteps === "number" ? { chainSteps: input.chainSteps } : {}),
|
|
273
|
+
...(input.parallelHandoff ? { parallelHandoff: input.parallelHandoff } : {}),
|
|
265
274
|
...(firstChild?.agent ? { agent: firstChild.agent } : {}),
|
|
266
275
|
...(firstChild?.index !== undefined ? { index: firstChild.index } : {}),
|
|
267
276
|
...(firstChild?.artifactPath ? { artifactPath: firstChild.artifactPath } : {}),
|
|
@@ -348,6 +357,8 @@ export function formatSubagentResultReceipt(input: {
|
|
|
348
357
|
`Children: ${formatStatusCounts(counts)}`,
|
|
349
358
|
];
|
|
350
359
|
|
|
360
|
+
if (input.payload.parallelHandoff) lines.push(`Parallel handoff: ${input.payload.parallelHandoff.path}`);
|
|
361
|
+
|
|
351
362
|
const artifacts = input.payload.children.filter((child) => typeof child.artifactPath === "string");
|
|
352
363
|
if (artifacts.length > 0) {
|
|
353
364
|
lines.push("Artifacts:");
|
|
@@ -242,9 +242,9 @@ function qualityTierToRoleTier(quality: QualityTier, cost: CostTier): Recommende
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
function agentsForRoleTier(roleTier: RecommendedRoleTier): BuiltinAgentName[] {
|
|
245
|
-
if (roleTier === "cheap") return ["
|
|
246
|
-
if (roleTier === "medium") return ["
|
|
247
|
-
return ["
|
|
245
|
+
if (roleTier === "cheap") return ["explorer", "recapper"];
|
|
246
|
+
if (roleTier === "medium") return ["architect", "researcher"];
|
|
247
|
+
return ["builder", "commentator"];
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
function classifyModel(input: ModelClassificationInput, context: ClassificationContext): {
|
|
@@ -386,14 +386,12 @@ function buildProfileFile(kind: ProfileKind, models: { cheap: string; medium: st
|
|
|
386
386
|
return {
|
|
387
387
|
subagents: {
|
|
388
388
|
agentOverrides: {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
"context-builder": { model: models.medium },
|
|
389
|
+
explorer: { model: models.cheap },
|
|
390
|
+
recapper: { model: models.cheap },
|
|
391
|
+
architect: { model: models.medium },
|
|
393
392
|
researcher: { model: models.medium },
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
oracle: { model: models.strong },
|
|
393
|
+
builder: { model: models.strong },
|
|
394
|
+
commentator: { model: models.strong },
|
|
397
395
|
},
|
|
398
396
|
},
|
|
399
397
|
};
|