Cycle break conditions
The starter orchestrator runs one step per request: route, branch, reply. Real agents often loop: tool, retrieve, tool again, synthesize. That is where things go wrong. A bug in the routing rules or a confused model can send the agent back to the same branch forever. Every cycle costs tokens, latency, and user patience. You need explicit budgets.
MAX_STEPS = 4
MAX_SAME_ROUTE = 2
class OrchestratorLayer:
def initial_state(self, message: str, thread_id: str) -> Dict[str, Any]:
return {
"message": message,
"thread_id": thread_id,
"route": None,
"route_history": [],
"steps": 0,
"tool_result": None,
"retrieved": [],
"reply": None,
}
def should_stop(self, state: Dict[str, Any]) -> tuple[bool, str]:
"""Return (stop, reason). Called before every step."""
if state["steps"] >= MAX_STEPS:
return True, "max_steps"
history = state["route_history"]
if len(history) >= MAX_SAME_ROUTE:
tail = history[-MAX_SAME_ROUTE:]
if all(r == tail[0] for r in tail):
return True, "repeat_route"
return False, ""
def advance(self, state: Dict[str, Any], route: str) -> None:
state["steps"] += 1
state["route_history"].append(route)Two budgets: a hard cap on total steps, and a repeat-route guard that stops when the same branch runs back-to-back. Both are explicit, both are logged, both show up in the trace.
Ordering exercise: Order the safe orchestrator loop
Loading practice…
Quiz: Quiz
Loading practice…