pi-subagents 0.67.0 → 0.69.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 +90 -0
- package/README.md +1 -1
- package/docs/agents.md +41 -12
- package/docs/configuration.md +61 -19
- package/docs/extension-api.md +5 -1
- package/docs/missions.md +2 -2
- package/docs/models.md +11 -79
- package/docs/observability.md +18 -8
- package/docs/standalone-background.md +13 -3
- package/docs/tool-reference.md +38 -14
- package/docs/watchdog.md +10 -12
- package/docs/workflows.md +59 -1
- package/index.ts +5 -2
- package/package.json +4 -2
- package/runner-peer-loader.mjs +24 -0
- package/runner-peer-preload.mjs +25 -11
- package/skills/pi-subagents/SKILL.md +18 -21
- package/skills/pi-subagents/references/constraints-and-recipes.md +3 -2
- package/skills/pi-subagents/references/execution-controls.md +6 -4
- package/skills/pi-subagents/references/management-authoring-rpc.md +0 -1
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +16 -12
- package/skills/pi-subagents/references/review-and-validation.md +3 -3
- package/src/agents/agent-management.ts +57 -58
- package/src/agents/agent-serializer.ts +4 -3
- package/src/agents/agents.ts +185 -72
- package/src/agents/chain-serializer.ts +5 -0
- package/src/agents/runtime-agent-registry.ts +7 -6
- package/src/agents/skills.ts +1 -1
- package/src/api/preflight.ts +20 -16
- package/src/api/required-child-extensions.ts +6 -0
- package/src/extension/config.ts +10 -37
- package/src/extension/fanout-child.ts +3 -0
- package/src/extension/herdr-pi-bridge.ts +160 -0
- package/src/extension/index.ts +42 -31
- package/src/extension/public-execution.ts +3 -3
- package/src/extension/schemas.ts +23 -6
- package/src/extension/tool-description.ts +8 -7
- package/src/inspectors/ghostty/plugin.ts +13 -1
- package/src/intercom/native-supervisor-channel.ts +22 -18
- package/src/policy/authority.ts +4 -0
- package/src/profiles/profiles.ts +12 -6
- package/src/runs/background/active-run-index.ts +17 -1
- package/src/runs/background/async-execution.ts +309 -126
- package/src/runs/background/async-job-tracker.ts +8 -6
- package/src/runs/background/async-resume.ts +13 -4
- package/src/runs/background/async-status.ts +15 -4
- package/src/runs/background/auto-drain.ts +20 -10
- package/src/runs/background/binary-bootstrap.ts +5 -0
- package/src/runs/background/chain-append.ts +1 -1
- package/src/runs/background/chain-root-attachment.ts +14 -33
- package/src/runs/background/notify.ts +74 -6
- package/src/runs/background/result-files.ts +8 -4
- package/src/runs/background/result-watcher.ts +19 -2
- package/src/runs/background/run-child-session.ts +20 -29
- package/src/runs/background/runner-aliases.ts +4 -33
- package/src/runs/background/runner-child-launch.ts +4 -1
- package/src/runs/background/runner-child-sessions.ts +2 -2
- package/src/runs/background/runner-http-dispatcher.ts +119 -0
- package/src/runs/background/scheduled-runs.ts +11 -5
- package/src/runs/background/stale-run-reconciler.ts +35 -11
- package/src/runs/background/subagent-runner.ts +413 -276
- package/src/runs/background/subagent-wait.ts +128 -23
- package/src/runs/background/wait-completions.ts +75 -27
- package/src/runs/background/wait-subscriptions.ts +9 -3
- package/src/runs/background/wait-tool.ts +4 -2
- package/src/runs/foreground/async-stop-action.ts +93 -3
- package/src/runs/foreground/execution.ts +115 -219
- package/src/runs/foreground/foreground-history.ts +2 -1
- package/src/runs/foreground/subagent-executor.ts +281 -80
- package/src/runs/shared/acceptance.ts +194 -37
- package/src/runs/shared/async-status-projection.ts +123 -33
- package/src/runs/shared/child-launch-plan.ts +15 -3
- package/src/runs/shared/child-launch.ts +19 -6
- package/src/runs/shared/child-runtime-config.ts +5 -0
- package/src/runs/shared/child-session.ts +94 -50
- package/src/runs/shared/child-tool-plan.ts +28 -16
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/external-cli-contract.ts +11 -1
- package/src/runs/shared/external-cli-preflight.ts +6 -2
- package/src/runs/shared/herdr-connection.ts +134 -0
- package/src/runs/shared/herdr-external-adapters.ts +169 -0
- package/src/runs/shared/herdr-machine.ts +279 -0
- package/src/runs/shared/herdr-pi-protocol.ts +59 -0
- package/src/runs/shared/herdr-placed-run.ts +263 -0
- package/src/runs/shared/model-resolution-diagnostic.ts +76 -0
- package/src/runs/shared/{model-fallback.ts → model-resolution.ts} +22 -237
- package/src/runs/shared/model-scope.ts +1 -1
- package/src/runs/shared/nested-events.ts +11 -2
- package/src/runs/shared/parallel-utils.ts +7 -2
- package/src/runs/shared/pi-spawn.ts +1 -1
- package/src/runs/shared/subagent-prompt-runtime.ts +4 -2
- package/src/runs/shared/worktree-setup-command.ts +27 -4
- package/src/runs/shared/worktree.ts +30 -8
- package/src/shared/child-cache-retention.ts +43 -0
- package/src/shared/launch-contract.ts +6 -9
- package/src/shared/pruned-fork.ts +1 -1
- package/src/shared/required-child-extensions.ts +81 -0
- package/src/shared/settings.ts +5 -2
- package/src/shared/shortcuts.ts +0 -4
- package/src/shared/types.ts +81 -29
- package/src/slash/slash-commands.ts +0 -6
- package/src/slash/subagents-admin.ts +13 -9
- package/src/tui/render.ts +20 -10
- package/src/watchdog/child-status.ts +28 -36
- package/src/watchdog/lsp-diagnostics.ts +1 -1
- package/src/watchdog/model-selection.ts +1 -1
- package/src/watchdog/register-child.ts +10 -3
- package/src/watchdog/register-main.ts +20 -20
- package/src/watchdog/render.ts +1 -1
- package/src/watchdog/review.ts +14 -30
- package/src/watchdog/rules.ts +1 -1
- package/src/watchdog/runtime.ts +23 -12
- package/src/watchdog/settings.ts +3 -6
- package/src/watchdog/types.ts +3 -5
- package/src/watchdog/warning-format.ts +1 -1
- package/src/workflows/scripted-workflow.ts +68 -7
- package/src/workflows/workflow-receipt.ts +21 -3
- package/src/workflows/workflow-resources.ts +13 -2
- package/src/runs/shared/model-exclusions.ts +0 -374
- package/src/runs/shared/readonly-model-continuation.ts +0 -69
- package/src/runs/shared/readonly-session-evidence.ts +0 -307
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
1
2
|
import * as path from "node:path";
|
|
2
3
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
3
|
-
import
|
|
4
|
+
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
5
|
+
import { DIRS, type AsyncStatus, type Details, type SubagentState } from "../../shared/types.ts";
|
|
6
|
+
import { updateActiveRunIndex } from "../background/active-run-index.ts";
|
|
4
7
|
import { deliverStopRequest } from "../background/control-channel.ts";
|
|
8
|
+
import { readProcessTerminal } from "../background/process-terminal.ts";
|
|
9
|
+
import { resultFilePath, resultPayloadPathForSessionRun, writeAsyncResultFile } from "../background/result-files.ts";
|
|
5
10
|
import { reconcileAsyncRun } from "../background/stale-run-reconciler.ts";
|
|
6
11
|
import { isStoppableAsyncStatusStep, resolveAsyncStatusChild, type ResolvedAsyncStatusChild } from "../shared/child-identity.ts";
|
|
7
12
|
|
|
@@ -21,6 +26,80 @@ function getAsyncStopTarget(
|
|
|
21
26
|
return direct ? { asyncId: direct.asyncId, asyncDir: direct.asyncDir } : undefined;
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
const STOP_MESSAGE = "Subagent stopped by user.";
|
|
30
|
+
|
|
31
|
+
function sealPausedRun(asyncDir: string, status: AsyncStatus): string | undefined {
|
|
32
|
+
const runnerProcessInstanceId = status.processTerminal?.runnerProcessInstanceId;
|
|
33
|
+
if (!runnerProcessInstanceId) return "runner process identity is missing";
|
|
34
|
+
const proof = readProcessTerminal(asyncDir, { runId: status.runId, runnerProcessInstanceId });
|
|
35
|
+
if (proof?.state !== "observed" || proof.runId !== status.runId || proof.runnerProcessInstanceId !== runnerProcessInstanceId) {
|
|
36
|
+
return `process-terminal proof is ${proof?.state === "unknown" ? `unknown (${proof.reason})` : proof?.state ?? "missing"}`;
|
|
37
|
+
}
|
|
38
|
+
if (!status.sessionId) return "session identity is missing";
|
|
39
|
+
const existingResultPath = resultPayloadPathForSessionRun(DIRS.results, status.sessionId, status.runId);
|
|
40
|
+
if (!existingResultPath) return "paused result is missing";
|
|
41
|
+
let existingResult: Record<string, unknown>;
|
|
42
|
+
try {
|
|
43
|
+
const parsed: unknown = JSON.parse(fs.readFileSync(existingResultPath, "utf-8"));
|
|
44
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("result is not an object");
|
|
45
|
+
existingResult = parsed as Record<string, unknown>;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return `paused result is unavailable: ${error instanceof Error ? error.message : String(error)}`;
|
|
48
|
+
}
|
|
49
|
+
const resultRunId = typeof existingResult.runId === "string" ? existingResult.runId : existingResult.id;
|
|
50
|
+
if (resultRunId !== status.runId || existingResult.sessionId !== status.sessionId) {
|
|
51
|
+
return "paused result identity does not match the run";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
const steps = (status.steps ?? []).map((step) => {
|
|
56
|
+
if (step.status !== "pending" && step.status !== "running" && step.status !== "paused") return step;
|
|
57
|
+
const { activityState: _activityState, ...rest } = step;
|
|
58
|
+
return {
|
|
59
|
+
...rest,
|
|
60
|
+
status: "stopped" as const,
|
|
61
|
+
error: STOP_MESSAGE,
|
|
62
|
+
exitCode: 1,
|
|
63
|
+
stopped: true,
|
|
64
|
+
endedAt: now,
|
|
65
|
+
durationMs: step.startedAt ? now - step.startedAt : 0,
|
|
66
|
+
lastActivityAt: now,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
const results = Array.isArray(existingResult.results)
|
|
70
|
+
? existingResult.results.map((entry, index) => {
|
|
71
|
+
const stepState = status.steps?.[index]?.status;
|
|
72
|
+
if ((stepState !== "pending" && stepState !== "running" && stepState !== "paused") || !entry || typeof entry !== "object" || Array.isArray(entry)) return entry;
|
|
73
|
+
const { interrupted: _interrupted, ...result } = entry as Record<string, unknown>;
|
|
74
|
+
return { ...result, output: STOP_MESSAGE, error: STOP_MESSAGE, success: false, exitCode: 1, stopped: true };
|
|
75
|
+
})
|
|
76
|
+
: existingResult.results;
|
|
77
|
+
const stoppedResult = {
|
|
78
|
+
...existingResult,
|
|
79
|
+
success: false,
|
|
80
|
+
state: "stopped",
|
|
81
|
+
summary: STOP_MESSAGE,
|
|
82
|
+
error: STOP_MESSAGE,
|
|
83
|
+
stopped: true,
|
|
84
|
+
exitCode: 1,
|
|
85
|
+
timestamp: now,
|
|
86
|
+
...(Array.isArray(existingResult.results) ? { results } : {}),
|
|
87
|
+
};
|
|
88
|
+
const stoppedStatus: AsyncStatus = {
|
|
89
|
+
...status,
|
|
90
|
+
state: "stopped",
|
|
91
|
+
stopped: true,
|
|
92
|
+
error: STOP_MESSAGE,
|
|
93
|
+
endedAt: now,
|
|
94
|
+
lastUpdate: now,
|
|
95
|
+
steps,
|
|
96
|
+
};
|
|
97
|
+
delete stoppedStatus.activityState;
|
|
98
|
+
writeAsyncResultFile(resultFilePath(DIRS.results, status.runId), stoppedResult);
|
|
99
|
+
writeAtomicJson(path.join(asyncDir, "status.json"), stoppedStatus);
|
|
100
|
+
updateActiveRunIndex(asyncDir, "stopped", status.toolCallId, { retryCapacityErrors: true, terminalIndexBeforeRelease: true });
|
|
101
|
+
}
|
|
102
|
+
|
|
24
103
|
export function stopAsyncRun(
|
|
25
104
|
state: SubagentState,
|
|
26
105
|
runId: string | undefined,
|
|
@@ -38,7 +117,8 @@ export function stopAsyncRun(
|
|
|
38
117
|
details: { mode: "management", results: [] },
|
|
39
118
|
};
|
|
40
119
|
}
|
|
41
|
-
|
|
120
|
+
const pausedWholeRun = status?.state === "paused" && childId === undefined;
|
|
121
|
+
if (!status || (status.state !== "running" && status.state !== "queued" && !pausedWholeRun)) {
|
|
42
122
|
return {
|
|
43
123
|
content: [{ type: "text", text: `No running or queued async run was found for '${runId ?? "current"}'.` }],
|
|
44
124
|
isError: true,
|
|
@@ -66,13 +146,23 @@ export function stopAsyncRun(
|
|
|
66
146
|
}
|
|
67
147
|
try {
|
|
68
148
|
deliverStopRequest({ asyncDir: target.asyncDir, pid: typeof status.pid === "number" ? status.pid : undefined, kill, source: "stop-action", targetIndex: child?.index, childId: child?.id ?? childId });
|
|
149
|
+
if (pausedWholeRun) {
|
|
150
|
+
const failure = sealPausedRun(target.asyncDir, status);
|
|
151
|
+
if (failure) {
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: `Stop request persisted for paused async run ${target.asyncId}, but terminal proof is not ready (${failure}). Retry stop after runner shutdown is observed.` }],
|
|
154
|
+
isError: true,
|
|
155
|
+
details: { mode: "management", results: [] },
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
69
159
|
const tracked = state.asyncJobs.get(target.asyncId);
|
|
70
160
|
if (tracked) {
|
|
71
161
|
tracked.activityState = undefined;
|
|
72
162
|
tracked.updatedAt = Date.now();
|
|
73
163
|
}
|
|
74
164
|
return {
|
|
75
|
-
content: [{ type: "text", text: child ? `Stop requested for child ${child.id} in async run ${target.asyncId}.` : `Stop requested for async run ${target.asyncId}.` }],
|
|
165
|
+
content: [{ type: "text", text: pausedWholeRun ? `Stopped paused async run ${target.asyncId}.` : child ? `Stop requested for child ${child.id} in async run ${target.asyncId}.` : `Stop requested for async run ${target.asyncId}.` }],
|
|
76
166
|
details: { mode: "management", results: [] },
|
|
77
167
|
};
|
|
78
168
|
} catch (error) {
|