@clemrig/flow 0.0.0-stage → 0.1.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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -2
  3. package/dist/app/run.d.ts +38 -0
  4. package/dist/app/run.js +104 -0
  5. package/dist/app/run.js.map +1 -0
  6. package/dist/app/runs.d.ts +32 -0
  7. package/dist/app/runs.js +55 -0
  8. package/dist/app/runs.js.map +1 -0
  9. package/dist/engine/metrics.d.ts +45 -0
  10. package/dist/engine/metrics.js +60 -0
  11. package/dist/engine/metrics.js.map +1 -0
  12. package/dist/engine/primitives.d.ts +34 -0
  13. package/dist/engine/primitives.js +81 -0
  14. package/dist/engine/primitives.js.map +1 -0
  15. package/dist/engine/profiles.d.ts +53 -0
  16. package/dist/engine/profiles.js +117 -0
  17. package/dist/engine/profiles.js.map +1 -0
  18. package/dist/engine/runner.d.ts +13 -0
  19. package/dist/engine/runner.js +157 -0
  20. package/dist/engine/runner.js.map +1 -0
  21. package/dist/engine/types.d.ts +194 -0
  22. package/dist/engine/types.js +2 -0
  23. package/dist/engine/types.js.map +1 -0
  24. package/dist/engine/workflow.d.ts +24 -0
  25. package/dist/engine/workflow.js +179 -0
  26. package/dist/engine/workflow.js.map +1 -0
  27. package/dist/index.d.ts +16 -0
  28. package/dist/index.js +16 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/system/process.d.ts +27 -0
  31. package/dist/system/process.js +261 -0
  32. package/dist/system/process.js.map +1 -0
  33. package/dist/system/runtimes/adapter.d.ts +90 -0
  34. package/dist/system/runtimes/adapter.js +20 -0
  35. package/dist/system/runtimes/adapter.js.map +1 -0
  36. package/dist/system/runtimes/agent-runtime.d.ts +45 -0
  37. package/dist/system/runtimes/agent-runtime.js +184 -0
  38. package/dist/system/runtimes/agent-runtime.js.map +1 -0
  39. package/dist/system/runtimes/claude-code.d.ts +10 -0
  40. package/dist/system/runtimes/claude-code.js +383 -0
  41. package/dist/system/runtimes/claude-code.js.map +1 -0
  42. package/dist/system/runtimes/inspect.d.ts +27 -0
  43. package/dist/system/runtimes/inspect.js +131 -0
  44. package/dist/system/runtimes/inspect.js.map +1 -0
  45. package/dist/system/runtimes/pi.d.ts +7 -0
  46. package/dist/system/runtimes/pi.js +235 -0
  47. package/dist/system/runtimes/pi.js.map +1 -0
  48. package/dist/system/runtimes/protocol.d.ts +9 -0
  49. package/dist/system/runtimes/protocol.js +38 -0
  50. package/dist/system/runtimes/protocol.js.map +1 -0
  51. package/dist/system/runtimes/registry.d.ts +5 -0
  52. package/dist/system/runtimes/registry.js +5 -0
  53. package/dist/system/runtimes/registry.js.map +1 -0
  54. package/dist/system/store.d.ts +26 -0
  55. package/dist/system/store.js +157 -0
  56. package/dist/system/store.js.map +1 -0
  57. package/package.json +34 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Clément CHESNEAU
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,56 @@
1
- # Temporary Holding Version
1
+ # @clemrig/flow
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Write agent workflows in TypeScript and run them with [Claude Code](https://code.claude.com) or [Pi](https://www.npmjs.com/package/@earendil-works/pi-coding-agent).
4
+
5
+ A workflow is an explicit graph of **CODE** stages (your code), **AGENT** stages (an agent run by Claude Code or Pi) and **GATE** stages that accept a result or send it back for correction, a bounded number of times. This package is the engine: the API to write workflows, their execution, the agent runtimes and the runs. [`@clemrig/factory`](https://www.npmjs.com/package/@clemrig/factory) builds a command and per-repository workflows on it; [`@clemrig/flow-ui`](https://www.npmjs.com/package/@clemrig/flow-ui) shows the runs in a local dashboard.
6
+
7
+ ## Requirements
8
+
9
+ macOS or Linux, Node.js 24 or later. For agent stages, the `claude` CLI (2.1.296 or later) or the `pi` CLI (1.1.0 or later) in the `PATH`, connected to its provider. The engine never reads or stores credentials.
10
+
11
+ ## Run a workflow
12
+
13
+ ```sh
14
+ npm install @clemrig/flow
15
+ ```
16
+
17
+ ```ts
18
+ import { defineWorkflow, END, node, startRun, step, z } from "@clemrig/flow";
19
+
20
+ const hello = defineWorkflow({
21
+ name: "hello",
22
+ input: z.object({ name: z.string().min(1) }),
23
+ initial: "greet",
24
+ nodes: {
25
+ greet: node(
26
+ step(async ({ state }) => ({ greeting: `Hello ${String(state.input.name)}` })),
27
+ { ok: END },
28
+ ),
29
+ },
30
+ });
31
+
32
+ const run = await startRun(
33
+ {
34
+ workflow: hello,
35
+ input: { name: "flow" },
36
+ prompts: async () => ({}), // prompt texts by name, for agent stages
37
+ dir: process.cwd(), // where stages and agents work; given to stages as `dir`
38
+ configDir: process.cwd(), // where relative skill, extension and MCP paths of profiles resolve
39
+ },
40
+ { onEvent: (event) => console.log(event.type, event.stage) },
41
+ );
42
+ const state = await run.done;
43
+ console.log(state.status, state.data);
44
+ ```
45
+
46
+ Before it creates the run, `startRun` checks, in this order, `dir` (an existing directory), the budget (`maxCostUsd`, in USD, replaces the workflow's), the input against the workflow's `input` (an `InvalidInputError` lists every problem), the prompts (a non-empty text for each agent stage's prompt) and each runtime the workflow uses, its version and connection checked in `dir`; the first failing check rejects it with its reasons. It then returns the run, its end (`done`) and `stop(reason)`, which fails the run before its next stage. Runs are kept in `runsDir` when it is given. The engine never changes the process's current directory: stage code reaches the working directory through `dir`. While child processes run (agents, commands), a SIGINT or SIGTERM to the program interrupts them, so that none outlives it, and stops each run before its next stage, even if a stage catches the interruption. A program about to quit at once can call `killChildProcesses()`, which kills the child processes of every run.
47
+
48
+ The stages, gates, corrections, agent profiles, sessions and prompts are described in the "Write a workflow" section of [`@clemrig/factory`'s README](https://www.npmjs.com/package/@clemrig/factory); import them from `@clemrig/flow` here. What it says of `.factory/`, prompt files and `factory run` options belongs to the factory: with the engine alone, the program gives the input, the prompt texts and the directories to `startRun`.
49
+
50
+ ## Runs
51
+
52
+ Each run keeps `state.json` and `events.jsonl` in its own folder of `runsDir`, by default `.flow/runs/` of `dir`. When the engine creates `.flow/`, it writes a `.gitignore` that ignores everything in it: runs hold inputs, agent outputs and the journal, and stay private. `listRuns(runsDir)`, `loadRun(runsDir, id)`, `loadRunEvents(runsDir, id)`, `summarizeRun(state)` and `presentResult(workflow, state)` read them; `flow-ui` shows them.
53
+
54
+ ## License
55
+
56
+ MIT
@@ -0,0 +1,38 @@
1
+ import type { RunEvent, RunState, Workflow } from "../engine/types.js";
2
+ import { type RuntimeStatus } from "../system/runtimes/inspect.js";
3
+ /** What a run needs: its workflow, its options, its prompts and its directories. */
4
+ export interface RunSetup {
5
+ workflow: Workflow;
6
+ /** The run's input, validated by the workflow's input object; none by default. */
7
+ input?: Record<string, unknown>;
8
+ /** The run's budget in USD instead of the workflow's. */
9
+ maxCostUsd?: number;
10
+ /** Prompt texts by name, read once the input is valid. */
11
+ prompts(): Promise<Record<string, string>>;
12
+ /** The directory stages and agents work in. */
13
+ dir: string;
14
+ /** Relative skill, extension and MCP command paths of profiles belong to it. */
15
+ configDir: string;
16
+ /** Where runs are kept, one directory per run; `.flow/runs/` of `dir` by default. */
17
+ runsDir?: string;
18
+ }
19
+ export interface RunHooks {
20
+ /** Each stage, journal and agent event, once recorded. */
21
+ onEvent(event: RunEvent): void;
22
+ }
23
+ /** A created run, executing in the foreground. */
24
+ export interface StartedRun {
25
+ state: Readonly<RunState>;
26
+ /** Each runtime the run uses: version, executable and connection. */
27
+ runtimes: RuntimeStatus[];
28
+ /** Settles with the run once it completed or failed. */
29
+ done: Promise<RunState>;
30
+ /** Fails the run with `reason` before its next stage. */
31
+ stop(reason: Error): void;
32
+ }
33
+ /**
34
+ * Checks input, budget, prompts and runtimes before creating the run, then runs
35
+ * it: stages and agents work in `dir`; the process's current directory is left
36
+ * as it is.
37
+ */
38
+ export declare function startRun(setup: RunSetup, hooks: RunHooks): Promise<StartedRun>;
@@ -0,0 +1,104 @@
1
+ import { budgetProblem, emptyMetrics, recordUsage } from "../engine/metrics.js";
2
+ import { executeWorkflow } from "../engine/runner.js";
3
+ import { parseInput } from "../engine/workflow.js";
4
+ import { whenInterrupted } from "../system/process.js";
5
+ import { AgentRuntime } from "../system/runtimes/agent-runtime.js";
6
+ import { inspectRuntimes, } from "../system/runtimes/inspect.js";
7
+ import { createFlowDirectory, defaultRunsDir, FileRunStore, isDirectory, newRunId, } from "../system/store.js";
8
+ /**
9
+ * Checks input, budget, prompts and runtimes before creating the run, then runs
10
+ * it: stages and agents work in `dir`; the process's current directory is left
11
+ * as it is.
12
+ */
13
+ export async function startRun(setup, hooks) {
14
+ const { workflow, dir, configDir } = setup;
15
+ if (!(await isDirectory(dir)))
16
+ throw new Error(`dir is not an existing directory: ${dir}`);
17
+ const maxCostUsd = setup.maxCostUsd ?? workflow.maxCostUsd;
18
+ if (setup.maxCostUsd !== undefined &&
19
+ !(Number.isFinite(setup.maxCostUsd) && setup.maxCostUsd > 0))
20
+ throw new Error(`maxCostUsd must be a positive number of USD, got ${typeof setup.maxCostUsd === "string" ? JSON.stringify(setup.maxCostUsd) : String(setup.maxCostUsd)}`);
21
+ const input = parseInput(workflow, setup.input ?? {});
22
+ const prompts = await setup.prompts();
23
+ const unprompted = [
24
+ ...new Set(Object.values(workflow.agents).map(({ prompt }) => prompt)),
25
+ ].filter((name) => !(Object.hasOwn(prompts, name) && prompts[name]?.trim()));
26
+ if (unprompted.length)
27
+ throw new Error(unprompted.map((name) => `Missing or empty prompt: ${name}`).join("; "));
28
+ const { runtimes, problems, executables } = await inspectRuntimes(workflow.agents, dir);
29
+ if (problems.length)
30
+ throw new Error(`Missing prerequisites: ${problems.map(({ stage, runtime, reason }) => `stage ${stage} (${runtime}): ${reason}`).join("; ")}`);
31
+ const now = new Date().toISOString();
32
+ const state = {
33
+ version: 4,
34
+ id: newRunId(),
35
+ workflow: workflow.name,
36
+ input,
37
+ stage: workflow.initial,
38
+ status: "running",
39
+ data: {},
40
+ createdAt: now,
41
+ updatedAt: now,
42
+ metrics: emptyMetrics(),
43
+ runtimes: Object.fromEntries(Object.entries(runtimes).map(([runtime, { detail }]) => [
44
+ runtime,
45
+ detail,
46
+ ])),
47
+ };
48
+ if (setup.runsDir === undefined)
49
+ await createFlowDirectory(dir);
50
+ else if ((await isDirectory(setup.runsDir)) === false)
51
+ throw new Error(`runsDir is not a directory: ${setup.runsDir}`);
52
+ const store = new FileRunStore(setup.runsDir ?? defaultRunsDir(dir), state.id);
53
+ const agent = new AgentRuntime({
54
+ dir,
55
+ configDir,
56
+ prompts,
57
+ onUsage: async (report) => {
58
+ if (state.metrics)
59
+ recordUsage(state.metrics, report);
60
+ await store.save(state);
61
+ },
62
+ run: { id: state.id, directory: store.directory },
63
+ executables,
64
+ });
65
+ await store.save(state);
66
+ const controller = new AbortController();
67
+ /**
68
+ * Past its budget, the run stops: the abort fails it at its next stage
69
+ * boundary even if workflow code catches the error, and no call starts.
70
+ */
71
+ const overBudget = () => {
72
+ const problem = maxCostUsd === undefined || !state.metrics
73
+ ? undefined
74
+ : budgetProblem(state.metrics, maxCostUsd);
75
+ if (problem)
76
+ controller.abort(new Error(problem));
77
+ return problem;
78
+ };
79
+ // Checked before each agent call and after it, failed or not, on the figures its runtime announced.
80
+ const budgeted = {
81
+ async execute(request, record) {
82
+ const refused = overBudget();
83
+ if (refused)
84
+ throw new Error(refused);
85
+ const value = await agent
86
+ .execute(request, record)
87
+ .finally(() => overBudget());
88
+ const exceeded = overBudget();
89
+ if (exceeded)
90
+ throw new Error(exceeded);
91
+ return value;
92
+ },
93
+ };
94
+ // The signal that interrupts its processes also stops the run, even if a stage catches the interruption.
95
+ const release = whenInterrupted((signal) => controller.abort(new Error(`Run interrupted by ${signal}`)));
96
+ const done = executeWorkflow(workflow, state, { agent: budgeted, dir }, store, { onEvent: hooks.onEvent, signal: controller.signal }).finally(release);
97
+ return {
98
+ state,
99
+ runtimes: Object.values(runtimes),
100
+ done,
101
+ stop: (reason) => controller.abort(reason),
102
+ };
103
+ }
104
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/app/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { RunEvent, RunState, Workflow } from "../engine/types.js";
2
+ /** A run, or why it cannot be read. */
3
+ export type RunEntry = {
4
+ id: string;
5
+ state: RunState;
6
+ } | {
7
+ id: string;
8
+ error: string;
9
+ };
10
+ /** The runs kept in `runsDir`, in creation order; an unreadable run comes with its error. */
11
+ export declare function listRuns(runsDir: string): Promise<RunEntry[]>;
12
+ /** A run as a list shows it; a cost no agent announced is unknown (`null`), not zero. */
13
+ export declare function summarizeRun(state: RunState): {
14
+ id: string;
15
+ workflow: string;
16
+ status: "completed" | "failed" | "running";
17
+ stage: string;
18
+ durationMs: number | null;
19
+ costUsd: number | null;
20
+ /** Some agent call announced no usage. */
21
+ partial: boolean;
22
+ updatedAt: string;
23
+ };
24
+ /** One run's state; an unknown ID is refused. */
25
+ export declare function loadRun(runsDir: string, id: string): Promise<RunState>;
26
+ /** One run's stage and journal events, in order. */
27
+ export declare function loadRunEvents(runsDir: string, id: string): Promise<RunEvent[]>;
28
+ /**
29
+ * A run's result lines: its workflow's rendering, or its validated data without
30
+ * its workflow. A failing rendering becomes the explanation.
31
+ */
32
+ export declare function presentResult(workflow: Workflow | undefined, state: Readonly<RunState>): string[];
@@ -0,0 +1,55 @@
1
+ import { elapsedMs } from "../engine/metrics.js";
2
+ import { presentData } from "../engine/workflow.js";
3
+ import { FileRunStore } from "../system/store.js";
4
+ const message = (error) => error instanceof Error ? error.message : String(error);
5
+ /** The runs kept in `runsDir`, in creation order; an unreadable run comes with its error. */
6
+ export async function listRuns(runsDir) {
7
+ const entries = [];
8
+ for (const id of await FileRunStore.list(runsDir))
9
+ try {
10
+ entries.push({
11
+ id,
12
+ state: await new FileRunStore(runsDir, id).load(),
13
+ });
14
+ }
15
+ catch (error) {
16
+ entries.push({ id, error: message(error) });
17
+ }
18
+ return entries;
19
+ }
20
+ /** A run as a list shows it; a cost no agent announced is unknown (`null`), not zero. */
21
+ export function summarizeRun(state) {
22
+ const usage = state.metrics?.usage;
23
+ return {
24
+ id: state.id,
25
+ workflow: state.workflow,
26
+ status: state.status,
27
+ stage: state.stage,
28
+ durationMs: elapsedMs(state),
29
+ costUsd: usage?.responses ? usage.costUsd : null,
30
+ /** Some agent call announced no usage. */
31
+ partial: Boolean(usage?.missing),
32
+ updatedAt: state.updatedAt,
33
+ };
34
+ }
35
+ /** One run's state; an unknown ID is refused. */
36
+ export async function loadRun(runsDir, id) {
37
+ return new FileRunStore(runsDir, id).load();
38
+ }
39
+ /** One run's stage and journal events, in order. */
40
+ export async function loadRunEvents(runsDir, id) {
41
+ return new FileRunStore(runsDir, id).events();
42
+ }
43
+ /**
44
+ * A run's result lines: its workflow's rendering, or its validated data without
45
+ * its workflow. A failing rendering becomes the explanation.
46
+ */
47
+ export function presentResult(workflow, state) {
48
+ try {
49
+ return workflow ? workflow.presentResult(state) : presentData(state);
50
+ }
51
+ catch (error) {
52
+ return [`Result unavailable: ${message(error)}`];
53
+ }
54
+ }
55
+ //# sourceMappingURL=runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/app/runs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOlD,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CACjC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEzD,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAe;IAC5C,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,EAAE,IAAI,MAAM,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC;QAC/C,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC;gBACX,EAAE;gBACF,KAAK,EAAE,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;aAClD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,KAAe;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC;IACnC,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC;QAC5B,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAChD,0CAA0C;QAC1C,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;QAChC,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC;AACJ,CAAC;AAED,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe,EAAE,EAAU;IACvD,OAAO,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAC9C,CAAC;AAED,oDAAoD;AACpD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,EAAU;IAEV,OAAO,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA8B,EAC9B,KAAyB;IAEzB,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,uBAAuB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { RunState } from "./types.js";
2
+ /** Tokens of a model response or of an agent call. */
3
+ export interface TokenCounts {
4
+ input: number;
5
+ output: number;
6
+ cacheRead: number;
7
+ cacheWrite: number;
8
+ }
9
+ /** Tokens and the runtime's estimated cost. */
10
+ export interface AgentUsage extends TokenCounts {
11
+ costUsd: number;
12
+ }
13
+ export interface RunMetrics {
14
+ /** The run's total, the sum of its sessions; `responses` counts measured reports, `missing` unmeasured ones. */
15
+ usage: AgentUsage & {
16
+ responses: number;
17
+ missing: number;
18
+ };
19
+ /**
20
+ * Per agent session, `<runtime>:<session>`: the latest total its runtime
21
+ * announced (Claude Code), or the sum of its responses (Pi). Absent from runs
22
+ * recorded before it existed.
23
+ */
24
+ sessions?: Record<string, AgentUsage>;
25
+ }
26
+ /** A measure as the runtime reports it: one response (Pi), or its session's total so far (Claude Code). */
27
+ export interface UsageReport {
28
+ session: string;
29
+ scope: "response" | "session";
30
+ /** `undefined` when the runtime reported nothing measurable. */
31
+ usage: AgentUsage | undefined;
32
+ }
33
+ /** Tokens and cost of several measures together. */
34
+ export declare function sumUsage(measures: AgentUsage[]): AgentUsage;
35
+ export declare function emptyMetrics(): RunMetrics;
36
+ /**
37
+ * Records a measure as its runtime reports it: a session total replaces the
38
+ * previous one, a response adds to its session. The run's total is the sum of
39
+ * its sessions; nothing else is computed.
40
+ */
41
+ export declare function recordUsage(metrics: RunMetrics, report: UsageReport): void;
42
+ /** Why a run past its budget must stop: its announced cost exceeds it, or a call announced none. */
43
+ export declare function budgetProblem(metrics: RunMetrics, maxCostUsd: number): string | undefined;
44
+ /** From creation to now while running, to the last update once completed or failed. */
45
+ export declare function elapsedMs(state: RunState, now?: number): number | null;
@@ -0,0 +1,60 @@
1
+ const fields = [
2
+ "input",
3
+ "output",
4
+ "cacheRead",
5
+ "cacheWrite",
6
+ "costUsd",
7
+ ];
8
+ const noUsage = () => ({
9
+ input: 0,
10
+ output: 0,
11
+ cacheRead: 0,
12
+ cacheWrite: 0,
13
+ costUsd: 0,
14
+ });
15
+ /** Tokens and cost of several measures together. */
16
+ export function sumUsage(measures) {
17
+ const total = noUsage();
18
+ for (const measure of measures)
19
+ for (const field of fields)
20
+ total[field] += measure[field];
21
+ return total;
22
+ }
23
+ export function emptyMetrics() {
24
+ return { usage: { ...noUsage(), responses: 0, missing: 0 }, sessions: {} };
25
+ }
26
+ /**
27
+ * Records a measure as its runtime reports it: a session total replaces the
28
+ * previous one, a response adds to its session. The run's total is the sum of
29
+ * its sessions; nothing else is computed.
30
+ */
31
+ export function recordUsage(metrics, report) {
32
+ if (!report.usage) {
33
+ metrics.usage.missing++;
34
+ return;
35
+ }
36
+ metrics.usage.responses++;
37
+ metrics.sessions ??= {};
38
+ const { sessions } = metrics;
39
+ const previous = sessions[report.session];
40
+ sessions[report.session] =
41
+ report.scope === "session" || !previous
42
+ ? report.usage
43
+ : sumUsage([previous, report.usage]);
44
+ Object.assign(metrics.usage, sumUsage(Object.values(sessions)));
45
+ }
46
+ /** Why a run past its budget must stop: its announced cost exceeds it, or a call announced none. */
47
+ export function budgetProblem(metrics, maxCostUsd) {
48
+ if (metrics.usage.missing)
49
+ return `Budget of ${maxCostUsd} USD cannot be checked: an agent call announced no cost`;
50
+ if (metrics.usage.costUsd > maxCostUsd)
51
+ return `Budget exceeded: ${metrics.usage.costUsd.toFixed(6)} USD spent, maximum ${maxCostUsd.toFixed(6)} USD`;
52
+ return undefined;
53
+ }
54
+ /** From creation to now while running, to the last update once completed or failed. */
55
+ export function elapsedMs(state, now = Date.now()) {
56
+ const end = state.status === "running" ? now : Date.parse(state.updatedAt);
57
+ const elapsed = end - Date.parse(state.createdAt);
58
+ return Number.isFinite(elapsed) && elapsed >= 0 ? elapsed : null;
59
+ }
60
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/engine/metrics.ts"],"names":[],"mappings":"AAqCA,MAAM,MAAM,GAAG;IACb,OAAO;IACP,QAAQ;IACR,WAAW;IACX,YAAY;IACZ,SAAS;CACD,CAAC;AAEX,MAAM,OAAO,GAAG,GAAe,EAAE,CAAC,CAAC;IACjC,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;IACT,SAAS,EAAE,CAAC;IACZ,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,CAAC;CACX,CAAC,CAAC;AAEH,oDAAoD;AACpD,MAAM,UAAU,QAAQ,CAAC,QAAsB;IAC7C,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC;IACxB,KAAK,MAAM,OAAO,IAAI,QAAQ;QAC5B,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,KAAK,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAC7E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAmB,EAAE,MAAmB;IAClE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACxB,OAAO;IACT,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IAC1B,OAAO,CAAC,QAAQ,KAAK,EAAE,CAAC;IACxB,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;QACtB,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,QAAQ;YACrC,CAAC,CAAC,MAAM,CAAC,KAAK;YACd,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACzC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,aAAa,CAC3B,OAAmB,EACnB,UAAkB;IAElB,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO;QACvB,OAAO,aAAa,UAAU,yDAAyD,CAAC;IAC1F,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,UAAU;QACpC,OAAO,oBAAoB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAChH,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,SAAS,CAAC,KAAe,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACzD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ import type { AgentDeclaration, Edge, RetryEdge, Stage, StageContext, StageResult, WorkflowNode } from "./types.js";
3
+ type Awaitable<T> = T | Promise<T>;
4
+ export declare const END: null;
5
+ /** A correction route, taken at most `max` times per run. */
6
+ export declare function retry(to: string, max: number): RetryEdge;
7
+ /** Binds a stage to its routes; every declared outcome must be routed. */
8
+ export declare function node<O extends string>(stage: Stage<O>, on: Record<O, Edge>): WorkflowNode;
9
+ /** Selects explicit agent context from the run input and workflow data. */
10
+ export declare function pick(...keys: string[]): (context: StageContext) => Record<string, unknown>;
11
+ /** AGENT primitive: one structured request; its untrusted output waits for a gate. */
12
+ export declare function agent(options: AgentDeclaration & {
13
+ schema: z.ZodType;
14
+ context: (context: StageContext) => Awaitable<Record<string, unknown>>;
15
+ }): Stage<"ok">;
16
+ /** CODE primitive: deterministic work with named outcomes. */
17
+ export declare function code<O extends string = "ok">(outcomes: readonly O[], run: (context: StageContext) => Promise<StageResult<O>>): Stage<O>;
18
+ /** What a step records: data, or nothing. */
19
+ type StepData = Record<string, unknown> | void;
20
+ /** CODE primitive with a single successful outcome. */
21
+ export declare function step(run: (context: StageContext) => Promise<StepData>): Stage<"ok">;
22
+ /** GATE primitive: decides acceptance or correction from saved facts. */
23
+ export declare function gate<O extends string>(outcomes: readonly O[], run: (context: StageContext) => Promise<StageResult<O>>): Stage<O>;
24
+ export type Check<T> = (value: T, context: StageContext) => Awaitable<string | undefined | {
25
+ data: Record<string, unknown>;
26
+ }>;
27
+ /** GATE over the last agent output: schema, then business invariants; failures are corrections. */
28
+ export declare function schemaGate<S extends z.ZodType>(options: {
29
+ schema: S;
30
+ /** Data key of the validated output. */
31
+ into: string;
32
+ check?: Check<z.output<S>>;
33
+ }): Stage<"ok" | "invalid">;
34
+ export {};
@@ -0,0 +1,81 @@
1
+ import { z } from "zod";
2
+ export const END = null;
3
+ /** A correction route, taken at most `max` times per run. */
4
+ export function retry(to, max) {
5
+ return { to, max };
6
+ }
7
+ /** Binds a stage to its routes; every declared outcome must be routed. */
8
+ export function node(stage, on) {
9
+ return { stage, on };
10
+ }
11
+ /** Selects explicit agent context from the run input and workflow data. */
12
+ export function pick(...keys) {
13
+ return ({ state }) => Object.fromEntries(keys.flatMap((key) => {
14
+ const value = key === "input" ? state.input : state.data[key];
15
+ return value === undefined ? [] : [[key, value]];
16
+ }));
17
+ }
18
+ /** AGENT primitive: one structured request; its untrusted output waits for a gate. */
19
+ export function agent(options) {
20
+ const { profile, prompt, session } = options;
21
+ return {
22
+ kind: "AGENT",
23
+ outcomes: ["ok"],
24
+ agent: {
25
+ profile,
26
+ ...(prompt === undefined ? {} : { prompt }),
27
+ ...(session === undefined ? {} : { session }),
28
+ },
29
+ async run(context) {
30
+ const { state } = context;
31
+ const output = await context.agent.execute({
32
+ profile,
33
+ prompt: prompt ?? state.stage,
34
+ session: typeof session === "function"
35
+ ? session(state)
36
+ : (session ?? state.stage),
37
+ context: {
38
+ ...(await options.context(context)),
39
+ ...(state.feedback === undefined ? {} : { feedback: state.feedback }),
40
+ },
41
+ schema: z.toJSONSchema(options.schema),
42
+ });
43
+ return { outcome: "ok", output };
44
+ },
45
+ };
46
+ }
47
+ /** CODE primitive: deterministic work with named outcomes. */
48
+ export function code(outcomes, run) {
49
+ return { kind: "CODE", outcomes, run };
50
+ }
51
+ /** CODE primitive with a single successful outcome. */
52
+ export function step(run) {
53
+ return code(["ok"], async (context) => {
54
+ const data = await run(context);
55
+ return { outcome: "ok", ...(data ? { data } : {}) };
56
+ });
57
+ }
58
+ /** GATE primitive: decides acceptance or correction from saved facts. */
59
+ export function gate(outcomes, run) {
60
+ return { kind: "GATE", outcomes, run };
61
+ }
62
+ /** GATE over the last agent output: schema, then business invariants; failures are corrections. */
63
+ export function schemaGate(options) {
64
+ return gate(["ok", "invalid"], async (context) => {
65
+ const parsed = options.schema.safeParse(context.state.output);
66
+ if (!parsed.success)
67
+ return {
68
+ outcome: "invalid",
69
+ reason: `Invalid structured output:\n${z.prettifyError(parsed.error)}`,
70
+ };
71
+ const checked = await options.check?.(parsed.data, context);
72
+ if (typeof checked === "string")
73
+ return { outcome: "invalid", reason: checked };
74
+ return {
75
+ outcome: "ok",
76
+ reason: `Structured output and invariants valid: ${options.into}`,
77
+ data: { ...(checked?.data ?? {}), [options.into]: parsed.data },
78
+ };
79
+ });
80
+ }
81
+ //# sourceMappingURL=primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/engine/primitives.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { z } from "zod";
2
+ /** An agent stage's runtime, settings and access, declared in full by its workflow. */
3
+ export declare const profileSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4
+ runtime: z.ZodLiteral<"pi">;
5
+ access: z.ZodDefault<z.ZodEnum<{
6
+ read: "read";
7
+ write: "write";
8
+ }>>;
9
+ provider: z.ZodString;
10
+ model: z.ZodString;
11
+ thinking: z.ZodEnum<{
12
+ high: "high";
13
+ low: "low";
14
+ max: "max";
15
+ medium: "medium";
16
+ minimal: "minimal";
17
+ off: "off";
18
+ xhigh: "xhigh";
19
+ }>;
20
+ tools: z.ZodArray<z.ZodString>;
21
+ skills: z.ZodDefault<z.ZodArray<z.ZodString>>;
22
+ extensions: z.ZodDefault<z.ZodArray<z.ZodString>>;
23
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
24
+ }, z.core.$strict>, z.ZodObject<{
25
+ runtime: z.ZodLiteral<"claude-code">;
26
+ access: z.ZodDefault<z.ZodEnum<{
27
+ read: "read";
28
+ write: "write";
29
+ }>>;
30
+ model: z.ZodString;
31
+ thinking: z.ZodEnum<{
32
+ high: "high";
33
+ low: "low";
34
+ max: "max";
35
+ medium: "medium";
36
+ xhigh: "xhigh";
37
+ }>;
38
+ tools: z.ZodArray<z.ZodString>;
39
+ mcpServers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
40
+ command: z.ZodString;
41
+ args: z.ZodDefault<z.ZodArray<z.ZodString>>;
42
+ }, z.core.$strict>>>;
43
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
44
+ }, z.core.$strict>], "runtime">;
45
+ /** A profile as a workflow declares it. */
46
+ export type AgentProfile = z.input<typeof profileSchema>;
47
+ /** A profile with its defaults applied. */
48
+ export type ResolvedProfile = z.output<typeof profileSchema>;
49
+ export type Runtime = ResolvedProfile["runtime"];
50
+ /** Each runtime's name as the operator reads it. */
51
+ export declare const runtimeLabels: Record<Runtime, string>;
52
+ /** The profile with its defaults applied; an invalid profile is refused with its problems. */
53
+ export declare function resolveProfile(profile: AgentProfile): ResolvedProfile;