@signalridge/pi-workflows 1.3.2 → 1.4.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 +5 -0
- package/README.md +40 -11
- package/package.json +3 -2
- package/skills/workflow-authoring/SKILL.md +166 -18
- package/skills/workflow-authoring/examples/named-task-graph.js +34 -0
- package/skills/workflow-authoring/references/capabilities.md +2 -1
- package/skills/workflow-authoring/references/capability-details.md +22 -4
- package/skills/workflow-authoring/references/focused-recipes.md +1 -0
- package/skills/workflow-authoring/references/lifecycle.md +3 -3
- package/skills/workflow-authoring/references/pattern-selection.md +1 -0
- package/skills/workflow-authoring/references/registry-ownership.md +1 -1
- package/skills/workflow-authoring/references/review.md +7 -5
- package/skills/workflow-authoring/references/runtime.md +4 -3
- package/skills/workflow-patterns/SKILL.md +72 -33
- package/skills/workflow-review/SKILL.md +70 -0
- package/src/capabilities.ts +28 -3
- package/src/engine.ts +384 -124
- package/src/index.ts +126 -9
- package/src/journal.ts +266 -27
- package/src/orchestrator.ts +478 -0
- package/src/runtime.ts +332 -123
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
### Minor Changes
|
|
5
|
+
|
|
6
|
+
- 28c8aa1: Strengthen script orchestration with deterministic named dependency graphs, bounded task retries and failure policies, safer fan-out barriers, durable nested-workflow replay, and reliable pause/resume accounting. The natural-language `/workflows run` path now plans, executes, and synthesizes a bounded task graph, while expanded authoring/pattern guidance and the new `workflow-review` skill make routing, recovery, and publication constraints explicit.
|
|
7
|
+
|
|
3
8
|
## 1.3.2
|
|
4
9
|
### Patch Changes
|
|
5
10
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
JavaScript orchestration for Pi. A workflow is a raw JavaScript module executed
|
|
4
4
|
in a determinism-guarded `node:vm` realm; the runtime supplies `agent()`,
|
|
5
|
-
`parallel()`, `pipeline()`, `workflow()`, quality helpers (`verify`,
|
|
5
|
+
`parallel()`, `pipeline()`, `orchestrate()`, `workflow()`, quality helpers (`verify`,
|
|
6
6
|
`judgePanel`, `loopUntilDry`, `completenessCheck`, `retry`, `gate`), human
|
|
7
7
|
`checkpoint()`, `phase()`, `log()`, `args`, `cwd`, restricted `process`, and
|
|
8
8
|
`budget`. Every live `agent()` call is dispatched through the additive
|
|
@@ -69,8 +69,9 @@ return report;
|
|
|
69
69
|
The meta statement must be the first statement and use only literals — spread,
|
|
70
70
|
computed keys, methods, template interpolation, and the reserved keys
|
|
71
71
|
`__proto__`/`constructor`/`prototype` are rejected. `Date.now()`,
|
|
72
|
-
`Math.random()`, and no-argument `new Date()` are unavailable (
|
|
73
|
-
plus in-realm stubs);
|
|
72
|
+
`Math.random()`, and no-argument `new Date()` are unavailable (an AST precheck
|
|
73
|
+
plus in-realm stubs); prompt text containing those words remains valid. Pass
|
|
74
|
+
timestamps and randomness through `args`. The vm is
|
|
74
75
|
a determinism guardrail, not a security boundary — scripts are generated by the
|
|
75
76
|
user's own LLM and run on the user's own machine.
|
|
76
77
|
|
|
@@ -78,7 +79,8 @@ user's own LLM and run on the user's own machine.
|
|
|
78
79
|
|
|
79
80
|
- `agent(prompt, { label, phase, schema, model, tier, isolation, thread, agentType, toolset, excludeTools, timeoutMs, retries })`
|
|
80
81
|
— dispatch one subagent through the managed spawn protocol. Returns text, a
|
|
81
|
-
schema-validated value, or recoverable `null` after retries.
|
|
82
|
+
schema-validated value, or recoverable `null` after retries. Replayed journal
|
|
83
|
+
calls consume no real-dispatch cap or token/phase budget. `schema` is a
|
|
82
84
|
plain JSON Schema; the reply is parsed and validated client-side with bounded
|
|
83
85
|
repair across attempts, and exhaustion throws `SCHEMA_NONCOMPLIANCE`.
|
|
84
86
|
Explicit `model` and `isolation: "worktree"` are resolved and enforced by pi-subagents; `tier` remains the provider-neutral route.
|
|
@@ -86,12 +88,21 @@ user's own LLM and run on the user's own machine.
|
|
|
86
88
|
conversation thread.
|
|
87
89
|
- `parallel(thunks)` — run thunks concurrently, preserve input order. Recoverable
|
|
88
90
|
thunk failures become `null`; non-recoverable failures (token budget, agent
|
|
89
|
-
limit) halt the run. Fan-out that breaches
|
|
90
|
-
batch.
|
|
91
|
+
limit) halt the run after the batch barrier settles. Fan-out that breaches
|
|
92
|
+
`maxAgents` cancels only its own batch; each call accepts at most 4096 thunks.
|
|
91
93
|
- `pipeline(items, ...stages)` — items run concurrently, stages per item run
|
|
92
|
-
sequentially with `(previousValue, originalItem, index)
|
|
94
|
+
sequentially with `(previousValue, originalItem, index)`; each call accepts at
|
|
95
|
+
most 4096 items and waits for the batch before surfacing fatal failures.
|
|
96
|
+
- `orchestrate(tasks, { onError })` — execute a named dependency graph in
|
|
97
|
+
deterministic declaration-order layers. Each task is `{ id, dependsOn?, phase?,
|
|
98
|
+
retries?, run }`; its callback receives `{ id, attempt, results, statuses }`.
|
|
99
|
+
`onError` is `skip-dependents` (default), `continue`, or `fail-fast`. Results
|
|
100
|
+
are keyed by task id, and task lifecycle events are observable through
|
|
101
|
+
`onRuntimeEvent`.
|
|
93
102
|
- `workflow(savedName, childArgs?)` — run a saved workflow inline; one nested
|
|
94
|
-
level, sharing the limiter, counters, token accounting, and store.
|
|
103
|
+
level, sharing the limiter, counters, token accounting, and store. The child
|
|
104
|
+
result is journaled as one parent call with a generation-scoped namespace, so
|
|
105
|
+
unchanged nested work replays without spawning again after resume.
|
|
95
106
|
- `verify(item, { reviewers, threshold, lens })`, `judgePanel(attempts,
|
|
96
107
|
{ judges, rubric })`, `loopUntilDry({ round, key, consecutiveEmpty,
|
|
97
108
|
maxRounds })`, `completenessCheck(taskArgs, results)`, `retry(thunk,
|
|
@@ -107,17 +118,35 @@ user's own LLM and run on the user's own machine.
|
|
|
107
118
|
### Resume
|
|
108
119
|
|
|
109
120
|
A script edit replays the longest unchanged prefix from the journal and runs
|
|
110
|
-
live from the first changed or inserted `agent()`/`checkpoint()` call.
|
|
111
|
-
`
|
|
121
|
+
live from the first changed or inserted `agent()`/`checkpoint()` call. The
|
|
122
|
+
original invocation `args` and execution limits are frozen and reused on manual
|
|
123
|
+
or automatic resume. Pass `resumeFromRunId` with the edited script; unchanged
|
|
124
|
+
calls report zero tokens,
|
|
112
125
|
and edited calls rotate their managed spawn key generation so pi-subagents
|
|
113
126
|
never raises a fingerprint conflict.
|
|
114
127
|
|
|
128
|
+
## Skills
|
|
129
|
+
|
|
130
|
+
The package ships three model-routable skills:
|
|
131
|
+
|
|
132
|
+
- `workflow-authoring` — design, review, and debug custom JavaScript workflows;
|
|
133
|
+
it teaches topology selection, stable work IDs, bounded failure handling, and
|
|
134
|
+
resume-safe authoring.
|
|
135
|
+
- `workflow-patterns` — choose and invoke a reviewed built-in for research,
|
|
136
|
+
adversarial review, code review, multi-perspective analysis, or codebase audit.
|
|
137
|
+
- `workflow-review` — audit an existing workflow for topology, data flow,
|
|
138
|
+
recovery, resume safety, and publication readiness without editing it.
|
|
139
|
+
|
|
140
|
+
Use the pattern skill for a standard task, the authoring skill for a custom
|
|
141
|
+
workflow, and the review skill before accepting a topology or recovery change.
|
|
142
|
+
|
|
115
143
|
## Tools and commands
|
|
116
144
|
|
|
117
145
|
- `workflow`: run a script (`script`) or a saved/built-in workflow (`name`),
|
|
118
146
|
with `args`, `background` (default true), `maxAgents`, `concurrency`,
|
|
119
147
|
`agentRetries`, `tokenBudget`, `agentTimeoutMs`, and `resumeFromRunId`.
|
|
120
148
|
- `workflow_control`: `list`, `get`, `pause`, `resume`, `stop`, or `rm` a run; `rm` writes a durable removal tombstone.
|
|
149
|
+
- `pi.events` emits `pi-workflows:runtime` snapshots (`{ runId, event }`) for phase, task, quality, retry, and nested-workflow progress; observer failures are contained.
|
|
121
150
|
- `/workflows`: TUI navigator plus `run`, `status`, `watch`, `stop`, `pause`,
|
|
122
151
|
`resume`, `rm`, and `save <name> [runId]` subcommands.
|
|
123
152
|
- `/workflows-models`: points at pi-subagents' `/agents → Model tiers` — there
|
|
@@ -163,4 +192,4 @@ The managed protocol carries semantic tiers plus optional exact model/thinking,
|
|
|
163
192
|
- **Agent registry and tier catalogue ownership.** `agentType` and `small|medium|large` profiles resolve in pi-subagents, avoiding a second registry/config schema.
|
|
164
193
|
- **Schema validation is client-side.** The managed request does not assume a structured-output tool; the runtime asks for JSON, parses, validates (including `additionalProperties`), and repairs across bounded attempts.
|
|
165
194
|
|
|
166
|
-
State is persisted as `pi.appendEntry("pi-workflows:journal", ...)` custom entries (schema v3), including script revisions and durable removals. Interrupted/provider-limited runs replay from the journal; schema-v2 declarative journals are quarantined rather than replayed. Foreground `AbortSignal`s stop owned children through explicit owner-scoped stop/quiescence, and dispose/branch replacement reject stale waiters.
|
|
195
|
+
State is persisted as `pi.appendEntry("pi-workflows:journal", ...)` custom entries (schema v3), including frozen invocation args, terminal result previews, script revisions, named nested-workflow result boundaries, and durable removals. Interrupted/provider-limited runs replay from the journal; schema-v2 declarative journals are quarantined rather than replayed. Foreground `AbortSignal`s stop owned children through explicit owner-scoped stop/quiescence, and dispose/branch replacement reject stale waiters.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signalridge/pi-workflows",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Deterministic JavaScript orchestration workflows backed by pi-subagents managed spawning.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
],
|
|
31
31
|
"skills": [
|
|
32
32
|
"skills/workflow-authoring",
|
|
33
|
-
"skills/workflow-patterns"
|
|
33
|
+
"skills/workflow-patterns",
|
|
34
|
+
"skills/workflow-review"
|
|
34
35
|
]
|
|
35
36
|
},
|
|
36
37
|
"repository": {
|
|
@@ -1,30 +1,178 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: workflow-authoring
|
|
3
|
-
description:
|
|
3
|
+
description: Design, write, review, and debug Pi JavaScript workflows that coordinate multiple subagents. Use when a request needs named dependencies, bounded fan-out, per-item pipelines, quality gates, saved or nested workflows, pause/resume, or workflow progress; do not use it merely to run an existing named workflow.
|
|
4
4
|
metadata:
|
|
5
|
-
version: "1.
|
|
5
|
+
version: "1.4.0"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Workflow authoring
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
A workflow is a small program that coordinates subagents; it is not a long prompt
|
|
11
|
+
that asks one agent to do every step. Keep semantic work in agents and keep
|
|
12
|
+
identity, ordering, bounds, failure handling, and aggregation deterministic in
|
|
13
|
+
JavaScript.
|
|
11
14
|
|
|
12
|
-
##
|
|
15
|
+
## Operating contract
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
- Use a workflow only when the task benefits from multiple agents, explicit
|
|
18
|
+
stages, independent coverage, or a quality/recovery loop. One or two simple
|
|
19
|
+
delegations should use the ordinary agent surface.
|
|
20
|
+
- Start every script with literal `export const meta = { name, description,
|
|
21
|
+
phases? }`. Return plain JSON data explicitly.
|
|
22
|
+
- Use `orchestrate()` for named dependencies, `parallel()` for a small
|
|
23
|
+
independent barrier, and `pipeline()` for independent items that each need a
|
|
24
|
+
sequential stage chain. Do not encode a dependency graph only in comments.
|
|
25
|
+
- Give every work unit a stable ID and every agent call a short unique label.
|
|
26
|
+
Keep IDs beside results before filtering; `null` is missing coverage, not a
|
|
27
|
+
successful finding.
|
|
28
|
+
- Bound graph tasks, fan-out items, loops, retries, agents, concurrency, and
|
|
29
|
+
evidence size. Invocation-level token and time caps are user constraints, not
|
|
30
|
+
substitutes for algorithmic bounds.
|
|
31
|
+
- Route an agent call with `tier: "small"`, `"medium"`, or `"large"`; omit
|
|
32
|
+
`tier` to use the pi-subagents workflow default. Never guess nonstandard model
|
|
33
|
+
routes, tiers, or agent types—use a name supplied by the current environment
|
|
34
|
+
and follow [registry ownership](references/registry-ownership.md).
|
|
35
|
+
- Workflows have no imports, filesystem/network APIs, timers, or unrestricted
|
|
36
|
+
Node APIs. Pass timestamps, randomness, and external decisions through `args`.
|
|
15
37
|
|
|
16
|
-
|
|
17
|
-
- **Helper task:** read [quality helpers](references/quality-helpers.md) only for `verify` or `judgePanel`, the [retry helper](references/retry-helper.md) only for `retry`, and [specialized helpers](references/specialized-helpers.md) only for `completenessCheck`, `loopUntilDry`, `gate`, or `checkpoint`.
|
|
18
|
-
- **Review:** use the [review checklist](references/review.md), plus only the matching [quality](references/quality-helpers.md) or [specialized](references/specialized-helpers.md) helper contracts.
|
|
19
|
-
- **Debug:** use the [debugging map](references/debugging.md).
|
|
20
|
-
- **Routing:** read [registry ownership](references/registry-ownership.md) before using `model`, `tier`, phase models, or `agentType`; use environment-specific names only when context supplies them.
|
|
21
|
-
- **Exact lookup or portability:** start with the generated [capability index](references/capabilities.md). Follow its exhaustive-facts pointer only for constraints or support boundaries. Use [versions](references/versions.md) when moving scripts between installations.
|
|
38
|
+
## The authoring pass
|
|
22
39
|
|
|
23
|
-
|
|
40
|
+
1. **Classify the topology.** Decide whether the work is direct, a named DAG,
|
|
41
|
+
homogeneous fan-out, a per-item pipeline, iterative discovery, or a quality
|
|
42
|
+
gate. Read [pattern selection](references/pattern-selection.md) only for the
|
|
43
|
+
chosen shape.
|
|
44
|
+
2. **Declare inputs and bounds.** Read `args` once, normalize the input, reject
|
|
45
|
+
or cap untrusted cardinality, and decide what incomplete coverage means.
|
|
46
|
+
3. **Write the envelope.** Declare only phases that are actually entered. Use
|
|
47
|
+
`phase(title, { budget })` for a soft token sub-budget, not as a scheduler.
|
|
48
|
+
4. **Build the smallest work ledger.** Store `{ id, status, result, error }`
|
|
49
|
+
(or an equivalent object) for each intended unit. Do not lose identity when
|
|
50
|
+
applying `.filter(Boolean)`.
|
|
51
|
+
5. **Dispatch with the right primitive.** Await every batch. For a dependent
|
|
52
|
+
prompt, include both the dependency ID and its actual result; do not assume
|
|
53
|
+
the child can see the parent conversation.
|
|
54
|
+
6. **Add quality only where it changes a decision.** Use a schema before reading
|
|
55
|
+
structured fields, then use `verify`, `judgePanel`, `gate`, or
|
|
56
|
+
`completenessCheck` with explicit bounds.
|
|
57
|
+
7. **Aggregate and report.** Return a bounded JSON result containing the answer,
|
|
58
|
+
coverage, and important failures. If the workflow runs in the background,
|
|
59
|
+
the run ID is the handle for later control/resume.
|
|
60
|
+
8. **Review the script.** Use [the review checklist](references/review.md), then
|
|
61
|
+
test with deterministic fake agents when changing topology or recovery.
|
|
24
62
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
63
|
+
## Topology rules
|
|
64
|
+
|
|
65
|
+
### Named dependencies: `orchestrate`
|
|
66
|
+
|
|
67
|
+
Use a task graph when a later step consumes a named earlier step:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
const graph = await orchestrate([
|
|
71
|
+
{ id: "scan", run: () => agent("Inspect the target", { label: "scan" }) },
|
|
72
|
+
{ id: "security", run: () => agent("Check security risks", { label: "security" }) },
|
|
73
|
+
{
|
|
74
|
+
id: "report",
|
|
75
|
+
dependsOn: ["scan", "security"],
|
|
76
|
+
run: ({ results, statuses }) =>
|
|
77
|
+
agent(
|
|
78
|
+
"Synthesize the named findings; mention unavailable coverage.\n\n" +
|
|
79
|
+
JSON.stringify({ results, statuses }),
|
|
80
|
+
{ label: "report" },
|
|
81
|
+
),
|
|
82
|
+
},
|
|
83
|
+
]);
|
|
84
|
+
return graph;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`orchestrate()` validates IDs, missing dependencies, duplicate edges, and
|
|
88
|
+
cycles before callbacks run. It executes ready tasks in declaration-order
|
|
89
|
+
layers with a barrier between layers and returns `{ results, tasks }`. Each task
|
|
90
|
+
callback receives detached `{ id, attempt, results, statuses }` snapshots.
|
|
91
|
+
`retries` retries ordinary task-callback failures up to three times. The default
|
|
92
|
+
`onError: "skip-dependents"` prevents a failed dependency from feeding a stale
|
|
93
|
+
prompt; use `onError: "continue"` only when the dependent explicitly handles
|
|
94
|
+
failed statuses. `fail-fast` stops discovery of later layers after the current
|
|
95
|
+
layer settles.
|
|
96
|
+
|
|
97
|
+
### Independent fan-out: `parallel`
|
|
98
|
+
|
|
99
|
+
Pass thunks, not already-started promises. Results preserve input order and a
|
|
100
|
+
recoverable item failure becomes `null`; fatal errors surface after the whole
|
|
101
|
+
batch barrier settles. Keep a ledger with IDs before filtering:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
const work = items.map((item) => ({ id: item.id, item }));
|
|
105
|
+
const outputs = await parallel(work.map(({ item }) => () =>
|
|
106
|
+
agent("Handle item " + item.id, { label: "item-" + item.id }),
|
|
107
|
+
));
|
|
108
|
+
const ledger = work.map(({ id }, index) => ({ id, result: outputs[index] }));
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Each `parallel()` call accepts at most 4096 thunks. It is a barrier: do not
|
|
112
|
+
start synthesis until the returned array is complete.
|
|
113
|
+
|
|
114
|
+
### Per-item stages: `pipeline`
|
|
115
|
+
|
|
116
|
+
Use `pipeline(items, ...stages)` when every item follows the same chain. Items
|
|
117
|
+
run concurrently, but stages for one item are sequential and receive
|
|
118
|
+
`(previousValue, originalItem, index)`. A stage failure drops that item to
|
|
119
|
+
`null`; guard missing values before the next stage. There is no cross-item
|
|
120
|
+
barrier between stages, and each call accepts at most 4096 items.
|
|
121
|
+
|
|
122
|
+
### Saved or nested workflows
|
|
123
|
+
|
|
124
|
+
`workflow(name, childArgs)` resolves a context-supplied saved workflow and runs
|
|
125
|
+
it inline with the parent's limiter, agent accounting, token accounting, and
|
|
126
|
+
store. One nested level is allowed; concurrent siblings are allowed. An
|
|
127
|
+
unchanged child is replayed as one parent journal call, while a changed or
|
|
128
|
+
interrupted child receives a generation-scoped managed identity. Do not use
|
|
129
|
+
nesting as an unbounded recursion mechanism.
|
|
130
|
+
|
|
131
|
+
## Prompt and result discipline
|
|
132
|
+
|
|
133
|
+
Every child prompt must be self-contained: state the role, exact task, relevant
|
|
134
|
+
inputs, expected output shape, and what the child must not do. Prefer a small
|
|
135
|
+
`schema` for values JavaScript will inspect. When a child consumes another
|
|
136
|
+
child's output, include the stable ID and actual bounded data, for example:
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
const prompt = "Review result " + JSON.stringify({ id: "scan", result: scan });
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Do not pass whole transcripts when a summary or structured fields are enough.
|
|
143
|
+
Use `log()` for progress and return a result that distinguishes completed work,
|
|
144
|
+
missing coverage, and failed/skipped work.
|
|
145
|
+
|
|
146
|
+
## Failure, limits, and recovery
|
|
147
|
+
|
|
148
|
+
- Recoverable child failures return `null` after agent retries. Fatal workflow
|
|
149
|
+
errors (invalid hooks, exhausted hard limits, unsupported selectors, and
|
|
150
|
+
schema exhaustion) throw and must not be dissolved into a normal result.
|
|
151
|
+
- Runtime `agent({ retries })` retries execution failures. `orchestrate` task
|
|
152
|
+
`retries` retries the callback. Semantic `retry()`/`gate()` attempts are a
|
|
153
|
+
third, intentional layer. Bound and ledger every layer separately.
|
|
154
|
+
- `agent()` schema repair includes concrete validation feedback in the next
|
|
155
|
+
attempt. Do not read fields from an unvalidated text response.
|
|
156
|
+
- `checkpoint()` is headless by default for background runs. Use
|
|
157
|
+
`background: false` only when a human decision must be shown.
|
|
158
|
+
- `budget` and phase budgets are soft pre-call gates; concurrent work may
|
|
159
|
+
overshoot. Do not promise an exact token ceiling unless the caller supplied
|
|
160
|
+
and accepted that policy.
|
|
161
|
+
|
|
162
|
+
## Resume and publication gate
|
|
163
|
+
|
|
164
|
+
Resume replays the longest unchanged prefix of journaled calls. Keep call order,
|
|
165
|
+
labels, prompts, routing options, and inputs stable. `orchestrate` layer order
|
|
166
|
+
and named dependency results make dynamic plans easier to replay, but arbitrary
|
|
167
|
+
branch/loop call counts can still invalidate the positional prefix. Never use
|
|
168
|
+
`Date.now()`, `Math.random()`, or no-argument `new Date()` in a script.
|
|
169
|
+
|
|
170
|
+
Before shipping a workflow change:
|
|
171
|
+
|
|
172
|
+
- read [lifecycle](references/lifecycle.md) for pause, stop, budget, and resume;
|
|
173
|
+
- read [debugging](references/debugging.md) when reproducing a failure;
|
|
174
|
+
- read [the review checklist](references/review.md) before accepting topology;
|
|
175
|
+
- read [the generated capability index](references/capabilities.md) when a
|
|
176
|
+
signature, default, or support boundary is disputed;
|
|
177
|
+
- ensure every package-relative example/reference link remains inside the
|
|
178
|
+
publishable package.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: "named-task-graph",
|
|
3
|
+
description: "Run independent research and synthesize it through named dependencies",
|
|
4
|
+
phases: [{ title: "research" }, { title: "synthesis" }],
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const graph = await orchestrate([
|
|
8
|
+
{
|
|
9
|
+
id: "architecture",
|
|
10
|
+
phase: "research",
|
|
11
|
+
description: "Inspect the architecture",
|
|
12
|
+
run: () => agent("Inspect the architecture and report concrete design constraints", { label: "architecture" }),
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "risk",
|
|
16
|
+
phase: "research",
|
|
17
|
+
description: "Find operational risks",
|
|
18
|
+
run: () => agent("Find operational and recovery risks", { label: "risk" }),
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "synthesis",
|
|
22
|
+
phase: "synthesis",
|
|
23
|
+
dependsOn: ["architecture", "risk"],
|
|
24
|
+
description: "Combine the named findings",
|
|
25
|
+
run: ({ results, statuses }) =>
|
|
26
|
+
agent(
|
|
27
|
+
"Combine these findings. Mention any unavailable dependency explicitly.\n\n" +
|
|
28
|
+
JSON.stringify({ results, statuses }),
|
|
29
|
+
{ label: "synthesis" },
|
|
30
|
+
),
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
return graph;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Workflow capability index
|
|
3
3
|
|
|
4
4
|
Contract format: `1.0.0`<br>
|
|
5
|
-
Contract content / skill / extension: `1.
|
|
5
|
+
Contract content / skill / extension: `1.4.0`
|
|
6
6
|
|
|
7
7
|
This compact generated index covers supported runtime globals and workflow-tool inputs. For constraints, compatibility behavior, internal boundaries, and dynamic-reference ownership, follow the [exhaustive generated facts](capability-details.md).
|
|
8
8
|
|
|
@@ -14,6 +14,7 @@ This compact generated index covers supported runtime globals and workflow-tool
|
|
|
14
14
|
| agent | runtime-global | `agent(prompt, options?) => Promise<string \| structured value \| null>` | `label`: string (optional); default: derived from phase and call count<br>`phase`: string (optional); default: current phase<br>`schema`: plain JSON Schema (optional)<br>`model`: string (optional); default: pi-subagents model resolver<br>`tier`: small\|medium\|large (optional); default: pi-subagents workflow tier<br>`isolation`: "worktree" (optional); default: pi-subagents worktree policy<br>`thread`: string (optional); default: fresh session per call<br>`toolset`: string (optional); default: configured host/agent toolset hint<br>`excludeTools`: string[] (optional)<br>`agentType`: string (optional); default: general-purpose<br>`timeoutMs`: number \| null (optional); default: 300000 (5min); null disables<br>`retries`: number (optional); default: run retry count |
|
|
15
15
|
| parallel | runtime-global | `parallel(thunks) => Promise<Array<unknown \| null>>` | — |
|
|
16
16
|
| pipeline | runtime-global | `pipeline(items, ...stages) => Promise<Array<unknown \| null>>` | — |
|
|
17
|
+
| orchestrate | runtime-global | `orchestrate(tasks, options?) => Promise<{ results, tasks }>` | `onError`: "skip-dependents"\|"continue"\|"fail-fast" (optional); default: "skip-dependents" |
|
|
17
18
|
| workflow | runtime-global | `workflow(savedName, childArgs?) => Promise<unknown>` | — |
|
|
18
19
|
| verify | runtime-global | `verify(item, options?) => Promise<{ real, realCount, total, votes }>` | `reviewers`: number (optional); default: 2<br>`threshold`: number (optional); default: 0.5<br>`lens`: string \| string[] (optional) |
|
|
19
20
|
| judgePanel | runtime-global | `judgePanel(attempts, options?) => Promise<{ index, attempt, score, judgments } \| undefined>` | `judges`: number (optional); default: 3<br>`rubric`: string (optional); default: overall quality and correctness |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Exhaustive workflow capability facts
|
|
3
3
|
|
|
4
4
|
Contract format: `1.0.0`<br>
|
|
5
|
-
Contract content / skill / extension: `1.
|
|
5
|
+
Contract content / skill / extension: `1.4.0`
|
|
6
6
|
|
|
7
7
|
Every exact fact below is projected from the installed extension's capability contract. Explanatory judgment belongs in the hand-written references next to this file.
|
|
8
8
|
|
|
@@ -28,6 +28,7 @@ Every exact fact below is projected from the installed extension's capability co
|
|
|
28
28
|
- Constraint: recoverable failures return null after retries; nonrecoverable failures throw
|
|
29
29
|
- Constraint: schema noncompliance after bounded repair attempts is nonrecoverable
|
|
30
30
|
- Constraint: resume replays only the longest unchanged prefix; the first miss and every later call execute live
|
|
31
|
+
- Constraint: replayed calls do not consume the real-dispatch maxAgents or token/phase budgets
|
|
31
32
|
- Constraint: spawnKeys rotate by generation on resume so pi-subagents never raises a fingerprint conflict
|
|
32
33
|
- Constraint: explicit model is resolved and scope-checked by pi-subagents; unavailable selectors fail closed
|
|
33
34
|
- Constraint: same-thread calls must be sequential and preserve a stable workflow thread name
|
|
@@ -41,8 +42,9 @@ Every exact fact below is projected from the installed extension's capability co
|
|
|
41
42
|
- Signature: `parallel(thunks) => Promise<Array<unknown \| null>>`
|
|
42
43
|
- Constraint: requires functions rather than promises
|
|
43
44
|
- Constraint: result order matches input order
|
|
44
|
-
- Constraint: recoverable thunk failures become null; nonrecoverable failures throw
|
|
45
|
+
- Constraint: recoverable thunk failures become null; nonrecoverable failures throw after the batch barrier settles
|
|
45
46
|
- Constraint: a breached agent cap cancels only its own batch
|
|
47
|
+
- Constraint: accepts at most 4096 thunks per call
|
|
46
48
|
|
|
47
49
|
<a id="runtime-global-pipeline"></a>
|
|
48
50
|
## pipeline
|
|
@@ -53,6 +55,21 @@ Every exact fact below is projected from the installed extension's capability co
|
|
|
53
55
|
- Constraint: items run concurrently while stages per item run sequentially
|
|
54
56
|
- Constraint: each stage receives previousValue, originalItem, and zero-based index
|
|
55
57
|
- Constraint: a null stage result is passed to the next stage
|
|
58
|
+
- Constraint: accepts at most 4096 items per call and awaits the whole batch before surfacing fatal errors
|
|
59
|
+
|
|
60
|
+
<a id="runtime-global-orchestrate"></a>
|
|
61
|
+
## orchestrate
|
|
62
|
+
|
|
63
|
+
- Classification: `runtime-global`
|
|
64
|
+
- Support: `supported`
|
|
65
|
+
- Signature: `orchestrate(tasks, options?) => Promise<{ results, tasks }>`
|
|
66
|
+
- `onError`: "skip-dependents"\|"continue"\|"fail-fast" (optional); default: "skip-dependents"
|
|
67
|
+
- Constraint: task ids and dependencies are validated before any callback runs
|
|
68
|
+
- Constraint: ready tasks run in declaration-order layers with a barrier between layers
|
|
69
|
+
- Constraint: task context carries detached named results and statuses
|
|
70
|
+
- Constraint: ordinary task failures can retry up to three times; fatal workflow errors propagate
|
|
71
|
+
- Constraint: failed or skipped dependencies skip descendants by default; continue runs them with null values
|
|
72
|
+
- Constraint: the graph accepts at most 128 tasks and emits task start/retry/end/skip runtime events
|
|
56
73
|
|
|
57
74
|
<a id="runtime-global-workflow"></a>
|
|
58
75
|
## workflow
|
|
@@ -60,9 +77,9 @@ Every exact fact below is projected from the installed extension's capability co
|
|
|
60
77
|
- Classification: `runtime-global`
|
|
61
78
|
- Support: `supported`
|
|
62
79
|
- Signature: `workflow(savedName, childArgs?) => Promise<unknown>`
|
|
63
|
-
- Constraint: one nested level
|
|
80
|
+
- Constraint: one nested level; concurrent sibling nested calls are allowed
|
|
64
81
|
- Constraint: shares limiter, counters, token accounting, and store
|
|
65
|
-
- Constraint: nested
|
|
82
|
+
- Constraint: nested calls use call-index/generation namespaces and replay as one parent result
|
|
66
83
|
|
|
67
84
|
<a id="runtime-global-verify"></a>
|
|
68
85
|
## verify
|
|
@@ -270,6 +287,7 @@ Every exact fact below is projected from the installed extension's capability co
|
|
|
270
287
|
- Support: `supported`
|
|
271
288
|
- Signature: `resumeFromRunId?: string`
|
|
272
289
|
- Constraint: resumes a prior incomplete run with an edited script
|
|
290
|
+
- Constraint: original args and execution limits are reused on resume
|
|
273
291
|
- Constraint: unchanged positional calls replay from cache until the first changed call
|
|
274
292
|
- Constraint: always runs in the background
|
|
275
293
|
|
|
@@ -4,6 +4,7 @@ Read only the recipe matching the concern. Change task prompts, schemas, bounds,
|
|
|
4
4
|
|
|
5
5
|
| Concern | Preserve when adapting | Tested recipe |
|
|
6
6
|
| --- | --- | --- |
|
|
7
|
+
| Named dependencies | Validate stable task IDs before dispatch; use the default skip policy unless dependents can consume `statuses` and null results. | [Named task graph](../examples/named-task-graph.js) |
|
|
7
8
|
| Phased budgets | Phase and run budgets are soft pre-call gates; active work can overshoot. Report shared spend and bound calls independently. | [Phased budgets](../examples/phased-budgets.js) |
|
|
8
9
|
| Saved workflows | Use a context-supplied name, await jobs sequentially, nest one level, and treat shared limits, counters, tokens, limiter, and store as parent capacity. | [Saved nested workflows](../examples/saved-nested-workflows.js) |
|
|
9
10
|
| Semantic retry | Separate it from recoverable runtime retries. Use a new unique label per bounded attempt and return the attempt ledger plus exhausted outcome. | [Bounded semantic retry](../examples/bounded-semantic-retry.js) |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Bounds and budget
|
|
4
4
|
|
|
5
|
-
Set finite bounds that match the work for `maxAgents`, `concurrency`, and `agentRetries`; bound loops and semantic retries inside the script. Treat invocation-level `agentTimeoutMs` and `tokenBudget` as opt-in user constraints, not precautionary defaults. Omit `tokenBudget` unless the user supplies a cap or explicitly asks you to choose one. If asked to choose, allow for every planned agent call, retry, synthesis, and verification pass, with headroom. A tight gate can terminate coverage; it does not reduce work already in flight. An omitted `agentTimeoutMs` uses the configured `defaultAgentTimeoutMs` and is otherwise unbounded. An omitted `tokenBudget` uses the configured `defaultTokenBudget` and is otherwise unlimited.
|
|
5
|
+
Set finite bounds that match the work for `maxAgents`, `concurrency`, and `agentRetries`; bound graph tasks, fan-out items, loops, and semantic retries inside the script. A journal replay is logical work and does not consume the real-dispatch `maxAgents` cap, but it still counts toward reported call totals. Treat invocation-level `agentTimeoutMs` and `tokenBudget` as opt-in user constraints, not precautionary defaults. Omit `tokenBudget` unless the user supplies a cap or explicitly asks you to choose one. If asked to choose, allow for every planned agent call, retry, synthesis, and verification pass, with headroom. A tight gate can terminate coverage; it does not reduce work already in flight. An omitted `agentTimeoutMs` uses the configured `defaultAgentTimeoutMs` and is otherwise unbounded. An omitted `tokenBudget` uses the configured `defaultTokenBudget` and is otherwise unlimited.
|
|
6
6
|
|
|
7
7
|
Enter a phase budget with `phase("Name", { budget: N })`; phase metadata does not carry budgets. `N` is a token allowance, not a call or round count: size it for the intended agent work instead of copying a small iteration limit. Token and phase budgets are soft pre-call gates. Spend lands after agents finish, so concurrent work can overshoot. A phase budget gates later calls in that phase; it neither reserves tokens nor cancels active calls. `budget.spent()` and `budget.remaining()` include nested work.
|
|
8
8
|
|
|
@@ -22,9 +22,9 @@ Always retain `{ id, status, result }` or an equivalent ledger for each intended
|
|
|
22
22
|
|
|
23
23
|
## Resume
|
|
24
24
|
|
|
25
|
-
Resume replays only the longest unchanged prefix of journaled calls. Once one call is new, changed, or unusable, that call and all later calls execute live. Stable lexical call ordering, prompts, labels, routing options, and inputs therefore matter. Retry chains can cascade after an upstream miss.
|
|
25
|
+
Resume replays only the longest unchanged prefix of journaled calls. Once one call is new, changed, or unusable, that call and all later calls execute live. Stable lexical call ordering, prompts, labels, routing options, and inputs therefore matter. Retry chains can cascade after an upstream miss. A nested workflow is cached as one parent call; an unchanged child replays its complete result, while a changed or interrupted child runs live in a generation-scoped namespace.
|
|
26
26
|
|
|
27
|
-
Only a call that finishes with a real result is journaled. A call whose every attempt was recoverable (including one that only ever produced `AGENT_EMPTY_OUTPUT`) contributes no journal entry, so resuming that run reruns exactly that call and everything lexically after it live; the earlier, already-succeeded prefix still replays from cache.
|
|
27
|
+
Only a call that finishes with a real result is journaled. A call whose every attempt was recoverable (including one that only ever produced `AGENT_EMPTY_OUTPUT`) contributes no journal entry, so resuming that run reruns exactly that call and everything lexically after it live; the earlier, already-succeeded prefix still replays from cache. Schema repair retries include the concrete validation errors in the next prompt.
|
|
28
28
|
|
|
29
29
|
The runtime blocks common accidental nondeterminism, but this is not a security boundary. Pass timestamps, randomness, and external decisions through `args`.
|
|
30
30
|
|
|
@@ -5,6 +5,7 @@ Choose from data dependencies, then read only the matching example. JavaScript o
|
|
|
5
5
|
<a id="fan-out-and-synthesize"></a>
|
|
6
6
|
| Dependency shape | Pattern | Preserve when adapting | Example |
|
|
7
7
|
| --- | --- | --- | --- |
|
|
8
|
+
| Named steps have explicit dependencies | Named task graph | Give every task a stable ID; let `orchestrate()` validate cycles, run declaration-order layers, and pass named results/statuses to dependents | [Adapt](../examples/named-task-graph.js) |
|
|
8
9
|
| Heterogeneous items need different handling | Classify and act | Finish all classification before routed action; ledger classification and action failures by item ID | [Adapt](../examples/classify-and-act.js) |
|
|
9
10
|
| Independent work needs whole-set judgment | Fan out and synthesize | Pass thunks; await the full set; give synthesis every intended ID, including `null` | [Adapt](../examples/fan-out-and-synthesize.js) |
|
|
10
11
|
| Claims need skeptical checks | Adversarial verification | Use separate producer and skeptic calls; start skepticism after production; ledger both failures | [Adapt](../examples/adversarial-verification.js) |
|
|
@@ -12,6 +12,6 @@ The agent registry owns agent-type names and their bound instructions, tools, mo
|
|
|
12
12
|
|
|
13
13
|
## Priority
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
An explicit per-call `model` wins. A named `agentType` model overrides a tier; an explicit `tier` suppresses the phase/run model so pi-subagents can apply the agent definition and then the selected workflow tier. Without a per-call model or tier, the phase/run model is used when present, followed by pi-subagents defaults and the parent session. Model and thinking fields are resolved independently. Avoid specifying competing selectors unless the override is deliberate.
|
|
16
16
|
|
|
17
17
|
Unavailability is fail-closed for explicit `model` and named tiers: pi-subagents reports the selector and does not silently run a different model. An omitted selector may inherit the parent session according to the companion's current settings.
|
|
@@ -11,10 +11,10 @@ Review author-visible behavior, not formatting preferences. When behavior depend
|
|
|
11
11
|
|
|
12
12
|
## Topology and identity
|
|
13
13
|
|
|
14
|
-
- Does topology match dependencies: thunks for independent parallel work, stages for per-item pipelines, barriers before whole-set synthesis?
|
|
15
|
-
- Is cardinality bounded before fan-out?
|
|
14
|
+
- Does topology match dependencies: `orchestrate` for named graphs, thunks for independent parallel work, stages for per-item pipelines, barriers before whole-set synthesis?
|
|
15
|
+
- Is cardinality bounded before graph construction and fan-out?
|
|
16
16
|
- Is every agent label short and unique?
|
|
17
|
-
- Are stable work-unit IDs retained beside ordered results?
|
|
17
|
+
- Are stable graph/work-unit IDs retained beside ordered results?
|
|
18
18
|
- Are failed/null identities recorded before any filtering?
|
|
19
19
|
|
|
20
20
|
## Data and routing
|
|
@@ -30,12 +30,14 @@ Review author-visible behavior, not formatting preferences. When behavior depend
|
|
|
30
30
|
- Are loops, agents, concurrency, timeout, and token spend bounded appropriately?
|
|
31
31
|
- Are budget claims honest about soft gates and in-flight overshoot?
|
|
32
32
|
- Are checkpoints limited to implemented confirmation/headless behavior?
|
|
33
|
-
- Does nesting stay one level and account for shared limits/store?
|
|
34
|
-
-
|
|
33
|
+
- Does nesting stay one level, allow only safe sibling concurrency, and account for shared limits/store?
|
|
34
|
+
- Are helper attempts and graph retries finite and separately visible?
|
|
35
|
+
- Would lexical call order and generated graph order remain stable under resume?
|
|
35
36
|
|
|
36
37
|
## Compatibility and publication
|
|
37
38
|
|
|
38
39
|
- Does new code use `log()` rather than compatibility-only `console`?
|
|
40
|
+
- Are runtime progress events and background result delivery described without promising durability the engine does not provide?
|
|
39
41
|
- Is compatibility behavior clearly distinguished from supported authoring behavior and VM substrate?
|
|
40
42
|
- Do package, skill, and generated contract versions match?
|
|
41
43
|
- Do all relative links resolve within the publishable package?
|
|
@@ -6,13 +6,14 @@ Use this page for routine scripts. Open the generated capability index only when
|
|
|
6
6
|
|
|
7
7
|
Start with the only legal export: `export const meta = { name, description, phases?: [{ title, detail?, model? }] }`. Values are nonblank literals; declare only used phases and call `phase()` before each phase's work. The remaining body already runs inside an async function: write helpers as ordinary declarations; `export default` and other exports are invalid. Return the result explicitly.
|
|
8
8
|
|
|
9
|
-
The runtime supplies `agent`, `parallel`, `pipeline`, `workflow`, quality/control helpers, `phase`, `log`, `args`, `cwd`, restricted `process.cwd()`, and `budget`. Imports, `require()`, filesystem modules, `Date.now()`, `Math.random()`, and no-argument `new Date()` are unavailable. The Node VM realm is implementation substrate, not a security boundary or public API.
|
|
9
|
+
The runtime supplies `agent`, `parallel`, `pipeline`, `orchestrate`, `workflow`, quality/control helpers, `phase`, `log`, `args`, `cwd`, restricted `process.cwd()`, and `budget`. Imports, `require()`, filesystem modules, `Date.now()`, `Math.random()`, and no-argument `new Date()` are unavailable. The Node VM realm is implementation substrate, not a security boundary or public API.
|
|
10
10
|
|
|
11
11
|
## Topology
|
|
12
12
|
|
|
13
13
|
- `parallel()` takes thunks, runs independent work, and preserves input order. Await the whole array before whole-set synthesis.
|
|
14
14
|
- `pipeline()` runs stages sequentially per item while items proceed concurrently. Each stage receives `(previousValue, originalItem, index)` and forwards `null` to the next stage, so guard missing coverage first.
|
|
15
|
-
- `
|
|
15
|
+
- `orchestrate()` is the preferred topology for named dependencies. Give each task a unique `id`, optional `dependsOn`, and a `run({ id, attempt, results, statuses })` callback. The runtime validates the graph, executes declaration-order ready layers behind barriers, and returns `{ results, tasks }`; use `onError: "continue"` only when a downstream task can handle failed dependencies.
|
|
16
|
+
- `workflow(name, childArgs?)` runs a context-supplied saved workflow. Nesting is one level, shares limits/counters/tokens/store, and journals the complete child result as one parent replay boundary.
|
|
16
17
|
|
|
17
18
|
## Data and failure
|
|
18
19
|
|
|
@@ -24,6 +25,6 @@ When JavaScript reads fields, pass a small plain JSON Schema. Schema noncomplian
|
|
|
24
25
|
|
|
25
26
|
## Routing and support
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
An explicit per-call `model` wins. A named `agentType` model overrides `tier`; specifying `tier` suppresses the phase/run model and delegates model/thinking resolution to pi-subagents. Without a per-call selector, the phase/run model is used when present, followed by pi-subagents defaults and the parent session. Explicit unavailable models and tiers fail closed. Worktree isolation is also fail-closed and remains owned by pi-subagents. See [registry ownership](registry-ownership.md).
|
|
28
29
|
|
|
29
30
|
Generated entries marked `supported` are authoring API. `console` and whole-script Markdown fences are compatibility-only. VM realm facilities are internal. Active model routes and agent types are dynamic. Use `log()` in new scripts.
|