pi-subagents 0.65.0 → 0.66.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 +87 -0
- package/README.md +1 -1
- package/agents/researcher.md +23 -13
- package/docs/agents.md +17 -3
- package/docs/configuration.md +34 -0
- package/docs/extension-api.md +94 -0
- package/docs/models.md +58 -1
- package/docs/observability.md +42 -2
- package/docs/tool-reference.md +11 -5
- package/docs/workflows.md +22 -7
- package/package.json +4 -1
- package/runner-server-preload.mjs +13 -0
- package/skills/pi-subagents/SKILL.md +2 -1
- package/skills/pi-subagents/references/execution-controls.md +19 -2
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
- package/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
- package/src/agents/advertised-agent-prompt.ts +63 -0
- package/src/agents/agent-management.ts +14 -1
- package/src/agents/agent-serializer.ts +2 -0
- package/src/agents/agents.ts +8 -0
- package/src/api/preflight.ts +5 -1
- package/src/api/shared-types.ts +1 -1
- package/src/api/workflow-resources.ts +6 -0
- package/src/extension/config.ts +4 -2
- package/src/extension/index.ts +71 -4
- package/src/extension/public-execution.ts +0 -1
- package/src/extension/rpc.ts +4 -21
- package/src/extension/schemas.ts +9 -7
- package/src/extension/tool-description.ts +10 -5
- package/src/integrations/pi-web-session-liveness.ts +73 -0
- package/src/intercom/native-supervisor-channel.ts +102 -88
- package/src/intercom/supervisor-ui.ts +3 -2
- package/src/missions/workflow-state.ts +37 -16
- package/src/runs/background/active-async-capacity.ts +18 -18
- package/src/runs/background/async-execution.ts +8 -1
- package/src/runs/background/async-job-tracker.ts +35 -3
- package/src/runs/background/async-resume.ts +3 -1
- package/src/runs/background/async-retention.ts +9 -0
- package/src/runs/background/async-status-snapshot.ts +10 -12
- package/src/runs/background/async-status.ts +17 -9
- package/src/runs/background/auto-drain.ts +40 -29
- package/src/runs/background/chain-root-attachment.ts +8 -0
- package/src/runs/background/control-channel.ts +78 -44
- package/src/runs/background/notify.ts +88 -12
- package/src/runs/background/owned-process-tree.ts +6 -6
- package/src/runs/background/process-terminal.ts +23 -23
- package/src/runs/background/retained-nested-route-tracker.ts +96 -0
- package/src/runs/background/run-child-session.ts +62 -33
- package/src/runs/background/run-status.ts +75 -5
- package/src/runs/background/runner-aliases.ts +46 -8
- package/src/runs/background/runner-child-launch.ts +86 -0
- package/src/runs/background/stale-run-reconciler.ts +3 -1
- package/src/runs/background/subagent-runner.ts +430 -208
- package/src/runs/background/subagent-wait.ts +3 -0
- package/src/runs/background/wait-completions.ts +4 -0
- package/src/runs/foreground/async-steering-action.ts +19 -0
- package/src/runs/foreground/execution.ts +116 -26
- package/src/runs/foreground/foreground-history.ts +3 -1
- package/src/runs/foreground/prompt-audit.ts +9 -5
- package/src/runs/foreground/subagent-executor.ts +531 -227
- package/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
- package/src/runs/foreground/workflow-foreground-steering.ts +56 -2
- package/src/runs/shared/acceptance.ts +16 -3
- package/src/runs/shared/agent-contract.ts +1 -1
- package/src/runs/shared/async-status-projection.ts +47 -47
- package/src/runs/shared/child-hooks.ts +151 -2
- package/src/runs/shared/child-launch.ts +18 -13
- package/src/runs/shared/child-session.ts +55 -24
- package/src/runs/shared/child-tool-plan.ts +2 -2
- package/src/runs/shared/completion-evidence.ts +2 -2
- package/src/runs/shared/completion-guard.ts +1 -0
- package/src/runs/shared/host-step-status.ts +11 -11
- package/src/runs/shared/llm-intent-arbiter.ts +30 -20
- package/src/runs/shared/model-exclusions.ts +2 -1
- package/src/runs/shared/model-fallback.ts +41 -8
- package/src/runs/shared/nested-events.ts +8 -8
- package/src/runs/shared/orca-progress-tabs.ts +6 -0
- package/src/runs/shared/parallel-handoff.ts +57 -12
- package/src/runs/shared/parallel-utils.ts +3 -2
- package/src/runs/shared/readonly-drain-observation.ts +42 -0
- package/src/runs/shared/readonly-model-continuation.ts +69 -0
- package/src/runs/shared/readonly-session-evidence.ts +307 -0
- package/src/runs/shared/run-fanout-budget.ts +8 -8
- package/src/runs/shared/runtime-acknowledged-extensions.ts +3 -3
- package/src/runs/shared/subagent-prompt-runtime.ts +13 -3
- package/src/runs/shared/worktree-cleanup-plan.ts +6 -3
- package/src/runs/shared/worktree-setup-command.ts +190 -0
- package/src/runs/shared/worktree.ts +403 -210
- package/src/shared/model-response-aliases.ts +13 -0
- package/src/shared/types.ts +89 -60
- package/src/shared/utils.ts +10 -2
- package/src/shared/watch-strategy.ts +2 -0
- package/src/shared/workflow-child-permit.ts +18 -13
- package/src/tui/fleet-status.ts +1 -1
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render.ts +44 -15
- package/src/workflows/chat-progress.ts +3 -3
- package/src/workflows/scripted-workflow.ts +70 -16
- package/src/workflows/workflow-checklist.ts +15 -18
- package/src/workflows/workflow-child-summary.ts +57 -8
- package/src/workflows/workflow-preflight.ts +19 -19
- package/src/workflows/workflow-receipt.ts +3 -3
- package/src/workflows/workflow-resources.ts +96 -21
- package/src/workflows/workflow-settlement.ts +3 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function validateModelResponseAliases(value: unknown, label = "config.modelResponseAliases"): void {
|
|
2
|
+
if (value === undefined) return;
|
|
3
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be a JSON object`);
|
|
4
|
+
for (const [candidate, aliases] of Object.entries(value)) {
|
|
5
|
+
const slash = candidate.indexOf("/");
|
|
6
|
+
if (slash <= 0 || !candidate.slice(0, slash).trim() || !candidate.slice(slash + 1).trim()) {
|
|
7
|
+
throw new Error(`${label} key ${JSON.stringify(candidate)} must be a non-empty provider/model ID`);
|
|
8
|
+
}
|
|
9
|
+
if (!Array.isArray(aliases) || aliases.some((alias) => typeof alias !== "string" || !alias.trim())) {
|
|
10
|
+
throw new Error(`${label}[${JSON.stringify(candidate)}] must be an array of non-empty response ID strings`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
package/src/shared/types.ts
CHANGED
|
@@ -47,14 +47,14 @@ export type HostStepMonitorKind = "command" | "ci" | "gate";
|
|
|
47
47
|
export type HostStepState = "pending" | "running" | "done" | "cancelled" | "error";
|
|
48
48
|
export type HostStepVerdict = "pass" | "fail" | "inconclusive";
|
|
49
49
|
|
|
50
|
-
export interface
|
|
50
|
+
export interface HostStepFreshness {
|
|
51
51
|
expectedRef: string;
|
|
52
52
|
observedRef?: string;
|
|
53
53
|
stale?: boolean;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/** Bounded, provider-agnostic status for a host-owned workflow monitor. */
|
|
57
|
-
export interface
|
|
57
|
+
export interface HostStepNode {
|
|
58
58
|
version: 1;
|
|
59
59
|
kind: "host-step";
|
|
60
60
|
/** Explicit monitor category; never inferred from labels or commands. */
|
|
@@ -68,7 +68,7 @@ export interface HostStepNodeV1 {
|
|
|
68
68
|
reasonCode?: string;
|
|
69
69
|
detail?: string;
|
|
70
70
|
target?: string;
|
|
71
|
-
freshness?:
|
|
71
|
+
freshness?: HostStepFreshness;
|
|
72
72
|
reportPath?: string;
|
|
73
73
|
exitCode?: number | null;
|
|
74
74
|
updatedAt: number;
|
|
@@ -97,7 +97,7 @@ export interface WorkflowGraphNode {
|
|
|
97
97
|
structured?: boolean;
|
|
98
98
|
acceptanceStatus?: AcceptanceLedgerStatus;
|
|
99
99
|
error?: string;
|
|
100
|
-
hostStep?:
|
|
100
|
+
hostStep?: HostStepNode;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
export interface WorkflowGraphSnapshot {
|
|
@@ -112,7 +112,7 @@ export type WorkflowPreflightCoverage = "complete" | "partial";
|
|
|
112
112
|
export type WorkflowPreflightMode = "mutation" | "review" | "scout" | "gate";
|
|
113
113
|
|
|
114
114
|
/** Bounded, display-only lane hints supplied alongside a workflowScript launch. */
|
|
115
|
-
export interface
|
|
115
|
+
export interface WorkflowPreflightLane {
|
|
116
116
|
key: string;
|
|
117
117
|
mode?: WorkflowPreflightMode;
|
|
118
118
|
decision?: string;
|
|
@@ -122,10 +122,10 @@ export interface WorkflowPreflightLaneV1 {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/** Versioned, display-only workflow launch plan; it never grants launch authority. */
|
|
125
|
-
export interface
|
|
125
|
+
export interface WorkflowPreflight {
|
|
126
126
|
version: 1;
|
|
127
127
|
coverage: WorkflowPreflightCoverage;
|
|
128
|
-
lanes:
|
|
128
|
+
lanes: WorkflowPreflightLane[];
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
export type WorkflowReceiptState = "complete" | "failed" | "paused" | "stopped";
|
|
@@ -149,7 +149,7 @@ export interface WorkflowRecoveryAction {
|
|
|
149
149
|
* Permission/policy extensions can use it to distinguish resolved content from
|
|
150
150
|
* raw workflow scripts. This audit projection never grants execution authority.
|
|
151
151
|
*/
|
|
152
|
-
export interface
|
|
152
|
+
export interface WorkflowResourceProvenance {
|
|
153
153
|
kind: "workflow";
|
|
154
154
|
name: string;
|
|
155
155
|
version: number;
|
|
@@ -174,7 +174,20 @@ export interface WorkflowLaneMetadata {
|
|
|
174
174
|
outputPaths?: string[];
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
/** Bounded foreground activity; excludes tool arguments and transcript content. */
|
|
178
|
+
export interface WorkflowChildActivity {
|
|
179
|
+
currentTool?: string;
|
|
180
|
+
currentToolStartedAt?: number;
|
|
181
|
+
lastActivityAt?: number;
|
|
182
|
+
durationMs?: number;
|
|
183
|
+
toolCount?: number;
|
|
184
|
+
turnCount?: number;
|
|
185
|
+
tokens?: number;
|
|
186
|
+
inputTokens?: number;
|
|
187
|
+
outputTokens?: number;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface WorkflowChildSummary {
|
|
178
191
|
version: 1;
|
|
179
192
|
parentToolCallId: string;
|
|
180
193
|
workflowRunId: string;
|
|
@@ -188,6 +201,8 @@ export interface WorkflowChildSummaryV1 {
|
|
|
188
201
|
sessionName?: string;
|
|
189
202
|
model?: string;
|
|
190
203
|
thinking?: string;
|
|
204
|
+
/** Present only while a synchronous foreground child is running. */
|
|
205
|
+
activity?: WorkflowChildActivity;
|
|
191
206
|
state: "pending" | "running" | "completed" | "failed" | "paused" | "stopped" | "rejected" | "detached";
|
|
192
207
|
}>;
|
|
193
208
|
}
|
|
@@ -215,9 +230,9 @@ export interface WorkflowReceipt {
|
|
|
215
230
|
state: WorkflowReceiptState;
|
|
216
231
|
createdAt: number;
|
|
217
232
|
entries: Record<string, WorkflowReceiptEntry>;
|
|
218
|
-
resource?:
|
|
219
|
-
hostSteps?:
|
|
220
|
-
workflowChildren?:
|
|
233
|
+
resource?: WorkflowResourceProvenance;
|
|
234
|
+
hostSteps?: HostStepNode[];
|
|
235
|
+
workflowChildren?: WorkflowChildSummary;
|
|
221
236
|
workflowResolution?: WorkflowTerminalResolution;
|
|
222
237
|
terminalOutcome?: WorkflowTerminalOutcome;
|
|
223
238
|
recovery?: WorkflowRecoveryAction[];
|
|
@@ -625,7 +640,7 @@ export type ProcessTerminalReason =
|
|
|
625
640
|
| "proof-write-failed"
|
|
626
641
|
| "stale-repair";
|
|
627
642
|
|
|
628
|
-
export interface
|
|
643
|
+
export interface RunnerProcessInstanceExit {
|
|
629
644
|
processInstanceId: string;
|
|
630
645
|
kind: "runner";
|
|
631
646
|
closeObservedAt: number;
|
|
@@ -633,7 +648,7 @@ export interface RunnerProcessInstanceExitV1 {
|
|
|
633
648
|
signal: string | null;
|
|
634
649
|
}
|
|
635
650
|
|
|
636
|
-
export type
|
|
651
|
+
export type ProcessTreeTerminal =
|
|
637
652
|
| {
|
|
638
653
|
state: "observed";
|
|
639
654
|
mechanism: "posix-process-group";
|
|
@@ -646,26 +661,26 @@ export type ProcessTreeTerminalV1 =
|
|
|
646
661
|
diagnostic?: string;
|
|
647
662
|
};
|
|
648
663
|
|
|
649
|
-
export interface
|
|
664
|
+
export interface PiWriterProcessInstanceExit {
|
|
650
665
|
processInstanceId: string;
|
|
651
666
|
kind: "pi-writer";
|
|
652
667
|
attempt: number;
|
|
653
668
|
closeObservedAt: number;
|
|
654
669
|
exitCode: number | null;
|
|
655
670
|
signal: string | null;
|
|
656
|
-
processTree:
|
|
671
|
+
processTree: ProcessTreeTerminal;
|
|
657
672
|
}
|
|
658
673
|
|
|
659
|
-
export type
|
|
674
|
+
export type ProcessInstanceExit = RunnerProcessInstanceExit | PiWriterProcessInstanceExit;
|
|
660
675
|
|
|
661
|
-
export interface
|
|
676
|
+
export interface CanonicalSessionTerminal {
|
|
662
677
|
canonicalSessionId: string;
|
|
663
678
|
leaseDisposition: "released" | "not-held";
|
|
664
679
|
freeAtObservation: true;
|
|
665
680
|
canonicalSessionLeaseReleased?: true;
|
|
666
681
|
}
|
|
667
682
|
|
|
668
|
-
interface
|
|
683
|
+
interface ProcessTerminalBase {
|
|
669
684
|
version: 1;
|
|
670
685
|
runId: string;
|
|
671
686
|
childIndex?: number;
|
|
@@ -675,15 +690,15 @@ interface ProcessTerminalBaseV1 {
|
|
|
675
690
|
resumeDisposition?: "resumable" | "non-resumable" | "unavailable";
|
|
676
691
|
}
|
|
677
692
|
|
|
678
|
-
export type
|
|
679
|
-
| (
|
|
680
|
-
| (
|
|
693
|
+
export type ProcessTerminal =
|
|
694
|
+
| (ProcessTerminalBase & { state: "pending" | "not-started" })
|
|
695
|
+
| (ProcessTerminalBase & {
|
|
681
696
|
state: "observed";
|
|
682
697
|
observedAt: number;
|
|
683
|
-
instances:
|
|
684
|
-
canonicalSession?:
|
|
698
|
+
instances: ProcessInstanceExit[];
|
|
699
|
+
canonicalSession?: CanonicalSessionTerminal;
|
|
685
700
|
})
|
|
686
|
-
| (
|
|
701
|
+
| (ProcessTerminalBase & {
|
|
687
702
|
state: "unknown";
|
|
688
703
|
reason: ProcessTerminalReason;
|
|
689
704
|
diagnostic?: string;
|
|
@@ -779,6 +794,8 @@ export interface RunFanoutRejection extends RunFanoutBudgetSnapshot {
|
|
|
779
794
|
}
|
|
780
795
|
|
|
781
796
|
export interface SteeringRecoveryDescriptor {
|
|
797
|
+
/** Captured response identity authority; absence means no declared aliases on revival. */
|
|
798
|
+
modelResponseAliases?: Record<string, string[]>;
|
|
782
799
|
version: 1;
|
|
783
800
|
launchContractDigest?: string;
|
|
784
801
|
extensionBindings?: ExtensionBindings;
|
|
@@ -830,7 +847,7 @@ export interface SteeringRecoveryDescriptor {
|
|
|
830
847
|
maxSubagentDepth: number;
|
|
831
848
|
maxOutput?: MaxOutputConfig;
|
|
832
849
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
833
|
-
launchResolvedExtensions?:
|
|
850
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
834
851
|
share: boolean;
|
|
835
852
|
sessionDir?: string;
|
|
836
853
|
artifactsDir?: string;
|
|
@@ -1162,7 +1179,7 @@ export interface AcceptanceLedger {
|
|
|
1162
1179
|
};
|
|
1163
1180
|
}
|
|
1164
1181
|
|
|
1165
|
-
export interface
|
|
1182
|
+
export interface LaunchResolvedChildExtensions {
|
|
1166
1183
|
version: 1;
|
|
1167
1184
|
/** This is parent-resolved launch intent, not child-runtime acknowledgement that extensions loaded. */
|
|
1168
1185
|
source: "launch-resolved";
|
|
@@ -1177,7 +1194,7 @@ export interface LaunchResolvedChildExtensionsV1 {
|
|
|
1177
1194
|
};
|
|
1178
1195
|
}
|
|
1179
1196
|
|
|
1180
|
-
export interface
|
|
1197
|
+
export interface RuntimeAcknowledgedChildExtensions {
|
|
1181
1198
|
version: 1;
|
|
1182
1199
|
/** Best-effort child-runtime registration acknowledgement, not extension health. */
|
|
1183
1200
|
source: "child-runtime";
|
|
@@ -1280,8 +1297,8 @@ export interface SingleResult {
|
|
|
1280
1297
|
acceptance?: AcceptanceLedger;
|
|
1281
1298
|
agentContract?: AgentContract;
|
|
1282
1299
|
launchContractDigest?: string;
|
|
1283
|
-
launchResolvedExtensions?:
|
|
1284
|
-
runtimeAcknowledgedExtensions?:
|
|
1300
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
1301
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
1285
1302
|
execution?: ExecutionProjection;
|
|
1286
1303
|
review?: ReviewProjection;
|
|
1287
1304
|
effects?: EffectsProjection;
|
|
@@ -1339,6 +1356,7 @@ export interface WaitCompletionChild {
|
|
|
1339
1356
|
*/
|
|
1340
1357
|
export interface WaitCompletion {
|
|
1341
1358
|
runId: string;
|
|
1359
|
+
workflowReceiptPath?: string;
|
|
1342
1360
|
agent?: string;
|
|
1343
1361
|
mode?: string;
|
|
1344
1362
|
state?: string;
|
|
@@ -1346,7 +1364,7 @@ export interface WaitCompletion {
|
|
|
1346
1364
|
/** Versioned bounded output archive retained with the durable completion replay. */
|
|
1347
1365
|
archivePath?: string;
|
|
1348
1366
|
results?: WaitCompletionChild[];
|
|
1349
|
-
workflowChildren?:
|
|
1367
|
+
workflowChildren?: WorkflowChildSummary;
|
|
1350
1368
|
}
|
|
1351
1369
|
|
|
1352
1370
|
export interface AgentCapabilitiesSnapshot {
|
|
@@ -1372,13 +1390,14 @@ export interface AgentCapabilityRow {
|
|
|
1372
1390
|
|
|
1373
1391
|
export interface Details {
|
|
1374
1392
|
mode: SubagentResultMode | "management";
|
|
1393
|
+
workflowReceiptPath?: string;
|
|
1375
1394
|
runId?: string;
|
|
1376
1395
|
/** Host tool-call id retained when it differs from the internal run id. */
|
|
1377
1396
|
toolCallId?: string;
|
|
1378
1397
|
/** Run-level context summary. "mixed" when children resolved to different modes. */
|
|
1379
1398
|
context?: "fresh" | "fork" | "mixed";
|
|
1380
1399
|
results: SingleResult[];
|
|
1381
|
-
workflowChildren?:
|
|
1400
|
+
workflowChildren?: WorkflowChildSummary;
|
|
1382
1401
|
/**
|
|
1383
1402
|
* Terminal completion payloads for runs this bg_wait call observed
|
|
1384
1403
|
* finishing. Async completions travel as result files that are consumed and
|
|
@@ -1421,7 +1440,7 @@ export interface Details {
|
|
|
1421
1440
|
currentStepIndex?: number; // 0-indexed current step (for running chains)
|
|
1422
1441
|
workflowGraph?: WorkflowGraphSnapshot;
|
|
1423
1442
|
/** Validated, display-only fanout plan supplied with a workflow launch. */
|
|
1424
|
-
preflight?:
|
|
1443
|
+
preflight?: WorkflowPreflight;
|
|
1425
1444
|
preflightWarnings?: string[];
|
|
1426
1445
|
outputs?: ChainOutputMap;
|
|
1427
1446
|
// Aggregated child usage across all agents in the run
|
|
@@ -1437,11 +1456,11 @@ export interface Details {
|
|
|
1437
1456
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1438
1457
|
parallelHandoff?: ParallelHandoffReference;
|
|
1439
1458
|
lifecycleStatus?: {
|
|
1440
|
-
processTerminal?:
|
|
1459
|
+
processTerminal?: ProcessTerminal;
|
|
1441
1460
|
};
|
|
1442
1461
|
launchContractDigest?: string;
|
|
1443
|
-
launchResolvedExtensions?:
|
|
1444
|
-
runtimeAcknowledgedExtensions?:
|
|
1462
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
1463
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
1445
1464
|
/** Original launch contract whose persisted session is being revived. */
|
|
1446
1465
|
sourceLaunchContractDigest?: string;
|
|
1447
1466
|
/** Durable mission attached to this run, when mission mode was explicitly used. */
|
|
@@ -1452,7 +1471,7 @@ export interface Details {
|
|
|
1452
1471
|
mission?: MissionRecord;
|
|
1453
1472
|
workflow?: {
|
|
1454
1473
|
value?: unknown;
|
|
1455
|
-
resource?:
|
|
1474
|
+
resource?: WorkflowResourceProvenance;
|
|
1456
1475
|
preflightWarnings?: string[];
|
|
1457
1476
|
trace: Array<{
|
|
1458
1477
|
operation: "run" | "status" | "steer" | "host";
|
|
@@ -1565,9 +1584,9 @@ export interface NestedStepSummary {
|
|
|
1565
1584
|
wrapUpRequested?: boolean;
|
|
1566
1585
|
toolBudget?: ToolBudgetState;
|
|
1567
1586
|
toolBudgetBlocked?: boolean;
|
|
1568
|
-
processTerminal?:
|
|
1569
|
-
launchResolvedExtensions?:
|
|
1570
|
-
runtimeAcknowledgedExtensions?:
|
|
1587
|
+
processTerminal?: ProcessTerminal;
|
|
1588
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
1589
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
1571
1590
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1572
1591
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1573
1592
|
children?: NestedRunSummary[];
|
|
@@ -1585,9 +1604,9 @@ export interface NestedRunSummary extends NestedRunAddress {
|
|
|
1585
1604
|
controlInbox?: string;
|
|
1586
1605
|
capabilityToken?: string;
|
|
1587
1606
|
mode?: SubagentRunMode;
|
|
1588
|
-
processTerminal?:
|
|
1589
|
-
launchResolvedExtensions?:
|
|
1590
|
-
runtimeAcknowledgedExtensions?:
|
|
1607
|
+
processTerminal?: ProcessTerminal;
|
|
1608
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
1609
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
1591
1610
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1592
1611
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1593
1612
|
state: NestedRunState;
|
|
@@ -1655,10 +1674,10 @@ export interface AsyncStartedEvent {
|
|
|
1655
1674
|
chainStepCount?: number;
|
|
1656
1675
|
parallelGroups?: AsyncParallelGroupStatus[];
|
|
1657
1676
|
workflowGraph?: WorkflowGraphSnapshot;
|
|
1658
|
-
preflight?:
|
|
1677
|
+
preflight?: WorkflowPreflight;
|
|
1659
1678
|
launchContractDigest?: string;
|
|
1660
|
-
launchResolvedExtensions?:
|
|
1661
|
-
runtimeAcknowledgedExtensions?:
|
|
1679
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
1680
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
1662
1681
|
usageBudget?: UsageBudgetState;
|
|
1663
1682
|
timeoutMs?: number;
|
|
1664
1683
|
deadlineAt?: number;
|
|
@@ -1779,6 +1798,8 @@ export interface ExternalProcessStatus {
|
|
|
1779
1798
|
}
|
|
1780
1799
|
|
|
1781
1800
|
export interface AsyncStatus {
|
|
1801
|
+
/** Exact reference returned by successful current workflow receipt publication. */
|
|
1802
|
+
workflowReceiptPath?: string;
|
|
1782
1803
|
lifecycleArtifactVersion?: SubagentLifecycleArtifactVersion;
|
|
1783
1804
|
runId: string;
|
|
1784
1805
|
/** Parent Pi process/window that owns local completion delivery. */
|
|
@@ -1823,17 +1844,17 @@ export interface AsyncStatus {
|
|
|
1823
1844
|
pendingAppends?: number;
|
|
1824
1845
|
parallelGroups?: AsyncParallelGroupStatus[];
|
|
1825
1846
|
workflowGraph?: WorkflowGraphSnapshot;
|
|
1826
|
-
preflight?:
|
|
1827
|
-
processTerminal?:
|
|
1847
|
+
preflight?: WorkflowPreflight;
|
|
1848
|
+
processTerminal?: ProcessTerminal;
|
|
1828
1849
|
runFanoutBudget?: RunFanoutBudgetSnapshot;
|
|
1829
1850
|
runFanoutBudgetDescriptor?: RunFanoutBudgetDescriptor;
|
|
1830
1851
|
launchContractDigest?: string;
|
|
1831
|
-
launchResolvedExtensions?:
|
|
1832
|
-
runtimeAcknowledgedExtensions?:
|
|
1852
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
1853
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
1833
1854
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1834
1855
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1835
1856
|
workflow?: Details["workflow"];
|
|
1836
|
-
workflowChildren?:
|
|
1857
|
+
workflowChildren?: WorkflowChildSummary;
|
|
1837
1858
|
parentWorkflowRunId?: string;
|
|
1838
1859
|
workflowKey?: string;
|
|
1839
1860
|
lane?: WorkflowLaneMetadata;
|
|
@@ -1919,13 +1940,13 @@ export interface AsyncStatus {
|
|
|
1919
1940
|
acceptance?: AcceptanceLedger;
|
|
1920
1941
|
agentContract?: AgentContract;
|
|
1921
1942
|
launchContractDigest?: string;
|
|
1922
|
-
launchResolvedExtensions?:
|
|
1923
|
-
runtimeAcknowledgedExtensions?:
|
|
1943
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
1944
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
1924
1945
|
execution?: ExecutionProjection;
|
|
1925
1946
|
review?: ReviewProjection;
|
|
1926
1947
|
effects?: EffectsProjection;
|
|
1927
1948
|
watchdog?: ChildWatchdogProgress;
|
|
1928
|
-
processTerminal?:
|
|
1949
|
+
processTerminal?: ProcessTerminal;
|
|
1929
1950
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1930
1951
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1931
1952
|
}>;
|
|
@@ -1975,11 +1996,11 @@ export interface AsyncJobState {
|
|
|
1975
1996
|
chainStepCount?: number;
|
|
1976
1997
|
parallelGroups?: AsyncParallelGroupStatus[];
|
|
1977
1998
|
/** Bounded host-owned CI/gate nodes loaded from the workflow status graph. */
|
|
1978
|
-
hostSteps?:
|
|
1999
|
+
hostSteps?: HostStepNode[];
|
|
1979
2000
|
/** Full bounded workflow plan, including not-yet-materialized stages. */
|
|
1980
2001
|
workflowGraph?: WorkflowGraphSnapshot;
|
|
1981
2002
|
steps?: AsyncJobStep[];
|
|
1982
|
-
preflight?:
|
|
2003
|
+
preflight?: WorkflowPreflight;
|
|
1983
2004
|
stepsTotal?: number;
|
|
1984
2005
|
runningSteps?: number;
|
|
1985
2006
|
completedSteps?: number;
|
|
@@ -2008,7 +2029,7 @@ export interface AsyncJobState {
|
|
|
2008
2029
|
parentWorkflowRunId?: string;
|
|
2009
2030
|
workflowKey?: string;
|
|
2010
2031
|
workflow?: Details["workflow"];
|
|
2011
|
-
workflowChildren?:
|
|
2032
|
+
workflowChildren?: WorkflowChildSummary;
|
|
2012
2033
|
lane?: WorkflowLaneMetadata;
|
|
2013
2034
|
}
|
|
2014
2035
|
|
|
@@ -2047,6 +2068,7 @@ export interface ForegroundResumeChild {
|
|
|
2047
2068
|
agentContract?: AgentContract;
|
|
2048
2069
|
/** Private bounded launch fields needed to preserve the child contract on resume. */
|
|
2049
2070
|
resumeContract?: {
|
|
2071
|
+
modelResponseAliases?: Record<string, string[]>;
|
|
2050
2072
|
outputSchema?: JsonSchemaObject;
|
|
2051
2073
|
agentContract?: AgentContract;
|
|
2052
2074
|
acceptance?: AcceptanceInput;
|
|
@@ -2056,8 +2078,8 @@ export interface ForegroundResumeChild {
|
|
|
2056
2078
|
launchContractDigest?: string;
|
|
2057
2079
|
/** Private retained launch authority. Never project into status or result output. */
|
|
2058
2080
|
extensionBindings?: ExtensionBindings;
|
|
2059
|
-
launchResolvedExtensions?:
|
|
2060
|
-
runtimeAcknowledgedExtensions?:
|
|
2081
|
+
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
2082
|
+
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
2061
2083
|
execution?: ExecutionProjection;
|
|
2062
2084
|
review?: ReviewProjection;
|
|
2063
2085
|
effects?: EffectsProjection;
|
|
@@ -2184,6 +2206,8 @@ export interface ActiveAsyncCapacitySnapshot {
|
|
|
2184
2206
|
export interface SubagentState {
|
|
2185
2207
|
baseCwd: string;
|
|
2186
2208
|
currentSessionId: string | null;
|
|
2209
|
+
/** Exact SDK runtime session ID for supervisor ownership; never a session file path. */
|
|
2210
|
+
supervisorOwnerSessionId?: string | null;
|
|
2187
2211
|
/** Session for which active status projections were restored successfully. */
|
|
2188
2212
|
statusProjectionSessionId?: string | null;
|
|
2189
2213
|
/** Reload-stable identity for this parent Pi process/window. */
|
|
@@ -2201,6 +2225,8 @@ export interface SubagentState {
|
|
|
2201
2225
|
trustedSessionFileRoot?: string;
|
|
2202
2226
|
/** Live async session roots created by this parent executor, keyed by run id. */
|
|
2203
2227
|
liveAsyncSessionRoots?: Map<string, string>;
|
|
2228
|
+
/** Foreground nested routes retained after their direct parent settles, keyed by root run id. */
|
|
2229
|
+
retainedForegroundNestedRoutes?: Map<string, NestedRouteInfo>;
|
|
2204
2230
|
/** Last valid parent session model observed for this session; used when continuation contexts omit ctx.model. */
|
|
2205
2231
|
lastParentModel?: { provider: string; id: string };
|
|
2206
2232
|
subagentInProgress?: boolean;
|
|
@@ -2368,7 +2394,7 @@ export interface RunSyncOptions {
|
|
|
2368
2394
|
/** Internal foreground receipt proposal; returns true only when the outer waiter accepted it. */
|
|
2369
2395
|
onDetachReceipt?: (result: SingleResult) => boolean;
|
|
2370
2396
|
/** Authoritative terminal result, emitted only after the full detached run finalizes. */
|
|
2371
|
-
onDetachedExit?: (result: SingleResult) => void
|
|
2397
|
+
onDetachedExit?: (result: SingleResult) => void | Promise<void>;
|
|
2372
2398
|
controlConfig?: ResolvedControlConfig;
|
|
2373
2399
|
intercomSessionName?: string;
|
|
2374
2400
|
orchestratorIntercomTarget?: string;
|
|
@@ -2409,6 +2435,7 @@ export interface RunSyncOptions {
|
|
|
2409
2435
|
workflowChildPermitLaunch?: WorkflowChildPermitContext;
|
|
2410
2436
|
/** Registry models available for heuristic bare-model resolution */
|
|
2411
2437
|
availableModels?: Array<{ provider: string; id: string; fullId: string; contextWindow?: number }>;
|
|
2438
|
+
modelResponseAliases?: Record<string, string[]>;
|
|
2412
2439
|
/** Current parent-session provider to prefer for ambiguous bare model ids */
|
|
2413
2440
|
preferredModelProvider?: string;
|
|
2414
2441
|
/** Parent Pi event host used to snapshot runtime-registered MCP servers before child launch. */
|
|
@@ -2544,6 +2571,8 @@ export interface ExtensionConfig {
|
|
|
2544
2571
|
asyncWidget?: boolean;
|
|
2545
2572
|
/** Configure the process-wide TTL policy for persisted model exclusions. */
|
|
2546
2573
|
modelExclusions?: ModelExclusionsConfig;
|
|
2574
|
+
/** Exact provider/model candidates mapped to operator-declared equivalent response IDs. Empty arrays add no accepted IDs. */
|
|
2575
|
+
modelResponseAliases?: Record<string, string[]>;
|
|
2547
2576
|
/** Tool description variant registered for the parent-facing subagent tool. Defaults to split metadata. */
|
|
2548
2577
|
toolDescriptionMode?: ToolDescriptionMode;
|
|
2549
2578
|
/** Inline chat rendering for the subagent tool. Defaults to rich. */
|
package/src/shared/utils.ts
CHANGED
|
@@ -135,6 +135,9 @@ function isNotFoundError(error: unknown): boolean {
|
|
|
135
135
|
* Read async job status from disk (with mtime-based caching)
|
|
136
136
|
*/
|
|
137
137
|
export function readStatus(asyncDir: string): AsyncStatus | null {
|
|
138
|
+
if (Buffer.byteLength(path.basename(asyncDir), "utf-8") > 255) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
138
141
|
const statusPath = path.join(asyncDir, "status.json");
|
|
139
142
|
|
|
140
143
|
let stat: fs.Stats;
|
|
@@ -454,8 +457,13 @@ export function hasEmptyTerminalAssistantResponse(messages: Message[]): boolean
|
|
|
454
457
|
const lastAssistant = messages.findLast((message) => message.role === "assistant");
|
|
455
458
|
return lastAssistant?.role === "assistant"
|
|
456
459
|
&& Array.isArray(lastAssistant.content)
|
|
457
|
-
&& lastAssistant.content.length === 0
|
|
458
|
-
|
|
460
|
+
&& ((lastAssistant.content.length === 0 && lastAssistant.usage.output === 0)
|
|
461
|
+
|| (messages.at(-1) === lastAssistant
|
|
462
|
+
&& lastAssistant.stopReason === "stop"
|
|
463
|
+
&& !lastAssistant.errorMessage
|
|
464
|
+
&& lastAssistant.content.length > 0
|
|
465
|
+
// Token accounting can be nonzero even when no response text was emitted.
|
|
466
|
+
&& lastAssistant.content.every((part) => part.type === "text" && part.text === "")));
|
|
459
467
|
}
|
|
460
468
|
|
|
461
469
|
export function formatEmptyTerminalAssistantResponseError(messages: Message[]): string {
|
|
@@ -2,9 +2,11 @@ export type FileWatchPurpose =
|
|
|
2
2
|
| "result-delivery"
|
|
3
3
|
| "supervisor-channel"
|
|
4
4
|
| "async-job-tracker"
|
|
5
|
+
| "retained-nested-route-tracker"
|
|
5
6
|
| "runner-control-inbox"
|
|
6
7
|
| "child-steering-inbox";
|
|
7
8
|
|
|
8
9
|
export function shouldUseNativeFsWatch(_purpose: FileWatchPurpose, platform: NodeJS.Platform = process.platform): boolean {
|
|
10
|
+
if (_purpose === "retained-nested-route-tracker" && platform === "win32") return false;
|
|
9
11
|
return platform !== "darwin";
|
|
10
12
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { stableJsonDigest } from "./launch-contract.ts";
|
|
2
|
-
import type {
|
|
2
|
+
import type { WorkflowResourceProvenance } from "./types.ts";
|
|
3
3
|
|
|
4
4
|
export interface WorkflowChildPermitInput {
|
|
5
5
|
issuerPackage: string;
|
|
@@ -117,12 +117,12 @@ export function workflowChildPermitConsumed(permit: WorkflowChildPermit): boolea
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
export interface WorkflowResourceHostAuthority {
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
key: string;
|
|
121
|
+
command: string;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
export interface WorkflowResourceAuthority {
|
|
125
|
-
host?: WorkflowResourceHostAuthority;
|
|
125
|
+
host?: readonly WorkflowResourceHostAuthority[];
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
export interface WorkflowResourcePermitInput {
|
|
@@ -143,7 +143,7 @@ interface WorkflowResourcePermitRecord {
|
|
|
143
143
|
resourceId: string;
|
|
144
144
|
scriptDigest: string;
|
|
145
145
|
authority: WorkflowResourceAuthority;
|
|
146
|
-
provenance:
|
|
146
|
+
provenance: WorkflowResourceProvenance;
|
|
147
147
|
state: "available" | "consumed";
|
|
148
148
|
}
|
|
149
149
|
|
|
@@ -152,11 +152,17 @@ const resourceRecords = new WeakMap<object, WorkflowResourcePermitRecord>();
|
|
|
152
152
|
function cloneWorkflowResourceAuthority(authority: WorkflowResourceAuthority): WorkflowResourceAuthority {
|
|
153
153
|
if (!authority || typeof authority !== "object" || Array.isArray(authority)) throw new Error("Workflow resource authority must be an object.");
|
|
154
154
|
if (authority.host === undefined) return Object.freeze({});
|
|
155
|
-
if (!authority.host ||
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
if (!Array.isArray(authority.host) || authority.host.length > 32) throw new Error("Workflow resource host authority must be an array of at most 32 grants.");
|
|
156
|
+
const keys = new Set<string>();
|
|
157
|
+
const host = Array.from(authority.host, (grant) => {
|
|
158
|
+
if (!grant || typeof grant !== "object" || Object.keys(grant).some((field) => field !== "key" && field !== "command")) throw new Error("Workflow resource host grant must contain only key and command.");
|
|
159
|
+
const { key, command } = grant;
|
|
160
|
+
if (typeof key !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(key) || keys.has(key)) throw new Error("Workflow resource host grant requires a unique safe key.");
|
|
161
|
+
if (typeof command !== "string" || !command.trim() || Buffer.byteLength(command.trim(), "utf8") > 16 * 1024 || command.includes("\0")) throw new Error("Workflow resource host grant requires a non-empty command of at most 16384 bytes without NUL.");
|
|
162
|
+
keys.add(key);
|
|
163
|
+
return Object.freeze({ key, command: command.trim() });
|
|
164
|
+
});
|
|
165
|
+
return Object.freeze({ host: Object.freeze(host) });
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
/** Package-internal permit for a workflow resource resolved by the extension. */
|
|
@@ -186,7 +192,7 @@ export function createWorkflowResourcePermit(input: WorkflowResourcePermitInput)
|
|
|
186
192
|
return permit;
|
|
187
193
|
}
|
|
188
194
|
|
|
189
|
-
export function consumeWorkflowResourcePermit(permit: WorkflowResourcePermit, script: string): { provenance:
|
|
195
|
+
export function consumeWorkflowResourcePermit(permit: WorkflowResourcePermit, script: string): { provenance: WorkflowResourceProvenance; authority: WorkflowResourceAuthority } | string {
|
|
190
196
|
const record = resourceRecords.get(permit as object);
|
|
191
197
|
if (!record) return "Workflow resource permit is invalid.";
|
|
192
198
|
if (record.state !== "available") return "Workflow resource permit is already consumed.";
|
|
@@ -201,7 +207,6 @@ export function authorizeWorkflowResourceHost(permit: WorkflowResourcePermit, ke
|
|
|
201
207
|
if (!record || record.state !== "consumed") return "Workflow resource authority is unavailable.";
|
|
202
208
|
const host = record.authority.host;
|
|
203
209
|
if (!host) return "runs.host is not allowed for this workflow resource.";
|
|
204
|
-
if (!host.
|
|
205
|
-
if (!host.commands.includes(command.trim())) return `The command for runs.host('${key}') is not allowed for workflow resource '${record.resourceName}'.`;
|
|
210
|
+
if (!host.some((grant) => grant.key === key && grant.command === command.trim())) return `The command for runs.host('${key}') is not allowed for workflow resource '${record.resourceName}'.`;
|
|
206
211
|
return undefined;
|
|
207
212
|
}
|
package/src/tui/fleet-status.ts
CHANGED
|
@@ -666,7 +666,7 @@ export class SubagentFleetStatus {
|
|
|
666
666
|
const capacity = this.state.activeAsyncCapacity;
|
|
667
667
|
const hasNativeRows = workEntries.some((entry) => !entry.external);
|
|
668
668
|
const showNativeSummary = hasNativeRows || Boolean(capacity?.used);
|
|
669
|
-
const asyncRuns = capacity && showNativeSummary ? `Async runs ${capacity.used}/${capacity.limit || "∞"}` : "";
|
|
669
|
+
const asyncRuns = capacity && showNativeSummary && (capacity.used > 0 || capacity.limit > 0) ? `Async runs ${capacity.used}/${capacity.limit || "∞"}` : "";
|
|
670
670
|
const activeEntries = activeLeafAgentCount(workEntries);
|
|
671
671
|
const noun = workEntries.some((entry) => entry.external) ? "job" : "agent";
|
|
672
672
|
const agents = activeEntries > 0 ? `${activeEntries} active ${noun}${activeEntries === 1 ? "" : "s"}` : "";
|
package/src/tui/fleet.ts
CHANGED
|
@@ -179,10 +179,16 @@ function asyncItems(run: AsyncRunSummary, description?: string): FleetItem[] {
|
|
|
179
179
|
}));
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
function orderFleetAsyncRuns(runs: AsyncRunSummary[], terminalLimit: number): AsyncRunSummary[] {
|
|
182
|
+
function orderFleetAsyncRuns(runs: AsyncRunSummary[], terminalLimit: number, trackedJobs: Map<string, AsyncJobState>): AsyncRunSummary[] {
|
|
183
183
|
const updatedAt = (run: AsyncRunSummary) => run.lastUpdate ?? run.endedAt ?? run.startedAt;
|
|
184
184
|
const byNewest = (left: AsyncRunSummary, right: AsyncRunSummary) => updatedAt(right) - updatedAt(left);
|
|
185
|
-
|
|
185
|
+
// Missing tracked starts must not inherit the summary's heartbeat-based display fallback.
|
|
186
|
+
const startedAt = (run: AsyncRunSummary) => {
|
|
187
|
+
const job = trackedJobs.get(run.id);
|
|
188
|
+
return job ? job.startedAt ?? 0 : run.startedAt;
|
|
189
|
+
};
|
|
190
|
+
const byStartedAt = (left: AsyncRunSummary, right: AsyncRunSummary) => startedAt(left) - startedAt(right) || left.id.localeCompare(right.id);
|
|
191
|
+
const active = runs.filter((run) => run.state === "queued" || run.state === "running").sort(byStartedAt);
|
|
186
192
|
const terminal = runs.filter((run) => run.state !== "queued" && run.state !== "running").sort(byNewest);
|
|
187
193
|
return [...active, ...terminal.slice(0, terminalLimit)];
|
|
188
194
|
}
|
|
@@ -208,7 +214,7 @@ export function collectFleetSnapshot(
|
|
|
208
214
|
liveWorkflowForegroundControls.add(control);
|
|
209
215
|
workflowForegroundChildCounts.set(control.parentWorkflowRunId, (workflowForegroundChildCounts.get(control.parentWorkflowRunId) ?? 0) + activeChildCount);
|
|
210
216
|
}
|
|
211
|
-
for (const control of [...state.foregroundControls.values()].sort((left, right) =>
|
|
217
|
+
for (const control of [...state.foregroundControls.values()].sort((left, right) => left.startedAt - right.startedAt || left.runId.localeCompare(right.runId))) {
|
|
212
218
|
activeForegroundIds.add(control.runId);
|
|
213
219
|
if (control.parentWorkflowRunId && workflowParentIds.has(control.parentWorkflowRunId)
|
|
214
220
|
&& ((workflowForegroundChildCounts.get(control.parentWorkflowRunId) ?? 0) <= 1 || !liveWorkflowForegroundControls.has(control))) continue;
|
|
@@ -249,7 +255,7 @@ export function collectFleetSnapshot(
|
|
|
249
255
|
const tracked = [...trackedJobs.values()]
|
|
250
256
|
.filter((job) => belongsToCurrentSession(job.sessionId, state.currentSessionId));
|
|
251
257
|
const byUpdate = (left: AsyncJobState, right: AsyncJobState) => (right.updatedAt ?? right.startedAt ?? 0) - (left.updatedAt ?? left.startedAt ?? 0);
|
|
252
|
-
const active = tracked.filter((job) => job.status === "queued" || job.status === "running")
|
|
258
|
+
const active = tracked.filter((job) => job.status === "queued" || job.status === "running");
|
|
253
259
|
const recent = tracked.filter((job) => job.status !== "queued" && job.status !== "running").sort(byUpdate).slice(0, options.limit ?? MAX_RECENT_ASYNC_RUNS);
|
|
254
260
|
const trackedRuns: AsyncRunSummary[] = [];
|
|
255
261
|
for (const job of [...active, ...recent]) {
|
|
@@ -272,7 +278,7 @@ export function collectFleetSnapshot(
|
|
|
272
278
|
} else {
|
|
273
279
|
runs = trackedRuns;
|
|
274
280
|
}
|
|
275
|
-
for (const run of orderFleetAsyncRuns(runs, options.limit ?? MAX_RECENT_ASYNC_RUNS)) {
|
|
281
|
+
for (const run of orderFleetAsyncRuns(runs, options.limit ?? MAX_RECENT_ASYNC_RUNS, trackedJobs)) {
|
|
276
282
|
items.push(...asyncItems(run, descriptions.get(run.id)));
|
|
277
283
|
}
|
|
278
284
|
} catch (cause) {
|