akashi_workflow 0.3.1
akashi_workflow: ^0.3.1 copied to clipboard
Deterministic, code-driven multi-agent orchestration for Akashi: bounded-concurrency fan-out, typed pipelines, retries with backoff, timeouts, cancellation, and an event stream.
akashi_workflow #
Deterministic, code-driven multi-agent orchestration for Akashi.
Akashi's built-in multi-agent primitives (Agent.asTool, handoffs, escalation)
are model-driven β the model decides at runtime whether to delegate or hand
off. akashi_workflow is the complement: code-driven orchestration where
you fix the topology (fan-out, pipelines, loops) and the engine supplies the
production concerns.
π¬ Live demo: the Workflow pipeline demo at akashi.azanello.com.
What it gives you #
- Bounded concurrency β a fan-out of hundreds of tasks runs at most
maxConcurrencyat a time (a FIFOSemaphore). - Retries β geometric backoff + jitter, per-task or workflow-default, with a
retryIfpredicate. - Timeouts β per task and a global
deadline; a timeout cooperatively cancels the task. - Cancellation β one
CancellationTokenfor the whole run, linkable to an external token, threaded into every task (and into agent runs viaagentTask). - Fail-fast or settled β
parallelrethrows the first failure and cancels siblings;parallelSettledreturns everyTaskResult. - Typed pipelines β chain stages with no barrier between them (item A can be in stage 3 while item B is in stage 1).
- Observability β a broadcast
eventsstream (TaskStarted/TaskSucceeded/TaskFailed/TaskRetrying) plusTracerspans. - A budget guard β
maxTaskscaps total executions (a runaway-loop backstop).
Quick start #
import 'package:akashi_workflow/akashi_workflow.dart';
final wf = Workflow(
maxConcurrency: 4,
defaultRetry: RetryPolicy.standard, // 3 attempts, backoff+jitter
defaultTimeout: const Duration(seconds: 30),
);
// Fan out research across questions β bounded to 4 at a time, each retried.
final findings = await wf.parallel([
for (final q in questions) agentTask(researcher, q.prompt, label: q.id),
]);
// Synthesize the results with another agent.
final report = await wf.run(agentTask(writer, synthesisPrompt(findings)));
wf.dispose();
Settled fan-out (partial results) #
final results = await wf.parallelSettled([
for (final url in urls) Task((ctx) => scrape(url, ctx.cancel), label: url),
]);
final ok = results.where((r) => r.ok).map((r) => r.value);
final failed = results.where((r) => !r.ok);
Typed pipeline (plan β research β verify) #
final pipeline = Pipeline.input<Topic>()
.stage('research', (topic, ctx) => researcher.run(topic.q,
options: RunOptions(cancel: ctx.cancel))) // Topic -> RunResult
.stage('verify', (res, ctx) => verifier.run(res.text,
options: RunOptions(cancel: ctx.cancel))); // RunResult -> Verdict
final verdicts = await wf.pipeline(topics, pipeline); // List<TaskResult<Verdict>>
Structured output between stages #
final plan = await wf.run(objectTask(planner, goal, schema: planSchema));
Live progress #
wf.events.listen((e) {
switch (e) {
case TaskStarted(): print('βΆ ${e.label} #${e.attempt}');
case TaskSucceeded(): print('β ${e.label}');
case TaskFailed(): print('β ${e.label} (retry: ${e.willRetry})');
case TaskRetrying(): print('β» ${e.label} in ${e.delay.inMilliseconds}ms');
}
});
When to use which #
Model-driven (akashi) |
Code-driven (akashi_workflow) |
|
|---|---|---|
| Who decides the shape | the LLM, at runtime | you, in Dart |
| Primitives | Agent.asTool, handoffs |
parallel, pipeline, run |
| Best for | open-ended delegation | known fan-out, batch jobs, ETL-style pipelines, audits |
They compose: a workflow stage can itself run a multi-agent (subagent/handoff)
Agent.
See example/akashi_workflow_example.dart
for a runnable plan β fan-out β synthesize pipeline on fake models.
Status #
v0.3.
License #
MIT.