pi-subagents 0.58.0 → 0.59.0
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 +65 -0
- package/docs/agents.md +5 -3
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +1 -1
- package/docs/models.md +24 -1
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +89 -4
- package/docs/workflows.md +93 -2
- package/package.json +3 -1
- package/prompts/review-loop.md +2 -2
- package/skills/council-mode/SKILL.md +1 -1
- package/skills/pi-subagents/SKILL.md +1 -1
- package/skills/pi-subagents/references/execution-controls.md +5 -1
- package/skills/pi-subagents/references/management-authoring-rpc.md +1 -2
- package/skills/pi-subagents/references/prompting-and-roles.md +24 -3
- package/src/agents/agent-management.ts +5 -17
- package/src/agents/agent-serializer.ts +4 -2
- package/src/agents/agents.ts +67 -26
- package/src/agents/runtime-agent-registry.ts +9 -16
- package/src/api/background-work.ts +5 -1
- package/src/api/delegation.ts +0 -7
- package/src/api/preflight.ts +6 -9
- package/src/extension/fanout-child.ts +5 -3
- package/src/extension/index.ts +51 -23
- package/src/extension/public-execution.ts +15 -2
- package/src/extension/schemas.ts +35 -10
- package/src/extension/tool-description.ts +18 -3
- package/src/intercom/result-intercom.ts +2 -0
- package/src/profiles/profiles.ts +5 -6
- package/src/runs/background/active-async-capacity.ts +2 -2
- package/src/runs/background/async-execution.ts +50 -35
- package/src/runs/background/async-job-tracker.ts +14 -12
- package/src/runs/background/async-resume.ts +23 -25
- package/src/runs/background/async-status-snapshot.ts +23 -261
- package/src/runs/background/async-status.ts +66 -7
- package/src/runs/background/chain-append.ts +6 -3
- package/src/runs/background/chain-root-attachment.ts +60 -8
- package/src/runs/background/fleet-view.ts +21 -11
- package/src/runs/background/notify.ts +158 -6
- package/src/runs/background/result-files.ts +2 -1
- package/src/runs/background/result-watcher.ts +2 -0
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/retained-children.ts +1 -1
- package/src/runs/background/run-status.ts +18 -8
- package/src/runs/background/scheduled-runs.ts +86 -7
- package/src/runs/background/stale-run-reconciler.ts +10 -4
- package/src/runs/background/steering.ts +4 -14
- package/src/runs/background/subagent-runner.ts +346 -357
- package/src/runs/background/subagent-wait.ts +58 -10
- package/src/runs/background/terminal-run-index.ts +1 -1
- package/src/runs/background/wait-completions.ts +22 -1
- package/src/runs/background/wait-config.ts +23 -9
- package/src/runs/background/wait-tool.ts +9 -2
- package/src/runs/foreground/async-steering-action.ts +2 -2
- package/src/runs/foreground/execution.ts +114 -120
- package/src/runs/foreground/foreground-control.ts +3 -0
- package/src/runs/foreground/foreground-history.ts +1 -0
- package/src/runs/foreground/subagent-executor.ts +478 -239
- package/src/runs/foreground/workflow-detach-reconcile.ts +99 -200
- package/src/runs/shared/abort-recovery.ts +119 -0
- package/src/runs/shared/async-status-projection.ts +463 -0
- package/src/runs/shared/child-identity.ts +19 -4
- package/src/runs/shared/child-launch-plan.ts +151 -0
- package/src/runs/shared/completion-evidence.ts +89 -0
- package/src/runs/shared/completion-guard.ts +1 -1
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/host-step-status.ts +230 -0
- package/src/runs/shared/lane-metadata.ts +105 -0
- package/src/runs/shared/mcp-config-sources.ts +42 -6
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +93 -143
- package/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/src/runs/shared/model-fallback.ts +9 -2
- package/src/runs/shared/nested-events.ts +6 -2
- package/src/runs/shared/nested-render.ts +7 -3
- package/src/runs/shared/parallel-handoff.ts +419 -7
- package/src/runs/shared/parallel-utils.ts +7 -0
- package/src/runs/shared/pi-args.ts +20 -2
- package/src/runs/shared/single-output.ts +27 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +13 -4
- package/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/src/runs/shared/worktree.ts +18 -0
- package/src/shared/child-session-name.ts +46 -0
- package/src/shared/extension-context.ts +24 -0
- package/src/shared/formatters.ts +5 -2
- package/src/shared/launch-contract.ts +1 -1
- package/src/shared/settings.ts +9 -103
- package/src/shared/types.ts +198 -29
- package/src/shared/utils.ts +35 -55
- package/src/slash/delegation-adapters.ts +1 -8
- package/src/slash/delegation-request.ts +0 -4
- package/src/slash/slash-bridge.ts +1 -2
- package/src/slash/slash-commands.ts +369 -90
- package/src/slash/slash-live-state.ts +22 -11
- package/src/tui/fleet-status.ts +125 -74
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render.ts +316 -27
- package/src/watchdog/turn-delta.ts +1 -1
- package/src/workflows/chat-progress.ts +6 -3
- package/src/workflows/host-command.ts +230 -0
- package/src/workflows/scripted-workflow.ts +452 -38
- package/src/workflows/workflow-child-summary.ts +9 -5
- package/src/workflows/workflow-preflight.ts +270 -0
- package/src/workflows/workflow-receipt.ts +43 -4
- package/src/workflows/workflow-settlement.ts +246 -0
- package/src/runs/shared/turn-budget.ts +0 -98
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
encodeChildWatchdogConfig,
|
|
49
49
|
type ChildWatchdogConfig,
|
|
50
50
|
} from "../../watchdog/child-status.ts";
|
|
51
|
-
import { WAIT_TOOL_ENABLED_ENV } from "../background/wait-config.ts";
|
|
51
|
+
import { WAIT_TOOL_DEFAULT_TIMEOUT_MS_ENV, WAIT_TOOL_ENABLED_ENV } from "../background/wait-config.ts";
|
|
52
52
|
import {
|
|
53
53
|
PI_CODING_AGENT_PACKAGE_ROOT_ENV,
|
|
54
54
|
getAgentDir,
|
|
@@ -170,6 +170,11 @@ export interface BuildPiArgsInput {
|
|
|
170
170
|
cwd?: string;
|
|
171
171
|
promptFileStem?: string;
|
|
172
172
|
intercomSessionName?: string;
|
|
173
|
+
/** Human-readable display name for the child session (agent + task excerpt,
|
|
174
|
+
* derived by the caller). Passed to the child as PI_SUBAGENT_SESSION_NAME;
|
|
175
|
+
* the prompt runtime applies it via pi.setSessionName unless an intercom
|
|
176
|
+
* target takes precedence. */
|
|
177
|
+
sessionName?: string;
|
|
173
178
|
orchestratorIntercomTarget?: string;
|
|
174
179
|
runId?: string;
|
|
175
180
|
childAgentName?: string;
|
|
@@ -206,6 +211,8 @@ export interface BuildPiArgsInput {
|
|
|
206
211
|
*/
|
|
207
212
|
taskDelivery?: SubagentTaskDelivery;
|
|
208
213
|
waitToolEnabled?: boolean;
|
|
214
|
+
waitToolDefaultTimeoutMs?: number;
|
|
215
|
+
allowNestedSubagents?: boolean;
|
|
209
216
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
210
217
|
thinkingCeiling?: import("../../shared/model-info.ts").ThinkingLevel;
|
|
211
218
|
extensionBindings?: ExtensionBindings;
|
|
@@ -283,6 +290,7 @@ function resolveFastModeExtension(input: Pick<ResolvePiLaunchToolPlanInput, "fas
|
|
|
283
290
|
|
|
284
291
|
export interface ResolvePiLaunchToolPlanInput {
|
|
285
292
|
tools?: string[];
|
|
293
|
+
allowNestedSubagents?: boolean;
|
|
286
294
|
extensions?: string[];
|
|
287
295
|
subagentOnlyExtensions?: string[];
|
|
288
296
|
mcpDirectTools?: string[];
|
|
@@ -481,7 +489,10 @@ export function resolvePiLaunchToolPlan(
|
|
|
481
489
|
? ["read", ...requestedBuiltinTools]
|
|
482
490
|
: requestedBuiltinTools
|
|
483
491
|
).filter((tool) => !allowedToolSet || allowedToolSet.has(tool));
|
|
484
|
-
const fanoutAuthorized = declaredBuiltinTools.includes("subagent")
|
|
492
|
+
const fanoutAuthorized = declaredBuiltinTools.includes("subagent") || (
|
|
493
|
+
input.allowNestedSubagents === true &&
|
|
494
|
+
(!allowedToolSet || allowedToolSet.has("subagent"))
|
|
495
|
+
);
|
|
485
496
|
const toolExtensionPaths: string[] = capabilityCeiling?.denyExtensions
|
|
486
497
|
? []
|
|
487
498
|
: (input.tools ?? []).filter(
|
|
@@ -684,6 +695,7 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
684
695
|
|
|
685
696
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
686
697
|
tools: input.tools,
|
|
698
|
+
allowNestedSubagents: input.allowNestedSubagents,
|
|
687
699
|
extensions: input.extensions,
|
|
688
700
|
subagentOnlyExtensions: input.subagentOnlyExtensions,
|
|
689
701
|
mcpDirectTools: input.mcpDirectTools,
|
|
@@ -795,6 +807,9 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
795
807
|
if (input.waitToolEnabled !== undefined) {
|
|
796
808
|
env[WAIT_TOOL_ENABLED_ENV] = input.waitToolEnabled ? "true" : "false";
|
|
797
809
|
}
|
|
810
|
+
if (input.waitToolDefaultTimeoutMs !== undefined) {
|
|
811
|
+
env[WAIT_TOOL_DEFAULT_TIMEOUT_MS_ENV] = String(input.waitToolDefaultTimeoutMs);
|
|
812
|
+
}
|
|
798
813
|
const inheritedNestedRoute = Boolean(
|
|
799
814
|
process.env[SUBAGENT_PARENT_EVENT_SINK_ENV] &&
|
|
800
815
|
process.env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] &&
|
|
@@ -878,6 +893,9 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
878
893
|
if (input.intercomSessionName) {
|
|
879
894
|
env.PI_SUBAGENT_INTERCOM_SESSION_NAME = input.intercomSessionName;
|
|
880
895
|
}
|
|
896
|
+
if (input.sessionName?.trim()) {
|
|
897
|
+
env.PI_SUBAGENT_SESSION_NAME = input.sessionName.trim();
|
|
898
|
+
}
|
|
881
899
|
if (input.orchestratorIntercomTarget) {
|
|
882
900
|
env[SUBAGENT_ORCHESTRATOR_TARGET_ENV] = input.orchestratorIntercomTarget;
|
|
883
901
|
}
|
|
@@ -161,6 +161,23 @@ export function validateFileOnlyOutputMode(outputMode: OutputMode | undefined, o
|
|
|
161
161
|
return undefined;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
export function resolveSingleOutputClaimPath(outputPath: string): string {
|
|
165
|
+
let existing = path.resolve(outputPath);
|
|
166
|
+
const missingSegments: string[] = [];
|
|
167
|
+
while (!fs.existsSync(existing)) {
|
|
168
|
+
missingSegments.unshift(path.basename(existing));
|
|
169
|
+
const parent = path.dirname(existing);
|
|
170
|
+
if (parent === existing) break;
|
|
171
|
+
existing = parent;
|
|
172
|
+
}
|
|
173
|
+
return path.join(fs.realpathSync(existing), ...missingSegments);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function outputClaimError(outputPath: string, expectedClaimPath: string | undefined): string | undefined {
|
|
177
|
+
if (expectedClaimPath && resolveSingleOutputClaimPath(outputPath) !== expectedClaimPath) return "Output path changed after it was claimed.";
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
164
181
|
export function captureSingleOutputSnapshot(outputPath: string | undefined): SingleOutputSnapshot | undefined {
|
|
165
182
|
if (!outputPath) return undefined;
|
|
166
183
|
try {
|
|
@@ -175,9 +192,12 @@ export function captureSingleOutputSnapshot(outputPath: string | undefined): Sin
|
|
|
175
192
|
function persistSingleOutput(
|
|
176
193
|
outputPath: string | undefined,
|
|
177
194
|
fullOutput: string,
|
|
178
|
-
|
|
195
|
+
expectedClaimPath?: string,
|
|
196
|
+
): { savedPath?: string; error?: string; fatalError?: boolean } {
|
|
179
197
|
if (!outputPath) return {};
|
|
180
198
|
try {
|
|
199
|
+
const claimError = outputClaimError(outputPath, expectedClaimPath);
|
|
200
|
+
if (claimError) return { error: claimError, fatalError: true };
|
|
181
201
|
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
182
202
|
fs.writeFileSync(outputPath, fullOutput, "utf-8");
|
|
183
203
|
return { savedPath: outputPath };
|
|
@@ -190,8 +210,11 @@ export function resolveSingleOutput(
|
|
|
190
210
|
outputPath: string | undefined,
|
|
191
211
|
fallbackOutput: string,
|
|
192
212
|
beforeRun: SingleOutputSnapshot | undefined,
|
|
193
|
-
|
|
213
|
+
expectedClaimPath?: string,
|
|
214
|
+
): { fullOutput: string; savedPath?: string; saveError?: string; fatalError?: boolean } {
|
|
194
215
|
if (!outputPath) return { fullOutput: fallbackOutput };
|
|
216
|
+
const claimError = outputClaimError(outputPath, expectedClaimPath);
|
|
217
|
+
if (claimError) return { fullOutput: fallbackOutput, saveError: claimError, fatalError: true };
|
|
195
218
|
|
|
196
219
|
let changedSinceStart = false;
|
|
197
220
|
try {
|
|
@@ -220,9 +243,9 @@ export function resolveSingleOutput(
|
|
|
220
243
|
}
|
|
221
244
|
}
|
|
222
245
|
|
|
223
|
-
const save = persistSingleOutput(outputPath, fallbackOutput);
|
|
246
|
+
const save = persistSingleOutput(outputPath, fallbackOutput, expectedClaimPath);
|
|
224
247
|
if (save.savedPath) return { fullOutput: fallbackOutput, savedPath: save.savedPath };
|
|
225
|
-
return { fullOutput: fallbackOutput, saveError: save.error };
|
|
248
|
+
return { fullOutput: fallbackOutput, saveError: save.error, ...(save.fatalError ? { fatalError: true } : {}) };
|
|
226
249
|
}
|
|
227
250
|
|
|
228
251
|
export function finalizeSingleOutput(params: {
|
|
@@ -32,6 +32,9 @@ import { drainOutstandingWork } from "../background/auto-drain.ts";
|
|
|
32
32
|
const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = "PI_SUBAGENT_INHERIT_PROJECT_CONTEXT";
|
|
33
33
|
const SUBAGENT_INHERIT_SKILLS_ENV = "PI_SUBAGENT_INHERIT_SKILLS";
|
|
34
34
|
export const SUBAGENT_INTERCOM_SESSION_NAME_ENV = "PI_SUBAGENT_INTERCOM_SESSION_NAME";
|
|
35
|
+
/** Human-readable child display name (agent + task excerpt) set by the parent
|
|
36
|
+
* at launch; applied via pi.setSessionName when no intercom target exists. */
|
|
37
|
+
export const SUBAGENT_SESSION_NAME_ENV = "PI_SUBAGENT_SESSION_NAME";
|
|
35
38
|
const STEERING_LEGACY_SETTLE_FALLBACK_MS = 1000;
|
|
36
39
|
const STEERING_SAFETY_POLL_INTERVAL_MS = 5000;
|
|
37
40
|
|
|
@@ -288,6 +291,7 @@ const PORTABLE_TOOL_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
|
288
291
|
const MAX_PORTABLE_TOOL_ID_LENGTH = 64;
|
|
289
292
|
const COMPOSITE_TOOL_ID_APIS = new Set([
|
|
290
293
|
"azure-openai-responses",
|
|
294
|
+
"cursor-native",
|
|
291
295
|
"openai-completions",
|
|
292
296
|
"openai-responses",
|
|
293
297
|
]);
|
|
@@ -671,7 +675,7 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
|
671
675
|
registerPermissionGate(pi);
|
|
672
676
|
registerToolBudget(pi, decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV], { allowZero: process.env[TOOL_BUDGET_ZERO_AUTH_ENV] === "1" }));
|
|
673
677
|
registerChildWatchdog(pi);
|
|
674
|
-
const
|
|
678
|
+
const waitToolConfig = resolveWaitToolConfig();
|
|
675
679
|
const waitState = {
|
|
676
680
|
baseCwd: "",
|
|
677
681
|
currentSessionId: null,
|
|
@@ -686,7 +690,7 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
|
686
690
|
watcherRestartTimer: null,
|
|
687
691
|
resultFileCoalescer: { schedule: () => false, clear: () => {} },
|
|
688
692
|
} as unknown as SubagentState;
|
|
689
|
-
if (typeof pi.registerTool === "function") registerWaitTool(pi, waitState,
|
|
693
|
+
if (typeof pi.registerTool === "function") registerWaitTool(pi, waitState, waitToolConfig.enabled, undefined, waitToolConfig.defaultTimeoutMs);
|
|
690
694
|
let nativeSupervisorClientRegistered = false;
|
|
691
695
|
const registerNativeSupervisorClientOnce = (): void => {
|
|
692
696
|
if (nativeSupervisorClientRegistered) return;
|
|
@@ -756,9 +760,14 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
|
756
760
|
onRuntimeEvent("before_agent_start", async (event: unknown) => {
|
|
757
761
|
if (!event || typeof event !== "object" || !("systemPrompt" in event) || typeof event.systemPrompt !== "string") return undefined;
|
|
758
762
|
registerNativeSupervisorClientOnce();
|
|
763
|
+
// The intercom target is a routing address and always wins; the display
|
|
764
|
+
// name (agent + task excerpt, computed by the parent at launch) only
|
|
765
|
+
// applies when the bridge is not addressing this child.
|
|
759
766
|
const intercomSessionName = process.env[SUBAGENT_INTERCOM_SESSION_NAME_ENV]?.trim();
|
|
760
|
-
|
|
761
|
-
|
|
767
|
+
const displaySessionName = process.env[SUBAGENT_SESSION_NAME_ENV]?.trim();
|
|
768
|
+
const childSessionName = intercomSessionName || displaySessionName;
|
|
769
|
+
if (childSessionName && typeof pi.setSessionName === "function") {
|
|
770
|
+
pi.setSessionName(childSessionName);
|
|
762
771
|
}
|
|
763
772
|
|
|
764
773
|
const inheritProjectContext = readBooleanEnv(SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV);
|