@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
|
@@ -1,288 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
SUBAGENT_DELEGATION_CANCEL_EVENT,
|
|
3
|
+
SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
4
|
+
SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
5
|
+
SUBAGENT_DELEGATION_REQUEST_EVENT,
|
|
6
|
+
SUBAGENT_DELEGATION_RESPONSE_EVENT,
|
|
7
|
+
SUBAGENT_DELEGATION_STARTED_EVENT,
|
|
8
|
+
SUBAGENT_DELEGATION_UPDATE_EVENT,
|
|
9
|
+
type SubagentDelegationRequest,
|
|
10
|
+
type SubagentDelegationResponse,
|
|
11
|
+
type SubagentDelegationV2InvalidResponse,
|
|
12
|
+
type SubagentDelegationV2Request,
|
|
13
|
+
type SubagentDelegationV2Response,
|
|
14
|
+
} from "../api/delegation.ts";
|
|
15
|
+
import { parseSubagentDelegationRequest } from "./delegation-request.ts";
|
|
16
|
+
import {
|
|
17
|
+
parsePromptTemplateRequest,
|
|
18
|
+
toDelegationUpdate,
|
|
19
|
+
toLegacyExecutionParams,
|
|
20
|
+
toPromptTemplateResponse,
|
|
21
|
+
toSubagentDelegationExecutionParams,
|
|
22
|
+
toSubagentDelegationResponse,
|
|
23
|
+
toSubagentDelegationUpdate,
|
|
24
|
+
toSubagentDelegationV2ExecutionParams,
|
|
25
|
+
toSubagentDelegationV2Response,
|
|
26
|
+
toSubagentDelegationV2Update,
|
|
27
|
+
type DelegatedSubagentExecutionParams,
|
|
28
|
+
type PromptTemplateBridgeResult,
|
|
29
|
+
type PromptTemplateDelegationRequest,
|
|
30
|
+
type PromptTemplateDelegationResponse,
|
|
31
|
+
} from "./delegation-adapters.ts";
|
|
6
32
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface PromptTemplateDelegationParallelResult {
|
|
15
|
-
agent: string;
|
|
16
|
-
messages: unknown[];
|
|
17
|
-
isError: boolean;
|
|
18
|
-
errorText?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface PromptTemplateDelegationRequest {
|
|
22
|
-
requestId: string;
|
|
23
|
-
agent: string;
|
|
24
|
-
task: string;
|
|
25
|
-
tasks?: PromptTemplateDelegationTask[];
|
|
26
|
-
context: "fresh" | "fork";
|
|
27
|
-
model: string;
|
|
28
|
-
cwd: string;
|
|
29
|
-
worktree?: boolean;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface PromptTemplateDelegationResponse extends PromptTemplateDelegationRequest {
|
|
33
|
-
messages: unknown[];
|
|
34
|
-
parallelResults?: PromptTemplateDelegationParallelResult[];
|
|
35
|
-
contentText?: string;
|
|
36
|
-
isError: boolean;
|
|
37
|
-
errorText?: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface PromptTemplateDelegationTaskProgress {
|
|
41
|
-
index?: number;
|
|
42
|
-
agent: string;
|
|
43
|
-
status?: string;
|
|
44
|
-
currentTool?: string;
|
|
45
|
-
currentToolArgs?: string;
|
|
46
|
-
recentOutput?: string;
|
|
47
|
-
recentOutputLines?: string[];
|
|
48
|
-
recentTools?: Array<{ tool: string; args: string }>;
|
|
49
|
-
model?: string;
|
|
50
|
-
toolCount?: number;
|
|
51
|
-
durationMs?: number;
|
|
52
|
-
tokens?: number;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface PromptTemplateDelegationUpdate {
|
|
56
|
-
requestId: string;
|
|
57
|
-
currentTool?: string;
|
|
58
|
-
currentToolArgs?: string;
|
|
59
|
-
recentOutput?: string;
|
|
60
|
-
recentOutputLines?: string[];
|
|
61
|
-
recentTools?: Array<{ tool: string; args: string }>;
|
|
62
|
-
model?: string;
|
|
63
|
-
toolCount?: number;
|
|
64
|
-
durationMs?: number;
|
|
65
|
-
tokens?: number;
|
|
66
|
-
taskProgress?: PromptTemplateDelegationTaskProgress[];
|
|
67
|
-
}
|
|
33
|
+
export const PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT = SUBAGENT_DELEGATION_REQUEST_EVENT;
|
|
34
|
+
export const PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT = SUBAGENT_DELEGATION_STARTED_EVENT;
|
|
35
|
+
export const PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT = SUBAGENT_DELEGATION_RESPONSE_EVENT;
|
|
36
|
+
export const PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT = SUBAGENT_DELEGATION_UPDATE_EVENT;
|
|
37
|
+
export const PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT = SUBAGENT_DELEGATION_CANCEL_EVENT;
|
|
68
38
|
|
|
69
39
|
export interface PromptTemplateBridgeEvents {
|
|
70
40
|
on(event: string, handler: (data: unknown) => void): (() => void) | void;
|
|
71
41
|
emit(event: string, data: unknown): void;
|
|
72
42
|
}
|
|
73
43
|
|
|
74
|
-
interface PromptTemplateBridgeResult {
|
|
75
|
-
isError?: boolean;
|
|
76
|
-
content?: unknown;
|
|
77
|
-
details?: {
|
|
78
|
-
results?: Array<{
|
|
79
|
-
agent?: string;
|
|
80
|
-
messages?: unknown[];
|
|
81
|
-
finalOutput?: string;
|
|
82
|
-
toolCalls?: Array<{ text?: string; expandedText?: string }>;
|
|
83
|
-
exitCode?: number;
|
|
84
|
-
error?: string;
|
|
85
|
-
model?: string;
|
|
86
|
-
}>;
|
|
87
|
-
progress?: Array<{
|
|
88
|
-
index?: number;
|
|
89
|
-
agent?: string;
|
|
90
|
-
status?: string;
|
|
91
|
-
currentTool?: string;
|
|
92
|
-
currentToolArgs?: string;
|
|
93
|
-
recentOutput?: string[];
|
|
94
|
-
recentTools?: Array<{ tool?: string; args?: string }>;
|
|
95
|
-
toolCount?: number;
|
|
96
|
-
durationMs?: number;
|
|
97
|
-
tokens?: number;
|
|
98
|
-
}>;
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
44
|
interface PromptTemplateBridgeOptions<Ctx extends { cwd?: string }> {
|
|
103
45
|
events: PromptTemplateBridgeEvents;
|
|
104
46
|
getContext: () => Ctx | null;
|
|
105
47
|
execute: (
|
|
106
48
|
requestId: string,
|
|
107
|
-
|
|
49
|
+
params: DelegatedSubagentExecutionParams,
|
|
50
|
+
signal: AbortSignal,
|
|
51
|
+
ctx: Ctx,
|
|
52
|
+
onUpdate: (result: PromptTemplateBridgeResult) => void,
|
|
53
|
+
) => Promise<PromptTemplateBridgeResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Concurrent-safe executor for strict versioned delegation requests.
|
|
56
|
+
* Non-versioned prompt-template requests retain the ordinary single-dispatch guard.
|
|
57
|
+
*/
|
|
58
|
+
executeVersioned?: (
|
|
59
|
+
requestId: string,
|
|
60
|
+
params: DelegatedSubagentExecutionParams,
|
|
108
61
|
signal: AbortSignal,
|
|
109
62
|
ctx: Ctx,
|
|
110
63
|
onUpdate: (result: PromptTemplateBridgeResult) => void,
|
|
111
64
|
) => Promise<PromptTemplateBridgeResult>;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function parseDelegationTasks(tasks: unknown): PromptTemplateDelegationTask[] {
|
|
115
|
-
if (!Array.isArray(tasks)) return [];
|
|
116
|
-
const parsed: PromptTemplateDelegationTask[] = [];
|
|
117
|
-
for (const item of tasks) {
|
|
118
|
-
if (!item || typeof item !== "object") return [];
|
|
119
|
-
const value = item as Partial<PromptTemplateDelegationTask>;
|
|
120
|
-
if (typeof value.agent !== "string" || !value.agent.trim()) return [];
|
|
121
|
-
if (typeof value.task !== "string" || !value.task.trim()) return [];
|
|
122
|
-
const model = typeof value.model === "string" && value.model.trim().length > 0 ? value.model : undefined;
|
|
123
|
-
const cwd = typeof value.cwd === "string" && value.cwd.trim().length > 0 ? value.cwd : undefined;
|
|
124
|
-
parsed.push({
|
|
125
|
-
agent: value.agent,
|
|
126
|
-
task: value.task,
|
|
127
|
-
...(model ? { model } : {}),
|
|
128
|
-
...(cwd ? { cwd } : {}),
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
return parsed;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function parsePromptTemplateRequest(data: unknown): PromptTemplateDelegationRequest | undefined {
|
|
135
|
-
if (!data || typeof data !== "object") return undefined;
|
|
136
|
-
const value = data as Partial<PromptTemplateDelegationRequest> & { tasks?: unknown };
|
|
137
|
-
if (typeof value.requestId !== "string" || !value.requestId) return undefined;
|
|
138
|
-
if (typeof value.model !== "string" || !value.model) return undefined;
|
|
139
|
-
if (typeof value.cwd !== "string" || !value.cwd) return undefined;
|
|
140
|
-
if (value.context !== "fresh" && value.context !== "fork") return undefined;
|
|
141
|
-
const tasks = parseDelegationTasks(value.tasks);
|
|
142
|
-
const worktree = value.worktree === true ? true : undefined;
|
|
143
|
-
const hasSingle =
|
|
144
|
-
typeof value.agent === "string" &&
|
|
145
|
-
value.agent.length > 0 &&
|
|
146
|
-
typeof value.task === "string" &&
|
|
147
|
-
value.task.length > 0;
|
|
148
|
-
if (!hasSingle && tasks.length === 0) return undefined;
|
|
149
|
-
|
|
150
|
-
const fallbackTask = tasks[0];
|
|
151
|
-
return {
|
|
152
|
-
requestId: value.requestId,
|
|
153
|
-
agent: hasSingle ? value.agent : fallbackTask!.agent,
|
|
154
|
-
task: hasSingle ? value.task : fallbackTask!.task,
|
|
155
|
-
...(tasks.length > 0 ? { tasks } : {}),
|
|
156
|
-
context: value.context,
|
|
157
|
-
model: value.model,
|
|
158
|
-
cwd: value.cwd,
|
|
159
|
-
...(worktree ? { worktree } : {}),
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function firstTextContent(content: unknown): string | undefined {
|
|
164
|
-
if (!Array.isArray(content)) return undefined;
|
|
165
|
-
for (const part of content) {
|
|
166
|
-
if (!part || typeof part !== "object") continue;
|
|
167
|
-
if ((part as { type?: string }).type !== "text") continue;
|
|
168
|
-
const text = (part as { text?: unknown }).text;
|
|
169
|
-
if (typeof text === "string" && text.trim()) return text.trim();
|
|
170
|
-
}
|
|
171
|
-
return undefined;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function filterRecentOutput(lines: string[] | undefined): string[] | undefined {
|
|
175
|
-
if (!lines || lines.length === 0) return undefined;
|
|
176
|
-
const filtered = lines.filter((line) => typeof line === "string" && line.trim() && line.trim() !== "(running...)");
|
|
177
|
-
if (filtered.length === 0) return undefined;
|
|
178
|
-
return filtered;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function sanitizeRecentTools(
|
|
182
|
-
tools: Array<{ tool?: string; args?: string }> | undefined,
|
|
183
|
-
): Array<{ tool: string; args: string }> | undefined {
|
|
184
|
-
if (!tools || tools.length === 0) return undefined;
|
|
185
|
-
const sanitized = tools.flatMap((entry) => {
|
|
186
|
-
if (typeof entry.tool !== "string" || entry.tool.trim().length === 0) return [];
|
|
187
|
-
return [{
|
|
188
|
-
tool: entry.tool,
|
|
189
|
-
args: typeof entry.args === "string" ? entry.args : String(entry.args ?? ""),
|
|
190
|
-
}];
|
|
191
|
-
});
|
|
192
|
-
return sanitized.length > 0 ? sanitized : undefined;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function resolveProgressModel(
|
|
196
|
-
update: PromptTemplateBridgeResult,
|
|
197
|
-
entry: { index?: number; agent?: string },
|
|
198
|
-
): string | undefined {
|
|
199
|
-
const results = update.details?.results;
|
|
200
|
-
if (!results || results.length === 0) return undefined;
|
|
201
|
-
if (typeof entry.index === "number" && entry.index >= 0) {
|
|
202
|
-
const byIndex = results[entry.index];
|
|
203
|
-
if (typeof byIndex?.model === "string") return byIndex.model;
|
|
204
|
-
}
|
|
205
|
-
if (entry.agent) {
|
|
206
|
-
const byAgent = results.find((result) => result.agent === entry.agent && typeof result.model === "string");
|
|
207
|
-
if (byAgent?.model) return byAgent.model;
|
|
208
|
-
}
|
|
209
|
-
const firstWithModel = results.find((result) => typeof result.model === "string");
|
|
210
|
-
return firstWithModel?.model;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function toolCallNameFromSummary(summary: { text?: string; expandedText?: string }): string | undefined {
|
|
214
|
-
const text = typeof summary.expandedText === "string" && summary.expandedText.trim().length > 0
|
|
215
|
-
? summary.expandedText.trim()
|
|
216
|
-
: typeof summary.text === "string"
|
|
217
|
-
? summary.text.trim()
|
|
218
|
-
: "";
|
|
219
|
-
if (!text) return undefined;
|
|
220
|
-
if (text.startsWith("$ ")) return "bash";
|
|
221
|
-
return text.match(/^[A-Za-z_][\w.-]*/)?.[0];
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function buildDelegationMessages(
|
|
225
|
-
result: { messages?: unknown[]; finalOutput?: string; toolCalls?: Array<{ text?: string; expandedText?: string }> },
|
|
226
|
-
fallbackText?: string,
|
|
227
|
-
): unknown[] {
|
|
228
|
-
if (Array.isArray(result.messages) && result.messages.length > 0) return result.messages;
|
|
229
|
-
const toolCallParts = (result.toolCalls ?? []).flatMap((summary) => {
|
|
230
|
-
const name = toolCallNameFromSummary(summary);
|
|
231
|
-
return name ? [{ type: "toolCall", name, arguments: { summary: summary.expandedText ?? summary.text ?? "" } }] : [];
|
|
232
|
-
});
|
|
233
|
-
const text = typeof result.finalOutput === "string" && result.finalOutput.trim().length > 0
|
|
234
|
-
? result.finalOutput.trim()
|
|
235
|
-
: fallbackText;
|
|
236
|
-
const content = [
|
|
237
|
-
...toolCallParts,
|
|
238
|
-
...(text ? [{ type: "text", text }] : []),
|
|
239
|
-
];
|
|
240
|
-
if (content.length === 0) return [];
|
|
241
|
-
return [{ role: "assistant", content }];
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function toDelegationUpdate(requestId: string, update: PromptTemplateBridgeResult): PromptTemplateDelegationUpdate | undefined {
|
|
245
|
-
const progress = update.details?.progress?.[0];
|
|
246
|
-
const taskProgress = update.details?.progress?.map((entry) => {
|
|
247
|
-
const lastOutput = entry.recentOutput?.[entry.recentOutput.length - 1];
|
|
248
|
-
const safeLastOutput =
|
|
249
|
-
typeof lastOutput === "string" && lastOutput.trim() && lastOutput !== "(running...)"
|
|
250
|
-
? lastOutput
|
|
251
|
-
: undefined;
|
|
252
|
-
return {
|
|
253
|
-
index: entry.index,
|
|
254
|
-
agent: entry.agent ?? "delegate",
|
|
255
|
-
status: entry.status,
|
|
256
|
-
currentTool: entry.currentTool,
|
|
257
|
-
currentToolArgs: entry.currentToolArgs,
|
|
258
|
-
recentOutput: safeLastOutput,
|
|
259
|
-
recentOutputLines: filterRecentOutput(entry.recentOutput),
|
|
260
|
-
recentTools: sanitizeRecentTools(entry.recentTools),
|
|
261
|
-
model: resolveProgressModel(update, entry),
|
|
262
|
-
toolCount: entry.toolCount,
|
|
263
|
-
durationMs: entry.durationMs,
|
|
264
|
-
tokens: entry.tokens,
|
|
265
|
-
};
|
|
266
|
-
});
|
|
267
|
-
if (!progress && (!taskProgress || taskProgress.length === 0)) return undefined;
|
|
268
|
-
const lastOutput = progress?.recentOutput?.[progress.recentOutput.length - 1];
|
|
269
|
-
const safeLastOutput =
|
|
270
|
-
typeof lastOutput === "string" && lastOutput.trim() && lastOutput !== "(running...)"
|
|
271
|
-
? lastOutput
|
|
272
|
-
: undefined;
|
|
273
|
-
return {
|
|
274
|
-
requestId,
|
|
275
|
-
currentTool: progress?.currentTool,
|
|
276
|
-
currentToolArgs: progress?.currentToolArgs,
|
|
277
|
-
recentOutput: safeLastOutput,
|
|
278
|
-
recentOutputLines: filterRecentOutput(progress?.recentOutput),
|
|
279
|
-
recentTools: sanitizeRecentTools(progress?.recentTools),
|
|
280
|
-
model: progress ? resolveProgressModel(update, progress) : undefined,
|
|
281
|
-
toolCount: progress?.toolCount,
|
|
282
|
-
durationMs: progress?.durationMs,
|
|
283
|
-
tokens: progress?.tokens,
|
|
284
|
-
taskProgress,
|
|
285
|
-
};
|
|
286
65
|
}
|
|
287
66
|
|
|
288
67
|
export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: string }>(
|
|
@@ -291,130 +70,359 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
291
70
|
cancelAll: () => void;
|
|
292
71
|
dispose: () => void;
|
|
293
72
|
} {
|
|
73
|
+
// Legacy and V1 retain requestId-only correlation. V2 attempts are isolated by
|
|
74
|
+
// their complete wire identity, while logical-node ownership is tracked separately.
|
|
294
75
|
const controllers = new Map<string, AbortController>();
|
|
295
|
-
const pendingCancels = new
|
|
76
|
+
const pendingCancels = new Map<string, true>();
|
|
77
|
+
const v2Controllers = new Map<string, AbortController>();
|
|
78
|
+
const pendingV2Cancels = new Map<string, true>();
|
|
79
|
+
const activeV2Nodes = new Map<string, { attemptKey: string; controller: AbortController }>();
|
|
80
|
+
const settledV2Attempts = new Map<string, true>();
|
|
296
81
|
const subscriptions: Array<() => void> = [];
|
|
82
|
+
let disposed = false;
|
|
83
|
+
let v2IdentitySaturated = false;
|
|
297
84
|
|
|
298
85
|
const subscribe = (event: string, handler: (data: unknown) => void): void => {
|
|
299
86
|
const unsubscribe = options.events.on(event, handler);
|
|
300
87
|
if (typeof unsubscribe === "function") subscriptions.push(unsubscribe);
|
|
301
88
|
};
|
|
89
|
+
const ownsRequest = (requestId: string, controller: AbortController): boolean =>
|
|
90
|
+
!disposed && controllers.get(requestId) === controller;
|
|
91
|
+
const ownsV2Attempt = (attemptKey: string, controller: AbortController): boolean =>
|
|
92
|
+
!disposed && v2Controllers.get(attemptKey) === controller;
|
|
93
|
+
const boundedRemember = (map: Map<string, true>, key: string): void => {
|
|
94
|
+
map.delete(key);
|
|
95
|
+
map.set(key, true);
|
|
96
|
+
while (map.size > 256) {
|
|
97
|
+
const oldest = map.keys().next().value;
|
|
98
|
+
if (typeof oldest !== "string") break;
|
|
99
|
+
map.delete(oldest);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const rememberV2Identity = (map: Map<string, true>, key: string): void => {
|
|
103
|
+
if (map.has(key) || v2IdentitySaturated) return;
|
|
104
|
+
if (map.size >= 8_192) {
|
|
105
|
+
v2IdentitySaturated = true;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
map.set(key, true);
|
|
109
|
+
if (map.size === 8_192) {
|
|
110
|
+
// V2 identity facts are security state, not an LRU cache. Saturate as
|
|
111
|
+
// soon as the bounded history fills so no later untracked attempt can
|
|
112
|
+
// start, rather than evicting a cancellation or settled-attempt fact.
|
|
113
|
+
v2IdentitySaturated = true;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const v2NodeKey = (ownerRunId: string, nodeId: string): string => JSON.stringify([ownerRunId, nodeId]);
|
|
117
|
+
const v2AttemptKey = (requestId: string, ownerRunId: string, nodeId: string): string => JSON.stringify([requestId, ownerRunId, nodeId]);
|
|
118
|
+
const rememberPendingCancel = (requestId: string): void => {
|
|
119
|
+
boundedRemember(pendingCancels, requestId);
|
|
120
|
+
};
|
|
121
|
+
const emitV2Terminal = (attemptKey: string, payload: SubagentDelegationV2Response): void => {
|
|
122
|
+
if (disposed || settledV2Attempts.has(attemptKey)) return;
|
|
123
|
+
rememberV2Identity(settledV2Attempts, attemptKey);
|
|
124
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, payload);
|
|
125
|
+
};
|
|
302
126
|
|
|
303
127
|
subscribe(PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT, (data) => {
|
|
304
|
-
if (!data || typeof data !== "object") return;
|
|
305
|
-
const
|
|
306
|
-
|
|
128
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return;
|
|
129
|
+
const value = data as Record<string, unknown>;
|
|
130
|
+
const requestId = value.requestId;
|
|
131
|
+
if (typeof requestId !== "string" || !requestId.trim() || requestId.length > 256 || /[\r\n]/.test(requestId)) return;
|
|
132
|
+
if (Object.hasOwn(value, "version")) {
|
|
133
|
+
if (value.version === SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION) {
|
|
134
|
+
if (Object.keys(value).some((key) => key !== "version" && key !== "requestId" && key !== "ownerRunId" && key !== "nodeId")) return;
|
|
135
|
+
const ownerRunId = value.ownerRunId;
|
|
136
|
+
const nodeId = value.nodeId;
|
|
137
|
+
if (typeof ownerRunId !== "string" || !ownerRunId.trim() || ownerRunId.length > 256 || /[\r\n]/.test(ownerRunId)) return;
|
|
138
|
+
if (typeof nodeId !== "string" || !nodeId.trim() || nodeId.length > 256 || /[\r\n]/.test(nodeId)) return;
|
|
139
|
+
const attemptKey = v2AttemptKey(requestId, ownerRunId, nodeId);
|
|
140
|
+
const controller = v2Controllers.get(attemptKey);
|
|
141
|
+
if (controller) controller.abort();
|
|
142
|
+
else rememberV2Identity(pendingV2Cancels, attemptKey);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (value.version !== SUBAGENT_DELEGATION_PROTOCOL_VERSION) return;
|
|
146
|
+
if (Object.keys(value).some((key) => key !== "version" && key !== "requestId")) return;
|
|
147
|
+
}
|
|
307
148
|
const controller = controllers.get(requestId);
|
|
308
149
|
if (controller) {
|
|
309
150
|
controller.abort();
|
|
310
151
|
return;
|
|
311
152
|
}
|
|
312
|
-
|
|
153
|
+
rememberPendingCancel(requestId);
|
|
313
154
|
});
|
|
314
155
|
|
|
315
156
|
subscribe(PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT, async (data) => {
|
|
316
|
-
const
|
|
317
|
-
|
|
157
|
+
const isVersioned = !!data && typeof data === "object" && Object.hasOwn(data, "version");
|
|
158
|
+
let requestId: string;
|
|
159
|
+
let params: DelegatedSubagentExecutionParams;
|
|
160
|
+
let versionedRequest: SubagentDelegationRequest | SubagentDelegationV2Request | undefined;
|
|
161
|
+
let v2Request: SubagentDelegationV2Request | undefined;
|
|
162
|
+
let v2Key: string | undefined;
|
|
163
|
+
let legacyRequest: PromptTemplateDelegationRequest | undefined;
|
|
164
|
+
|
|
165
|
+
if (isVersioned) {
|
|
166
|
+
const parsed = parseSubagentDelegationRequest(data);
|
|
167
|
+
if (parsed.ok === false) {
|
|
168
|
+
if (!disposed && parsed.requestId) {
|
|
169
|
+
if (parsed.version === SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION) {
|
|
170
|
+
const payload = {
|
|
171
|
+
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
172
|
+
requestId: parsed.requestId,
|
|
173
|
+
...(parsed.ownerRunId ? { ownerRunId: parsed.ownerRunId } : {}),
|
|
174
|
+
...(parsed.nodeId ? { nodeId: parsed.nodeId } : {}),
|
|
175
|
+
status: "invalid_request",
|
|
176
|
+
error: parsed.error,
|
|
177
|
+
} satisfies SubagentDelegationV2InvalidResponse;
|
|
178
|
+
if (parsed.ownerRunId && parsed.nodeId) {
|
|
179
|
+
const attemptKey = v2AttemptKey(parsed.requestId, parsed.ownerRunId, parsed.nodeId);
|
|
180
|
+
if (!v2Controllers.has(attemptKey)) emitV2Terminal(attemptKey, payload);
|
|
181
|
+
} else {
|
|
182
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, payload);
|
|
183
|
+
}
|
|
184
|
+
} else if (!controllers.has(parsed.requestId)) {
|
|
185
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
186
|
+
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
187
|
+
requestId: parsed.requestId,
|
|
188
|
+
status: "invalid_request",
|
|
189
|
+
error: parsed.error,
|
|
190
|
+
} satisfies SubagentDelegationResponse);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
versionedRequest = parsed.request;
|
|
196
|
+
requestId = parsed.request.requestId;
|
|
197
|
+
if (parsed.request.version === SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION) {
|
|
198
|
+
v2Request = parsed.request;
|
|
199
|
+
v2Key = v2AttemptKey(requestId, parsed.request.ownerRunId, parsed.request.nodeId);
|
|
200
|
+
params = toSubagentDelegationV2ExecutionParams(parsed.request);
|
|
201
|
+
} else {
|
|
202
|
+
params = toSubagentDelegationExecutionParams(parsed.request);
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
legacyRequest = parsePromptTemplateRequest(data);
|
|
206
|
+
if (!legacyRequest) return;
|
|
207
|
+
requestId = legacyRequest.requestId;
|
|
208
|
+
params = toLegacyExecutionParams(legacyRequest);
|
|
209
|
+
}
|
|
318
210
|
|
|
211
|
+
// Legacy and V1 keep requestId-only ownership. V2 retransmission and terminal
|
|
212
|
+
// suppression use the full tuple, independently from logical-node ownership.
|
|
213
|
+
if (!v2Request && controllers.has(requestId)) return;
|
|
214
|
+
if (v2Request && v2Key) {
|
|
215
|
+
if (v2Controllers.has(v2Key) || settledV2Attempts.has(v2Key)) return;
|
|
216
|
+
if (pendingV2Cancels.delete(v2Key)) {
|
|
217
|
+
emitV2Terminal(v2Key, {
|
|
218
|
+
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
219
|
+
requestId,
|
|
220
|
+
ownerRunId: v2Request.ownerRunId,
|
|
221
|
+
nodeId: v2Request.nodeId,
|
|
222
|
+
status: "cancelled",
|
|
223
|
+
});
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (v2IdentitySaturated) {
|
|
227
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
228
|
+
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
229
|
+
requestId,
|
|
230
|
+
ownerRunId: v2Request.ownerRunId,
|
|
231
|
+
nodeId: v2Request.nodeId,
|
|
232
|
+
status: "unavailable_context",
|
|
233
|
+
error: "Delegation v2 identity capacity is exhausted for this extension context.",
|
|
234
|
+
} satisfies SubagentDelegationV2Response);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const active = activeV2Nodes.get(v2NodeKey(v2Request.ownerRunId, v2Request.nodeId));
|
|
238
|
+
if (active) {
|
|
239
|
+
emitV2Terminal(v2Key, {
|
|
240
|
+
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
241
|
+
requestId,
|
|
242
|
+
ownerRunId: v2Request.ownerRunId,
|
|
243
|
+
nodeId: v2Request.nodeId,
|
|
244
|
+
status: "duplicate_node",
|
|
245
|
+
});
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
319
249
|
const ctx = options.getContext();
|
|
320
250
|
if (!ctx) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
251
|
+
if (v2Request && v2Key) {
|
|
252
|
+
emitV2Terminal(v2Key, {
|
|
253
|
+
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
254
|
+
requestId,
|
|
255
|
+
ownerRunId: v2Request.ownerRunId,
|
|
256
|
+
nodeId: v2Request.nodeId,
|
|
257
|
+
status: "unavailable_context",
|
|
258
|
+
error: "No active extension context for delegated subagent execution.",
|
|
259
|
+
});
|
|
260
|
+
} else if (versionedRequest) {
|
|
261
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
262
|
+
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
263
|
+
requestId,
|
|
264
|
+
status: "unavailable_context",
|
|
265
|
+
error: "No active extension context for delegated subagent execution.",
|
|
266
|
+
} satisfies SubagentDelegationResponse);
|
|
267
|
+
} else if (legacyRequest) {
|
|
268
|
+
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {
|
|
269
|
+
...legacyRequest,
|
|
270
|
+
messages: [],
|
|
271
|
+
isError: true,
|
|
272
|
+
errorText: "No active extension context for delegated subagent execution.",
|
|
273
|
+
} satisfies PromptTemplateDelegationResponse);
|
|
274
|
+
}
|
|
328
275
|
return;
|
|
329
276
|
}
|
|
330
277
|
|
|
331
278
|
const controller = new AbortController();
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
279
|
+
if (v2Request && v2Key) {
|
|
280
|
+
v2Controllers.set(v2Key, controller);
|
|
281
|
+
activeV2Nodes.set(v2NodeKey(v2Request.ownerRunId, v2Request.nodeId), { attemptKey: v2Key, controller });
|
|
282
|
+
} else {
|
|
283
|
+
controllers.set(requestId, controller);
|
|
284
|
+
if (pendingCancels.delete(requestId)) controller.abort();
|
|
285
|
+
}
|
|
286
|
+
if (controller.signal.aborted) {
|
|
287
|
+
if (v2Request && v2Key) {
|
|
288
|
+
emitV2Terminal(v2Key, {
|
|
289
|
+
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
290
|
+
requestId,
|
|
291
|
+
ownerRunId: v2Request.ownerRunId,
|
|
292
|
+
nodeId: v2Request.nodeId,
|
|
293
|
+
status: "cancelled",
|
|
294
|
+
});
|
|
295
|
+
activeV2Nodes.delete(v2NodeKey(v2Request.ownerRunId, v2Request.nodeId));
|
|
296
|
+
} else if (versionedRequest) {
|
|
297
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
298
|
+
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
299
|
+
requestId,
|
|
300
|
+
status: "cancelled",
|
|
301
|
+
} satisfies SubagentDelegationResponse);
|
|
302
|
+
} else if (legacyRequest) {
|
|
303
|
+
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {
|
|
304
|
+
...legacyRequest,
|
|
305
|
+
messages: [],
|
|
306
|
+
isError: true,
|
|
307
|
+
errorText: "Delegated prompt cancelled.",
|
|
308
|
+
} satisfies PromptTemplateDelegationResponse);
|
|
309
|
+
}
|
|
310
|
+
if (v2Key) v2Controllers.delete(v2Key);
|
|
311
|
+
else controllers.delete(requestId);
|
|
344
312
|
return;
|
|
345
313
|
}
|
|
346
314
|
|
|
347
|
-
options.events.emit(
|
|
315
|
+
options.events.emit(
|
|
316
|
+
versionedRequest ? SUBAGENT_DELEGATION_STARTED_EVENT : PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT,
|
|
317
|
+
v2Request
|
|
318
|
+
? { version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION, requestId, ownerRunId: v2Request.ownerRunId, nodeId: v2Request.nodeId }
|
|
319
|
+
: versionedRequest
|
|
320
|
+
? { version: SUBAGENT_DELEGATION_PROTOCOL_VERSION, requestId }
|
|
321
|
+
: { requestId },
|
|
322
|
+
);
|
|
348
323
|
|
|
349
324
|
try {
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
325
|
+
const executeRequest = versionedRequest && options.executeVersioned
|
|
326
|
+
? options.executeVersioned
|
|
327
|
+
: options.execute;
|
|
328
|
+
const result = await executeRequest(
|
|
329
|
+
requestId,
|
|
330
|
+
params,
|
|
353
331
|
controller.signal,
|
|
354
332
|
ctx,
|
|
355
333
|
(update) => {
|
|
356
|
-
|
|
357
|
-
if (
|
|
358
|
-
|
|
334
|
+
if (v2Key ? !ownsV2Attempt(v2Key, controller) : !ownsRequest(requestId, controller)) return;
|
|
335
|
+
if (v2Request) {
|
|
336
|
+
const payload = toSubagentDelegationV2Update(v2Request, update);
|
|
337
|
+
if (payload) options.events.emit(SUBAGENT_DELEGATION_UPDATE_EVENT, payload);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (versionedRequest) {
|
|
341
|
+
const payload = toSubagentDelegationUpdate(requestId, update);
|
|
342
|
+
if (payload) options.events.emit(SUBAGENT_DELEGATION_UPDATE_EVENT, payload);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const payload = toDelegationUpdate(requestId, update);
|
|
346
|
+
if (payload) options.events.emit(PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT, payload);
|
|
359
347
|
},
|
|
360
348
|
);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
agent: step.agent ?? task.agent,
|
|
378
|
-
messages: buildDelegationMessages(step),
|
|
379
|
-
isError: (exitCode !== undefined && exitCode !== 0) || !!errorText,
|
|
380
|
-
errorText: errorText || undefined,
|
|
381
|
-
};
|
|
382
|
-
})
|
|
383
|
-
: undefined;
|
|
384
|
-
const response: PromptTemplateDelegationResponse = {
|
|
385
|
-
...request,
|
|
386
|
-
messages,
|
|
387
|
-
...(parallelResults ? { parallelResults } : {}),
|
|
388
|
-
...(contentText ? { contentText } : {}),
|
|
389
|
-
isError: result.isError === true,
|
|
390
|
-
errorText: result.isError ? contentText : undefined,
|
|
391
|
-
};
|
|
392
|
-
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, response);
|
|
349
|
+
if (v2Key ? !ownsV2Attempt(v2Key, controller) : !ownsRequest(requestId, controller)) return;
|
|
350
|
+
if (v2Request && v2Key) {
|
|
351
|
+
emitV2Terminal(v2Key, toSubagentDelegationV2Response(v2Request, result, controller.signal.aborted));
|
|
352
|
+
} else if (versionedRequest) {
|
|
353
|
+
options.events.emit(
|
|
354
|
+
SUBAGENT_DELEGATION_RESPONSE_EVENT,
|
|
355
|
+
toSubagentDelegationResponse(requestId, result, controller.signal.aborted),
|
|
356
|
+
);
|
|
357
|
+
} else if (legacyRequest) {
|
|
358
|
+
options.events.emit(
|
|
359
|
+
PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT,
|
|
360
|
+
controller.signal.aborted
|
|
361
|
+
? { ...legacyRequest, messages: [], isError: true, errorText: "Delegated prompt cancelled." }
|
|
362
|
+
: toPromptTemplateResponse(legacyRequest, result),
|
|
363
|
+
);
|
|
364
|
+
}
|
|
393
365
|
} catch (error) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
366
|
+
if (v2Key ? !ownsV2Attempt(v2Key, controller) : !ownsRequest(requestId, controller)) return;
|
|
367
|
+
if (v2Request && v2Key) {
|
|
368
|
+
emitV2Terminal(v2Key, {
|
|
369
|
+
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
370
|
+
requestId,
|
|
371
|
+
ownerRunId: v2Request.ownerRunId,
|
|
372
|
+
nodeId: v2Request.nodeId,
|
|
373
|
+
status: controller.signal.aborted ? "cancelled" : "failed",
|
|
374
|
+
...(controller.signal.aborted ? {} : { error: error instanceof Error ? error.message : String(error) }),
|
|
375
|
+
});
|
|
376
|
+
} else if (versionedRequest) {
|
|
377
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
378
|
+
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
379
|
+
requestId,
|
|
380
|
+
status: controller.signal.aborted ? "cancelled" : "failed",
|
|
381
|
+
...(controller.signal.aborted ? {} : { error: error instanceof Error ? error.message : String(error) }),
|
|
382
|
+
} satisfies SubagentDelegationResponse);
|
|
383
|
+
} else if (legacyRequest) {
|
|
384
|
+
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {
|
|
385
|
+
...legacyRequest,
|
|
386
|
+
messages: [],
|
|
387
|
+
isError: true,
|
|
388
|
+
errorText: error instanceof Error ? error.message : String(error),
|
|
389
|
+
} satisfies PromptTemplateDelegationResponse);
|
|
390
|
+
}
|
|
401
391
|
} finally {
|
|
402
|
-
|
|
392
|
+
if (v2Key) {
|
|
393
|
+
if (v2Controllers.get(v2Key) === controller) v2Controllers.delete(v2Key);
|
|
394
|
+
} else if (controllers.get(requestId) === controller) controllers.delete(requestId);
|
|
395
|
+
if (v2Request) {
|
|
396
|
+
const key = v2NodeKey(v2Request.ownerRunId, v2Request.nodeId);
|
|
397
|
+
if (activeV2Nodes.get(key)?.controller === controller) activeV2Nodes.delete(key);
|
|
398
|
+
}
|
|
403
399
|
}
|
|
404
400
|
});
|
|
405
401
|
|
|
406
402
|
return {
|
|
407
403
|
cancelAll: () => {
|
|
408
|
-
for (const controller of controllers.values())
|
|
409
|
-
|
|
410
|
-
}
|
|
404
|
+
for (const controller of controllers.values()) controller.abort();
|
|
405
|
+
for (const controller of v2Controllers.values()) controller.abort();
|
|
411
406
|
controllers.clear();
|
|
407
|
+
v2Controllers.clear();
|
|
412
408
|
pendingCancels.clear();
|
|
409
|
+
pendingV2Cancels.clear();
|
|
410
|
+
activeV2Nodes.clear();
|
|
411
|
+
settledV2Attempts.clear();
|
|
412
|
+
v2IdentitySaturated = false;
|
|
413
413
|
},
|
|
414
414
|
dispose: () => {
|
|
415
|
+
disposed = true;
|
|
416
|
+
for (const controller of controllers.values()) controller.abort();
|
|
417
|
+
for (const controller of v2Controllers.values()) controller.abort();
|
|
418
|
+
controllers.clear();
|
|
419
|
+
v2Controllers.clear();
|
|
415
420
|
for (const unsubscribe of subscriptions) unsubscribe();
|
|
416
421
|
subscriptions.length = 0;
|
|
417
422
|
pendingCancels.clear();
|
|
423
|
+
pendingV2Cancels.clear();
|
|
424
|
+
activeV2Nodes.clear();
|
|
425
|
+
settledV2Attempts.clear();
|
|
418
426
|
},
|
|
419
427
|
};
|
|
420
428
|
}
|