@fitchmultz/pi-subagents 0.0.0-stage → 0.44.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1645 -0
- package/LICENSE +21 -0
- package/README.md +1529 -2
- package/agents/context-builder.md +97 -0
- package/agents/debugger.md +51 -0
- package/agents/delegate.md +13 -0
- package/agents/fixer.md +37 -0
- package/agents/oracle.md +71 -0
- package/agents/planner.md +72 -0
- package/agents/researcher.md +51 -0
- package/agents/reviewer-claude.md +69 -0
- package/agents/reviewer-gpt.md +68 -0
- package/agents/reviewer-ponytail.md +82 -0
- package/agents/reviewer-security.md +81 -0
- package/agents/reviewer.md +69 -0
- package/agents/scout.md +66 -0
- package/agents/ui-designer.md +51 -0
- package/agents/watcher.md +26 -0
- package/agents/worker.md +46 -0
- package/agents/writer.md +36 -0
- package/dist/agents/agent-management.js +923 -0
- package/dist/agents/agent-scope.js +7 -0
- package/dist/agents/agent-selection.js +20 -0
- package/dist/agents/agent-serializer.js +100 -0
- package/dist/agents/agents.js +752 -0
- package/dist/agents/chain-serializer.js +367 -0
- package/dist/agents/frontmatter.js +21 -0
- package/dist/agents/identity.js +29 -0
- package/dist/agents/skills.js +570 -0
- package/dist/extension/build-info.js +1 -0
- package/dist/extension/compact-tools.js +112 -0
- package/dist/extension/config.js +22 -0
- package/dist/extension/control-notices.js +29 -0
- package/dist/extension/doctor.js +143 -0
- package/dist/extension/fanout-child.js +326 -0
- package/dist/extension/index.js +577 -0
- package/dist/extension/schemas.js +416 -0
- package/dist/extension/tool-input.js +20 -0
- package/dist/extension/tool-result.js +14 -0
- package/dist/history/canonical-result.js +81 -0
- package/dist/history/database.js +72 -0
- package/dist/history/index.js +194 -0
- package/dist/history/ingest.js +447 -0
- package/dist/history/queries.js +350 -0
- package/dist/history/store.js +216 -0
- package/dist/history/types.js +4 -0
- package/dist/history/worker.js +461 -0
- package/dist/intercom/intercom-bridge.js +112 -0
- package/dist/intercom/live-intercom.js +94 -0
- package/dist/intercom/result-intercom.js +373 -0
- package/dist/pi-intercom/agent-dir.js +10 -0
- package/dist/pi-intercom/broker/broker.js +426 -0
- package/dist/pi-intercom/broker/client.js +492 -0
- package/dist/pi-intercom/broker/framing.js +65 -0
- package/dist/pi-intercom/broker/paths.js +42 -0
- package/dist/pi-intercom/broker/pid.js +66 -0
- package/dist/pi-intercom/broker/spawn.js +221 -0
- package/dist/pi-intercom/config.js +102 -0
- package/dist/pi-intercom/index.js +2942 -0
- package/dist/pi-intercom/reply-tracker.js +182 -0
- package/dist/pi-intercom/session-targets.js +128 -0
- package/dist/pi-intercom/subagent-live-events.js +132 -0
- package/dist/pi-intercom/topics.js +157 -0
- package/dist/pi-intercom/types.js +163 -0
- package/dist/pi-intercom/ui/compose.js +269 -0
- package/dist/pi-intercom/ui/inline-message.js +80 -0
- package/dist/pi-intercom/ui/session-list.js +124 -0
- package/dist/runs/background/async-control.js +95 -0
- package/dist/runs/background/async-execution.js +676 -0
- package/dist/runs/background/async-job-tracker.js +383 -0
- package/dist/runs/background/async-result-file.js +58 -0
- package/dist/runs/background/async-resume.js +305 -0
- package/dist/runs/background/async-status.js +442 -0
- package/dist/runs/background/completion-dedupe.js +69 -0
- package/dist/runs/background/completion-delivery.js +245 -0
- package/dist/runs/background/notify.js +71 -0
- package/dist/runs/background/parallel-groups.js +55 -0
- package/dist/runs/background/result-watcher.js +426 -0
- package/dist/runs/background/run-id-resolver.js +64 -0
- package/dist/runs/background/run-status.js +382 -0
- package/dist/runs/background/stale-run-reconciler.js +335 -0
- package/dist/runs/background/subagent-runner-launcher.js +55 -0
- package/dist/runs/background/subagent-runner.js +1872 -0
- package/dist/runs/background/top-level-async.js +5 -0
- package/dist/runs/foreground/chain-clarify.js +1152 -0
- package/dist/runs/foreground/clarify-invocation.js +72 -0
- package/dist/runs/foreground/execution-input.js +423 -0
- package/dist/runs/foreground/foreground-control.js +817 -0
- package/dist/runs/foreground/question-control.js +77 -0
- package/dist/runs/foreground/run-async-path.js +205 -0
- package/dist/runs/foreground/subagent-executor.js +442 -0
- package/dist/runs/foreground/subagent-params.js +165 -0
- package/dist/runs/foreground/wait-run.js +139 -0
- package/dist/runs/shared/acceptance-contract.js +253 -0
- package/dist/runs/shared/acceptance-evaluation.js +256 -0
- package/dist/runs/shared/acceptance-finalization.js +280 -0
- package/dist/runs/shared/acceptance-reports.js +147 -0
- package/dist/runs/shared/acceptance.js +4 -0
- package/dist/runs/shared/chain-outputs.js +110 -0
- package/dist/runs/shared/child-attempt.js +693 -0
- package/dist/runs/shared/child-execution-cwd.js +96 -0
- package/dist/runs/shared/child-observations.js +114 -0
- package/dist/runs/shared/claude-code.js +199 -0
- package/dist/runs/shared/completion-guard.js +31 -0
- package/dist/runs/shared/dynamic-fanout.js +274 -0
- package/dist/runs/shared/history-index.js +72 -0
- package/dist/runs/shared/mcp-direct-tool-allowlist.js +334 -0
- package/dist/runs/shared/model-fallback.js +185 -0
- package/dist/runs/shared/mutating-tool-guard.js +170 -0
- package/dist/runs/shared/native-finalization.js +101 -0
- package/dist/runs/shared/native-usage.js +153 -0
- package/dist/runs/shared/nested-events.js +700 -0
- package/dist/runs/shared/nested-path.js +48 -0
- package/dist/runs/shared/nested-render.js +108 -0
- package/dist/runs/shared/parallel-utils.js +61 -0
- package/dist/runs/shared/parent-receipts.js +68 -0
- package/dist/runs/shared/parent-usage.js +121 -0
- package/dist/runs/shared/pi-args.js +310 -0
- package/dist/runs/shared/pi-spawn.js +52 -0
- package/dist/runs/shared/run-history-queries.js +45 -0
- package/dist/runs/shared/run-history.js +103 -0
- package/dist/runs/shared/run-id-ambiguity.js +4 -0
- package/dist/runs/shared/run-records.js +679 -0
- package/dist/runs/shared/session-cwd-preload.js +33 -0
- package/dist/runs/shared/single-output.js +222 -0
- package/dist/runs/shared/streaming-text.js +15 -0
- package/dist/runs/shared/structured-output.js +55 -0
- package/dist/runs/shared/subagent-control.js +179 -0
- package/dist/runs/shared/subagent-prompt-runtime.js +197 -0
- package/dist/runs/shared/subagent-tool-loop-guard.js +66 -0
- package/dist/runs/shared/supervisor-questions.js +320 -0
- package/dist/runs/shared/workflow-graph.js +214 -0
- package/dist/runs/shared/workflow-policy.js +84 -0
- package/dist/runs/shared/worktree.js +525 -0
- package/dist/shared/agent-context-policy.js +126 -0
- package/dist/shared/artifacts.js +96 -0
- package/dist/shared/atomic-json.js +13 -0
- package/dist/shared/cooperative.js +20 -0
- package/dist/shared/execution-cwd.js +14 -0
- package/dist/shared/file-coalescer.js +21 -0
- package/dist/shared/fork-context.js +49 -0
- package/dist/shared/formatters.js +85 -0
- package/dist/shared/journal-reader.js +407 -0
- package/dist/shared/lazy-tools.js +32 -0
- package/dist/shared/model-info.js +68 -0
- package/dist/shared/native-session.js +15 -0
- package/dist/shared/native-tui.js +18 -0
- package/dist/shared/native-typebox.js +20 -0
- package/dist/shared/post-exit-stdio-guard.js +197 -0
- package/dist/shared/prompt-sections.js +8 -0
- package/dist/shared/session-entries.js +52 -0
- package/dist/shared/session-identity.js +14 -0
- package/dist/shared/settings.js +254 -0
- package/dist/shared/status-format.js +111 -0
- package/dist/shared/temp-root.js +114 -0
- package/dist/shared/types.js +207 -0
- package/dist/shared/ui-mode.js +3 -0
- package/dist/shared/utils.js +334 -0
- package/dist/slash/prompt-template-bridge.js +298 -0
- package/dist/slash/slash-bridge.js +116 -0
- package/dist/slash/slash-commands.js +607 -0
- package/dist/slash/slash-live-state.js +246 -0
- package/dist/tui/action-hints.js +75 -0
- package/dist/tui/agent-history.js +197 -0
- package/dist/tui/agent-view.js +1656 -0
- package/dist/tui/render.js +1515 -0
- package/docs/intercom.md +579 -0
- package/docs/performance.md +121 -0
- package/package.json +101 -4
- package/prompts/gather-context-and-clarify.md +14 -0
- package/prompts/parallel-cleanup.md +62 -0
- package/prompts/parallel-context-build.md +56 -0
- package/prompts/parallel-handoff-plan.md +62 -0
- package/prompts/parallel-research.md +51 -0
- package/prompts/parallel-review.md +59 -0
- package/prompts/review-loop.md +42 -0
- package/scripts/build.mjs +134 -0
- package/scripts/check-compat.mjs +48 -0
- package/scripts/compat-host.mjs +19 -0
- package/scripts/linux-smoke.sh +51 -0
- package/scripts/local-install-smoke.mjs +66 -0
- package/scripts/native-package-smoke.mjs +82 -0
- package/scripts/package-smoke.mjs +205 -0
- package/scripts/prepare.mjs +67 -0
- package/scripts/real-pi-smoke.mjs +415 -0
- package/scripts/run-tests.mjs +149 -0
- package/skills/pi-intercom/SKILL.md +113 -0
- package/skills/pi-intercom/evals/evals.json +29 -0
- package/skills/pi-intercom/evals/trigger-evals.json +47 -0
- package/skills/pi-intercom/references/peer-sessions.md +69 -0
- package/skills/pi-subagents/SKILL.md +76 -0
- package/skills/pi-subagents/evals/evals.json +29 -0
- package/skills/pi-subagents/evals/trigger-evals.json +42 -0
- package/skills/pi-subagents/references/full-orchestration-guide.md +863 -0
- package/src/agents/agent-management.ts +813 -0
- package/src/agents/agent-scope.ts +7 -0
- package/src/agents/agent-selection.ts +23 -0
- package/src/agents/agent-serializer.ts +99 -0
- package/src/agents/agents.ts +916 -0
- package/src/agents/chain-serializer.ts +329 -0
- package/src/agents/frontmatter.ts +21 -0
- package/src/agents/identity.ts +30 -0
- package/src/agents/skills.ts +637 -0
- package/src/extension/build-info.ts +2 -0
- package/src/extension/compact-tools.ts +114 -0
- package/src/extension/config.ts +23 -0
- package/src/extension/control-notices.ts +47 -0
- package/src/extension/doctor.ts +171 -0
- package/src/extension/fanout-child.ts +312 -0
- package/src/extension/index.ts +649 -0
- package/src/extension/schemas.ts +444 -0
- package/src/extension/tool-input.ts +19 -0
- package/src/extension/tool-result.ts +16 -0
- package/src/history/canonical-result.ts +62 -0
- package/src/history/database.ts +59 -0
- package/src/history/index.ts +152 -0
- package/src/history/ingest.ts +332 -0
- package/src/history/queries.ts +241 -0
- package/src/history/store.ts +203 -0
- package/src/history/types.ts +166 -0
- package/src/history/worker.ts +317 -0
- package/src/intercom/intercom-bridge.ts +123 -0
- package/src/intercom/live-intercom.ts +104 -0
- package/src/intercom/result-intercom.ts +429 -0
- package/src/pi-intercom/agent-dir.ts +9 -0
- package/src/pi-intercom/broker/broker.ts +463 -0
- package/src/pi-intercom/broker/client.ts +558 -0
- package/src/pi-intercom/broker/framing.ts +77 -0
- package/src/pi-intercom/broker/paths.ts +47 -0
- package/src/pi-intercom/broker/pid.ts +59 -0
- package/src/pi-intercom/broker/spawn.ts +248 -0
- package/src/pi-intercom/config.ts +142 -0
- package/src/pi-intercom/index.ts +2929 -0
- package/src/pi-intercom/reply-tracker.ts +211 -0
- package/src/pi-intercom/session-targets.ts +172 -0
- package/src/pi-intercom/subagent-live-events.ts +133 -0
- package/src/pi-intercom/topics.ts +125 -0
- package/src/pi-intercom/types.ts +271 -0
- package/src/pi-intercom/ui/compose.ts +289 -0
- package/src/pi-intercom/ui/inline-message.ts +92 -0
- package/src/pi-intercom/ui/session-list.ts +139 -0
- package/src/runs/background/async-control.ts +89 -0
- package/src/runs/background/async-execution.ts +850 -0
- package/src/runs/background/async-job-tracker.ts +385 -0
- package/src/runs/background/async-result-file.ts +62 -0
- package/src/runs/background/async-resume.ts +333 -0
- package/src/runs/background/async-status.ts +481 -0
- package/src/runs/background/completion-dedupe.ts +79 -0
- package/src/runs/background/completion-delivery.ts +195 -0
- package/src/runs/background/notify.ts +123 -0
- package/src/runs/background/parallel-groups.ts +53 -0
- package/src/runs/background/result-watcher.ts +423 -0
- package/src/runs/background/run-id-resolver.ts +69 -0
- package/src/runs/background/run-status.ts +384 -0
- package/src/runs/background/stale-run-reconciler.ts +369 -0
- package/src/runs/background/subagent-runner-launcher.ts +56 -0
- package/src/runs/background/subagent-runner.ts +2053 -0
- package/src/runs/background/top-level-async.ts +13 -0
- package/src/runs/foreground/chain-clarify.ts +1340 -0
- package/src/runs/foreground/clarify-invocation.ts +77 -0
- package/src/runs/foreground/execution-input.ts +467 -0
- package/src/runs/foreground/foreground-control.ts +821 -0
- package/src/runs/foreground/question-control.ts +70 -0
- package/src/runs/foreground/run-async-path.ts +243 -0
- package/src/runs/foreground/subagent-executor.ts +501 -0
- package/src/runs/foreground/subagent-params.ts +320 -0
- package/src/runs/foreground/wait-run.ts +121 -0
- package/src/runs/shared/acceptance-contract.ts +257 -0
- package/src/runs/shared/acceptance-evaluation.ts +275 -0
- package/src/runs/shared/acceptance-finalization.ts +353 -0
- package/src/runs/shared/acceptance-reports.ts +152 -0
- package/src/runs/shared/acceptance.ts +33 -0
- package/src/runs/shared/chain-outputs.ts +114 -0
- package/src/runs/shared/child-attempt.ts +623 -0
- package/src/runs/shared/child-execution-cwd.ts +91 -0
- package/src/runs/shared/child-observations.ts +99 -0
- package/src/runs/shared/claude-code.ts +243 -0
- package/src/runs/shared/completion-guard.ts +35 -0
- package/src/runs/shared/dynamic-fanout.ts +295 -0
- package/src/runs/shared/history-index.ts +69 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +376 -0
- package/src/runs/shared/model-fallback.ts +219 -0
- package/src/runs/shared/mutating-tool-guard.ts +194 -0
- package/src/runs/shared/native-finalization.ts +128 -0
- package/src/runs/shared/native-usage.ts +113 -0
- package/src/runs/shared/nested-events.ts +752 -0
- package/src/runs/shared/nested-path.ts +52 -0
- package/src/runs/shared/nested-render.ts +119 -0
- package/src/runs/shared/parallel-utils.ts +153 -0
- package/src/runs/shared/parent-receipts.ts +59 -0
- package/src/runs/shared/parent-usage.ts +121 -0
- package/src/runs/shared/pi-args.ts +350 -0
- package/src/runs/shared/pi-spawn.ts +52 -0
- package/src/runs/shared/run-history-queries.ts +44 -0
- package/src/runs/shared/run-history.ts +93 -0
- package/src/runs/shared/run-id-ambiguity.ts +4 -0
- package/src/runs/shared/run-records.ts +607 -0
- package/src/runs/shared/session-cwd-preload.ts +27 -0
- package/src/runs/shared/single-output.ts +267 -0
- package/src/runs/shared/streaming-text.ts +18 -0
- package/src/runs/shared/structured-output.ts +68 -0
- package/src/runs/shared/subagent-control.ts +219 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +201 -0
- package/src/runs/shared/subagent-tool-loop-guard.ts +89 -0
- package/src/runs/shared/supervisor-questions.ts +372 -0
- package/src/runs/shared/workflow-graph.ts +220 -0
- package/src/runs/shared/workflow-policy.ts +125 -0
- package/src/runs/shared/worktree.ts +635 -0
- package/src/shared/agent-context-policy.ts +184 -0
- package/src/shared/artifacts.ts +95 -0
- package/src/shared/atomic-json.ts +16 -0
- package/src/shared/cooperative.ts +21 -0
- package/src/shared/execution-cwd.ts +14 -0
- package/src/shared/file-coalescer.ts +29 -0
- package/src/shared/fork-context.ts +68 -0
- package/src/shared/formatters.ts +84 -0
- package/src/shared/journal-reader.ts +333 -0
- package/src/shared/lazy-tools.ts +36 -0
- package/src/shared/model-info.ts +81 -0
- package/src/shared/native-session.ts +8 -0
- package/src/shared/native-tui.ts +10 -0
- package/src/shared/native-typebox.ts +14 -0
- package/src/shared/post-exit-stdio-guard.ts +204 -0
- package/src/shared/prompt-sections.ts +10 -0
- package/src/shared/session-entries.ts +49 -0
- package/src/shared/session-identity.ts +18 -0
- package/src/shared/settings.ts +384 -0
- package/src/shared/status-format.ts +123 -0
- package/src/shared/temp-root.ts +107 -0
- package/src/shared/types.ts +1259 -0
- package/src/shared/ui-mode.ts +5 -0
- package/src/shared/utils.ts +342 -0
- package/src/slash/prompt-template-bridge.ts +408 -0
- package/src/slash/slash-bridge.ts +178 -0
- package/src/slash/slash-commands.ts +617 -0
- package/src/slash/slash-live-state.ts +292 -0
- package/src/tui/action-hints.ts +69 -0
- package/src/tui/agent-history.ts +210 -0
- package/src/tui/agent-view.ts +1323 -0
- package/src/tui/render.ts +1550 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { resolveExecutionAgentScope } from "../../agents/agent-scope.js";
|
|
5
|
+
import { handleManagementAction } from "../../agents/agent-management.js";
|
|
6
|
+
import { buildDoctorReport } from "../../extension/doctor.js";
|
|
7
|
+
import { providerQualifiedModelId, toModelInfo } from "../../shared/model-info.js";
|
|
8
|
+
import { resolveModelCandidate } from "../shared/model-fallback.js";
|
|
9
|
+
import { getArtifactsDir } from "../../shared/artifacts.js";
|
|
10
|
+
import { collectInvocationAgentNames, isParallelStep, isDynamicParallelStep, } from "../../shared/settings.js";
|
|
11
|
+
import { buildFlatAgentNameResolver, createPerAgentForkContextResolver, invocationUsesForkContext, resolveAgentContext, validateForkContextModelPolicy, } from "../../shared/agent-context-policy.js";
|
|
12
|
+
import { resolveCurrentSessionId } from "../../shared/session-identity.js";
|
|
13
|
+
import { resolveExecutionCwd } from "../../shared/execution-cwd.js";
|
|
14
|
+
import { resolveIntercomBridge, resolveIntercomSessionTarget, resolveOrchestratorIntercomTarget } from "../../intercom/intercom-bridge.js";
|
|
15
|
+
import { resolveControlConfig } from "../shared/subagent-control.js";
|
|
16
|
+
import { createNestedRoute, resolveInheritedNestedRouteFromEnv } from "../shared/nested-events.js";
|
|
17
|
+
import { resolveSubagentRunId } from "../background/run-id-resolver.js";
|
|
18
|
+
import { inspectSubagentStatus } from "../background/run-status.js";
|
|
19
|
+
import { applyForceTopLevelAsyncOverride } from "../background/top-level-async.js";
|
|
20
|
+
import { queryLiveIntercomHealth, queryLiveIntercomStatus } from "../../intercom/live-intercom.js";
|
|
21
|
+
import { saveQuestionOwner } from "../shared/supervisor-questions.js";
|
|
22
|
+
import { buildWorkflowGraphSnapshot, workflowAgentNodes } from "../shared/workflow-graph.js";
|
|
23
|
+
import { ownedRunList, ownedRunStatusResult, ownedRunView, rememberOwnedRun, resolveOwnedRun, workflowChildren } from "../shared/run-records.js";
|
|
24
|
+
import { ownedHistoryQuery } from "../shared/run-history-queries.js";
|
|
25
|
+
import { cancelSupervisorInput, controlSupervisorQuestion, projectSupervisorQuestions } from "./question-control.js";
|
|
26
|
+
import {} from "../../agents/agents.js";
|
|
27
|
+
import { SUBAGENT_ACTIONS, checkSubagentDepth, } from "../../shared/types.js";
|
|
28
|
+
import { resolveAsyncExecutionMode, } from "./subagent-params.js";
|
|
29
|
+
import { MUTATING_MANAGEMENT_ACTIONS, extendAsyncTimeoutResult, interruptAsyncRun, interruptNestedRun, nestedResolutionScopeForExecutor, nudgeSubagentRun, rememberedForegroundStatusResult, resolveRememberedForegroundRun, resolveRequestedCwd, resumeAsyncRun, } from "./foreground-control.js";
|
|
30
|
+
import { buildRequestedModeError, normalizeRepeatedParallelCounts, normalizeRoleForegroundTimeout, resolveForegroundTimeoutMs, toExecutionErrorResult, validateExecutionInput, withForkContext, } from "./execution-input.js";
|
|
31
|
+
import { runAsyncPath } from "./run-async-path.js";
|
|
32
|
+
import { clarifyInvocation } from "./clarify-invocation.js";
|
|
33
|
+
import { waitForOwnedRun } from "./wait-run.js";
|
|
34
|
+
export { normalizeSubagentParamsLike, resolveAsyncExecutionMode } from "./subagent-params.js";
|
|
35
|
+
export { writeAsyncInterruptRequest } from "./foreground-control.js";
|
|
36
|
+
export function createSubagentExecutor(deps) {
|
|
37
|
+
const execute = async (_id, params, signal, onUpdate, ctx, executionCwd) => {
|
|
38
|
+
const needsExecutionCwd = !params.action || params.cwd !== undefined || ["list", "get", "create", "update", "delete", "doctor"].includes(params.action);
|
|
39
|
+
const invocationCwd = needsExecutionCwd ? executionCwd ?? resolveExecutionCwd(deps.pi, ctx) : ctx.cwd;
|
|
40
|
+
await deps.ensureSessionState?.(ctx);
|
|
41
|
+
if (needsExecutionCwd)
|
|
42
|
+
deps.state.baseCwd = invocationCwd;
|
|
43
|
+
deps.state.foregroundRuns ??= new Map();
|
|
44
|
+
const requestCwd = resolveRequestedCwd(invocationCwd, params.cwd);
|
|
45
|
+
const paramsWithResolvedCwd = params.cwd === undefined ? params : { ...params, cwd: requestCwd };
|
|
46
|
+
if (params.action) {
|
|
47
|
+
if (params.action === "review") {
|
|
48
|
+
try {
|
|
49
|
+
if (!(params.id ?? params.runId) || (params.decision !== "accepted" && params.decision !== "needs_changes"))
|
|
50
|
+
throw new Error("action='review' requires id and decision ('accepted' or 'needs_changes').");
|
|
51
|
+
const run = resolveOwnedRun(deps.state, (params.id ?? params.runId));
|
|
52
|
+
if (!run)
|
|
53
|
+
throw new Error("Run not found in this parent session.");
|
|
54
|
+
if (ownedRunView(run, deps.state).state === "live")
|
|
55
|
+
throw new Error("The run is still live. Use nudge for guidance, or stop it before reviewing its result.");
|
|
56
|
+
const reviewed = { ...run, review: { decision: params.decision, ...(params.message ? { message: params.message } : {}), reviewedAt: Date.now() } };
|
|
57
|
+
rememberOwnedRun(deps.state, reviewed);
|
|
58
|
+
const result = ownedRunStatusResult(reviewed, deps.state, undefined, { childSafe: Boolean(nestedResolutionScopeForExecutor(deps)) });
|
|
59
|
+
return { ...result, content: [{ type: "text", text: `Saved parent review for ${run.runId}: ${params.decision}.\nThe review note is parent-only and was not sent to the child. Put actionable instructions in ${deps.allowMutatingManagementActions === false && deps.config.compactChildTools === false ? "subagent resume/nudge" : "agent_runs continue/nudge"}. No work started.` }] };
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (params.action === "history" || params.action === "search") {
|
|
66
|
+
try {
|
|
67
|
+
return await ownedHistoryQuery(deps.state, params, signal);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (params.action === "questions" || params.action === "answer") {
|
|
74
|
+
return controlSupervisorQuestion({ params: paramsWithResolvedCwd, requestCwd, ctx, deps });
|
|
75
|
+
}
|
|
76
|
+
if (params.action === "doctor") {
|
|
77
|
+
let currentSessionFile = null;
|
|
78
|
+
let currentSessionId = deps.state.currentSessionId;
|
|
79
|
+
let sessionError;
|
|
80
|
+
try {
|
|
81
|
+
currentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
|
|
82
|
+
currentSessionId = ctx.sessionManager.getSessionId();
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
sessionError = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
86
|
+
}
|
|
87
|
+
let orchestratorTarget;
|
|
88
|
+
try {
|
|
89
|
+
const fallbackTarget = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
90
|
+
orchestratorTarget = resolveOrchestratorIntercomTarget(deps.pi.events, fallbackTarget);
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
const { connection } = await queryLiveIntercomStatus(deps.pi.events);
|
|
94
|
+
return {
|
|
95
|
+
content: [{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: buildDoctorReport({
|
|
98
|
+
cwd: requestCwd,
|
|
99
|
+
nativeSessionCwd: ctx.cwd,
|
|
100
|
+
config: deps.config,
|
|
101
|
+
state: deps.state,
|
|
102
|
+
requestedSessionDir: paramsWithResolvedCwd.sessionDir,
|
|
103
|
+
currentSessionFile,
|
|
104
|
+
currentSessionId,
|
|
105
|
+
orchestratorTarget,
|
|
106
|
+
connection,
|
|
107
|
+
sessionError,
|
|
108
|
+
projectTrusted: ctx.isProjectTrusted(),
|
|
109
|
+
expandTilde: deps.expandTilde,
|
|
110
|
+
}),
|
|
111
|
+
}],
|
|
112
|
+
details: { mode: "management", results: [] },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (params.action === "status") {
|
|
116
|
+
const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
|
|
117
|
+
if (!targetRunId && !params.dir && deps.state.ownedRuns && deps.allowMutatingManagementActions !== false) {
|
|
118
|
+
try {
|
|
119
|
+
return await ownedRunList(deps.state, { ...params, signal });
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
let includeRunHeader = true;
|
|
126
|
+
if (targetRunId) {
|
|
127
|
+
try {
|
|
128
|
+
includeRunHeader = Boolean(params.dir) || !resolveOwnedRun(deps.state, targetRunId);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
132
|
+
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
let inspected = inspectSubagentStatus({ ...paramsWithResolvedCwd, action: "status" }, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps), includeRunHeader });
|
|
136
|
+
const targets = inspected.details.intercomTargets ?? [];
|
|
137
|
+
if (!inspected.isError && targets.length) {
|
|
138
|
+
const intercomHealth = await queryLiveIntercomHealth(deps.pi.events, targets);
|
|
139
|
+
if (intercomHealth.size)
|
|
140
|
+
inspected = inspectSubagentStatus({ ...paramsWithResolvedCwd, action: "status" }, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps), intercomHealth, includeRunHeader });
|
|
141
|
+
}
|
|
142
|
+
if (targetRunId && inspected.isError && inspected.content[0]?.type === "text" && inspected.content[0].text.startsWith("Async run not found.")) {
|
|
143
|
+
try {
|
|
144
|
+
const remembered = resolveRememberedForegroundRun(targetRunId, deps.state);
|
|
145
|
+
if (remembered)
|
|
146
|
+
return rememberedForegroundStatusResult(remembered, Boolean(nestedResolutionScopeForExecutor(deps)));
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
150
|
+
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (!targetRunId && !params.dir && deps.allowMutatingManagementActions !== false) {
|
|
154
|
+
const foreground = [...(deps.state.foregroundRuns?.values() ?? [])]
|
|
155
|
+
.sort((a, b) => b.updatedAt - a.updatedAt)
|
|
156
|
+
.map((run) => rememberedForegroundStatusResult(run));
|
|
157
|
+
if (foreground.length) {
|
|
158
|
+
inspected = {
|
|
159
|
+
...inspected,
|
|
160
|
+
content: [...foreground.flatMap((result) => result.content), ...inspected.content],
|
|
161
|
+
details: {
|
|
162
|
+
...inspected.details,
|
|
163
|
+
managementControls: [...foreground.flatMap((result) => result.details.managementControl ? [result.details.managementControl] : []), ...(inspected.details.managementControls ?? [])],
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return inspected;
|
|
169
|
+
}
|
|
170
|
+
if (params.action === "nudge") {
|
|
171
|
+
return nudgeSubagentRun({ params: paramsWithResolvedCwd, deps, ctx });
|
|
172
|
+
}
|
|
173
|
+
if (params.action === "resume") {
|
|
174
|
+
return resumeAsyncRun({ params: paramsWithResolvedCwd, requestCwd, ctx, deps });
|
|
175
|
+
}
|
|
176
|
+
if (params.action === "extend") {
|
|
177
|
+
const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
|
|
178
|
+
let resolved;
|
|
179
|
+
if (targetRunId) {
|
|
180
|
+
try {
|
|
181
|
+
resolved = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
185
|
+
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return extendAsyncTimeoutResult(deps.state, resolved?.id ?? targetRunId, paramsWithResolvedCwd.extendMs ?? paramsWithResolvedCwd.timeoutMs ?? paramsWithResolvedCwd.maxRuntimeMs ?? 0);
|
|
189
|
+
}
|
|
190
|
+
if (params.action === "interrupt") {
|
|
191
|
+
const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
|
|
192
|
+
let resolved;
|
|
193
|
+
if (targetRunId) {
|
|
194
|
+
try {
|
|
195
|
+
resolved = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
199
|
+
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (resolved?.kind === "nested")
|
|
203
|
+
return interruptNestedRun(resolved, paramsWithResolvedCwd.index);
|
|
204
|
+
const asyncInterruptResult = interruptAsyncRun(deps.state, resolved?.kind === "async" ? resolved.id : targetRunId, paramsWithResolvedCwd.index);
|
|
205
|
+
if (asyncInterruptResult)
|
|
206
|
+
return asyncInterruptResult;
|
|
207
|
+
return {
|
|
208
|
+
content: [{ type: "text", text: "No interrupt-capable run found in this session." }],
|
|
209
|
+
isError: true,
|
|
210
|
+
details: { mode: "management", results: [] },
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (!SUBAGENT_ACTIONS.includes(params.action)) {
|
|
214
|
+
return {
|
|
215
|
+
content: [{ type: "text", text: `Unknown action: ${params.action}. Valid: ${SUBAGENT_ACTIONS.join(", ")}` }],
|
|
216
|
+
isError: true,
|
|
217
|
+
details: { mode: "management", results: [] },
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(params.action)) {
|
|
221
|
+
return {
|
|
222
|
+
content: [{ type: "text", text: `Action '${params.action}' is not available from child-safe subagent fanout mode.` }],
|
|
223
|
+
isError: true,
|
|
224
|
+
details: { mode: "management", results: [] },
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return handleManagementAction(params.action, paramsWithResolvedCwd, { ...ctx, cwd: requestCwd });
|
|
228
|
+
}
|
|
229
|
+
const { blocked, depth, maxDepth } = checkSubagentDepth(deps.config.maxSubagentDepth);
|
|
230
|
+
if (blocked) {
|
|
231
|
+
return {
|
|
232
|
+
content: [
|
|
233
|
+
{
|
|
234
|
+
type: "text",
|
|
235
|
+
text: `Nested subagent call blocked (depth=${depth}, max=${maxDepth}). ` +
|
|
236
|
+
"You are running at the maximum subagent nesting depth. " +
|
|
237
|
+
"Complete your current task directly without delegating to further subagents.",
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
isError: true,
|
|
241
|
+
details: { mode: "single", results: [] },
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const normalized = normalizeRepeatedParallelCounts(paramsWithResolvedCwd);
|
|
245
|
+
if (normalized.error)
|
|
246
|
+
return normalized.error;
|
|
247
|
+
const normalizedParams = normalized.params;
|
|
248
|
+
let effectiveParams = applyForceTopLevelAsyncOverride(normalizedParams, depth, deps.config.forceTopLevelAsync === true);
|
|
249
|
+
const scope = resolveExecutionAgentScope(effectiveParams.agentScope);
|
|
250
|
+
const effectiveCwd = effectiveParams.cwd ?? invocationCwd;
|
|
251
|
+
const parentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
|
|
252
|
+
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
253
|
+
const inheritedModel = providerQualifiedModelId(ctx.model?.provider, ctx.model?.id);
|
|
254
|
+
const discoveredAgents = deps.discoverAgents(effectiveCwd, scope, { projectTrusted: ctx.isProjectTrusted() }).agents
|
|
255
|
+
.map((agent) => agent.model || !inheritedModel ? agent : { ...agent, model: inheritedModel });
|
|
256
|
+
const invocationAgentNames = collectInvocationAgentNames(effectiveParams);
|
|
257
|
+
const invocationContext = invocationUsesForkContext(effectiveParams.context, invocationAgentNames, discoveredAgents)
|
|
258
|
+
? "fork"
|
|
259
|
+
: undefined;
|
|
260
|
+
const fallbackTarget = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
261
|
+
const orchestratorTarget = resolveOrchestratorIntercomTarget(deps.pi.events, fallbackTarget);
|
|
262
|
+
const intercomBridge = resolveIntercomBridge(orchestratorTarget);
|
|
263
|
+
const runId = randomUUID();
|
|
264
|
+
const agentNameAtIndex = buildFlatAgentNameResolver(effectiveParams);
|
|
265
|
+
const resolveContextForAgent = (agentName) => resolveAgentContext(effectiveParams.context, agentName, discoveredAgents);
|
|
266
|
+
const resolveContextForIndex = (index) => resolveContextForAgent(agentNameAtIndex(index ?? 0));
|
|
267
|
+
const agents = discoveredAgents.map((agent) => ({ ...agent, defaultContext: resolveContextForAgent(agent.name) }));
|
|
268
|
+
const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
|
|
269
|
+
const nestedRoute = inheritedNestedRoute ?? createNestedRoute(runId);
|
|
270
|
+
const shareEnabled = effectiveParams.share === true;
|
|
271
|
+
const hasChain = (effectiveParams.chain?.length ?? 0) > 0;
|
|
272
|
+
const hasTasks = (effectiveParams.tasks?.length ?? 0) > 0;
|
|
273
|
+
const hasSingle = !hasChain && !hasTasks && Boolean(effectiveParams.agent);
|
|
274
|
+
const allowClarifyTaskPrompt = hasChain
|
|
275
|
+
&& effectiveParams.clarify === true
|
|
276
|
+
&& ctx.hasUI
|
|
277
|
+
&& !(effectiveParams.chain?.some(isParallelStep) ?? false);
|
|
278
|
+
const validationError = validateExecutionInput(effectiveParams, agents, hasChain, hasTasks, hasSingle, allowClarifyTaskPrompt);
|
|
279
|
+
if (validationError)
|
|
280
|
+
return validationError;
|
|
281
|
+
if (invocationContext === "fork") {
|
|
282
|
+
let availableModels;
|
|
283
|
+
try {
|
|
284
|
+
availableModels = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
return toExecutionErrorResult(effectiveParams, error, invocationContext);
|
|
288
|
+
}
|
|
289
|
+
const forkModelPolicyError = validateForkContextModelPolicy(effectiveParams, discoveredAgents, (model) => resolveModelCandidate(model, availableModels, ctx.model?.provider));
|
|
290
|
+
if (forkModelPolicyError) {
|
|
291
|
+
return toExecutionErrorResult(effectiveParams, new Error(forkModelPolicyError), invocationContext);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
const clarified = await clarifyInvocation({ params: effectiveParams, agents, ctx, cwd: effectiveCwd, runId });
|
|
296
|
+
if (!clarified)
|
|
297
|
+
return { content: [{ type: "text", text: "Cancelled" }], details: { mode: hasChain ? "chain" : hasTasks ? "parallel" : "single", results: [] } };
|
|
298
|
+
effectiveParams = clarified;
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
return toExecutionErrorResult(effectiveParams, error, invocationContext);
|
|
302
|
+
}
|
|
303
|
+
if (signal?.aborted)
|
|
304
|
+
return toExecutionErrorResult(effectiveParams, new Error("Subagent cancelled before launch."), invocationContext);
|
|
305
|
+
let sessionFileForIndex = () => undefined;
|
|
306
|
+
let forkSessionFileForAgentIndex = () => undefined;
|
|
307
|
+
try {
|
|
308
|
+
const forkContextResolver = createPerAgentForkContextResolver(ctx.sessionManager, resolveContextForIndex, {
|
|
309
|
+
resolveContextForAgentIndex: (agentName) => resolveContextForAgent(agentName),
|
|
310
|
+
});
|
|
311
|
+
sessionFileForIndex = forkContextResolver.sessionFileForIndex;
|
|
312
|
+
forkSessionFileForAgentIndex = forkContextResolver.sessionFileForAgentIndex;
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
return toExecutionErrorResult(effectiveParams, error, invocationContext);
|
|
316
|
+
}
|
|
317
|
+
const asyncMode = resolveAsyncExecutionMode(effectiveParams, deps.asyncByDefault);
|
|
318
|
+
const backgroundRequestedWhileClarifying = (hasChain || hasTasks) && asyncMode.backgroundRequestedWhileClarifying;
|
|
319
|
+
const effectiveAsync = asyncMode.effectiveAsync;
|
|
320
|
+
const foregroundTimeout = resolveForegroundTimeoutMs(effectiveParams);
|
|
321
|
+
if (foregroundTimeout.error)
|
|
322
|
+
return buildRequestedModeError(effectiveParams, foregroundTimeout.error);
|
|
323
|
+
if (effectiveAsync && foregroundTimeout.timeoutMs !== undefined) {
|
|
324
|
+
return buildRequestedModeError(effectiveParams, "timeoutMs/maxRuntimeMs only applies to foreground subagent runs. Set async:false or use action:'interrupt' for background runs.");
|
|
325
|
+
}
|
|
326
|
+
if (!effectiveAsync)
|
|
327
|
+
foregroundTimeout.timeoutMs = normalizeRoleForegroundTimeout(effectiveParams, foregroundTimeout.timeoutMs);
|
|
328
|
+
const controlConfig = resolveControlConfig(deps.config.control, effectiveParams.control);
|
|
329
|
+
const artifactsEnabled = effectiveParams.artifacts !== false;
|
|
330
|
+
const artifactsDir = effectiveAsync ? deps.tempArtifactsDir : getArtifactsDir(parentSessionFile);
|
|
331
|
+
let sessionRoot;
|
|
332
|
+
if (effectiveParams.sessionDir) {
|
|
333
|
+
sessionRoot = path.resolve(deps.expandTilde(effectiveParams.sessionDir));
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const baseSessionRoot = deps.config.defaultSessionDir
|
|
337
|
+
? path.resolve(deps.expandTilde(deps.config.defaultSessionDir))
|
|
338
|
+
: deps.getSubagentSessionRoot(parentSessionFile);
|
|
339
|
+
sessionRoot = path.join(baseSessionRoot, runId);
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
fs.mkdirSync(sessionRoot, { recursive: true });
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
346
|
+
return toExecutionErrorResult(effectiveParams, new Error(`Failed to create session directory '${sessionRoot}': ${message}`), invocationContext);
|
|
347
|
+
}
|
|
348
|
+
const sessionDirForIndex = (idx) => path.join(sessionRoot, `run-${idx ?? 0}`);
|
|
349
|
+
const childSessionFileForIndex = (idx) => sessionFileForIndex(idx) ?? path.join(sessionDirForIndex(idx), "session.jsonl");
|
|
350
|
+
const childSessionFileForAgentIndex = (agentName, idx) => forkSessionFileForAgentIndex(agentName, idx) ?? path.join(sessionDirForIndex(idx), "session.jsonl");
|
|
351
|
+
const workflowGraph = effectiveParams.chain ? buildWorkflowGraphSnapshot({ runId, steps: effectiveParams.chain }) : undefined;
|
|
352
|
+
const assignmentNodes = workflowGraph && workflowAgentNodes(workflowGraph);
|
|
353
|
+
const onUpdateWithContext = (r) => {
|
|
354
|
+
const owned = deps.state.ownedRuns?.get(runId);
|
|
355
|
+
if (owned && r.details.workflowGraph)
|
|
356
|
+
rememberOwnedRun(deps.state, { ...owned, children: workflowChildren(owned.children, r.details.workflowGraph) });
|
|
357
|
+
onUpdate?.(withForkContext(r, invocationContext));
|
|
358
|
+
};
|
|
359
|
+
const assignments = effectiveParams.tasks ?? effectiveParams.chain?.flatMap((step) => isParallelStep(step) ? step.parallel : isDynamicParallelStep(step) ? [step.parallel] : [step])
|
|
360
|
+
?? [{ agent: effectiveParams.agent, task: effectiveParams.task, label: effectiveParams.label }];
|
|
361
|
+
saveQuestionOwner(runId, ctx.sessionManager.getSessionId());
|
|
362
|
+
const execData = {
|
|
363
|
+
params: effectiveParams,
|
|
364
|
+
effectiveCwd,
|
|
365
|
+
ctx,
|
|
366
|
+
signal,
|
|
367
|
+
onUpdate: onUpdateWithContext,
|
|
368
|
+
agents,
|
|
369
|
+
runId,
|
|
370
|
+
shareEnabled,
|
|
371
|
+
sessionRoot,
|
|
372
|
+
sessionDirForIndex,
|
|
373
|
+
sessionFileForIndex: childSessionFileForIndex,
|
|
374
|
+
sessionFileForAgentIndex: childSessionFileForAgentIndex,
|
|
375
|
+
artifactsEnabled,
|
|
376
|
+
artifactsDir,
|
|
377
|
+
backgroundRequestedWhileClarifying,
|
|
378
|
+
effectiveAsync,
|
|
379
|
+
...(foregroundTimeout.timeoutMs !== undefined ? { foregroundTimeoutMs: foregroundTimeout.timeoutMs } : {}),
|
|
380
|
+
controlConfig,
|
|
381
|
+
intercomBridge,
|
|
382
|
+
nestedRoute,
|
|
383
|
+
};
|
|
384
|
+
try {
|
|
385
|
+
const result = runAsyncPath(execData, deps);
|
|
386
|
+
if (!result)
|
|
387
|
+
throw new Error("Invalid subagent execution mode.");
|
|
388
|
+
if (result.isError)
|
|
389
|
+
return withForkContext(result, invocationContext);
|
|
390
|
+
rememberOwnedRun(deps.state, {
|
|
391
|
+
runId, ownerSessionId: ctx.sessionManager.getSessionId(), rootRunId: runId,
|
|
392
|
+
source: "async", mode: hasChain ? "chain" : hasTasks ? "parallel" : "single",
|
|
393
|
+
cwd: effectiveCwd, task: effectiveParams.task ?? effectiveParams.tasks?.map((task) => task.task).join("\n") ?? "Delegated workflow",
|
|
394
|
+
asyncDir: result.details.asyncDir, pid: result.details.asyncPid ?? deps.state.asyncJobs.get(runId)?.pid,
|
|
395
|
+
startedAt: Date.now(), children: assignments.map(({ agent, task, label }, index) => ({ agent, index, task, label, ...(assignmentNodes?.[index] ? { workflowNodeId: assignmentNodes[index].id } : {}) })),
|
|
396
|
+
});
|
|
397
|
+
if (!effectiveAsync && result.details.asyncId) {
|
|
398
|
+
return withForkContext(await waitForOwnedRun({ id: runId, deps, ctx, signal, onUpdate: onUpdateWithContext,
|
|
399
|
+
cancelNewRun: !effectiveAsync, executionResult: true, includeProgress: effectiveParams.includeProgress }), invocationContext);
|
|
400
|
+
}
|
|
401
|
+
return withForkContext(result, invocationContext);
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
const result = toExecutionErrorResult(effectiveParams, error, invocationContext);
|
|
405
|
+
const owned = deps.state.ownedRuns?.get(runId);
|
|
406
|
+
if (owned)
|
|
407
|
+
rememberOwnedRun(deps.state, { ...owned, error: result.content.filter((part) => part.type === "text").map((part) => part.text).join("\n") });
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
return { execute: async (...args) => {
|
|
412
|
+
const [id, params, signal, onUpdate, ctx, executionCwd] = args;
|
|
413
|
+
const waiting = params.async === false && (params.action === "resume" || params.action === "answer");
|
|
414
|
+
const before = waiting ? new Set(deps.state.ownedRuns?.keys()) : undefined;
|
|
415
|
+
let result = await execute(id, params, signal, onUpdate, ctx, executionCwd);
|
|
416
|
+
// Launch/answer receipts and claims are saved before waiting; execution failure must not undo a successful launch.
|
|
417
|
+
if (waiting && !result.isError) {
|
|
418
|
+
const question = result.details.questions?.find((question) => question.delivery || question.state === "answer_pending");
|
|
419
|
+
const id = result.details.asyncId ?? result.details.managementControl?.runId ?? question?.delivery?.runId ?? question?.runId ?? params.id ?? params.runId;
|
|
420
|
+
const index = result.details.asyncId || question?.delivery?.kind === "revive" ? 0
|
|
421
|
+
: result.details.managementControl?.nextActions.find((action) => action.index !== undefined)?.index ?? question?.index ?? params.index;
|
|
422
|
+
if (id)
|
|
423
|
+
return waitForOwnedRun({ id, index, deps, ctx, signal, onUpdate, cancelNewRun: params.async === false && !before?.has(id) && deps.state.ownedRuns?.has(id), executionResult: true, includeProgress: params.includeProgress });
|
|
424
|
+
}
|
|
425
|
+
if (args[1].action === "interrupt")
|
|
426
|
+
return cancelSupervisorInput(result, args[1], args[4].sessionManager.getSessionId(), deps.pi.events);
|
|
427
|
+
if (args[1].action !== "status" || result.details.runList)
|
|
428
|
+
return result;
|
|
429
|
+
const requested = args[1].id ?? args[1].runId;
|
|
430
|
+
if (requested && !args[1].dir) {
|
|
431
|
+
try {
|
|
432
|
+
const owned = resolveOwnedRun(deps.state, requested);
|
|
433
|
+
if (owned)
|
|
434
|
+
result = ownedRunStatusResult(owned, deps.state, result, { full: args[1].full, childSafe: Boolean(nestedResolutionScopeForExecutor(deps)) });
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return projectSupervisorQuestions(result, args[1], args[4].sessionManager.getSessionId(), Boolean(nestedResolutionScopeForExecutor(deps)));
|
|
441
|
+
} };
|
|
442
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import {} from "../../agents/agents.js";
|
|
2
|
+
import { materializeAgentDefaultOutputPath, normalizeSingleOutputOverride } from "../shared/single-output.js";
|
|
3
|
+
import {} from "../../shared/settings.js";
|
|
4
|
+
import {} from "../../shared/types.js";
|
|
5
|
+
export function maxParallelTasksMessage(maxParallelTasks) {
|
|
6
|
+
return `Max ${maxParallelTasks} tasks. Split the batch into smaller parallel calls or raise parallel.maxTasks in ~/.pi/agent/extensions/subagent/config.json.`;
|
|
7
|
+
}
|
|
8
|
+
export function isRecord(value) {
|
|
9
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
function isTaskParamLike(value) {
|
|
12
|
+
return isRecord(value) && typeof value.agent === "string";
|
|
13
|
+
}
|
|
14
|
+
function isDynamicParallelStepLike(value) {
|
|
15
|
+
return isRecord(value)
|
|
16
|
+
&& isRecord(value.expand)
|
|
17
|
+
&& isRecord(value.parallel)
|
|
18
|
+
&& typeof value.parallel.agent === "string"
|
|
19
|
+
&& isRecord(value.collect)
|
|
20
|
+
&& typeof value.collect.as === "string";
|
|
21
|
+
}
|
|
22
|
+
function isParallelStepLike(value) {
|
|
23
|
+
return isRecord(value) && Array.isArray(value.parallel) && value.parallel.every(isTaskParamLike);
|
|
24
|
+
}
|
|
25
|
+
function isSequentialStepLike(value) {
|
|
26
|
+
return isRecord(value) && typeof value.agent === "string";
|
|
27
|
+
}
|
|
28
|
+
function isChainStepLike(value) {
|
|
29
|
+
if (!isRecord(value))
|
|
30
|
+
return false;
|
|
31
|
+
return isDynamicParallelStepLike(value) || isParallelStepLike(value) || isSequentialStepLike(value);
|
|
32
|
+
}
|
|
33
|
+
export function resolveAsyncExecutionMode(params, asyncByDefault) {
|
|
34
|
+
const hasForegroundTimeout = params.timeoutMs !== undefined || params.maxRuntimeMs !== undefined;
|
|
35
|
+
const requestedAsync = params.async ?? (hasForegroundTimeout ? false : asyncByDefault);
|
|
36
|
+
return {
|
|
37
|
+
effectiveAsync: requestedAsync && params.clarify !== true,
|
|
38
|
+
backgroundRequestedWhileClarifying: params.async === true && params.clarify === true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function stringValue(params, key) {
|
|
42
|
+
const value = params[key];
|
|
43
|
+
return typeof value === "string" ? value : undefined;
|
|
44
|
+
}
|
|
45
|
+
function booleanValue(params, key) {
|
|
46
|
+
const value = params[key];
|
|
47
|
+
return typeof value === "boolean" ? value : undefined;
|
|
48
|
+
}
|
|
49
|
+
function numberValue(params, key) {
|
|
50
|
+
const value = params[key];
|
|
51
|
+
return typeof value === "number" ? value : undefined;
|
|
52
|
+
}
|
|
53
|
+
function contextValue(params) {
|
|
54
|
+
const value = params.context;
|
|
55
|
+
return value === "fresh" || value === "fork" ? value : undefined;
|
|
56
|
+
}
|
|
57
|
+
function outputModeValue(params) {
|
|
58
|
+
const value = params.outputMode;
|
|
59
|
+
return value === "inline" || value === "file-only" ? value : undefined;
|
|
60
|
+
}
|
|
61
|
+
function outputValue(params) {
|
|
62
|
+
const value = params.output;
|
|
63
|
+
return typeof value === "string" || typeof value === "boolean" ? value : undefined;
|
|
64
|
+
}
|
|
65
|
+
export function usesAgentDefaultOutput(output) {
|
|
66
|
+
return output === undefined || output === true || output === "true";
|
|
67
|
+
}
|
|
68
|
+
export function resolveTopLevelOutputOverride(params) {
|
|
69
|
+
const effectiveOutput = usesAgentDefaultOutput(params.requestedOutput)
|
|
70
|
+
? normalizeSingleOutputOverride(true, params.agentDefaultOutput)
|
|
71
|
+
: normalizeSingleOutputOverride(params.requestedOutput, params.agentDefaultOutput);
|
|
72
|
+
if (!usesAgentDefaultOutput(params.requestedOutput))
|
|
73
|
+
return effectiveOutput;
|
|
74
|
+
return materializeAgentDefaultOutputPath({
|
|
75
|
+
output: effectiveOutput,
|
|
76
|
+
artifactsDir: params.artifactsDir,
|
|
77
|
+
runId: params.runId,
|
|
78
|
+
agent: params.agent,
|
|
79
|
+
index: params.index,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function skillValue(params) {
|
|
83
|
+
const value = params.skill;
|
|
84
|
+
if (typeof value === "string" || typeof value === "boolean")
|
|
85
|
+
return value;
|
|
86
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
|
|
87
|
+
}
|
|
88
|
+
function maxOutputValue(params) {
|
|
89
|
+
const value = params.maxOutput;
|
|
90
|
+
if (!isRecord(value))
|
|
91
|
+
return undefined;
|
|
92
|
+
return {
|
|
93
|
+
...(typeof value.bytes === "number" ? { bytes: value.bytes } : {}),
|
|
94
|
+
...(typeof value.lines === "number" ? { lines: value.lines } : {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function isControlConfig(value) {
|
|
98
|
+
return isRecord(value);
|
|
99
|
+
}
|
|
100
|
+
function isAcceptanceInput(value) {
|
|
101
|
+
return isRecord(value);
|
|
102
|
+
}
|
|
103
|
+
export function normalizeSubagentParamsLike(params) {
|
|
104
|
+
const normalized = {
|
|
105
|
+
action: stringValue(params, "action"),
|
|
106
|
+
id: stringValue(params, "id"),
|
|
107
|
+
runId: stringValue(params, "runId"),
|
|
108
|
+
questionId: stringValue(params, "questionId"),
|
|
109
|
+
decision: params.decision === "accepted" || params.decision === "needs_changes" ? params.decision : undefined,
|
|
110
|
+
offset: numberValue(params, "offset"),
|
|
111
|
+
limit: numberValue(params, "limit"),
|
|
112
|
+
cursor: stringValue(params, "cursor"),
|
|
113
|
+
sort: ["attention", "newest", "oldest", "relevance"].includes(String(params.sort)) ? params.sort : undefined,
|
|
114
|
+
state: ["live", "completed", "failed", "blocked", "paused", "unknown"].includes(String(params.state)) ? params.state : undefined,
|
|
115
|
+
text: stringValue(params, "text"),
|
|
116
|
+
query: stringValue(params, "query"),
|
|
117
|
+
before: numberValue(params, "before"),
|
|
118
|
+
full: booleanValue(params, "full"),
|
|
119
|
+
dir: stringValue(params, "dir"),
|
|
120
|
+
index: numberValue(params, "index"),
|
|
121
|
+
agent: stringValue(params, "agent"),
|
|
122
|
+
task: stringValue(params, "task"),
|
|
123
|
+
label: stringValue(params, "label"),
|
|
124
|
+
message: stringValue(params, "message"),
|
|
125
|
+
concurrency: numberValue(params, "concurrency"),
|
|
126
|
+
timeoutMs: numberValue(params, "timeoutMs"),
|
|
127
|
+
maxRuntimeMs: numberValue(params, "maxRuntimeMs"),
|
|
128
|
+
extendMs: numberValue(params, "extendMs"),
|
|
129
|
+
worktree: booleanValue(params, "worktree"),
|
|
130
|
+
context: contextValue(params),
|
|
131
|
+
async: booleanValue(params, "async"),
|
|
132
|
+
clarify: booleanValue(params, "clarify"),
|
|
133
|
+
share: booleanValue(params, "share"),
|
|
134
|
+
control: isControlConfig(params.control) ? params.control : undefined,
|
|
135
|
+
sessionDir: stringValue(params, "sessionDir"),
|
|
136
|
+
cwd: stringValue(params, "cwd"),
|
|
137
|
+
maxOutput: maxOutputValue(params),
|
|
138
|
+
artifacts: booleanValue(params, "artifacts"),
|
|
139
|
+
includeProgress: booleanValue(params, "includeProgress"),
|
|
140
|
+
progress: booleanValue(params, "progress"),
|
|
141
|
+
model: stringValue(params, "model"),
|
|
142
|
+
skill: skillValue(params),
|
|
143
|
+
output: outputValue(params),
|
|
144
|
+
outputMode: outputModeValue(params),
|
|
145
|
+
outputSchema: isRecord(params.outputSchema) ? params.outputSchema : undefined,
|
|
146
|
+
agentScope: stringValue(params, "agentScope"),
|
|
147
|
+
chainName: stringValue(params, "chainName"),
|
|
148
|
+
config: params.config,
|
|
149
|
+
chainDir: stringValue(params, "chainDir"),
|
|
150
|
+
acceptance: isAcceptanceInput(params.acceptance) ? params.acceptance : undefined,
|
|
151
|
+
};
|
|
152
|
+
if (params.tasks !== undefined) {
|
|
153
|
+
if (!Array.isArray(params.tasks) || !params.tasks.every(isTaskParamLike)) {
|
|
154
|
+
throw new Error("tasks must be an array of task objects with an agent.");
|
|
155
|
+
}
|
|
156
|
+
normalized.tasks = params.tasks;
|
|
157
|
+
}
|
|
158
|
+
if (params.chain !== undefined) {
|
|
159
|
+
if (!Array.isArray(params.chain) || !params.chain.every(isChainStepLike)) {
|
|
160
|
+
throw new Error("chain must contain valid sequential, parallel, or dynamic fanout steps.");
|
|
161
|
+
}
|
|
162
|
+
normalized.chain = params.chain;
|
|
163
|
+
}
|
|
164
|
+
return normalized;
|
|
165
|
+
}
|