@agwab/pi-workflow 0.2.1 → 0.3.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/dist/compiler.js +6 -8
- package/dist/dynamic-decision.d.ts +0 -1
- package/dist/dynamic-decision.js +0 -7
- package/dist/dynamic-profiles.d.ts +0 -1
- package/dist/dynamic-profiles.js +0 -3
- package/dist/engine-run-graph.d.ts +1 -0
- package/dist/engine-run-graph.js +142 -2
- package/dist/engine.d.ts +5 -0
- package/dist/engine.js +112 -27
- package/dist/extension.d.ts +2 -1
- package/dist/extension.js +27 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -1
- package/dist/store.js +55 -11
- package/dist/subagent-backend.js +155 -29
- package/dist/types.d.ts +6 -0
- package/dist/workflow-runtime.js +10 -1
- package/dist/workflow-view.js +3 -1
- package/dist/workflow-web-source-extension.js +167 -48
- package/dist/workflow-web-source.d.ts +2 -1
- package/dist/workflow-web-source.js +84 -19
- package/node_modules/@agwab/pi-subagent/README.md +3 -3
- package/node_modules/@agwab/pi-subagent/api.mjs +1 -0
- package/node_modules/@agwab/pi-subagent/docs/usage.md +63 -12
- package/node_modules/@agwab/pi-subagent/package.json +2 -2
- package/node_modules/@agwab/pi-subagent/src/api.ts +54 -1
- package/node_modules/@agwab/pi-subagent/src/artifacts/registry.ts +9 -4
- package/node_modules/@agwab/pi-subagent/src/artifacts/result.ts +8 -0
- package/node_modules/@agwab/pi-subagent/src/core/constants.ts +9 -0
- package/node_modules/@agwab/pi-subagent/src/core/validation.ts +21 -0
- package/node_modules/@agwab/pi-subagent/src/index.ts +995 -573
- package/node_modules/@agwab/pi-subagent/src/orchestrate/async.ts +279 -156
- package/node_modules/@agwab/pi-subagent/src/orchestrate/interrupt.ts +165 -89
- package/node_modules/@agwab/pi-subagent/src/orchestrate/reconcile.ts +111 -65
- package/node_modules/@agwab/pi-subagent/src/orchestrate/run-ref.ts +219 -0
- package/node_modules/@agwab/pi-subagent/src/orchestrate/run.ts +88 -8
- package/node_modules/@agwab/pi-subagent/src/orchestrate/status.ts +614 -298
- package/node_modules/@agwab/pi-subagent/src/panel.ts +1352 -560
- package/node_modules/@agwab/pi-subagent/src/runners/headless-model.ts +53 -5
- package/node_modules/@agwab/pi-subagent/src/runners/tmux.ts +13 -6
- package/package.json +2 -2
- package/src/compiler.ts +14 -9
- package/src/dynamic-decision.ts +0 -11
- package/src/dynamic-profiles.ts +0 -4
- package/src/engine-run-graph.ts +185 -2
- package/src/engine.ts +145 -24
- package/src/extension.ts +33 -4
- package/src/index.ts +3 -1
- package/src/store.ts +74 -11
- package/src/subagent-backend.ts +201 -28
- package/src/types.ts +6 -0
- package/src/workflow-runtime.ts +18 -2
- package/src/workflow-view.ts +2 -1
- package/src/workflow-web-source-extension.ts +621 -228
- package/src/workflow-web-source.ts +118 -28
- package/workflows/deep-research/helpers/claim-evidence-gate.mjs +56 -16
- package/workflows/deep-research/helpers/final-audit-packet.mjs +1 -4
- package/workflows/deep-research/helpers/normalize-input-packet.mjs +1 -1
- package/workflows/deep-research/helpers/render-executive.mjs +8 -21
- package/workflows/deep-research/helpers/sanitize-verification-candidates.mjs +89 -15
- package/workflows/deep-research/schemas/deep-research-executive-render-control.schema.json +0 -1
- package/workflows/deep-research/schemas/deep-research-verify-claims-control.schema.json +4 -1
- package/workflows/impact-review/spec.json +3 -3
- package/workflows/spec-review/helpers/spec-review-pipeline.mjs +1 -8
- package/dist/dynamic-loader.d.ts +0 -25
- package/dist/dynamic-loader.js +0 -13
- package/src/dynamic-loader.ts +0 -49
- package/workflows/impact-review/schemas/docs-release-impact-control.schema.json +0 -42
- package/workflows/impact-review/schemas/security-performance-impact-control.schema.json +0 -42
- package/workflows/impact-review/schemas/state-data-impact-control.schema.json +0 -42
|
@@ -33,20 +33,23 @@ Every call has an `action`. The default is `run`, so omitting `action` starts a
|
|
|
33
33
|
| `action` | Purpose | Key parameters |
|
|
34
34
|
|---|---|---|
|
|
35
35
|
| `run` (default) | Start a new subagent run, or launch independent runs in parallel. | `agent`/`task` or `tasks`; plus `sandbox`, `worktree`, `model`, `async`, etc. |
|
|
36
|
-
| `status` | Read a run's current state. | `runId`, optional `attemptId` |
|
|
37
|
-
| `logs` | Read a run's captured logs. | `runId`, optional `attemptId` |
|
|
38
|
-
| `wait` | Block until a run finishes. | `runId`, optional `timeoutMs`, `pollIntervalMs` |
|
|
39
|
-
| `interrupt` | Signal a process-backed run. | `runId`, optional `attemptId`, `signal`, `escalateAfterMs`, `killAfterMs`, `reason` |
|
|
40
|
-
| `mark-background` | Mark a run as not needed before the final answer. | `runId` |
|
|
41
|
-
| `reconcile` | Re-read durable artifacts and repair stale/orphaned state when possible. | `runId` |
|
|
36
|
+
| `status` | Read a run's current state. | `runId`, optional `cwd`, `attemptId` |
|
|
37
|
+
| `logs` | Read a run's captured logs. | `runId`, optional `cwd`, `attemptId` |
|
|
38
|
+
| `wait` | Block until a run finishes. | `runId`, optional `cwd`, `timeoutMs`, `pollIntervalMs` |
|
|
39
|
+
| `interrupt` | Signal a process-backed run. | `runId`, optional `cwd`, `attemptId`, `signal`, `escalateAfterMs`, `killAfterMs`, `reason` |
|
|
40
|
+
| `mark-background` | Mark a run as not needed before the final answer. | `runId`, optional `cwd` |
|
|
41
|
+
| `reconcile` | Re-read durable artifacts and repair stale/orphaned state when possible. | `runId`, optional `cwd` |
|
|
42
42
|
|
|
43
|
-
State is file-based under `.pi/agent/runs/<run-id>/`. `status`/`logs`/`wait` read those files; `interrupt` sends a real OS signal; `mark-background` updates run metadata; `reconcile` repairs local metadata from durable attempt artifacts without relaunching work.
|
|
43
|
+
State is file-based under `.pi/agent/runs/<run-id>/`. `status`/`logs`/`wait` read those files; `interrupt` sends a real OS signal; `mark-background` updates run metadata; `reconcile` repairs local metadata from durable attempt artifacts without relaunching work. Recent runs also write a global locator pointer, so existing-run actions can often resolve a `runId` even when `cwd` is omitted or the run was launched from another cwd.
|
|
44
|
+
|
|
45
|
+
Parent orchestrators may record descendant state with `recordSubagentChildEvent`, which appends `child.*` events to the parent run's `events.jsonl` (`child.started`, `child.failed`, `child.completed`, or `child.cancelled`). `status` and `/subagent panel` aggregate those into `childSummary`, including failure counts, active child run IDs, and the latest child failure. This keeps parent status distinct from descendant failures and makes retry attempts distinguishable from newly-started child work.
|
|
44
46
|
|
|
45
47
|
Model:
|
|
46
48
|
|
|
47
49
|
```text
|
|
48
50
|
run = one subagent execution
|
|
49
51
|
attempt = one launch attempt
|
|
52
|
+
child = descendant work reported by an orchestrator through child.* events
|
|
50
53
|
correlationId = optional external trace label
|
|
51
54
|
```
|
|
52
55
|
|
|
@@ -68,6 +71,7 @@ import {
|
|
|
68
71
|
waitForSubagent,
|
|
69
72
|
interruptSubagent,
|
|
70
73
|
reconcileSubagentRun,
|
|
74
|
+
recordSubagentChildEvent,
|
|
71
75
|
} from "@agwab/pi-subagent/api";
|
|
72
76
|
|
|
73
77
|
const run = await runSubagent({
|
|
@@ -83,9 +87,17 @@ const logs = await getSubagentLogs({ cwd: process.cwd(), runId: run.runId });
|
|
|
83
87
|
await waitForSubagent({ cwd: process.cwd(), runId: run.runId, timeoutMs: 300000 });
|
|
84
88
|
await interruptSubagent({ cwd: process.cwd(), runId: run.runId, reason: "caller cancelled" });
|
|
85
89
|
await reconcileSubagentRun({ cwd: process.cwd(), runId: run.runId });
|
|
90
|
+
await recordSubagentChildEvent({
|
|
91
|
+
cwd: process.cwd(),
|
|
92
|
+
runId: run.runId,
|
|
93
|
+
event: "failed",
|
|
94
|
+
childRunId: "run_child_123",
|
|
95
|
+
childTaskId: "task-4",
|
|
96
|
+
failureKind: "model",
|
|
97
|
+
});
|
|
86
98
|
```
|
|
87
99
|
|
|
88
|
-
`runSubagent` accepts the same run options as the tool, plus an optional `signal`. Existing-run helpers accept `
|
|
100
|
+
`runSubagent` accepts the same run options as the tool, plus an optional `signal`. Existing-run helpers accept `runId`, optional `cwd`, optional `attemptId`, and optional `runsDir`; when `cwd` is omitted they use the global locator index first and fall back to the current cwd for legacy records. The API is intentionally object-only and does not expose the lower-level runner internals.
|
|
89
101
|
|
|
90
102
|
The code API is ESM-only. Import `@agwab/pi-subagent/api`; do not deep-import internal files such as `src/orchestrate/*` because only documented package subpaths are public.
|
|
91
103
|
|
|
@@ -128,6 +140,21 @@ Use `concurrency` to cap parallel fan-out:
|
|
|
128
140
|
}
|
|
129
141
|
```
|
|
130
142
|
|
|
143
|
+
For synchronous parallel fan-out, `failFast:true` stops scheduling additional siblings after the first failed result. Add `cancelSiblingsOnFailure:true` to also abort siblings that are already running:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"failFast": true,
|
|
148
|
+
"cancelSiblingsOnFailure": true,
|
|
149
|
+
"tasks": [
|
|
150
|
+
{ "task": "Run check A." },
|
|
151
|
+
{ "task": "Run check B." }
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The parallel response includes `totalTasks`, `startedCount`, `skippedCount`, and `failFastTriggered` so callers can distinguish skipped siblings from completed/failed runs. Async parallel launches return once children are started, so fail-fast decisions for later runtime failures must be handled by the parent/workflow layer.
|
|
157
|
+
|
|
131
158
|
Chain/sequential execution is intentionally not supported by this engine. If step B needs output from step A, keep that sequencing in the parent agent or a workflow layer.
|
|
132
159
|
|
|
133
160
|
## Async and existing runs
|
|
@@ -177,14 +204,26 @@ Interrupt a process-backed run:
|
|
|
177
204
|
|
|
178
205
|
`interrupt` is conservative. It can signal runs with registered process metadata. Unsupported or already-terminal runs return explicit status rather than pretending cancellation succeeded.
|
|
179
206
|
|
|
207
|
+
### Existing-run resolution
|
|
208
|
+
|
|
209
|
+
For `status`, `logs`, `wait`, `interrupt`, `mark-background`, and `reconcile`, the lookup order is:
|
|
210
|
+
|
|
211
|
+
1. Use the explicit `cwd`/`runsDir` when provided.
|
|
212
|
+
2. Otherwise, check the current cwd's `.pi/agent/runs` for legacy/local records.
|
|
213
|
+
3. Otherwise, resolve `runId` through the global locator index and read the pointed-to run directory.
|
|
214
|
+
|
|
215
|
+
The locator index is only a pointer for finding runs across cwd boundaries. `run.json`, `events.jsonl`, and attempt `result.json` files remain the source of truth.
|
|
216
|
+
|
|
180
217
|
## Common run options
|
|
181
218
|
|
|
182
219
|
| Option | Use |
|
|
183
220
|
|---|---|
|
|
184
|
-
| `cwd` | Run from a specific project directory. Existing-run actions
|
|
221
|
+
| `cwd` | Run from a specific project directory. Existing-run actions accept `cwd` to force a registry location; if omitted, recent runs can be found by global locator and older runs fall back to the current cwd. |
|
|
185
222
|
| `timeoutMs` | Limit worker execution time for `run`; limit polling duration for `action: "wait"`. Omit it for no runtime kill deadline; `wait` alone defaults to 60s polling. |
|
|
186
223
|
| `visible` | Use a visible tmux-backed worker (`visible: true`). |
|
|
187
224
|
| `concurrency` | Cap parallel run fan-out. |
|
|
225
|
+
| `failFast` | For synchronous parallel runs, stop scheduling new siblings after the first failed result. |
|
|
226
|
+
| `cancelSiblingsOnFailure` | For synchronous parallel runs, abort already-running siblings after the first failed result; implies fail-fast scheduling. |
|
|
188
227
|
| `model` | Select a Pi model/provider for model-backed workers. |
|
|
189
228
|
| `thinking` / `thinkingLevel` / `reasoningLevel` | Set the reasoning level. |
|
|
190
229
|
| `tools` | Tool allowlist. With a named agent this may only narrow agent-declared tools; it cannot expand authority. For agentless runs it sets the full tool allowlist. |
|
|
@@ -247,8 +286,8 @@ There are three inputs for worktree isolation, in order of preference:
|
|
|
247
286
|
| Input | When to use |
|
|
248
287
|
|---|---|
|
|
249
288
|
| `worktree` | Primary switch. `true` to isolate; or a string path for an explicit worktree location. |
|
|
250
|
-
| `workspace` | Advanced. `"shared"
|
|
251
|
-
| `worktreePolicy` | Advanced. `"auto"
|
|
289
|
+
| `workspace` | Advanced. `"shared" \| "worktree" \| "auto"`, or `{ mode, path }` for an explicit path. |
|
|
290
|
+
| `worktreePolicy` | Advanced. `"auto" \| "required" \| "never"` to force or forbid isolation. |
|
|
252
291
|
|
|
253
292
|
Most calls only need `worktree`:
|
|
254
293
|
|
|
@@ -389,6 +428,8 @@ Runs write durable evidence under:
|
|
|
389
428
|
|
|
390
429
|
`run.json` records a `parentSessionId` field: the Pi session id of the session that launched the run, injected from the tool context (not a model-settable argument). Consumers (e.g. status panels) can use it to scope a shared per-`cwd` runs directory to the session that owns each run. The field is omitted when no session id is available, and older records simply lack it.
|
|
391
430
|
|
|
431
|
+
Recent runs also write a small locator file under Pi's global subagent-run index. A locator contains the `runId`, absolute `cwd`, optional `runsDir`, optional `parentSessionId`, optional `correlationId`, and `updatedAt`. It is not authoritative evidence and can become stale if the pointed-to run directory is moved or deleted; use `run.json`, `events.jsonl`, and attempt `result.json` as the source of truth.
|
|
432
|
+
|
|
392
433
|
Older `schemaVersion: 1` artifacts under `<run-id>/<task-id>/` are still readable for compatibility.
|
|
393
434
|
|
|
394
435
|
Tool responses return compact status and artifact references rather than raw logs.
|
|
@@ -399,7 +440,17 @@ Tool responses return compact status and artifact references rather than raw log
|
|
|
399
440
|
/subagent panel
|
|
400
441
|
```
|
|
401
442
|
|
|
402
|
-
The panel shows
|
|
443
|
+
The panel shows run/attempt details, workspace/artifact paths, dependency metadata, event tail, and log tail. It has three scopes:
|
|
444
|
+
|
|
445
|
+
- `session`: runs whose `run.json.parentSessionId` matches the current Pi session. This is the default when a session id is available.
|
|
446
|
+
- `cwd`: runs under the current workspace's `.pi/agent/runs`, including legacy records that lack `parentSessionId`.
|
|
447
|
+
- `all`: the global locator index plus current-cwd legacy records.
|
|
448
|
+
|
|
449
|
+
Status filters are `all`, `running`, `completed`, and `failed`. In the `all` status view, the default list shows all active runs plus recent terminal runs only: 20 for `session`/`cwd`, 50 for `all`. The `completed` and `failed` filters use the same recent terminal cap; `running` is uncapped. The header reports `shown/total`, and when older matching runs are hidden, press `m` in the panel to show more; no separate command is needed. The panel keeps a fixed-height layout, uses an internally scrollable detail pane, and never renders raw `parentSessionId` values.
|
|
450
|
+
|
|
451
|
+
Stale or malformed locators are counted in the header and skipped. Active runs whose process metadata is dead and whose heartbeat/update timestamp is stale are rendered read-only as `failed` with failure `stale`; the panel does not mutate or delete records. Use `action:"reconcile"` to repair local registry state from durable artifacts when possible.
|
|
452
|
+
|
|
453
|
+
The panel is for human inspection; existing-run tool actions remain the programmatic interface.
|
|
403
454
|
|
|
404
455
|
## Development validation
|
|
405
456
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agwab/pi-subagent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Minimal subagent runtime for Pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"image": "https://raw.githubusercontent.com/AgwaB/pi-subagent/main/assets/subagent-panel.png"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
|
-
"check:scripts": "for d in scripts test
|
|
40
|
+
"check:scripts": "for d in scripts test; do [ -d \"$d\" ] && find \"$d\" -name '*.mjs' -print; done | xargs -n1 node --check",
|
|
41
41
|
"check:resolver": "node ./test/checks/resolver.mjs",
|
|
42
42
|
"check:api": "node ./test/checks/api.mjs",
|
|
43
43
|
"check:artifacts": "node ./test/checks/artifacts.mjs",
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { loadAgentByName, type AgentDefinition } from "./agents.ts";
|
|
3
|
-
import
|
|
3
|
+
import {
|
|
4
|
+
appendRunEvent,
|
|
5
|
+
type ResultEnvelope,
|
|
6
|
+
type RunEvent,
|
|
7
|
+
} from "./artifacts/index.ts";
|
|
4
8
|
import type {
|
|
5
9
|
ExecutionMode,
|
|
10
|
+
FailureKind,
|
|
6
11
|
ResolveInput,
|
|
7
12
|
ResolvedBackend,
|
|
13
|
+
Status,
|
|
8
14
|
} from "./core/constants.ts";
|
|
9
15
|
import { resolveBackend } from "./core/resolver.ts";
|
|
10
16
|
import { validateResolveInput } from "./core/validation.ts";
|
|
@@ -22,6 +28,7 @@ import {
|
|
|
22
28
|
type ReconcileSubagentRunOptions as ReconcileRunOptions,
|
|
23
29
|
type ReconcileSubagentRunResult,
|
|
24
30
|
} from "./orchestrate/reconcile.ts";
|
|
31
|
+
import { resolveRunRef } from "./orchestrate/run-ref.ts";
|
|
25
32
|
import {
|
|
26
33
|
runParallelSubagentTasks,
|
|
27
34
|
runSubagentTask,
|
|
@@ -50,6 +57,16 @@ export type WaitForSubagentOptions = WaitForRunOptions;
|
|
|
50
57
|
export type InterruptSubagentOptions = InterruptRunOptions;
|
|
51
58
|
export type ReconcileSubagentOptions = ReconcileRunOptions;
|
|
52
59
|
|
|
60
|
+
export interface RecordSubagentChildEventOptions extends RunStatusRef {
|
|
61
|
+
event: "started" | "updated" | "completed" | "failed" | "cancelled";
|
|
62
|
+
childRunId: string;
|
|
63
|
+
workflowRunId?: string;
|
|
64
|
+
childTaskId?: string;
|
|
65
|
+
status?: Status;
|
|
66
|
+
failureKind?: FailureKind | string | null;
|
|
67
|
+
message?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
export class SubagentValidationError extends Error {
|
|
54
71
|
readonly failureKind = "validation" as const;
|
|
55
72
|
readonly backend?: ResolvedBackend;
|
|
@@ -269,6 +286,40 @@ export async function reconcileSubagentRun(
|
|
|
269
286
|
return await reconcileRun(options);
|
|
270
287
|
}
|
|
271
288
|
|
|
289
|
+
function defaultChildStatus(
|
|
290
|
+
event: RecordSubagentChildEventOptions["event"],
|
|
291
|
+
): Status {
|
|
292
|
+
if (event === "started" || event === "updated") return "running";
|
|
293
|
+
if (event === "completed") return "completed";
|
|
294
|
+
if (event === "cancelled") return "cancelled";
|
|
295
|
+
return "failed";
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export async function recordSubagentChildEvent(
|
|
299
|
+
options: RecordSubagentChildEventOptions,
|
|
300
|
+
): Promise<RunEvent> {
|
|
301
|
+
const {
|
|
302
|
+
event,
|
|
303
|
+
childRunId,
|
|
304
|
+
workflowRunId,
|
|
305
|
+
childTaskId,
|
|
306
|
+
failureKind,
|
|
307
|
+
message,
|
|
308
|
+
} = options;
|
|
309
|
+
const ref = await resolveRunRef(options);
|
|
310
|
+
return await appendRunEvent(ref, {
|
|
311
|
+
type: `child.${event}`,
|
|
312
|
+
status: options.status ?? defaultChildStatus(event),
|
|
313
|
+
...(message === undefined ? {} : { message }),
|
|
314
|
+
data: {
|
|
315
|
+
childRunId,
|
|
316
|
+
...(workflowRunId === undefined ? {} : { workflowRunId }),
|
|
317
|
+
...(childTaskId === undefined ? {} : { taskId: childTaskId }),
|
|
318
|
+
...(failureKind === undefined ? {} : { failureKind }),
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
272
323
|
export type {
|
|
273
324
|
ArtifactRef,
|
|
274
325
|
CompletionMetadata,
|
|
@@ -294,6 +345,8 @@ export type { InterruptRunResult } from "./orchestrate/interrupt.ts";
|
|
|
294
345
|
export type { ReconcileSubagentRunResult } from "./orchestrate/reconcile.ts";
|
|
295
346
|
export type { ParallelRunResult } from "./orchestrate/run.ts";
|
|
296
347
|
export type {
|
|
348
|
+
RunChildFailureSummary,
|
|
349
|
+
RunChildSummary,
|
|
297
350
|
RunLogRef,
|
|
298
351
|
RunLogsSnapshot,
|
|
299
352
|
RunStatusRef,
|
|
@@ -18,6 +18,11 @@ export type RunEventType =
|
|
|
18
18
|
| "run.cancelled"
|
|
19
19
|
| "run.interrupt_requested"
|
|
20
20
|
| "run.mark_background"
|
|
21
|
+
| "child.started"
|
|
22
|
+
| "child.updated"
|
|
23
|
+
| "child.completed"
|
|
24
|
+
| "child.failed"
|
|
25
|
+
| "child.cancelled"
|
|
21
26
|
| "attempt.started"
|
|
22
27
|
| "attempt.process_started"
|
|
23
28
|
| "attempt.heartbeat"
|
|
@@ -716,11 +721,11 @@ export async function readRunEvents(ref: RunRef, limit = 50): Promise<RunEvent[]
|
|
|
716
721
|
const paths = runPaths(ref);
|
|
717
722
|
try {
|
|
718
723
|
const text = await readFile(paths.eventsPath, "utf8");
|
|
719
|
-
|
|
724
|
+
const lines = text
|
|
720
725
|
.split(/\r?\n/)
|
|
721
|
-
.filter(Boolean)
|
|
722
|
-
|
|
723
|
-
|
|
726
|
+
.filter(Boolean);
|
|
727
|
+
const selected = Number.isFinite(limit) ? lines.slice(-limit) : lines;
|
|
728
|
+
return selected.map((line) => JSON.parse(line) as RunEvent);
|
|
724
729
|
} catch (error) {
|
|
725
730
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return [];
|
|
726
731
|
throw error;
|
|
@@ -80,6 +80,7 @@ export interface ResultSessionMetadata {
|
|
|
80
80
|
|
|
81
81
|
export interface ResultMetadata {
|
|
82
82
|
contextLengthExceeded: boolean;
|
|
83
|
+
contextOverflowRecovered?: boolean;
|
|
83
84
|
provider?: string;
|
|
84
85
|
model?: string;
|
|
85
86
|
usage?: unknown;
|
|
@@ -89,6 +90,7 @@ export interface ResultMetadata {
|
|
|
89
90
|
session?: ResultSessionMetadata;
|
|
90
91
|
streamErrors?: string[];
|
|
91
92
|
nonFatalStreamErrors?: string[];
|
|
93
|
+
recoveredStreamErrors?: string[];
|
|
92
94
|
parseErrors?: string[];
|
|
93
95
|
}
|
|
94
96
|
|
|
@@ -199,6 +201,9 @@ function normalizeMetadata(input: ResultEnvelopeInput): ResultMetadata {
|
|
|
199
201
|
const metadata = input.metadata ?? {};
|
|
200
202
|
return {
|
|
201
203
|
contextLengthExceeded: metadata.contextLengthExceeded ?? false,
|
|
204
|
+
...(metadata.contextOverflowRecovered === undefined
|
|
205
|
+
? {}
|
|
206
|
+
: { contextOverflowRecovered: metadata.contextOverflowRecovered }),
|
|
202
207
|
...(metadata.provider === undefined ? {} : { provider: metadata.provider }),
|
|
203
208
|
...(metadata.model === undefined ? {} : { model: metadata.model }),
|
|
204
209
|
...(metadata.usage === undefined ? {} : { usage: metadata.usage }),
|
|
@@ -218,6 +223,9 @@ function normalizeMetadata(input: ResultEnvelopeInput): ResultMetadata {
|
|
|
218
223
|
...(metadata.nonFatalStreamErrors === undefined
|
|
219
224
|
? {}
|
|
220
225
|
: { nonFatalStreamErrors: metadata.nonFatalStreamErrors }),
|
|
226
|
+
...(metadata.recoveredStreamErrors === undefined
|
|
227
|
+
? {}
|
|
228
|
+
: { recoveredStreamErrors: metadata.recoveredStreamErrors }),
|
|
221
229
|
...(metadata.parseErrors === undefined
|
|
222
230
|
? {}
|
|
223
231
|
: { parseErrors: metadata.parseErrors }),
|
|
@@ -16,6 +16,11 @@ export const FAILURE_KINDS = [
|
|
|
16
16
|
"sandbox",
|
|
17
17
|
"rpc",
|
|
18
18
|
"model",
|
|
19
|
+
"provider_error",
|
|
20
|
+
"model_error",
|
|
21
|
+
"output_schema_error",
|
|
22
|
+
"guard_failure",
|
|
23
|
+
"user_cancelled",
|
|
19
24
|
"tool",
|
|
20
25
|
"exit",
|
|
21
26
|
"parse",
|
|
@@ -109,6 +114,10 @@ export interface ResolveInput {
|
|
|
109
114
|
mode?: ExecutionMode;
|
|
110
115
|
tasks?: SubagentTaskInput[];
|
|
111
116
|
concurrency?: number;
|
|
117
|
+
/** Stop scheduling additional parallel siblings after the first failed result. */
|
|
118
|
+
failFast?: boolean;
|
|
119
|
+
/** Abort already-running parallel siblings after the first failed result. Implies fail-fast scheduling. */
|
|
120
|
+
cancelSiblingsOnFailure?: boolean;
|
|
112
121
|
asyncDependency?: AsyncDependency;
|
|
113
122
|
workspace?: WorkspaceInput | WorkspaceMode;
|
|
114
123
|
worktree?: boolean | string;
|
|
@@ -572,6 +572,27 @@ export function validateResolveInput(
|
|
|
572
572
|
input.concurrency = concurrency;
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
+
if (raw.failFast !== undefined) {
|
|
576
|
+
const failFast = validateBoolean(
|
|
577
|
+
raw.failFast,
|
|
578
|
+
"failFast",
|
|
579
|
+
backendForKnownFailure,
|
|
580
|
+
);
|
|
581
|
+
if (typeof failFast !== "boolean") return failFast;
|
|
582
|
+
input.failFast = failFast;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (raw.cancelSiblingsOnFailure !== undefined) {
|
|
586
|
+
const cancelSiblingsOnFailure = validateBoolean(
|
|
587
|
+
raw.cancelSiblingsOnFailure,
|
|
588
|
+
"cancelSiblingsOnFailure",
|
|
589
|
+
backendForKnownFailure,
|
|
590
|
+
);
|
|
591
|
+
if (typeof cancelSiblingsOnFailure !== "boolean")
|
|
592
|
+
return cancelSiblingsOnFailure;
|
|
593
|
+
input.cancelSiblingsOnFailure = cancelSiblingsOnFailure;
|
|
594
|
+
}
|
|
595
|
+
|
|
575
596
|
if (raw.chain !== undefined) {
|
|
576
597
|
return failure(
|
|
577
598
|
'chain mode is not supported by pi-subagent; use mode:"parallel" for fanout or have the parent orchestrate sequencing.',
|