1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//! Dynamic Workflow runtime for CodeWhale.
//!
//! This crate is the imperative half of Workflow: a sandboxed QuickJS
//! (rquickjs) runtime that executes a model-authored JS program which
//! dispatches fleet-routed subagents via `task()`, fans out with
//! `parallel()`/`pipeline()`, reports progress with `log()`/`phase()`, and
//! scales itself to a token pool via the `budget` global. The static,
//! declarative IR (record/replay, model policy) stays in `codewhale-workflow`;
//! this crate only speaks to the outside world through the
//! [`WorkflowDriver`] seam, so it is fully testable without spawning a real
//! subagent (see [`testing::FakeDriver`]).
//!
//! # Script surface
//!
//! Every script runs inside an async function with these globals:
//!
//! * `args` — the invocation input, verbatim.
//! * `await task(opts)` — dispatch one subagent; resolves to the full result
//! text, or to a parsed + schema-validated object when `opts.responseSchema`
//! is set. Throws on rejection, failure, cancellation, budget exhaustion,
//! or once [`WORKFLOW_LIFETIME_CAP`] spawn attempts have been made.
//! * `parallel(thunks)` — all-settled fan-out; an ordinary failed slot becomes
//! `null`; schema-contract failures and run cancellation still fail the run;
//! at most [`PARALLEL_MAX_ITEMS`] items.
//! * `pipeline(items, ...stages)` — per-item stage chains with no barrier
//! between stages; an ordinary stage error drops that item to `null`, while
//! schema-contract failures and cancellation still fail the run; same cap.
//! * `log(msg)` / `phase(title)` — progress events forwarded to the driver.
//! * `budget.total` / `budget.spent()` / `budget.remaining()` — live driver
//! snapshots (`total` is `null` and `remaining()` is `Infinity` when no
//! ceiling is configured).
//!
//! `Date.now()`, `new Date()`, `Date.parse/UTC`, and `Math.random()` throw:
//! runs must be deterministic so recorded traces can be replayed.
//!
//! # Ownership boundaries
//!
//! Token accounting and admission belong to the driver; the VM only reads
//! snapshots and fast-fails a spawn when the shared pool is already exhausted.
//! Already-running parallel children can reconcile above the hint because
//! provider usage arrives at response boundaries, not token-by-token. Fleet
//! roster resolution for `profile` also happens driver-side; this crate
//! normalizes and token-validates the profile string, nothing more.
pub use ;
pub use ;
pub use ;
/// Maximum `task()` spawn attempts per run (design §4.3). Counted in the VM
/// before the driver is consulted, so a runaway `loop-until-dry` terminates
/// even if the driver would keep admitting work.
///
/// Product scale: up to 1_000 agents per Workflow run.
pub const WORKFLOW_LIFETIME_CAP: u64 = 1000;
/// Maximum concurrently executing agents within one Workflow run.
///
/// Fan-out may *declare* more work via `parallel()` / `pipeline()`, but the
/// host admits at most this many live `task()` children at once; additional
/// spawns wait for a slot.
pub const WORKFLOW_MAX_CONCURRENT: usize = 16;
/// Maximum items per `parallel()` or `pipeline()` call (design §4.2).
/// Kept at the per-run agent ceiling so a single fan-out cannot declare more
/// work than the lifetime cap can ever complete.
pub const PARALLEL_MAX_ITEMS: usize = 1000;