---
name: agentbyte-round-robin-orchestration
description: Guide for creating Round-Robin multi-agent orchestration in Agentbyte. Use this when coordinating multiple agents in sequential turns until a termination condition is met.
license: MIT
---

Use this skill when implementing multi-agent collaboration where agents take turns in a fixed sequence (poet/critic, research/writing, review/revise patterns).

## Inputs to confirm
- Which agents participate, in what fixed order
- What termination condition should stop the loop
- Whether the default full-history text context is sufficient or a custom `HistoryContextPolicy` is needed

## Pattern: Basic Round-Robin Orchestration

```python
import asyncio
from agentbyte import (
    Agent,
    AgentHistoryPolicy,
    HistoryContextPolicy,
    RoundRobinOrchestrator,
    UserMessage,
)
from agentbyte.llm import OpenAIChatCompletionClient
from agentbyte.termination import MaxMessageTermination, TextMentionTermination

async def main():
    # 1. Create model client
    client = OpenAIChatCompletionClient.from_api_key(model="gpt-4o-mini")

    # 2. Create agents
    poet = Agent(
        name="poet",
        description="A creative poet that writes and refines haikus",
        instructions="Write a haiku. If you received feedback, refine it.",
        model_client=client
    )

    critic = Agent(
        name="critic",
        description="A strict poetry critic",
        instructions="Review the poem. If good, say APPROVED. Else provide feedback.",
        model_client=client
    )

    # 3. Define termination conditions (composable with | and &)
    termination = TextMentionTermination("APPROVED") | MaxMessageTermination(6)

    # 4. Initialize orchestrator
    orchestrator = RoundRobinOrchestrator(
        agents=[poet, critic],
        termination=termination,
        max_iterations=10,  # Safety fallback
        history_policy=HistoryContextPolicy(
            default=AgentHistoryPolicy(window="full", format="text")
        ),
    )

    # 5. Run the collaboration
    task = UserMessage(content="Write a haiku about programming", source="user")
    result = await orchestrator.run(task)

    print(f"Stop reason: {result.stop_message.content}")
    print(f"Total tokens: {result.usage.total_tokens}")
    print(f"Cycles: {result.pattern_metadata['cycles_completed']}")

asyncio.run(main())
```

## Pattern: Streaming Round-Robin

```python
async for item in orchestrator.run_stream(task, verbose=True):
    if isinstance(item, Message):
        print(f"[{item.source}] {item.content}")
    elif isinstance(item, OrchestrationEvent):
        # Track selection, execution events
        print(f"Event: {item.__class__.__name__}")
    elif isinstance(item, OrchestrationResponse):
        # Final result
        print(f"Complete: {item.stop_message.content}")
```

## Available Termination Conditions

| Termination Type | Purpose | Example |
|-----------------|---------|---------|
| `MaxMessageTermination(n)` | Stop after n messages | `MaxMessageTermination(10)` |
| `TextMentionTermination("X")` | Stop when any agent says X | `TextMentionTermination("APPROVED")` |
| `SourceTermination("name")` | Stop when a specific agent speaks | `SourceTermination("critic")` |
| `PredicateTermination(fn)` | Stop on any custom callable condition | see below |
| `TokenUsageTermination(n)` | Stop after n tokens | `TokenUsageTermination(5000)` |
| `TimeoutTermination(sec)` | Stop after timeout | `TimeoutTermination(60.0)` |
| `CancellationTermination()` | Stop when cancelled | `CancellationTermination()` |
| Composite (OR) | Stop if any condition met | `T1 \| T2 \| T3` |
| Composite (AND) | Stop if all conditions met | `T1 & T2 & T3` |

### Reviewer-Gated Termination

`TextMentionTermination("APPROVED")` fires if **any** agent says "APPROVED". For writer/critic patterns where only the critic should trigger the stop, use `SourceTermination` or a precise predicate:

```python
from agentbyte.termination import SourceTermination, PredicateTermination, MaxMessageTermination

# Stop as soon as the critic speaks — regardless of content
termination = SourceTermination("critic") | MaxMessageTermination(8)

# Stop only when the critic says APPROVED in the same message (most precise)
termination = (
    PredicateTermination(
        lambda msgs: any(
            getattr(m, "source", None) == "critic"
            and "APPROVED" in str(getattr(m, "content", ""))
            for m in msgs
        ),
        reason="Critic approved",
    )
    | MaxMessageTermination(8)
)
```

## History Policy

```python
orchestrator = RoundRobinOrchestrator(
    agents=[agent1, agent2, agent3],
    termination=termination_condition,
    max_iterations=10,
    history_policy=HistoryContextPolicy(
        default=AgentHistoryPolicy(window="full", format="text"),
        per_agent={
            "critic": AgentHistoryPolicy(
                window="recent",
                message_limit=4,
                format="markdown",
            )
        },
    ),
)
```

Use `HistoryContextPolicy` to control:
- `default`: one `AgentHistoryPolicy` used for all agents unless overridden
- `per_agent`: optional agent-specific `AgentHistoryPolicy` overrides

Each `AgentHistoryPolicy` controls:
- `window`: `full` or `recent`
- `message_limit`: required when `window="recent"`
- `format`: `messages`, `text`, `markdown`, or `json`

Default round-robin behavior is still full shared history rendered as text.

## Pattern Metadata

After completion, `result.pattern_metadata` contains:
- `cycles_completed`: Number of full round-robin cycles
- `iterations_completed`: Total agent executions
- `agents_order`: Agent names in round-robin order
- `message_count`: Number of shared messages retained

## Guardrails

- **Agent Order:** Agents execute in the order provided in the `agents` list.
- **Termination Required:** Always provide at least one termination condition to prevent infinite loops.
- **Safety Limit:** Set `max_iterations` as a failsafe even with other termination conditions.
- **Shared Context:** By default all agents see full history as text, but `HistoryContextPolicy` can narrow the window or change the format.
- **Model Client:** Each agent needs its own `model_client` configured.
- **Event Observability:** Use `verbose=True` with `run_stream()` to track selection and execution events.

## Common Use Cases

1. **Poet/Critic Pattern:** Writer creates, reviewer approves or requests changes
2. **Research/Writing:** Researcher gathers facts, writer synthesizes into prose
3. **Code/Review:** Developer writes code, reviewer provides feedback
4. **Plan/Execute:** Planner designs approach, executor implements steps
5. **Draft/Polish:** Rough draft agent, then polish/editing agent
