Skip to main content
The turn executor decides where a session’s agent turn runs, so a wedged, runaway, or crashed turn is contained to its own worker instead of taking down every session on the gateway.

Quick Start

1

Default — every turn runs on the current loop, no config

The gateway uses InProcessTurnExecutor when nothing is set, so every turn runs on the current event loop exactly as today.
2

Isolate a bad session's turn on its own worker

Select an isolated executor from a wrapper package (subprocess / container / remote) when you need blast-radius containment. Core ships only the seam and the safe in-process default — the wrapper ships concrete isolated executors.

How It Works

The gateway asks the executor to place a session, runs the turn on that placement, and tears the placement down only when its worker wedges — never the whole process. InProcessTurnExecutor is the default and reproduces today’s on-loop behaviour exactly: leaving the executor unset changes nothing and adds no dependency.

The Contract

TurnExecutorProtocol is a runtime-checkable protocol with three async methods. TurnPlacement is a frozen dataclass — mutating any field raises dataclasses.FrozenInstanceError. WorkerWedgedError is a plain Exception subclass. It is scoped: the gateway tears down only the offending placement and re-places its session — never a process-wide os._exit. Ordinary turn errors surface as the turn’s own exception and do not condemn the worker.
An isolated executor does not ship the live turn callable (and its captured loop/agent state) across a process boundary. The worker owns the session via place() and rebuilds the turn from serialisable inputs on its own side; the passed turn is the gateway-side await point for the worker’s result.

Configuration Options

The seam is a typed contract, not a config block. Reach for these SDK references for the full surface.
TurnExecutorProtocol — auto-generated SDK reference.
TurnPlacement — auto-generated SDK reference.
InProcessTurnExecutor — auto-generated SDK reference.
WorkerWedgedError — auto-generated SDK reference.
limits on execute_turn is a typed Any today, accepted for protocol symmetry. It is inert in-process and honoured only by isolated executors — there is no limits= config class in core.

Common Patterns

Three shapes cover almost every use.

Best Practices

epoch is the fencing token. Bump it whenever a session’s worker is replaced, and refuse any turn carrying a stale epoch — that is what stops a reclaimed worker from executing against a session it no longer owns.
teardown reclaims a single placement’s worker. A worker fault must fail scoped: tear down the offending placement and re-place its session, never the whole gateway. That is the whole point of the seam versus a process-wide os._exit.
The in-process default is zero-cost and dependency-free but offers no isolation — a turn that wedges the loop still affects the process. Switch to an isolated executor (subprocess / container / remote) when one bad session must not degrade the rest.
An isolated worker owns the session via place() and rebuilds the turn from serialisable inputs on its own side. Do not try to send the live turn callable across a process boundary — treat it as the gateway-side await point for the worker’s result.

Gateway Turn Lock

Sibling primitive — serialises turns per session across replicas.

Gateway Loop Watchdog

Detects a wedged event loop.