pi-extensible-workflows 1.0.1 → 3.0.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/README.md +9 -2
- package/dist/src/agent-execution.d.ts +13 -14
- package/dist/src/agent-execution.js +110 -197
- package/dist/src/budget.d.ts +38 -0
- package/dist/src/budget.js +160 -0
- package/dist/src/cli.d.ts +9 -0
- package/dist/src/cli.js +536 -6
- package/dist/src/doctor.d.ts +4 -4
- package/dist/src/doctor.js +9 -29
- package/dist/src/execution.d.ts +17 -0
- package/dist/src/execution.js +630 -0
- package/dist/src/herdr.d.ts +12 -0
- package/dist/src/herdr.js +74 -0
- package/dist/src/host.d.ts +62 -0
- package/dist/src/host.js +2696 -0
- package/dist/src/index.d.ts +11 -557
- package/dist/src/index.js +8 -3974
- package/dist/src/persistence.d.ts +32 -19
- package/dist/src/persistence.js +310 -70
- package/dist/src/registry.d.ts +31 -0
- package/dist/src/registry.js +169 -0
- package/dist/src/session-inspector.d.ts +1 -0
- package/dist/src/session-inspector.js +4 -1
- package/dist/src/types.d.ts +565 -0
- package/dist/src/types.js +27 -0
- package/dist/src/utils.d.ts +26 -0
- package/dist/src/utils.js +128 -0
- package/dist/src/validation.d.ts +24 -0
- package/dist/src/validation.js +740 -0
- package/dist/src/workflow-evals.js +2 -1
- package/package.json +4 -3
- package/skills/pi-extensible-workflows/SKILL.md +52 -67
- package/src/agent-execution.ts +84 -147
- package/src/budget.ts +75 -0
- package/src/cli.ts +427 -6
- package/src/doctor.ts +13 -32
- package/src/execution.ts +540 -0
- package/src/herdr.ts +73 -0
- package/src/host.ts +2265 -0
- package/src/index.ts +11 -3453
- package/src/persistence.ts +255 -47
- package/src/registry.ts +157 -0
- package/src/session-inspector.ts +5 -1
- package/src/types.ts +113 -0
- package/src/utils.ts +108 -0
- package/src/validation.ts +616 -0
- package/src/workflow-evals.ts +2 -1
|
@@ -707,6 +707,7 @@ export async function replayWorkflowScript(script, args = null, signal) {
|
|
|
707
707
|
active -= 1;
|
|
708
708
|
}
|
|
709
709
|
},
|
|
710
|
+
worktree: async () => ({ path: "/worktrees/eval", branch: "eval-branch" }),
|
|
710
711
|
phase: (name) => { phases.push(name); },
|
|
711
712
|
log: (message) => { logs.push(message); },
|
|
712
713
|
}, signal);
|
|
@@ -860,7 +861,7 @@ function semanticJudgePrompt(evalCase, calls, cwd, home) {
|
|
|
860
861
|
return [];
|
|
861
862
|
} }));
|
|
862
863
|
const roleText = [...usedRoles].map((role) => `${role}: ${roles[role]?.description ?? "no description"}`).join("\n") || "none";
|
|
863
|
-
const docs = "agent(prompt, options) delegates; parallel(name, tasks) runs independent tasks concurrently; pipeline(name, items, stages) applies ordered stages; prompt(template, data) carries values into prompts. A role owns model/thinking/tools policy.";
|
|
864
|
+
const docs = "agent(prompt, options) delegates; shell(command, options) runs a deterministic host command and returns exitCode/stdout/stderr; parallel(name, tasks) runs independent tasks concurrently; pipeline(name, items, stages) applies ordered stages; prompt(template, data) carries values into prompts. A role owns model/thinking/tools policy.";
|
|
864
865
|
return `Judge whether the captured workflow design satisfies each criterion. Do not execute it. Return only JSON: {"criteria":[{"id":"criterion id","pass":true,"evidence":"specific script evidence"}]}.\n\nOriginal request:\n${evalCase.prompt}\n\nCriteria:\n${JSON.stringify(evalCase.semanticCriteria ?? [])}\n\nDSL:\n${docs}\n\nRelevant roles:\n${roleText}\n\nCaptured workflow script(s):\n${calls.map((call, index) => `--- ${String(index)} ---\n${call.script ?? "<missing>"}`).join("\n")}`;
|
|
865
866
|
}
|
|
866
867
|
async function runSemanticJudge(input, calls, cwd, home, sessionDir, maxCost) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extensible-workflows",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Deterministic multi-agent workflow orchestration for Pi",
|
|
5
5
|
"homepage": "https://vekexasia.github.io/pi-extensible-workflows/",
|
|
6
6
|
"repository": {
|
|
@@ -31,8 +31,9 @@
|
|
|
31
31
|
"build": "rm -rf dist && tsc -p tsconfig.json && chmod +x dist/src/cli.js",
|
|
32
32
|
"inspect": "node dist/src/cli.js inspect",
|
|
33
33
|
"lint": "eslint .",
|
|
34
|
-
"test": "npm run build &&
|
|
35
|
-
"
|
|
34
|
+
"test": "npm run build && TEST_FILES='dist/test/*.test.js' npm run test:run",
|
|
35
|
+
"test:run": "tmp=$(mktemp -d); trap 'rm -rf \"$tmp\"' EXIT; TMPDIR=\"$tmp\" node --test $TEST_FILES",
|
|
36
|
+
"acceptance": "npm run build && TEST_FILES='dist/test/runtime-acceptance.test.js' npm run test:run",
|
|
36
37
|
"docs:check": "node scripts/check-docs.mjs",
|
|
37
38
|
"check": "npm run lint && npm test && npm run docs:check",
|
|
38
39
|
"evals": "npm run build && node dist/src/workflow-evals.js",
|
|
@@ -4,87 +4,81 @@ description: Use when the task is complex enough to require multiple subagents o
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# pi-extensible-workflows
|
|
7
|
+
Use `workflow` only for genuinely multi-agent orchestration; one agent uses ordinary tools or `Agent` directly. Give phases distinct responsibilities and keep result flow explicit.
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## Pattern
|
|
11
|
-
|
|
9
|
+
## Example
|
|
12
10
|
```js
|
|
13
|
-
const reportSchema = {
|
|
14
|
-
|
|
15
|
-
properties: {
|
|
16
|
-
summary: { type: "string" },
|
|
17
|
-
findings: { type: "array", items: { type: "string" } },
|
|
18
|
-
},
|
|
19
|
-
required: ["summary", "findings"],
|
|
20
|
-
additionalProperties: false,
|
|
21
|
-
};
|
|
11
|
+
const reportSchema = { type: "object", properties: { summary: { type: "string" }, findings: { type: "array", items: { type: "string" } } }, required: ["summary", "findings"], additionalProperties: false };
|
|
12
|
+
|
|
22
13
|
|
|
23
14
|
const reports = await parallel("research", {
|
|
24
15
|
first: () => agent("Research the first target.", { role: "scout", outputSchema: reportSchema }),
|
|
25
16
|
second: () => agent("Research the second target.", { role: "scout", outputSchema: reportSchema }),
|
|
26
17
|
});
|
|
27
18
|
|
|
28
|
-
// Add a downstream agent only when synthesis or independent review is a real phase.
|
|
29
19
|
return agent(
|
|
30
20
|
prompt("Review these reports:\n\n{reports}", { reports }),
|
|
31
21
|
{ role: "reviewer", outputSchema: reportSchema },
|
|
32
22
|
);
|
|
33
23
|
```
|
|
34
24
|
|
|
35
|
-
|
|
25
|
+
Inline launches require a non-empty `name`. Registered function launches must omit `name`; they use `workflow` as the run name:
|
|
36
26
|
```json
|
|
37
27
|
{ "workflow": "workflowName", "args": { "issue": 42 } }
|
|
38
28
|
```
|
|
39
|
-
Inside the workflow, read `args.issue
|
|
40
|
-
|
|
41
|
-
If `workflow_catalog` is available, call it once before creating the first workflow for a task. Use the returned global functions, variables, registered workflows, and configured model aliases as needed for the rest of that task. Alias targets are catalog metadata, not an availability probe. Do not try to reinvent already exposed functions.
|
|
29
|
+
Inside the workflow, read `args.issue` (`args` is `null` when omitted). `workflow_stop` requires the exact run ID; foreground results retain their value and completed `runId`, while background launches return `runId` immediately. A terminal `parentRunId` reuses matching named `withWorktree` scopes but does not replay journal results. For an explicitly failed run, use the exact `runId` from failure diagnostics with `workflow_retry({ runId })`: diagnostics list replayable and incomplete paths, artifacts, and valid named worktrees; the tool creates a linked child, replays completed agent, shell, function, and checkpoint operations, and executes incomplete work. Retry versus per-agent `retries` and `workflow_resume` is always explicit; external side effects before failure are not guaranteed exactly once.
|
|
30
|
+
Inspect tool `workflow_catalog` result at least once before creating the first workflow for a task.
|
|
42
31
|
|
|
43
|
-
|
|
32
|
+
Workflow JavaScript has no imports, filesystem, network, process, or timers. Delegate that work to agents. `shell(command, options)` is the trusted host RPC for deterministic gates: it inherits the workflow or active-worktree cwd, merges string `env` overrides, and returns `{ exitCode, stdout, stderr }`; nonzero exits are results, but launch failures and timeouts fail with `SHELL_FAILED`.
|
|
44
33
|
|
|
45
|
-
|
|
34
|
+
Example use of `shell`:
|
|
46
35
|
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
tools?: string[]; // [] = no tools; omitted uses role or launch tools
|
|
54
|
-
outputSchema?: JsonSchema;
|
|
55
|
-
retries?: number; // non-negative; use for safe, repeatable work
|
|
56
|
-
timeoutMs?: number | null; // positive milliseconds; null means unlimited
|
|
36
|
+
```js
|
|
37
|
+
// ... other code
|
|
38
|
+
const testRes = await shell("yarn test", { env: { CI: "1" } });
|
|
39
|
+
if (testRes.exitCode === 0) {
|
|
40
|
+
// success path
|
|
41
|
+
return {...}
|
|
57
42
|
}
|
|
58
43
|
```
|
|
59
44
|
|
|
60
|
-
|
|
45
|
+
Most of the times using `shell()` to perform mutations is an antipattern. Use it mainly for verifications or idempotent actions.
|
|
61
46
|
|
|
62
|
-
|
|
47
|
+
## `agent()` options
|
|
48
|
+
```typescript
|
|
49
|
+
export interface AgentOptions {
|
|
50
|
+
label?: string; model?: string; role?: string; tools?: string[];
|
|
51
|
+
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
52
|
+
outputSchema?: JsonSchema;
|
|
53
|
+
retries?: number;
|
|
54
|
+
timeoutMs?: number | null;
|
|
55
|
+
[key: string]: JsonValue;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
63
58
|
|
|
64
|
-
|
|
59
|
+
Extensions may add JSON-compatible agent options such as `advisor: true`; core keys retain validation and role constraints. Extension options go to setup hooks/native setup and are not inherited by child agents.
|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
Agent calls are unnamed. Direct calls receive hidden source call-site identity; aliases are unsupported, and calls from one source site must not race outside `parallel` or `pipeline`, whose structural keys make replay deterministic.
|
|
67
62
|
|
|
63
|
+
## Passing agent results
|
|
64
|
+
Use independent `agent(prompt, options)` calls and pass each completed result explicitly to the next prompt. This keeps workflow execution deterministic and makes replay state local to each call:
|
|
68
65
|
```js
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}));
|
|
66
|
+
const findings = await agent("Inspect the implementation.");
|
|
67
|
+
const fix = await agent(prompt("Propose the smallest fix from these findings:\n\n{findings}", { findings }));
|
|
68
|
+
return { findings, fix };
|
|
73
69
|
```
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`parallel()` tasks may call any workflow function, not only `agent()`:
|
|
78
|
-
|
|
71
|
+
## Worktrees
|
|
72
|
+
Use `withWorktree(name, callback)` for top-level agents that collaborate in one explicitly named worktree scope:
|
|
79
73
|
```js
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
const result = await withWorktree("issue", async ({ path, branch }) => {
|
|
75
|
+
const report = await agent("Implement the issue");
|
|
76
|
+
return { path, branch, report };
|
|
83
77
|
});
|
|
84
78
|
```
|
|
79
|
+
Entering the scope materializes its worktree before the callback. The callback receives a frozen reference containing only the real string `path` and `branch`; callbacks may ignore the argument, and their bare return value is preserved. Concurrent agents share mutable files, so assign non-conflicting work or coordinate explicitly.
|
|
85
80
|
|
|
86
|
-
Use separate named scopes when
|
|
87
|
-
|
|
81
|
+
Branches may call any workflow function, not only `agent()`. Use separate named scopes when parallel branches need isolated worktrees:
|
|
88
82
|
```js
|
|
89
83
|
const results = await parallel("implementation", {
|
|
90
84
|
api: () => withWorktree("api", () => agent("Implement the API")),
|
|
@@ -92,26 +86,17 @@ const results = await parallel("implementation", {
|
|
|
92
86
|
});
|
|
93
87
|
```
|
|
94
88
|
|
|
95
|
-
Registered extension functions receive `withWorktree` in
|
|
96
|
-
```ts
|
|
97
|
-
const report = await context.invoke("reviewRepository", { focus: "security" });
|
|
98
|
-
```
|
|
99
|
-
Their public inputs and outputs must remain JSON; callbacks cannot cross the extension-function boundary.
|
|
89
|
+
Registered extension functions receive `withWorktree` in context and can compose other registered functions with `context.invoke("reviewRepository", { focus: "security" })`. Their public inputs and outputs remain JSON; callbacks cannot cross the extension boundary.
|
|
100
90
|
|
|
101
91
|
## Rules
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
- Use `
|
|
105
|
-
-
|
|
106
|
-
- Use
|
|
107
|
-
- Call shapes are `parallel(operationName, tasksRecord)` and `pipeline(operationName, itemsRecord, stagesRecord)`; object keys are stable task, item, and stage names.
|
|
108
|
-
- Preserve item metadata in workflow code between pipeline stages instead of requiring agents to echo it through `outputSchema`.
|
|
109
|
-
- Repeated work uses a JavaScript loop; each direct `agent(...)` call receives deterministic call-site and occurrence identity.
|
|
92
|
+
- Use `log(messageString)` for brief operator status.
|
|
93
|
+
- A role owns execution policy: with `role`, do not set `model`, `thinking`, or `tools`; only task options such as `outputSchema`, retries, timeout, or a `withWorktree` scope may accompany it.
|
|
94
|
+
- Use `parallel()` for independent tasks with different flows and `pipeline()` when every keyed item follows the same ordered stages; do not duplicate identical chains in `parallel()`. Signatures are `parallel(operationName, tasksRecord)` and `pipeline(operationName, itemsRecord, stagesRecord)`; keys are stable task, item, and stage names.
|
|
95
|
+
- Preserve item metadata in workflow code between pipeline stages instead of making agents echo it through `outputSchema`.
|
|
96
|
+
- Use a JavaScript loop for repeated work; each direct `agent(...)` call gets deterministic call-site and occurrence identity.
|
|
110
97
|
- Runs default to background; set tool-call `foreground: true` when asked to wait.
|
|
111
|
-
- Add `budget` only
|
|
112
|
-
-
|
|
113
|
-
- `parallel()` and `pipeline()` return keyed bare values
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
- With `outputSchema`, agents must call `workflow_result`; one repair prompt is built in. Omit `retries` unless an additional retry is justified and the work is idempotent.
|
|
117
|
-
- Do not add "persona" specs to the prompt for agents. Just define the task.
|
|
98
|
+
- Add `budget` only for aggregate limits. Do not invent limits, omit if user do not ask explicitly. Valid dimensions are exactly `tokens`, `costUsd`, `durationMs`, and `agentLaunches`; each is `{ soft?: number, hard?: number }` with `soft < hard`.
|
|
99
|
+
- `budget_exhausted` runs resume through `workflow_resume`: omitted patch values stay unchanged, `null` removes a limit, and tightening resumes directly. Relaxation stores the exact proposal and returns `{ state: "awaiting_approval", proposalId }`; `workflow_respond` must answer that ID. Rejection leaves the run exhausted; approval applies the budget and cold-resumes it. `workflow_retry` is only for persisted `failed` runs and inherits cumulative usage; replay itself consumes no budget.
|
|
100
|
+
- `parallel()` and `pipeline()` return keyed bare values; await them before use. Interpolate results with `prompt("...{value}", { value })`; placeholders in plain strings remain literal.
|
|
101
|
+
- Use `outputSchema` only when another phase compares, aggregates, or validates a result, never for final prose. Keep only consumer-needed fields and avoid repeated evidence. Agents with it must call `workflow_result`; one repair prompt is built in. Omit `retries` unless an extra retry is justified and work is idempotent.
|
|
102
|
+
- Do not add persona specifications to agent prompts; define the task directly.
|