Quick Start
The planner names the next speaker from an immutable(roster, transcript) snapshot. You append each reply and ask again.
1
Schedule the opening round
Round 0 lets every rostered agent speak once, in roster order, after a human message.
2
Hand off with @-mentions
An agent addresses a teammate with
@name to admit them into the next round. Admitted agents speak in roster order.How It Works
The gateway persists the transcript and replays the planner; the planner never touches a clock, RNG, or external state.plan_next returns None when the current activity is settled, signalling the room to wait for the next human message.
Configuration Options
RoundRobinRoomPlanner is a dataclass with two hard caps.
RoomEvent is a frozen dataclass — immutable, hashable, and safe to persist or replay.
Turn-Taking Rules
Round 0 — opening fan-out
Round 0 — opening fan-out
After a human message, every rostered agent speaks once in roster order. This is the “everyone on round 0” default.
Later rounds — @-mention admission
Later rounds — @-mention admission
A round N+1 admits only the agents that were
@-mentioned by an agent during round N, and only agents actually on the roster. Mentions are honoured in roster order (not mention order). An agent speaks at most once per round.Bounded — hard stops
Bounded — hard stops
max_rounds and max_messages are hard stops; a room can never loop unbounded.Restart-safe — pure replay
Restart-safe — pure replay
The plan is a pure function of
(roster, transcript). Replaying a persisted transcript yields the identical next speaker — no double-execution, no lost turn.Current Activity Semantics
The planner scopes accounting to the slice of the transcript from the last human (non-roster) message onward.- A room only starts once a human (non-roster) message has been seen. Before that,
plan_nextreturnsNone. max_messagesis per activity, not lifetime. A settled room reliably restarts on the next human message, no matter how long the historical transcript is.@-mention admission is also scoped to the current activity — stale mentions from a prior settled activity do not leak into a new activity’s later rounds.
Mention Parsing
extract_mentions(text) returns the ordered, de-duplicated list of @name mentions found in text.
- First-seen order is preserved so addressing is deterministic.
- Case is preserved; matching against roster ids is case-sensitive.
- Name grammar:
@followed by[A-Za-z0-9][\w\-.]*— letters, digits, underscore, dash, dot; a name may not start with_,-, or.. - Email-safe: a
@glued to a preceding word character does not match, so scanning human text is safe.
Common Patterns
Pick a planner based on whether the default round-robin policy fits your room.- Round 0 fan-out — every rostered agent speaks once, in roster order.
@-mention hand-off — an agent addresses a teammate to admit them to the next round.- Explicit pass — an agent has nothing to add; emit
RoomEvent(speaker=..., passed=True)to advance without a reply. - Restart-safe replay — persist the transcript; on restart, re-run
plan_next(roster, transcript)for the identical next speaker. - Custom planner — implement
RoomTurnPlannerProtocol.plan_nextfor a domain-specific policy. Keep it pure and I/O-free.
RoomTurnPlannerProtocol because the protocol is @runtime_checkable:
Best Practices
Keep custom planners pure
Keep custom planners pure
No clock, no RNG, no I/O. Purity is the whole property that makes a room restart-safe.
Roster order is your tie-breaker
Roster order is your tie-breaker
When multiple agents are admitted (round 0, or several
@-mentions in one round), they speak in roster order, not mention order. Design roster order intentionally.Set caps conservatively
Set caps conservatively
max_rounds and max_messages are the guardrails against runaway loops. RoundRobinRoomPlanner() defaults to 3 rounds and 20 messages per activity.Prefer passed=True over an empty reply
Prefer passed=True over an empty reply
A pass consumes the turn and advances the planner while reading as an intentional silence in the transcript.
Don't rely on lifetime transcript length
Don't rely on lifetime transcript length
Message caps are per activity (per human message), by design. A long historical transcript never permanently disables a room.
Related
Bot Gateway
The gateway that drives the planner in a live chat.
AgentTeam
The in-process, run-to-completion counterpart to a live conversation room.
Gateway Turn Lock
Serialise per-session turns across replicas.
Gateway Turn Executor
Runs a scheduled turn against an agent.

