Execution Model
2.4 Execution Model
Phase-Ordered Message Delivery
The fundamental correctness property of the SDK is:
Messages sent during Phase N are delivered to agent inboxes BEFORE Phase N+1 begins.
When you write self.run(Sequence(action_A, action_B)), the runtime guarantees that all messages sent by agents during action_A are delivered to recipient inboxes before action_B starts executing. This eliminates race conditions and ensures deterministic execution regardless of which backend is used or how many threads/processes are involved.
This means the order of actions in run() IS the message delivery order. If Bank agents broadcast their status in Phase 1, and Bank agents check solvency in Phase 2, then every bank sees every other bank's status message when it checks solvency. This is the no-write-sharing invariant: agents never read each other's state directly, only through messages, and messages have a well-defined delivery time.
Eight Execution Backends
All backends implement the ExecutionBackend abstract base class with three methods: execute_action(), deliver_messages(), and get_agents_for(). The model code does not know or care which backend is running it --- the same model.py produces identical results on any backend (guaranteed by the SHA-256 seed hierarchy and phase-ordered delivery).
| Backend | __init__ Params | Parallelism | Best For |
|---|---|---|---|
LocalBackend | (none) | Sequential | Debugging, small models, determinism verification |
ThreadPoolBackend | max_workers: int = 4 | Threads | I/O-bound agents, moderate parallelism |
ProcessPoolBackend | max_workers: Optional[int] = None | Processes | CPU-bound models (GIL bypass) |
MCPBackend | mcp_config: MCPConfig | Distributed HTTP | Multi-machine deployment |
EmulatorBackend | (inherits MCP) | In-process | Testing distributed logic locally |
AsyncBackend | semaphore_limit: int = 128 | asyncio | LLM-heavy models (bifurcated execution) |
PregelBackend | max_supersteps: int = 100 | BSP supersteps | Graph algorithms (PageRank, label propagation) |
DaskBackend | scheduler_address, n_workers, partition_strategy | Distributed cluster | Large-scale production |
Backends are switched via settings.json without any code changes:
{"orchestration": {"mode": "local"}}
{"orchestration": {"mode": "threaded", "max_workers": 8}}
{"orchestration": {"mode": "async", "async_semaphore_limit": 128}}
{"orchestration": {"mode": "dask", "scheduler_address": "tcp://scheduler:8786"}}
The PregelBackend deserves special mention: it implements the Bulk Synchronous Parallel (BSP) model where agents can vote_to_halt() when they have nothing more to do. Execution continues in supersteps until all agents have halted or a convergence condition is met. This is the natural execution model for iterative graph algorithms.