Composition¶
Composing agents:
chain,Agent.parallel,Plan, ortools=[...]?
Pick by who decides what runs when — pre-scripted by you, LLM-driven, or declared with compile-time validation.
Decision tree¶
Linear pipeline, output of step N becomes task of N+1?
→ Agent.chain(a, b, c)
# sugar for Agent(engine=Plan(Step(target=a, name=a.name),
# Step(target=b, name=b.name), …))
Run the same task on N agents concurrently, get the joined output?
→ Agent.parallel(a, b, c)
# asyncio.gather over a/b/c — returns ONE Envelope whose
# text() is the labelled-text join. Call .run_branches(task)
# (async) if you need typed per-branch list[Envelope].
Let the LLM decide which sub-agent(s) to call (and when, including
in parallel)?
→ Agent(engine=LLMEngine("…"), tools=[a, b, c])
# the engine fans out automatically when the model emits
# multiple tool calls in one turn — no config needed
Declared workflow with typed hand-offs, routing, parallel bands,
or crash-resume?
→ Agent(engine=Plan(Step("…", output=…), Step("…", routes={…}), …),
tools=[…])
Quick reference¶
| Who decides the flow? | Use |
|---|---|
| You, linear and fixed | Agent.chain(a, b, c) |
| You, deterministic fan-out → list | Agent.parallel(a, b, c) |
| You, declared DAG with types / routing / resume | Plan(Step(…), …) |
| The LLM (which to call, when, in parallel) | Agent(tools=[a, b, c]) |
Notes¶
Agent.chainis sugar for a linearPlan. Use it for one-liner sequential handoffs; reach for the explicitPlanthe moment you can see a router or a parallel band coming.Agent.parallelreturns ONE Envelope (since 0.7.9) whosepayloadis the labelled-text join of every branch. For typed per-branch access callparallel.run_branches(task)(async) →list[Envelope].tools=[a, b, c]is the LLM-driven path. When the model emits multiple tool calls in one turn, LazyBridge dispatches them concurrently viaasyncio.gather— automatic parallelism, no flag.- All four shapes compose recursively. A
Planstep'stargetcan be an agent built fromAgent.chainorAgent.parallel; anAgent.parallelbranch can itself contain aPlan. The unit at every level is the sameAgent.
See also: scripted composition¶
- Chain — sequential composition reference.
- Parallel —
Agent.parallelsemantics;ParallelAgentreturn type. - As tool — when to pass an agent in
tools=[…]directly vsagent.as_tool("alias"). - Plan — declared orchestration with compile-time DAG validation.
- Parallelism decision — automatic vs declared.
See also: LLM-driven orchestrators¶
When the structure of the work is decided at runtime, two factory
helpers in lazybridge.ext.planners ship a pre-built orchestrator
agent:
orchestrator_agent(...)(aliasmake_planner) — DAG builder; the LLM composes aPlanstep by step via builder tools, with compile-time validation.blackboard_orchestrator_agent(...)(aliasmake_blackboard_planner) — flat to-do list; the LLM manages tasks viaset_plan/get_plan/mark_donetools without DAG structure.
Both wrap an LLM with the planning toolkit. Use them when you want LLM-driven dispatch but don't want to author the planning prompt from scratch. See the Plan tool and Blackboard planner recipes.