Engine-agnostic multi-agent workflow orchestration with journaled replay/resume
Dependencies
///|
async fn verdict_runner(call : @workflow.AgentCall) -> @workflow.AgentOutcome {
@async.pause()
let verdict : Json = if call.input is { "query": String(q), .. } &&
q.contains("lens=repro") {
{ "confirmed": false }
} else {
{ "confirmed": true }
}
Finished(value=verdict, attempt={
attempt_id: "sr-\{call.label}",
steps_used: 3,
prompt_tokens: 70,
completion_tokens: 30,
})
}
///|
async test "fan out three lenses, gate on a 2-of-3 quorum" {
let wf = @workflow.Workflow(
runner=@workflow.Runner(verdict_runner),
max_concurrent=4,
max_calls=16,
)
wf.phase("Verify")
let results = @workflow.fan_out(["correctness", "security", "repro"], lens => {
wf.try_agent(
kind="judge",
"Judge the finding through lens=\{lens}: real?",
label="verify:\{lens}",
)
})
let confirmed = @workflow.quorum(results, need=2)
.filter(v => v is { "confirmed": True, .. })
.length()
assert_eq(confirmed, 2)
assert_eq(wf.calls_made(), 3)
assert_eq(wf.tokens_spent(), 300)
}///|
async test "find then verify, with no barrier between the stages" {
let wf = @workflow.Workflow(runner=@workflow.Runner(verdict_runner))
let verified = @workflow.fan_out(["pkg/a", "pkg/b"], target => {
let finding = wf.try_agent("Find the worst bug in \{target}", kind="judge")
match finding {
// Each finding proceeds to verification the moment ITS finder
// returns — b's finder may still be running while a verifies.
Ok(_) =>
wf.try_agent(
"Adversarially verify the finding in \{target}",
kind="judge",
)
Err(error) => Err(error)
}
})
assert_eq(@workflow.all_ok(verified).length(), 2)
}///|
async test "the second generation replays instead of re-paying" {
let journal = @workflow.Journal::in_memory()
let wf1 = @workflow.Workflow(
runner=@workflow.Runner(verdict_runner),
journal~,
)
let first = wf1.agent(
"Judge the finding through lens=security: real?",
kind="judge",
)
assert_eq(wf1.tokens_spent(), 100)
// Same program, next generation: served from the journal — no launch,
// no slot, no fresh spend.
let wf2 = @workflow.Workflow(
runner=@workflow.Runner(verdict_runner),
journal=@workflow.Journal::in_memory(prior=journal.recorded()),
)
assert_eq(
wf2.agent("Judge the finding through lens=security: real?", kind="judge"),
first,
)
assert_eq(wf2.calls_made(), 0)
assert_eq(wf2.calls_replayed(), 1)
assert_eq(wf2.tokens_spent(), 0)
}///|
let runner = @spawn.contract_runner(launch=_ => {
command: "my-engine",
args: [],
cwd: None,
extra_env: None,
deadline_ms: None,
})///|
let runner = @workflow.Runner(call => {
// spawn something, await it, and account honestly:
Finished(value=report_json, attempt={
subrun_id,
steps_used,
prompt_tokens,
completion_tokens,
})
})pub suberror JournalCorrupted {
JournalCorrupted(path~ : String, line~ : Int)
}impl Show for JournalCorruptedpub suberror WorkflowError {
AgentFailed(label~ : String, failure~ : AgentFailure)
CallBudgetExhausted(label~ : String)
QuorumNotReached(need~ : Int, ok~ : Int, of~ : Int)
}impl Show for WorkflowErrorimpl Show for AgentFailurepub(all) enum AgentOutcome {
Finished(value~ : Json, attempt~ : AgentAttempt)
DidNotFinish(failure~ : AgentFailure, attempt~ : AgentAttempt?)
} derive(Eq, ToJson, FromJson)pub struct Journal {
// private fields
}pub(all) struct JournalEntry {
call : AgentCall
outcome : AgentOutcome
} derive(Eq, ToJson, FromJson)pub struct Runner {
// private fields
}fn Runner::Runner(run : async (AgentCall) -> AgentOutcome, validate_replay? : async (AgentCall, AgentOutcome) -> ReplayDecision) -> Runnerpub struct Workflow {
runner : Runner
slots : Semaphore
on_event : (WorkflowEvent) -> Unit
journal : Journal?
replay_scope : String
max_calls : Int?
calls_made : Int
replays : Int
prompt_tokens : Int
completion_tokens : Int
current_phase : String?
}fn Workflow::Workflow(runner~ : Runner, max_concurrent? : Int, max_calls? : Int, journal? : Journal, replay_scope? : String, on_event? : (WorkflowEvent) -> Unit) -> Workflow raiseasync fn Workflow::try_agent(self : Workflow, prompt : String, kind~ : String, hints? : String, label? : String, max_steps? : Int) -> Result[Json, WorkflowError]pub(all) enum WorkflowEvent {
PhaseStarted(String)
Log(String)
AgentStarted(label~ : String, kind~ : String, phase~ : String?)
AgentFinished(label~ : String, disposition~ : AgentDisposition)
AgentReplayed(label~ : String, disposition~ : AgentDisposition)
}fn[T] collect_ok(results : Array[Result[T, WorkflowError]], min_ok? : Int) -> Array[T] raise WorkflowErrorasync fn[A, B] fan_out(items : Array[A], run : async (A) -> Result[B, WorkflowError]) -> Array[Result[B, WorkflowError]]async fn[T] parallel(thunks : Array[async () -> Result[T, WorkflowError]]) -> Array[Result[T, WorkflowError]]fn[T] quorum(results : Array[Result[T, WorkflowError]], need~ : Int) -> Array[T] raise WorkflowErrorInstall
Download zipEngine-agnostic multi-agent workflow orchestration with journaled replay/resume
Dependencies