@duckmind/dm-windows-x64 0.61.4 → 0.61.9
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/dm.exe +0 -0
- package/extensions/.dm-extensions.json +211 -67
- package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
- package/extensions/dm-subagents/agents/claude-code.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec.md +15 -0
- package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
- package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
- package/extensions/dm-subagents/agents/delegate.md +3 -2
- package/extensions/dm-subagents/agents/oracle.md +10 -5
- package/extensions/dm-subagents/agents/researcher.md +2 -2
- package/extensions/dm-subagents/agents/reviewer.md +17 -7
- package/extensions/dm-subagents/agents/scout.md +5 -5
- package/extensions/dm-subagents/agents/worker.md +6 -2
- package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
- package/extensions/dm-subagents/index.js +4 -0
- package/extensions/dm-subagents/inspector-runner.mjs +10 -0
- package/extensions/dm-subagents/install.mjs +3 -2
- package/extensions/dm-subagents/package.json +2 -2
- package/extensions/dm-subagents/prompts/council.md +60 -0
- package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
- package/extensions/dm-subagents/prompts/review-loop.md +13 -7
- package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
- package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
- package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
- package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
- package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
- package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
- package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
- package/extensions/dm-subagents/src/agents/agents.js +1447 -299
- package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
- package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
- package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
- package/extensions/dm-subagents/src/agents/identity.js +1 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
- package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
- package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
- package/extensions/dm-subagents/src/agents/skills.js +52 -35
- package/extensions/dm-subagents/src/api/agents.js +6 -0
- package/extensions/dm-subagents/src/api/background-work.js +151 -0
- package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
- package/extensions/dm-subagents/src/api/control-channel.js +3 -0
- package/extensions/dm-subagents/src/api/delegation.js +5 -0
- package/extensions/dm-subagents/src/api/dm-args.js +3 -0
- package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
- package/extensions/dm-subagents/src/api/external-runs.js +233 -0
- package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
- package/extensions/dm-subagents/src/api/preflight.js +322 -0
- package/extensions/dm-subagents/src/api/project-panes.js +11 -0
- package/extensions/dm-subagents/src/api/shared-types.js +4 -0
- package/extensions/dm-subagents/src/extension/config.js +175 -0
- package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
- package/extensions/dm-subagents/src/extension/doctor.js +71 -17
- package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
- package/extensions/dm-subagents/src/extension/index.js +711 -265
- package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
- package/extensions/dm-subagents/src/extension/rpc.js +427 -22
- package/extensions/dm-subagents/src/extension/schemas.js +158 -65
- package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
- package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
- package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
- package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
- package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
- package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
- package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
- package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
- package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
- package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
- package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
- package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
- package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
- package/extensions/dm-subagents/src/missions/actions.js +394 -0
- package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
- package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
- package/extensions/dm-subagents/src/missions/store.js +548 -0
- package/extensions/dm-subagents/src/missions/types.js +9 -0
- package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
- package/extensions/dm-subagents/src/policy/authority.js +37 -0
- package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
- package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
- package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
- package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
- package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
- package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
- package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
- package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
- package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
- package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
- package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
- package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
- package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
- package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
- package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
- package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
- package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
- package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
- package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
- package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
- package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
- package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
- package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
- package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
- package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
- package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
- package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
- package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
- package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
- package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
- package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
- package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
- package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
- package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
- package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
- package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
- package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
- package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
- package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
- package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
- package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
- package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
- package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
- package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
- package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
- package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
- package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
- package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
- package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
- package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
- package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
- package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
- package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
- package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
- package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
- package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
- package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
- package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
- package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
- package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
- package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
- package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
- package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
- package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
- package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
- package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
- package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
- package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
- package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
- package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
- package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
- package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
- package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
- package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
- package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
- package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
- package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
- package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
- package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
- package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
- package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
- package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
- package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
- package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
- package/extensions/dm-subagents/src/shared/display-text.js +142 -0
- package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
- package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
- package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
- package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
- package/extensions/dm-subagents/src/shared/formatters.js +21 -7
- package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
- package/extensions/dm-subagents/src/shared/model-info.js +10 -5
- package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
- package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
- package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
- package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
- package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
- package/extensions/dm-subagents/src/shared/settings.js +39 -47
- package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
- package/extensions/dm-subagents/src/shared/status-format.js +9 -2
- package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
- package/extensions/dm-subagents/src/shared/types.js +47 -7
- package/extensions/dm-subagents/src/shared/utf8.js +12 -0
- package/extensions/dm-subagents/src/shared/utils.js +151 -131
- package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
- package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
- package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
- package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
- package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
- package/extensions/dm-subagents/src/slash/selector.js +101 -0
- package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
- package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
- package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
- package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
- package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
- package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
- package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
- package/extensions/dm-subagents/src/tui/render.js +1511 -261
- package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
- package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
- package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
- package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
- package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
- package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
- package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
- package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
- package/extensions/dm-subagents/src/watchdog/render.js +54 -0
- package/extensions/dm-subagents/src/watchdog/review.js +251 -0
- package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
- package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
- package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
- package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
- package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
- package/extensions/dm-subagents/src/watchdog/types.js +29 -0
- package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
- package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
- package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
- package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
- package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
- package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
- package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
- package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
- package/package.json +4 -3
- package/extensions/dm-fff/package.json +0 -21
- package/extensions/dm-fff/src/index.js +0 -691
- package/extensions/dm-fff/src/query.js +0 -60
- package/extensions/dm-subagents/agents/context-builder.md +0 -46
- package/extensions/dm-subagents/agents/planner.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
- package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
|
@@ -1,16 +1,200 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { Compile } from "typebox/compile";
|
|
3
3
|
import { resolveAsyncRunLocation } from "../runs/background/async-resume.js";
|
|
4
|
-
import {
|
|
4
|
+
import { deliverStopRequest } from "../runs/background/control-channel.js";
|
|
5
5
|
import { reconcileAsyncRun } from "../runs/background/stale-run-reconciler.js";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveCurrentSessionId } from "../shared/session-identity.js";
|
|
7
|
+
import {
|
|
8
|
+
DIRS,
|
|
9
|
+
SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
10
|
+
SUBAGENT_CHILD_STATUS_EVENT,
|
|
11
|
+
SUBAGENT_PROCESS_TERMINAL_EVENT,
|
|
12
|
+
SUBAGENT_LIFECYCLE_ARTIFACT_VERSION
|
|
13
|
+
} from "../shared/types.js";
|
|
14
|
+
import { sanitizeDisplayText, truncateDisplayText } from "../shared/display-text.js";
|
|
7
15
|
import { readStatus } from "../shared/utils.js";
|
|
8
16
|
import { SubagentParams } from "./schemas.js";
|
|
17
|
+
import { normalizePublicSubagentExecution } from "./public-execution.js";
|
|
18
|
+
import { ASYNC_STATUS_SNAPSHOT_KIND, ASYNC_STATUS_SNAPSHOT_VERSION, buildAsyncStatusSnapshotForState } from "../runs/background/async-status-snapshot.js";
|
|
19
|
+
import { isStoppableAsyncStatusStep, resolveAsyncStatusChild } from "../runs/shared/child-identity.js";
|
|
9
20
|
export const SUBAGENT_RPC_PROTOCOL_VERSION = 1;
|
|
10
21
|
export const SUBAGENT_RPC_REQUEST_EVENT = "subagents:rpc:v1:request";
|
|
11
22
|
export const SUBAGENT_RPC_READY_EVENT = "subagents:rpc:v1:ready";
|
|
12
23
|
export const SUBAGENT_RPC_REPLY_EVENT_PREFIX = "subagents:rpc:v1:reply:";
|
|
13
|
-
export const SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "interrupt", "stop"];
|
|
24
|
+
export const SUBAGENT_RPC_METHODS = ["ping", "status", "manage", "spawn", "steer", "interrupt", "stop", "resume"];
|
|
25
|
+
export const SUBAGENT_RPC_MANAGEMENT_ACTIONS = [
|
|
26
|
+
"schedule.list",
|
|
27
|
+
"schedule.show",
|
|
28
|
+
"schedule.history",
|
|
29
|
+
"schedule.pause",
|
|
30
|
+
"schedule.resume",
|
|
31
|
+
"schedule.run",
|
|
32
|
+
"schedule.delete"
|
|
33
|
+
];
|
|
34
|
+
const MAX_FLEET_ENTRIES = 16;
|
|
35
|
+
const MAX_FLEET_CANDIDATES = 256;
|
|
36
|
+
const MAX_AGENT_LENGTH = 96;
|
|
37
|
+
const MAX_GOAL_LENGTH = 512;
|
|
38
|
+
const MAX_METADATA_LENGTH = 128;
|
|
39
|
+
function displayText(value, maxLength) {
|
|
40
|
+
if (typeof value !== "string")
|
|
41
|
+
return;
|
|
42
|
+
const normalized = sanitizeDisplayText(value.slice(0, 4096));
|
|
43
|
+
return normalized ? truncateDisplayText(normalized, maxLength) : undefined;
|
|
44
|
+
}
|
|
45
|
+
function publicTokens(value) {
|
|
46
|
+
const record = isRecord(value) ? value : {};
|
|
47
|
+
const count = (field) => {
|
|
48
|
+
const raw = record[field];
|
|
49
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? Math.min(Number.MAX_SAFE_INTEGER, Math.floor(raw)) : 0;
|
|
50
|
+
};
|
|
51
|
+
const input = count("input");
|
|
52
|
+
const output = count("output");
|
|
53
|
+
const sum = Math.min(Number.MAX_SAFE_INTEGER, input + output);
|
|
54
|
+
const optionalCount = (field) => {
|
|
55
|
+
const raw = record[field];
|
|
56
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? Math.min(Number.MAX_SAFE_INTEGER, Math.floor(raw)) : undefined;
|
|
57
|
+
};
|
|
58
|
+
const window = optionalCount("window");
|
|
59
|
+
const windowPeak = optionalCount("windowPeak");
|
|
60
|
+
return {
|
|
61
|
+
input,
|
|
62
|
+
output,
|
|
63
|
+
total: Math.max(sum, count("total")),
|
|
64
|
+
...window !== undefined ? { window } : {},
|
|
65
|
+
...windowPeak !== undefined ? { windowPeak } : {}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function activeState(value) {
|
|
69
|
+
return value === "running" || value === "queued" || value === "pending";
|
|
70
|
+
}
|
|
71
|
+
function buildFleetStatus(state, keyState, sessionId) {
|
|
72
|
+
const authoritativeSessionId = sessionId ?? null;
|
|
73
|
+
if (keyState.sessionId !== authoritativeSessionId) {
|
|
74
|
+
keyState.sessionId = authoritativeSessionId;
|
|
75
|
+
keyState.next = 0;
|
|
76
|
+
keyState.keys.clear();
|
|
77
|
+
}
|
|
78
|
+
if (!state || !authoritativeSessionId || state.currentSessionId !== authoritativeSessionId) {
|
|
79
|
+
keyState.keys.clear();
|
|
80
|
+
return { version: 1, entries: [], totalActive: 0, topLevelAsyncCapacity: { used: 0, limit: 0 }, omitted: 0 };
|
|
81
|
+
}
|
|
82
|
+
let totalActive = 0;
|
|
83
|
+
const candidates = [];
|
|
84
|
+
const addCandidate = (candidate) => {
|
|
85
|
+
totalActive += 1;
|
|
86
|
+
if (candidates.length < MAX_FLEET_CANDIDATES)
|
|
87
|
+
candidates.push(candidate);
|
|
88
|
+
};
|
|
89
|
+
for (const control of state.foregroundControls.values()) {
|
|
90
|
+
if (control.sessionId !== authoritativeSessionId)
|
|
91
|
+
continue;
|
|
92
|
+
if (control.activeChildren?.size) {
|
|
93
|
+
for (const child of control.activeChildren.values())
|
|
94
|
+
addCandidate({
|
|
95
|
+
internalKey: `foreground:${control.runId}:${child.index}`,
|
|
96
|
+
agent: child.agent,
|
|
97
|
+
model: child.model,
|
|
98
|
+
effort: child.thinking,
|
|
99
|
+
startedAt: child.startedAt,
|
|
100
|
+
tokens: { input: child.inputTokens ?? 0, output: child.outputTokens ?? 0, total: child.tokens ?? 0, ...child.window !== undefined ? { window: child.window } : {}, ...child.windowPeak !== undefined ? { windowPeak: child.windowPeak } : {} }
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
addCandidate({
|
|
104
|
+
internalKey: `foreground:${control.runId}:${control.currentIndex ?? 0}`,
|
|
105
|
+
agent: control.currentAgent ?? control.mode,
|
|
106
|
+
model: control.model,
|
|
107
|
+
effort: control.thinking,
|
|
108
|
+
startedAt: control.startedAt,
|
|
109
|
+
tokens: { input: control.inputTokens ?? 0, output: control.outputTokens ?? 0, total: control.tokens ?? 0, ...control.window !== undefined ? { window: control.window } : {}, ...control.windowPeak !== undefined ? { windowPeak: control.windowPeak } : {} }
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const job of state.asyncJobs.values()) {
|
|
114
|
+
if (job.sessionId !== authoritativeSessionId || !activeState(job.status))
|
|
115
|
+
continue;
|
|
116
|
+
const startedAt = job.startedAt ?? job.updatedAt;
|
|
117
|
+
if (job.mode === "workflow") {
|
|
118
|
+
addCandidate({
|
|
119
|
+
internalKey: `async:${job.asyncId}`,
|
|
120
|
+
agent: "workflow",
|
|
121
|
+
startedAt,
|
|
122
|
+
tokens: job.totalTokens
|
|
123
|
+
});
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const steps = job.steps?.length ? job.steps : job.agents?.map((agent, index) => ({
|
|
127
|
+
agent,
|
|
128
|
+
index,
|
|
129
|
+
status: job.status === "queued" ? "pending" : "running"
|
|
130
|
+
}));
|
|
131
|
+
if (!steps?.length) {
|
|
132
|
+
addCandidate({
|
|
133
|
+
internalKey: `async:${job.asyncId}`,
|
|
134
|
+
agent: job.mode ?? "subagent",
|
|
135
|
+
startedAt,
|
|
136
|
+
tokens: job.totalTokens
|
|
137
|
+
});
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
for (const [offset, step] of steps.entries()) {
|
|
141
|
+
if (!activeState(step.status))
|
|
142
|
+
continue;
|
|
143
|
+
const index = step.index ?? offset;
|
|
144
|
+
if (step.status === "pending" && job.mode === "chain" && !job.activeParallelGroup && index !== (job.currentStep ?? 0))
|
|
145
|
+
continue;
|
|
146
|
+
addCandidate({
|
|
147
|
+
internalKey: `async:${job.asyncId}:${index}`,
|
|
148
|
+
agent: step.agent,
|
|
149
|
+
role: step.label,
|
|
150
|
+
model: step.model,
|
|
151
|
+
effort: step.thinking,
|
|
152
|
+
startedAt: step.startedAt ?? startedAt,
|
|
153
|
+
tokens: step.tokens ?? (steps.length === 1 ? job.totalTokens : undefined)
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
candidates.sort((left, right) => {
|
|
158
|
+
const leftStarted = typeof left.startedAt === "number" ? left.startedAt : Number.MAX_SAFE_INTEGER;
|
|
159
|
+
const rightStarted = typeof right.startedAt === "number" ? right.startedAt : Number.MAX_SAFE_INTEGER;
|
|
160
|
+
return leftStarted - rightStarted || left.internalKey.localeCompare(right.internalKey);
|
|
161
|
+
});
|
|
162
|
+
const activeKeys = new Set(candidates.map((candidate) => candidate.internalKey));
|
|
163
|
+
const entries = [];
|
|
164
|
+
for (const candidate of candidates) {
|
|
165
|
+
if (entries.length >= MAX_FLEET_ENTRIES)
|
|
166
|
+
break;
|
|
167
|
+
const agent = displayText(candidate.agent, MAX_AGENT_LENGTH);
|
|
168
|
+
const startedAt = candidate.startedAt;
|
|
169
|
+
if (!agent || typeof startedAt !== "number" || !Number.isSafeInteger(startedAt) || startedAt < 0)
|
|
170
|
+
continue;
|
|
171
|
+
let key = keyState.keys.get(candidate.internalKey);
|
|
172
|
+
if (!key) {
|
|
173
|
+
key = `fleet-${++keyState.next}`;
|
|
174
|
+
keyState.keys.set(candidate.internalKey, key);
|
|
175
|
+
}
|
|
176
|
+
const role = displayText(candidate.role, MAX_AGENT_LENGTH);
|
|
177
|
+
const model = displayText(candidate.model, MAX_METADATA_LENGTH);
|
|
178
|
+
const effort = displayText(candidate.effort, MAX_METADATA_LENGTH);
|
|
179
|
+
const goal = displayText(candidate.goal, MAX_GOAL_LENGTH);
|
|
180
|
+
entries.push({
|
|
181
|
+
key,
|
|
182
|
+
agent,
|
|
183
|
+
...role ? { role } : {},
|
|
184
|
+
...model ? { model } : {},
|
|
185
|
+
...effort ? { effort } : {},
|
|
186
|
+
startedAt,
|
|
187
|
+
tokens: publicTokens(candidate.tokens),
|
|
188
|
+
...goal ? { goal } : {}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
for (const internalKey of keyState.keys.keys()) {
|
|
192
|
+
if (!activeKeys.has(internalKey))
|
|
193
|
+
keyState.keys.delete(internalKey);
|
|
194
|
+
}
|
|
195
|
+
const omitted = Math.max(0, totalActive - entries.length);
|
|
196
|
+
return { version: 1, entries, totalActive, topLevelAsyncCapacity: state.activeAsyncCapacity ?? { used: 0, limit: 0 }, omitted };
|
|
197
|
+
}
|
|
14
198
|
|
|
15
199
|
class SubagentRpcError extends Error {
|
|
16
200
|
code;
|
|
@@ -62,8 +246,7 @@ function failIfToolError(result) {
|
|
|
62
246
|
return;
|
|
63
247
|
throw new SubagentRpcError("execution_failed", textFromToolResult(result) || "Subagent RPC execution failed.");
|
|
64
248
|
}
|
|
65
|
-
function
|
|
66
|
-
const input = assertRecordParams(params, method);
|
|
249
|
+
function normalizeTargetParamsFromRecord(input) {
|
|
67
250
|
const output = {};
|
|
68
251
|
if (input.id !== undefined)
|
|
69
252
|
output.id = input.id;
|
|
@@ -75,6 +258,28 @@ function normalizeTargetParams(params, method) {
|
|
|
75
258
|
output.index = input.index;
|
|
76
259
|
return output;
|
|
77
260
|
}
|
|
261
|
+
function normalizeTargetParams(params, method) {
|
|
262
|
+
return normalizeTargetParamsFromRecord(assertRecordParams(params, method));
|
|
263
|
+
}
|
|
264
|
+
function normalizeStatusParams(params) {
|
|
265
|
+
const input = assertRecordParams(params, "status");
|
|
266
|
+
const output = normalizeTargetParamsFromRecord(input);
|
|
267
|
+
if (input.view !== undefined)
|
|
268
|
+
output.view = input.view;
|
|
269
|
+
if (input.lines !== undefined)
|
|
270
|
+
output.lines = input.lines;
|
|
271
|
+
return output;
|
|
272
|
+
}
|
|
273
|
+
function hasStatusTarget(params) {
|
|
274
|
+
return params.id !== undefined || params.runId !== undefined || params.dir !== undefined || params.index !== undefined || params.view !== undefined || params.lines !== undefined;
|
|
275
|
+
}
|
|
276
|
+
function canUseInMemoryStatus(state, sessionId) {
|
|
277
|
+
return Boolean(state && sessionId && state.currentSessionId === sessionId && state.statusProjectionSessionId === sessionId && state.foregroundControls instanceof Map && state.asyncJobs instanceof Map);
|
|
278
|
+
}
|
|
279
|
+
function inMemoryStatusSummary(fleet) {
|
|
280
|
+
const noun = fleet.totalActive === 1 ? "child" : "children";
|
|
281
|
+
return `In-memory subagent status: ${fleet.totalActive} active ${noun}.`;
|
|
282
|
+
}
|
|
78
283
|
function sessionData(ctx) {
|
|
79
284
|
if (!ctx)
|
|
80
285
|
return {};
|
|
@@ -90,14 +295,27 @@ function pingData(ctx) {
|
|
|
90
295
|
methods: [...SUBAGENT_RPC_METHODS],
|
|
91
296
|
capabilities: {
|
|
92
297
|
status: true,
|
|
298
|
+
statusProjection: { version: 1, untargeted: "in-memory-when-ready", targeted: "executor" },
|
|
299
|
+
managementActions: [...SUBAGENT_RPC_MANAGEMENT_ACTIONS],
|
|
300
|
+
fleetStatus: { version: 1 },
|
|
301
|
+
asyncStatusSnapshot: { kind: ASYNC_STATUS_SNAPSHOT_KIND, version: ASYNC_STATUS_SNAPSHOT_VERSION },
|
|
93
302
|
asyncSpawn: true,
|
|
303
|
+
steer: true,
|
|
304
|
+
nonRecoveringSteer: true,
|
|
94
305
|
interrupt: true,
|
|
95
|
-
stop: true
|
|
306
|
+
stop: true,
|
|
307
|
+
resume: true,
|
|
308
|
+
launchResolvedExtensions: { version: 1, source: "launch-resolved" },
|
|
309
|
+
runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", event: "subagent:acknowledge-extension" },
|
|
310
|
+
processTerminalProof: { version: 1, lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION }
|
|
96
311
|
},
|
|
97
312
|
events: {
|
|
98
313
|
ready: SUBAGENT_RPC_READY_EVENT,
|
|
99
314
|
request: SUBAGENT_RPC_REQUEST_EVENT,
|
|
100
|
-
replyPrefix: SUBAGENT_RPC_REPLY_EVENT_PREFIX
|
|
315
|
+
replyPrefix: SUBAGENT_RPC_REPLY_EVENT_PREFIX,
|
|
316
|
+
asyncComplete: SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
317
|
+
childStatus: SUBAGENT_CHILD_STATUS_EVENT,
|
|
318
|
+
processTerminal: SUBAGENT_PROCESS_TERMINAL_EVENT
|
|
101
319
|
},
|
|
102
320
|
session: sessionData(ctx)
|
|
103
321
|
};
|
|
@@ -109,24 +327,85 @@ async function executeChecked(options, ctx, requestId, method, params) {
|
|
|
109
327
|
failIfToolError(result);
|
|
110
328
|
return dataFromToolResult(result);
|
|
111
329
|
}
|
|
330
|
+
function manageParams(params) {
|
|
331
|
+
const input = assertRecordParams(params, "manage");
|
|
332
|
+
if (typeof input.action !== "string" || !SUBAGENT_RPC_MANAGEMENT_ACTIONS.includes(input.action)) {
|
|
333
|
+
throw new SubagentRpcError("invalid_params", `RPC manage action must be one of: ${SUBAGENT_RPC_MANAGEMENT_ACTIONS.join(", ")}.`);
|
|
334
|
+
}
|
|
335
|
+
if (input.id !== undefined && (typeof input.id !== "string" || !input.id.trim())) {
|
|
336
|
+
throw new SubagentRpcError("invalid_params", "RPC manage id must be a non-empty string.");
|
|
337
|
+
}
|
|
338
|
+
const action = input.action;
|
|
339
|
+
const requiresId = action !== "schedule.list";
|
|
340
|
+
if (requiresId && typeof input.id !== "string") {
|
|
341
|
+
throw new SubagentRpcError("invalid_params", `RPC manage ${action} requires id.`);
|
|
342
|
+
}
|
|
343
|
+
const output = {
|
|
344
|
+
action,
|
|
345
|
+
...typeof input.id === "string" ? { id: input.id.trim() } : {}
|
|
346
|
+
};
|
|
347
|
+
assertSubagentParams(output, "RPC manage params");
|
|
348
|
+
return output;
|
|
349
|
+
}
|
|
112
350
|
function spawnParams(params) {
|
|
113
351
|
const input = assertRecordParams(params, "spawn");
|
|
114
|
-
|
|
352
|
+
const normalized = normalizePublicSubagentExecution(input);
|
|
353
|
+
if (!normalized.ok)
|
|
354
|
+
throw new SubagentRpcError("invalid_params", normalized.error);
|
|
355
|
+
if (normalized.params.action !== undefined) {
|
|
115
356
|
throw new SubagentRpcError("invalid_params", "RPC spawn does not accept management/control actions. Use status or interrupt RPC methods instead.");
|
|
116
357
|
}
|
|
117
358
|
if (input.async === false) {
|
|
118
359
|
throw new SubagentRpcError("invalid_params", "RPC spawn only supports detached async launches; omit async or set async: true.");
|
|
119
360
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
361
|
+
return { ...normalized.params, async: true };
|
|
362
|
+
}
|
|
363
|
+
function steerParams(params) {
|
|
364
|
+
const input = assertRecordParams(params, "steer");
|
|
365
|
+
if (typeof input.message !== "string" || !input.message.trim())
|
|
366
|
+
throw new SubagentRpcError("invalid_params", "RPC steer requires a non-empty message.");
|
|
367
|
+
const target = normalizeTargetParams(input, "steer");
|
|
368
|
+
if (!target.id && !target.runId && !target.dir)
|
|
369
|
+
throw new SubagentRpcError("invalid_params", "RPC steer requires id, runId, or dir.");
|
|
370
|
+
if (input.mode !== undefined && input.mode !== "steer" && input.mode !== "follow_up" && input.mode !== "auto")
|
|
371
|
+
throw new SubagentRpcError("invalid_params", "RPC steer mode must be steer, follow_up, or auto.");
|
|
372
|
+
return {
|
|
373
|
+
action: "steer",
|
|
374
|
+
...target,
|
|
375
|
+
message: input.message.trim(),
|
|
376
|
+
...typeof input.mode === "string" ? { mode: input.mode } : {},
|
|
377
|
+
steeringRecovery: false
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function resumeParams(params) {
|
|
381
|
+
const input = assertRecordParams(params, "resume");
|
|
382
|
+
if (typeof input.message !== "string" || !input.message.trim())
|
|
383
|
+
throw new SubagentRpcError("invalid_params", "RPC resume requires a non-empty message.");
|
|
384
|
+
const target = normalizeTargetParams(input, "resume");
|
|
385
|
+
if (!target.id && !target.runId && !target.dir)
|
|
386
|
+
throw new SubagentRpcError("invalid_params", "RPC resume requires id, runId, or dir.");
|
|
387
|
+
if (input.output !== undefined && (typeof input.output !== "string" || !input.output.trim()))
|
|
388
|
+
throw new SubagentRpcError("invalid_params", "RPC resume output must be a non-empty path.");
|
|
389
|
+
if (input.outputMode !== undefined && input.outputMode !== "file-only")
|
|
390
|
+
throw new SubagentRpcError("invalid_params", "RPC resume supports only file-only output mode.");
|
|
391
|
+
return {
|
|
392
|
+
action: "resume",
|
|
393
|
+
...target,
|
|
394
|
+
message: input.message.trim(),
|
|
395
|
+
...typeof input.output === "string" ? { output: input.output.trim(), outputMode: "file-only" } : {}
|
|
396
|
+
};
|
|
124
397
|
}
|
|
125
398
|
function stopAsyncRun(params, options, ctx) {
|
|
126
|
-
const
|
|
399
|
+
const input = assertRecordParams(params, "stop");
|
|
400
|
+
const rawChildId = input.childId;
|
|
401
|
+
if (rawChildId !== undefined && (typeof rawChildId !== "string" || !rawChildId.trim() || /[\r\n]/.test(rawChildId) || rawChildId.length > 256)) {
|
|
402
|
+
throw new SubagentRpcError("invalid_params", "RPC stop childId must be a non-empty string without newlines and at most 256 characters.");
|
|
403
|
+
}
|
|
404
|
+
const childId = typeof rawChildId === "string" ? rawChildId : undefined;
|
|
405
|
+
const target = normalizeTargetParams(input, "stop");
|
|
127
406
|
assertSubagentParams({ action: "status", ...target }, "RPC stop target params");
|
|
128
|
-
const asyncDirRoot = options.asyncDirRoot ??
|
|
129
|
-
const resultsDir = options.resultsDir ??
|
|
407
|
+
const asyncDirRoot = options.asyncDirRoot ?? DIRS.async;
|
|
408
|
+
const resultsDir = options.resultsDir ?? DIRS.results;
|
|
130
409
|
let location;
|
|
131
410
|
try {
|
|
132
411
|
location = resolveAsyncRunLocation(target, asyncDirRoot, resultsDir);
|
|
@@ -136,7 +415,7 @@ function stopAsyncRun(params, options, ctx) {
|
|
|
136
415
|
if (!location.asyncDir) {
|
|
137
416
|
throw new SubagentRpcError("not_found", "Async run not found or already completed; stop requires a live async run directory.");
|
|
138
417
|
}
|
|
139
|
-
const currentSessionId = ctx.sessionManager
|
|
418
|
+
const currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
140
419
|
const initialStatus = readStatus(location.asyncDir);
|
|
141
420
|
const initialRunId = initialStatus?.runId ?? location.resolvedId ?? path.basename(location.asyncDir);
|
|
142
421
|
if (!initialStatus)
|
|
@@ -144,6 +423,86 @@ function stopAsyncRun(params, options, ctx) {
|
|
|
144
423
|
if (!currentSessionId || initialStatus.sessionId !== currentSessionId) {
|
|
145
424
|
throw new SubagentRpcError("not_found", `Async run '${initialRunId}' was not found in the active session.`);
|
|
146
425
|
}
|
|
426
|
+
let child;
|
|
427
|
+
const emitChildStopping = (runId, asyncDir, stoppedChild, ts = options.now?.() ?? Date.now()) => {
|
|
428
|
+
options.events.emit(SUBAGENT_CHILD_STATUS_EVENT, {
|
|
429
|
+
type: "subagent.child-status",
|
|
430
|
+
version: 1,
|
|
431
|
+
runId,
|
|
432
|
+
childId: stoppedChild.id,
|
|
433
|
+
status: "stopping",
|
|
434
|
+
ts,
|
|
435
|
+
reason: "rpc",
|
|
436
|
+
source: "rpc",
|
|
437
|
+
asyncDir,
|
|
438
|
+
stepIndex: stoppedChild.index,
|
|
439
|
+
agent: stoppedChild.step.agent,
|
|
440
|
+
...stoppedChild.step.runId ? { childRunId: stoppedChild.step.runId } : {},
|
|
441
|
+
...stoppedChild.step.workflowKey ? { workflowKey: stoppedChild.step.workflowKey } : {},
|
|
442
|
+
...stoppedChild.step.phase ? { phase: stoppedChild.step.phase } : {},
|
|
443
|
+
...stoppedChild.step.label ? { label: stoppedChild.step.label } : {}
|
|
444
|
+
});
|
|
445
|
+
};
|
|
446
|
+
if (childId !== undefined) {
|
|
447
|
+
const resolution = resolveAsyncStatusChild(initialStatus, childId);
|
|
448
|
+
if (!resolution.ok)
|
|
449
|
+
throw new SubagentRpcError(resolution.code === "not_found" ? "not_found" : "invalid_params", resolution.message);
|
|
450
|
+
child = resolution.child;
|
|
451
|
+
if (!isStoppableAsyncStatusStep(child.step)) {
|
|
452
|
+
throw new SubagentRpcError("invalid_state", `Child '${childId}' in async run '${initialRunId}' is ${child.step.status}; stop only supports pending or running children.`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (initialStatus.mode === "workflow" && initialStatus.state === "running") {
|
|
456
|
+
if (child) {
|
|
457
|
+
const stopChild = options.state?.workflowChildStops?.get(initialRunId);
|
|
458
|
+
if (stopChild) {
|
|
459
|
+
if (!stopChild(child.id, `Workflow child '${child.id}' stopped by RPC.`))
|
|
460
|
+
throw new SubagentRpcError("invalid_state", `Child '${childId}' in workflow ${initialRunId} is not available to stop.`);
|
|
461
|
+
emitChildStopping(initialRunId, location.asyncDir, child);
|
|
462
|
+
return {
|
|
463
|
+
runId: initialRunId,
|
|
464
|
+
asyncDir: location.asyncDir,
|
|
465
|
+
previousState: initialStatus.state,
|
|
466
|
+
state: "stopping",
|
|
467
|
+
childId: child.id,
|
|
468
|
+
message: `Stop requested for child ${child.id} in async run ${initialRunId}.`
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const workflowController = options.state?.workflowControllers?.get(initialRunId);
|
|
473
|
+
if (workflowController && !child) {
|
|
474
|
+
workflowController.abort(new Error("Workflow stopped by RPC."));
|
|
475
|
+
return {
|
|
476
|
+
runId: initialRunId,
|
|
477
|
+
asyncDir: location.asyncDir,
|
|
478
|
+
previousState: initialStatus.state,
|
|
479
|
+
state: "stopping",
|
|
480
|
+
message: `Stop requested for async run ${initialRunId}.`
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
deliverStopRequest({
|
|
485
|
+
asyncDir: location.asyncDir,
|
|
486
|
+
pid: initialStatus.pid,
|
|
487
|
+
kill: options.kill,
|
|
488
|
+
now: options.now,
|
|
489
|
+
source: "rpc-stop",
|
|
490
|
+
...child ? { targetIndex: child.index, childId: child.id } : {}
|
|
491
|
+
});
|
|
492
|
+
} catch (error) {
|
|
493
|
+
throw new SubagentRpcError("execution_failed", error instanceof Error ? error.message : String(error));
|
|
494
|
+
}
|
|
495
|
+
if (child)
|
|
496
|
+
emitChildStopping(initialRunId, location.asyncDir, child);
|
|
497
|
+
return {
|
|
498
|
+
runId: initialRunId,
|
|
499
|
+
asyncDir: location.asyncDir,
|
|
500
|
+
previousState: initialStatus.state,
|
|
501
|
+
state: "stopping",
|
|
502
|
+
...child ? { childId: child.id } : {},
|
|
503
|
+
message: child ? `Stop requested for child ${child.id} in async run ${initialRunId}.` : `Stop requested for async run ${initialRunId}.`
|
|
504
|
+
};
|
|
505
|
+
}
|
|
147
506
|
let status;
|
|
148
507
|
try {
|
|
149
508
|
status = reconcileAsyncRun(location.asyncDir, { resultsDir, kill: options.kill, now: options.now }).status;
|
|
@@ -159,36 +518,78 @@ function stopAsyncRun(params, options, ctx) {
|
|
|
159
518
|
if (status.state !== "running") {
|
|
160
519
|
throw new SubagentRpcError("invalid_state", `Async run ${runId} is ${status.state}; stop only supports running async runs.`);
|
|
161
520
|
}
|
|
521
|
+
if (childId !== undefined) {
|
|
522
|
+
const resolution = resolveAsyncStatusChild(status, childId);
|
|
523
|
+
if (!resolution.ok)
|
|
524
|
+
throw new SubagentRpcError(resolution.code === "not_found" ? "not_found" : "invalid_params", resolution.message);
|
|
525
|
+
child = resolution.child;
|
|
526
|
+
if (!isStoppableAsyncStatusStep(child.step)) {
|
|
527
|
+
throw new SubagentRpcError("invalid_state", `Child '${childId}' in async run '${runId}' is ${child.step.status}; stop only supports pending or running children.`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
162
530
|
try {
|
|
163
|
-
|
|
531
|
+
deliverStopRequest({
|
|
164
532
|
asyncDir: location.asyncDir,
|
|
165
533
|
pid: status.pid,
|
|
166
534
|
kill: options.kill,
|
|
167
535
|
now: options.now,
|
|
168
|
-
source: "rpc-stop"
|
|
536
|
+
source: "rpc-stop",
|
|
537
|
+
...child ? { targetIndex: child.index, childId: child.id } : {}
|
|
169
538
|
});
|
|
170
539
|
} catch (error) {
|
|
171
540
|
throw new SubagentRpcError("execution_failed", error instanceof Error ? error.message : String(error));
|
|
172
541
|
}
|
|
542
|
+
if (child)
|
|
543
|
+
emitChildStopping(runId, location.asyncDir, child);
|
|
173
544
|
return {
|
|
174
545
|
runId,
|
|
175
546
|
asyncDir: location.asyncDir,
|
|
176
547
|
previousState: status.state,
|
|
177
548
|
state: "stopping",
|
|
178
|
-
|
|
549
|
+
...child ? { childId: child.id } : {},
|
|
550
|
+
message: child ? `Stop requested for child ${child.id} in async run ${runId}.` : `Stop requested for async run ${runId}.`
|
|
179
551
|
};
|
|
180
552
|
}
|
|
181
|
-
async function handleRequest(request, options) {
|
|
553
|
+
async function handleRequest(request, options, fleetKeys) {
|
|
182
554
|
const ctx = options.getContext();
|
|
183
555
|
if (request.method === "ping")
|
|
184
556
|
return pingData(ctx);
|
|
185
557
|
if (!ctx)
|
|
186
558
|
throw new SubagentRpcError("no_active_session", "No active extension context for subagent RPC.");
|
|
559
|
+
if (request.method === "manage") {
|
|
560
|
+
return executeChecked(options, ctx, request.requestId, request.method, manageParams(request.params));
|
|
561
|
+
}
|
|
187
562
|
if (request.method === "spawn") {
|
|
188
563
|
return executeChecked(options, ctx, request.requestId, request.method, spawnParams(request.params));
|
|
189
564
|
}
|
|
190
565
|
if (request.method === "status") {
|
|
191
|
-
|
|
566
|
+
const statusParams = normalizeStatusParams(request.params);
|
|
567
|
+
let sessionId;
|
|
568
|
+
if (!hasStatusTarget(statusParams)) {
|
|
569
|
+
try {
|
|
570
|
+
sessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
571
|
+
} catch {}
|
|
572
|
+
if (canUseInMemoryStatus(options.state, sessionId)) {
|
|
573
|
+
const fleet = buildFleetStatus(options.state, fleetKeys, sessionId);
|
|
574
|
+
const asyncSnapshot = buildAsyncStatusSnapshotForState(options.state, sessionId);
|
|
575
|
+
return {
|
|
576
|
+
text: inMemoryStatusSummary(fleet),
|
|
577
|
+
details: { mode: "management", results: [] },
|
|
578
|
+
fleet,
|
|
579
|
+
asyncSnapshot
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
const status = await executeChecked(options, ctx, request.requestId, request.method, { action: "status", ...statusParams });
|
|
584
|
+
sessionId ??= resolveCurrentSessionId(ctx.sessionManager);
|
|
585
|
+
return {
|
|
586
|
+
...status,
|
|
587
|
+
fleet: buildFleetStatus(options.state, fleetKeys, sessionId),
|
|
588
|
+
asyncSnapshot: buildAsyncStatusSnapshotForState(options.state, sessionId)
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
if (request.method === "steer") {
|
|
592
|
+
return executeChecked(options, ctx, request.requestId, request.method, steerParams(request.params));
|
|
192
593
|
}
|
|
193
594
|
if (request.method === "interrupt") {
|
|
194
595
|
return executeChecked(options, ctx, request.requestId, request.method, { action: "interrupt", ...normalizeTargetParams(request.params, "interrupt") });
|
|
@@ -196,6 +597,9 @@ async function handleRequest(request, options) {
|
|
|
196
597
|
if (request.method === "stop") {
|
|
197
598
|
return stopAsyncRun(request.params, options, ctx);
|
|
198
599
|
}
|
|
600
|
+
if (request.method === "resume") {
|
|
601
|
+
return executeChecked(options, ctx, request.requestId, request.method, resumeParams(request.params));
|
|
602
|
+
}
|
|
199
603
|
throw new SubagentRpcError("unsupported_method", `Unsupported subagent RPC method: ${String(request.method)}`);
|
|
200
604
|
}
|
|
201
605
|
function parseRequest(raw) {
|
|
@@ -238,11 +642,12 @@ function errorReply(raw, error) {
|
|
|
238
642
|
};
|
|
239
643
|
}
|
|
240
644
|
export function registerSubagentRpcBridge(options) {
|
|
645
|
+
const fleetKeys = { sessionId: null, next: 0, keys: new Map };
|
|
241
646
|
const unsubscribe = options.events.on(SUBAGENT_RPC_REQUEST_EVENT, async (raw) => {
|
|
242
647
|
let request;
|
|
243
648
|
try {
|
|
244
649
|
request = parseRequest(raw);
|
|
245
|
-
const data = await handleRequest(request, options);
|
|
650
|
+
const data = await handleRequest(request, options, fleetKeys);
|
|
246
651
|
options.events.emit(subagentRpcReplyEvent(request.requestId), {
|
|
247
652
|
version: SUBAGENT_RPC_PROTOCOL_VERSION,
|
|
248
653
|
requestId: request.requestId,
|