pi-subagents 0.57.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 +104 -0
- package/docs/agents.md +18 -9
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +40 -1
- package/docs/models.md +27 -4
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +92 -6
- package/docs/workflows.md +115 -0
- 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 +3 -1
- package/skills/pi-subagents/references/execution-controls.md +6 -2
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/prompting-and-roles.md +26 -5
- package/src/agents/agent-management.ts +28 -17
- package/src/agents/agent-serializer.ts +9 -2
- package/src/agents/agents.ts +103 -27
- package/src/agents/runtime-agent-events.ts +70 -0
- package/src/agents/runtime-agent-registry.ts +19 -18
- package/src/api/agents.ts +10 -5
- package/src/api/background-work.ts +5 -1
- package/src/api/delegation.ts +0 -7
- package/src/api/preflight.ts +32 -10
- package/src/extension/fanout-child.ts +5 -3
- package/src/extension/index.ts +66 -27
- package/src/extension/public-execution.ts +15 -2
- package/src/extension/rpc.ts +35 -14
- package/src/extension/schemas.ts +37 -12
- package/src/extension/tool-description.ts +25 -6
- package/src/integrations/herdr-status.ts +5 -0
- 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 +78 -46
- package/src/runs/background/async-job-tracker.ts +14 -12
- package/src/runs/background/async-resume.ts +29 -27
- package/src/runs/background/async-status-snapshot.ts +23 -261
- package/src/runs/background/async-status.ts +68 -7
- package/src/runs/background/chain-append.ts +8 -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 +184 -9
- package/src/runs/background/result-delivery-ownership.ts +45 -0
- package/src/runs/background/result-files.ts +2 -1
- package/src/runs/background/result-watcher.ts +29 -10
- 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 +389 -350
- 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 +134 -121
- 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 +527 -257
- package/src/runs/foreground/workflow-detach-reconcile.ts +130 -120
- 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 +5 -4
- package/src/runs/shared/dynamic-fanout.ts +3 -3
- package/src/runs/shared/fast-mode-extension.ts +5 -5
- package/src/runs/shared/host-step-status.ts +230 -0
- package/src/runs/shared/lane-metadata.ts +105 -0
- package/src/runs/shared/launch-cwd.ts +16 -0
- package/src/runs/shared/long-running-guard.ts +2 -1
- package/src/runs/shared/mcp-config-sources.ts +422 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
- package/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/src/runs/shared/model-exclusions.ts +12 -0
- package/src/runs/shared/model-fallback.ts +25 -6
- 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 +15 -1
- package/src/runs/shared/pi-args.ts +81 -8
- package/src/runs/shared/single-output.ts +44 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +98 -13
- 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 +11 -2
- package/src/shared/launch-contract.ts +5 -1
- package/src/shared/settings.ts +9 -103
- package/src/shared/types.ts +240 -30
- package/src/shared/utils.ts +41 -84
- 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/slash/subagents-admin.ts +3 -0
- package/src/tui/fleet-status.ts +125 -74
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render.ts +330 -33
- 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 +496 -35
- package/src/workflows/workflow-child-summary.ts +9 -5
- package/src/workflows/workflow-preflight.ts +270 -0
- package/src/workflows/workflow-receipt.ts +79 -5
- package/src/workflows/workflow-settlement.ts +246 -0
- package/src/runs/shared/turn-budget.ts +0 -98
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { splitKnownThinkingSuffix, type ModelInfo as AvailableModelInfo } from "../../shared/model-info.ts";
|
|
2
2
|
import type { Usage } from "../../shared/types.ts";
|
|
3
|
-
import { filterFallbackCandidates, parseModelKey, recordModelFailure } from "./model-exclusions.ts";
|
|
3
|
+
import { filterFallbackCandidates, findModelExclusion, parseModelKey, recordModelFailure } from "./model-exclusions.ts";
|
|
4
4
|
import { checkModelScope, type ModelScopeCheckRule, type ModelScopeViolation, type ModelSource } from "./model-scope.ts";
|
|
5
5
|
import { redactSecretValues } from "./permissions.ts";
|
|
6
6
|
|
|
@@ -24,7 +24,12 @@ export function formatSubagentModelVerificationError(expectedModel: string, obse
|
|
|
24
24
|
const observedBase = splitThinkingSuffix(observedModel).baseModel;
|
|
25
25
|
if (expectedBase === observedBase) return undefined;
|
|
26
26
|
const expectedEntry = availableModels.find((entry) => entry.fullId === expectedBase);
|
|
27
|
-
if (expectedEntry
|
|
27
|
+
if (expectedEntry) {
|
|
28
|
+
if (expectedEntry.id === observedBase) return undefined;
|
|
29
|
+
const expectedIdLeaf = expectedEntry.id.slice(expectedEntry.id.lastIndexOf("/") + 1);
|
|
30
|
+
const expectedFullIdLeaf = expectedEntry.fullId.slice(expectedEntry.fullId.lastIndexOf("/") + 1);
|
|
31
|
+
if (expectedIdLeaf === observedBase || expectedFullIdLeaf === observedBase) return undefined;
|
|
32
|
+
}
|
|
28
33
|
return `model_verification_failed: child reported a different model than the launch candidate. Expected '${expectedModel}' but observed '${observedModel}'.`;
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -279,6 +284,14 @@ function enforceModelScopes(
|
|
|
279
284
|
for (const violation of violations) (onWarn ?? defaultScopeWarn)(violation);
|
|
280
285
|
}
|
|
281
286
|
|
|
287
|
+
function throwForExplicitModelExclusion(model: string): void {
|
|
288
|
+
const exclusion = findModelExclusion(model);
|
|
289
|
+
if (!exclusion) return;
|
|
290
|
+
const reason = redactSecretValues((exclusion.reason ?? "runtime-failure").replace(/[\u0000-\u001f\u007f]+/g, " ")).slice(0, 240);
|
|
291
|
+
const expiry = Number.isFinite(exclusion.expiresAt) ? `; expires: ${new Date(exclusion.expiresAt).toISOString()}` : "";
|
|
292
|
+
throw new Error(`Requested subagent model '${model}' is excluded and cannot be replaced by a fallback (reason: ${reason}${expiry}).`);
|
|
293
|
+
}
|
|
294
|
+
|
|
282
295
|
/**
|
|
283
296
|
* Resolve the `--model` override passed to a spawned subagent.
|
|
284
297
|
*
|
|
@@ -313,6 +326,9 @@ export function resolveSubagentModelOverride(
|
|
|
313
326
|
} else {
|
|
314
327
|
resolved = resolveRequiredSubagentModelCandidate(explicit, availableModels, preferredProvider);
|
|
315
328
|
}
|
|
329
|
+
if (resolved && explicit !== undefined && options?.source === "explicit") {
|
|
330
|
+
throwForExplicitModelExclusion(resolved);
|
|
331
|
+
}
|
|
316
332
|
if (resolved && options?.scope) {
|
|
317
333
|
const source: ModelSource = explicit === undefined ? "inherited" : (options.source ?? "inherited");
|
|
318
334
|
enforceModelScopes(resolved, options.scope, source, options.onWarn);
|
|
@@ -326,14 +342,15 @@ export function resolveEffectiveSubagentModel(
|
|
|
326
342
|
parentModel: ParentModel | undefined,
|
|
327
343
|
availableModels: AvailableModelInfo[] | undefined,
|
|
328
344
|
preferredProvider?: string,
|
|
329
|
-
options?:
|
|
345
|
+
options?: ResolveSubagentModelOverrideOptions,
|
|
330
346
|
): string | undefined {
|
|
347
|
+
const source = options?.source ?? (explicitModel !== undefined ? "explicit" : "inherited");
|
|
331
348
|
const resolved = resolveSubagentModelOverride(
|
|
332
349
|
explicitModel ?? agentModel,
|
|
333
350
|
parentModel,
|
|
334
351
|
availableModels,
|
|
335
352
|
preferredProvider,
|
|
336
|
-
{ ...options, source
|
|
353
|
+
{ ...options, source },
|
|
337
354
|
);
|
|
338
355
|
if (resolved || explicitModel === undefined) return resolved;
|
|
339
356
|
return resolveSubagentModelOverride(
|
|
@@ -341,7 +358,7 @@ export function resolveEffectiveSubagentModel(
|
|
|
341
358
|
parentModel,
|
|
342
359
|
availableModels,
|
|
343
360
|
preferredProvider,
|
|
344
|
-
{ ...options, source: "inherited" },
|
|
361
|
+
{ ...options, source: options?.source ?? "inherited" },
|
|
345
362
|
);
|
|
346
363
|
}
|
|
347
364
|
|
|
@@ -434,9 +451,11 @@ const RETRYABLE_MODEL_FAILURE_PATTERNS = [
|
|
|
434
451
|
/upstream/i,
|
|
435
452
|
/timed? out/i,
|
|
436
453
|
/timeout/i,
|
|
454
|
+
/\b500\b/,
|
|
437
455
|
/\b502\b/,
|
|
438
456
|
/\b503\b/,
|
|
439
457
|
/\b504\b/,
|
|
458
|
+
/internal server error/i,
|
|
440
459
|
/cold.?start/i,
|
|
441
460
|
/empty response/i,
|
|
442
461
|
/no output/i,
|
|
@@ -467,7 +486,7 @@ function messageError(message: unknown): string | undefined {
|
|
|
467
486
|
export function isRetryableModelFailureAttempt(input: { error: string | undefined; messages?: readonly unknown[]; toolCount?: number }): boolean {
|
|
468
487
|
if (!isRetryableModelFailure(input.error)) return false;
|
|
469
488
|
if ((input.toolCount ?? 0) > 0) return false;
|
|
470
|
-
if (input.error === "Subagent produced no output (possible model cold-start or empty response).") return true;
|
|
489
|
+
if (input.error === "Subagent produced no output (possible model cold-start or empty response)." || /^Subagent produced no output after terminal assistant stopReason "[^"]+"\.$/.test(input.error ?? "")) return true;
|
|
471
490
|
if ((input.toolCount ?? 0) === 0 && (input.messages?.length ?? 0) === 0) return true;
|
|
472
491
|
const error = input.error?.trim();
|
|
473
492
|
return Boolean(error && input.messages?.some((message) => messageError(message)?.trim() === error));
|
|
@@ -286,7 +286,7 @@ function sanitizeTurnBudget(value: unknown): TurnBudgetState | undefined {
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
function sanitizeState(value: unknown, fallback: NestedRunState): NestedRunState {
|
|
289
|
-
return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "paused" || value === "stopped"
|
|
289
|
+
return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "partial" || value === "paused" || value === "stopped"
|
|
290
290
|
? value
|
|
291
291
|
: fallback;
|
|
292
292
|
}
|
|
@@ -306,6 +306,7 @@ function sanitizeStep(input: unknown, depth: number): NestedStepSummary | undefi
|
|
|
306
306
|
status,
|
|
307
307
|
...(model ? { model } : {}),
|
|
308
308
|
...(thinking ? { thinking } : {}),
|
|
309
|
+
...(stringValue(raw.sessionName, 256) ? { sessionName: stringValue(raw.sessionName, 256) } : {}),
|
|
309
310
|
...(stringValue(raw.sessionFile, 2048) ? { sessionFile: stringValue(raw.sessionFile, 2048) } : {}),
|
|
310
311
|
...(raw.activityState === "active_long_running" || raw.activityState === "needs_attention" ? { activityState: raw.activityState } : {}),
|
|
311
312
|
...(clampNumber(raw.lastActivityAt) !== undefined ? { lastActivityAt: clampNumber(raw.lastActivityAt) } : {}),
|
|
@@ -346,6 +347,7 @@ export function sanitizeSummary(input: unknown, depth = 0): NestedRunSummary | u
|
|
|
346
347
|
depth: Math.min(Math.max(0, clampNumber(raw.depth) ?? 0), MAX_DEPTH),
|
|
347
348
|
path: pathParts,
|
|
348
349
|
state: sanitizeState(raw.state, "running"),
|
|
350
|
+
...(stringValue(raw.sessionName, 256) ? { sessionName: stringValue(raw.sessionName, 256) } : {}),
|
|
349
351
|
...(stringValue(raw.model) ? { model: stringValue(raw.model) } : {}),
|
|
350
352
|
...(THINKING_LEVELS.find((level) => level === raw.thinking) ? { thinking: THINKING_LEVELS.find((level) => level === raw.thinking) } : {}),
|
|
351
353
|
...(stringValue(raw.asyncDir, 2048) ? { asyncDir: stringValue(raw.asyncDir, 2048) } : {}),
|
|
@@ -436,7 +438,7 @@ export function parseNestedEventRecords(content: string, route: NestedRoute): Ne
|
|
|
436
438
|
}
|
|
437
439
|
|
|
438
440
|
function terminal(state: NestedRunState): boolean {
|
|
439
|
-
return state === "complete" || state === "failed" || state === "paused" || state === "stopped";
|
|
441
|
+
return state === "complete" || state === "failed" || state === "partial" || state === "paused" || state === "stopped";
|
|
440
442
|
}
|
|
441
443
|
|
|
442
444
|
function mergeBoundedChildren(existing: NestedRunSummary[] | undefined, incoming: NestedRunSummary[] | undefined): NestedRunSummary[] | undefined {
|
|
@@ -1005,6 +1007,7 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
|
|
|
1005
1007
|
mode: status.mode ?? fallback.mode,
|
|
1006
1008
|
...(status.steps?.length === 1 && status.steps[0]?.model ? { model: status.steps[0].model } : {}),
|
|
1007
1009
|
...(status.steps?.length === 1 && status.steps[0]?.thinking ? { thinking: status.steps[0].thinking } : {}),
|
|
1010
|
+
...(status.steps?.length === 1 && status.steps[0]?.sessionName ? { sessionName: status.steps[0].sessionName } : {}),
|
|
1008
1011
|
...(status.processTerminal ? { processTerminal: sanitizeProcessTerminal(status.processTerminal, { runId: status.runId || fallback.id, runnerProcessInstanceId: status.processTerminal.runnerProcessInstanceId }, `${asyncDir}/status.json`) } : {}),
|
|
1009
1012
|
...(status.launchResolvedExtensions ? { launchResolvedExtensions: status.launchResolvedExtensions } : {}),
|
|
1010
1013
|
...runtimeAcknowledgedEntry(status.runtimeAcknowledgedExtensions),
|
|
@@ -1035,6 +1038,7 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
|
|
|
1035
1038
|
...(status.sessionFile ? { sessionFile: status.sessionFile } : {}),
|
|
1036
1039
|
...(status.steps?.length ? { steps: status.steps.map((step, index) => ({
|
|
1037
1040
|
agent: step.agent,
|
|
1041
|
+
...(step.sessionName ? { sessionName: step.sessionName } : {}),
|
|
1038
1042
|
status: step.status,
|
|
1039
1043
|
...(step.model ? { model: step.model } : {}),
|
|
1040
1044
|
...(step.thinking ? { thinking: step.thinking } : {}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formatDuration, formatModelThinking, formatTokenUsage, shortenPath } from "../../shared/formatters.ts";
|
|
2
2
|
import { formatActivityLabel } from "../../shared/status-format.ts";
|
|
3
|
-
import type { ActivityState, NestedRunSummary
|
|
3
|
+
import type { ActivityState, NestedRunSummary } from "../../shared/types.ts";
|
|
4
4
|
|
|
5
5
|
export interface NestedRunCounts {
|
|
6
6
|
total: number;
|
|
@@ -8,13 +8,14 @@ export interface NestedRunCounts {
|
|
|
8
8
|
paused: number;
|
|
9
9
|
complete: number;
|
|
10
10
|
failed: number;
|
|
11
|
+
partial: number;
|
|
11
12
|
rejected: number;
|
|
12
13
|
stopped: number;
|
|
13
14
|
queued: number;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export function countNestedRuns(children: NestedRunSummary[] | undefined): NestedRunCounts {
|
|
17
|
-
const counts: NestedRunCounts = { total: 0, running: 0, paused: 0, complete: 0, failed: 0, rejected: 0, stopped: 0, queued: 0 };
|
|
18
|
+
const counts: NestedRunCounts = { total: 0, running: 0, paused: 0, complete: 0, failed: 0, partial: 0, rejected: 0, stopped: 0, queued: 0 };
|
|
18
19
|
for (const child of children ?? []) {
|
|
19
20
|
counts.total++;
|
|
20
21
|
counts[child.state]++;
|
|
@@ -24,6 +25,7 @@ export function countNestedRuns(children: NestedRunSummary[] | undefined): Neste
|
|
|
24
25
|
counts.paused += nested.paused;
|
|
25
26
|
counts.complete += nested.complete;
|
|
26
27
|
counts.failed += nested.failed;
|
|
28
|
+
counts.partial += nested.partial;
|
|
27
29
|
counts.rejected += nested.rejected;
|
|
28
30
|
counts.stopped += nested.stopped;
|
|
29
31
|
counts.queued += nested.queued;
|
|
@@ -38,6 +40,7 @@ export function formatNestedAggregate(children: NestedRunSummary[] | undefined):
|
|
|
38
40
|
counts.running > 0 ? `${counts.running} running` : "",
|
|
39
41
|
counts.paused > 0 ? `${counts.paused} paused` : "",
|
|
40
42
|
counts.failed > 0 ? `${counts.failed} failed` : "",
|
|
43
|
+
counts.partial > 0 ? `${counts.partial} partial` : "",
|
|
41
44
|
counts.rejected > 0 ? `${counts.rejected} rejected` : "",
|
|
42
45
|
counts.stopped > 0 ? `${counts.stopped} stopped` : "",
|
|
43
46
|
counts.complete > 0 ? `${counts.complete} complete` : "",
|
|
@@ -47,6 +50,7 @@ export function formatNestedAggregate(children: NestedRunSummary[] | undefined):
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
function nestedRunLabel(run: NestedRunSummary): string {
|
|
53
|
+
if (run.sessionName?.trim()) return run.sessionName.trim();
|
|
50
54
|
if (run.agent) return run.agent;
|
|
51
55
|
if (run.agents?.length) return run.agents.length === 1 ? run.agents[0]! : `${run.agents.slice(0, 2).join(", ")}${run.agents.length > 2 ? ` +${run.agents.length - 2}` : ""}`;
|
|
52
56
|
return run.id;
|
|
@@ -103,7 +107,7 @@ function formatNestedRunLines(children: NestedRunSummary[] | undefined, options:
|
|
|
103
107
|
if (lines.length >= options.maxLines) return;
|
|
104
108
|
const stepActivity = step.status === "running" ? formatNestedActivity(step) : undefined;
|
|
105
109
|
const stepModelThinking = formatModelThinking(step.model, step.thinking);
|
|
106
|
-
lines.push(`${indent} ${stepIndex + 1}. ${step.agent} ${step.status}${stepModelThinking ? ` | ${stepModelThinking}` : ""}${stepActivity ? ` | ${stepActivity}` : ""}${step.error ? ` | error: ${step.error}` : ""}`);
|
|
110
|
+
lines.push(`${indent} ${stepIndex + 1}. ${step.sessionName?.trim() || step.agent} ${step.status}${stepModelThinking ? ` | ${stepModelThinking}` : ""}${stepActivity ? ` | ${stepActivity}` : ""}${step.error ? ` | error: ${step.error}` : ""}`);
|
|
107
111
|
append(step.children, depth + 1, `${indent} `);
|
|
108
112
|
}
|
|
109
113
|
append(child.children, depth + 1, `${indent} `);
|