pi-subagents 0.59.0 → 0.60.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 +37 -0
- package/docs/tool-reference.md +4 -1
- package/docs/workflows.md +2 -2
- package/package.json +1 -1
- package/skills/council-mode/SKILL.md +48 -243
- package/skills/council-mode/references/pass-contracts.md +150 -0
- package/skills/pi-subagents/SKILL.md +87 -37
- package/skills/pi-subagents/references/constraints-and-recipes.md +29 -233
- package/skills/pi-subagents/references/execution-controls.md +47 -6
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/multi-lane-orchestration.md +13 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +34 -27
- package/skills/pi-subagents/references/review-and-validation.md +73 -0
- package/src/agents/agent-management.ts +154 -25
- package/src/api/shared-types.ts +2 -0
- package/src/extension/public-execution.ts +1 -0
- package/src/extension/schemas.ts +1 -0
- package/src/extension/tool-description.ts +8 -4
- package/src/runs/background/async-execution.ts +2 -2
- package/src/runs/background/async-job-tracker.ts +3 -0
- package/src/runs/background/async-status.ts +45 -2
- package/src/runs/background/control-channel.ts +3 -2
- package/src/runs/background/run-status.ts +13 -2
- package/src/runs/background/subagent-runner.ts +5 -1
- package/src/runs/background/subagent-wait.ts +10 -2
- package/src/runs/background/wait-completions.ts +3 -0
- package/src/runs/foreground/execution.ts +11 -2
- package/src/runs/foreground/subagent-executor.ts +98 -1
- package/src/runs/shared/async-status-projection.ts +138 -4
- package/src/runs/shared/background-process-options.ts +9 -0
- package/src/runs/shared/mcp-direct-tool-grant.ts +2 -5
- package/src/runs/shared/mutation-evidence.ts +52 -3
- package/src/runs/shared/pi-args.ts +47 -1
- package/src/runs/shared/single-output.ts +45 -18
- package/src/runs/shared/subagent-prompt-runtime.ts +20 -2
- package/src/runs/shared/workflow-graph.ts +15 -0
- package/src/shared/types.ts +34 -1
- package/src/tui/fleet-status.ts +11 -3
- package/src/tui/render-helpers.ts +31 -0
- package/src/tui/render.ts +597 -112
- package/src/watchdog/change-signature.ts +40 -1
- package/src/workflows/host-command.ts +6 -1
- package/src/workflows/scripted-workflow.ts +53 -2
package/src/shared/types.ts
CHANGED
|
@@ -559,6 +559,10 @@ export interface TimeoutRecoverySummary {
|
|
|
559
559
|
termination: "timed-out" | "stopped";
|
|
560
560
|
changedFiles: string[];
|
|
561
561
|
truncated?: boolean;
|
|
562
|
+
/** True only when a timed-out child left tracked changes without its requested report. */
|
|
563
|
+
recoveryNeeded?: boolean;
|
|
564
|
+
reason?: "timed-out-with-dirty-worktree";
|
|
565
|
+
reportStatus?: "missing" | "written" | "not-requested" | "unknown";
|
|
562
566
|
currentTool?: string;
|
|
563
567
|
currentToolArgs?: string;
|
|
564
568
|
currentPath?: string;
|
|
@@ -569,6 +573,9 @@ export interface TimeoutRecoverySummary {
|
|
|
569
573
|
message: string;
|
|
570
574
|
}
|
|
571
575
|
|
|
576
|
+
/** Safe parent-facing subset of a timeout recovery summary. */
|
|
577
|
+
export type TimeoutRecoveryProjection = Pick<TimeoutRecoverySummary, "termination" | "changedFiles" | "truncated" | "recoveryNeeded" | "reason" | "reportStatus">;
|
|
578
|
+
|
|
572
579
|
export const SUBAGENT_LIFECYCLE_ARTIFACT_VERSION = 3;
|
|
573
580
|
export type SubagentLifecycleArtifactVersion = typeof SUBAGENT_LIFECYCLE_ARTIFACT_VERSION;
|
|
574
581
|
|
|
@@ -1272,6 +1279,7 @@ export interface WaitCompletionChild {
|
|
|
1272
1279
|
model?: string;
|
|
1273
1280
|
contextOverflow?: boolean;
|
|
1274
1281
|
artifactPaths?: Partial<ArtifactPaths>;
|
|
1282
|
+
timeoutRecovery?: TimeoutRecoveryProjection;
|
|
1275
1283
|
}
|
|
1276
1284
|
|
|
1277
1285
|
/**
|
|
@@ -1290,6 +1298,27 @@ export interface WaitCompletion {
|
|
|
1290
1298
|
workflowChildren?: WorkflowChildSummaryV1;
|
|
1291
1299
|
}
|
|
1292
1300
|
|
|
1301
|
+
export interface AgentCapabilitiesSnapshot {
|
|
1302
|
+
agents: AgentCapabilityRow[];
|
|
1303
|
+
restrictedCount: number;
|
|
1304
|
+
capabilityCeilingSources?: string[];
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
export interface AgentCapabilityRow {
|
|
1308
|
+
name: string;
|
|
1309
|
+
description: string;
|
|
1310
|
+
source: "builtin" | "package" | "user" | "project" | "runtime";
|
|
1311
|
+
executable: boolean;
|
|
1312
|
+
restrictionSources?: string[];
|
|
1313
|
+
aliases?: string[];
|
|
1314
|
+
runner: { type: "pi" } | { type: "external-cli"; adapter?: string; capabilities: ExternalCliCapabilities } | { type: "external-job"; provider: string; available?: boolean; capabilities: ExternalJobRunnerStatus["capabilities"] };
|
|
1315
|
+
tools: { ambient: boolean; names: string[]; mcpDirectTools: string[]; mutationTools?: string[] };
|
|
1316
|
+
model?: { value?: string; fallbackModels?: string[]; thinking?: string | false };
|
|
1317
|
+
execution?: { defaultAsync?: boolean; timeoutMs?: number };
|
|
1318
|
+
output?: { path?: string; mode?: OutputMode };
|
|
1319
|
+
extensions?: { names?: string[]; subagentOnly?: string[]; skills?: string[] };
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1293
1322
|
export interface Details {
|
|
1294
1323
|
mode: SubagentResultMode | "management";
|
|
1295
1324
|
runId?: string;
|
|
@@ -1352,6 +1381,7 @@ export interface Details {
|
|
|
1352
1381
|
runFanoutBudget?: RunFanoutBudgetSnapshot;
|
|
1353
1382
|
runFanoutRejection?: RunFanoutRejection;
|
|
1354
1383
|
activeAsyncCapacity?: ActiveAsyncCapacitySnapshot;
|
|
1384
|
+
agentCapabilities?: AgentCapabilitiesSnapshot;
|
|
1355
1385
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1356
1386
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1357
1387
|
parallelHandoff?: ParallelHandoffReference;
|
|
@@ -1852,9 +1882,10 @@ export interface AsyncStatus {
|
|
|
1852
1882
|
parallelHandoff?: ParallelHandoffReference;
|
|
1853
1883
|
}
|
|
1854
1884
|
|
|
1855
|
-
export type AsyncJobStep = NonNullable<AsyncStatus["steps"]>[number] & {
|
|
1885
|
+
export type AsyncJobStep = Omit<NonNullable<AsyncStatus["steps"]>[number], "timeoutRecovery"> & {
|
|
1856
1886
|
index?: number;
|
|
1857
1887
|
description?: string;
|
|
1888
|
+
timeoutRecovery?: TimeoutRecoveryProjection;
|
|
1858
1889
|
};
|
|
1859
1890
|
|
|
1860
1891
|
export interface AsyncJobState {
|
|
@@ -1889,6 +1920,8 @@ export interface AsyncJobState {
|
|
|
1889
1920
|
parallelGroups?: AsyncParallelGroupStatus[];
|
|
1890
1921
|
/** Bounded host-owned CI/gate nodes loaded from the workflow status graph. */
|
|
1891
1922
|
hostSteps?: HostStepNodeV1[];
|
|
1923
|
+
/** Full bounded workflow plan, including not-yet-materialized stages. */
|
|
1924
|
+
workflowGraph?: WorkflowGraphSnapshot;
|
|
1892
1925
|
steps?: AsyncJobStep[];
|
|
1893
1926
|
preflight?: WorkflowPreflightV1;
|
|
1894
1927
|
stepsTotal?: number;
|
package/src/tui/fleet-status.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { snapshotExternalRuns } from "../api/external-runs.ts";
|
|
|
4
4
|
import { formatModelThinking } from "../shared/formatters.ts";
|
|
5
5
|
import type { AsyncJobState, AsyncJobStep, FleetViewPlacement, HerdrProjectPaneSnapshot, HostStepState, HostStepVerdict, NestedRunSummary, NestedStepSummary, SubagentState } from "../shared/types.ts";
|
|
6
6
|
import { projectAsyncWorkflowRows, type AsyncStatusWorkflowRow } from "../runs/shared/async-status-projection.ts";
|
|
7
|
+
import { contextModeLabel } from "../runs/shared/context-mode.ts";
|
|
7
8
|
import { formatWorkflowJsonPreview } from "../workflows/scripted-workflow.ts";
|
|
8
9
|
import { hostStepReportName, hostStepVerdictLabel } from "../runs/shared/host-step-status.ts";
|
|
9
10
|
import { isStaleExtensionContextError } from "../shared/extension-context.ts";
|
|
@@ -362,7 +363,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
362
363
|
if (job.mode === "workflow") {
|
|
363
364
|
const latestEmit = job.workflow?.emits?.length ? formatWorkflowJsonPreview(job.workflow.emits.at(-1), 120) : undefined;
|
|
364
365
|
const workflowSteps = workflowStepsWithoutMaterializedChildren(job.steps, materializedChildrenByWorkflow.get(`async:${job.asyncId}`));
|
|
365
|
-
const workflowRows = projectAsyncWorkflowRows(workflowSteps, job.hostSteps, job.preflight);
|
|
366
|
+
const workflowRows = projectAsyncWorkflowRows(workflowSteps, job.workflowGraph ?? job.hostSteps, job.preflight);
|
|
366
367
|
entries.push({
|
|
367
368
|
key: `async:${job.asyncId}`,
|
|
368
369
|
...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
|
|
@@ -550,7 +551,12 @@ export class SubagentFleetStatus {
|
|
|
550
551
|
this.lastRenderKey = renderKey;
|
|
551
552
|
return;
|
|
552
553
|
}
|
|
553
|
-
if (renderKey === this.lastRenderKey)
|
|
554
|
+
if (renderKey === this.lastRenderKey) {
|
|
555
|
+
// Repaint anyway while anything is running so the wall-clock
|
|
556
|
+
// spinner animates between state changes (500ms tick).
|
|
557
|
+
if (this.entries.some((entry) => entry.state === "running")) this.tui?.requestRender();
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
554
560
|
this.lastRenderKey = renderKey;
|
|
555
561
|
this.tui?.requestRender();
|
|
556
562
|
}
|
|
@@ -728,6 +734,7 @@ export class SubagentFleetStatus {
|
|
|
728
734
|
const marker = last ? "└─" : "├─";
|
|
729
735
|
const indent = " ";
|
|
730
736
|
if (row.overflow !== undefined) return truncateToWidth(`${indent}${marker} ${theme.fg("dim", `+${row.overflow} hidden workflow steps`)}`, width);
|
|
737
|
+
const context = contextModeLabel(row.context);
|
|
731
738
|
const modelThinking = row.modelThinking ? ` (${row.modelThinking})` : "";
|
|
732
739
|
const activity = row.activity ? ` · ${row.activity}` : "";
|
|
733
740
|
const kind = row.kind ? `${row.kind}: ` : "";
|
|
@@ -738,7 +745,7 @@ export class SubagentFleetStatus {
|
|
|
738
745
|
row.preflight.expectedOutput ? `expected:${row.preflight.expectedOutput}` : undefined,
|
|
739
746
|
row.preflight.independence ? `independence:${row.preflight.independence}` : undefined,
|
|
740
747
|
].filter((value): value is string => Boolean(value)).join(" · ") : "";
|
|
741
|
-
const left = `${indent}${marker} ${this.workflowRowGlyph(row, theme)} ${theme.fg("muted", `${kind}${row.name}${modelThinking}`)} · ${this.workflowRowStateLabel(row, theme)}${activity}${hints ? ` · ${hints}` : ""}`;
|
|
748
|
+
const left = `${indent}${marker} ${this.workflowRowGlyph(row, theme)} ${theme.fg("muted", `${kind}${row.name}${context ? ` ${context}` : ""}${modelThinking}`)} · ${this.workflowRowStateLabel(row, theme)}${activity}${hints ? ` · ${hints}` : ""}`;
|
|
742
749
|
const details = [
|
|
743
750
|
row.startedAt !== undefined ? formatFleetElapsed(Date.now() - row.startedAt) : undefined,
|
|
744
751
|
row.tokens !== undefined ? formatFleetTokens(row.tokens, row.window) : undefined,
|
|
@@ -806,6 +813,7 @@ export class SubagentFleetStatus {
|
|
|
806
813
|
row.kind,
|
|
807
814
|
row.name,
|
|
808
815
|
row.state,
|
|
816
|
+
row.context,
|
|
809
817
|
row.modelThinking,
|
|
810
818
|
row.activity,
|
|
811
819
|
row.startedAt,
|
|
@@ -30,6 +30,37 @@ export function fuzzyFilter<T extends { name: string; description: string; model
|
|
|
30
30
|
.map((x) => x.item);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/** Remove a repeated job name from a child label when a safe separator follows it. */
|
|
34
|
+
export function stripRepeatedAgentPrefix(label: string, jobName: string | undefined): string {
|
|
35
|
+
const value = label.trim();
|
|
36
|
+
const prefix = jobName?.trim();
|
|
37
|
+
if (!prefix || !value.startsWith(prefix)) return value;
|
|
38
|
+
|
|
39
|
+
const suffix = value.slice(prefix.length);
|
|
40
|
+
if (!suffix || !/^(?::|·|\s)/u.test(suffix)) return value;
|
|
41
|
+
return suffix.replace(/^\s*(?::|·)?\s*/u, "").trim();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Whether a status label may omit the one logical step marker. */
|
|
45
|
+
export function shouldSuppressSingleStep(chainStepCount?: number, stepsTotal?: number): boolean {
|
|
46
|
+
return (chainStepCount ?? stepsTotal) === 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Add an Agent fraction only when visible candidates collide. */
|
|
50
|
+
export function withDuplicateLabelDiscriminators<T extends { index: number; displayName: string }>(
|
|
51
|
+
rows: readonly T[],
|
|
52
|
+
total: number,
|
|
53
|
+
): Array<T & { rowLabel: string }> {
|
|
54
|
+
const counts = new Map<string, number>();
|
|
55
|
+
for (const row of rows) counts.set(row.displayName, (counts.get(row.displayName) ?? 0) + 1);
|
|
56
|
+
return rows.map((row) => ({
|
|
57
|
+
...row,
|
|
58
|
+
rowLabel: (counts.get(row.displayName) ?? 0) > 1
|
|
59
|
+
? `Agent ${row.index + 1}/${total}: ${row.displayName}`
|
|
60
|
+
: row.displayName,
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
|
|
33
64
|
export function pad(s: string, len: number): string {
|
|
34
65
|
const vis = visibleWidth(s);
|
|
35
66
|
return s + " ".repeat(Math.max(0, len - vis));
|