skip to content

In AutoGen AgentChat, how do termination conditions end a team run, and what do | and & do?

level: middleimportance: must knowfreq 84%

answer

  1. policy object, checked between messages
  2. or is any, and is all
  3. TaskResult carries the reason
  4. caps are fuses, not success
  5. the magic word can appear in the task

basics

~20 s

Termination conditions from autogen_agentchat.conditions are evaluated as messages flow through a team; when one fires the team stops and run() returns a TaskResult whose stop_reason names it. The | operator means stop when either condition fires; & means stop only once all of them have.

solid answer

~40 s

A team such as `RoundRobinGroupChat` or `SelectorGroupChat` takes a `termination_condition`. After each message the group-chat manager asks the condition whether to stop; when it says yes, no further turns are scheduled and `run()`/`run_stream()` returns a `TaskResult` carrying the messages and a human-readable `stop_reason`. The built-ins cover different axes: `MaxMessageTermination(n)` counts messages, `TextMentionTermination("APPROVE")` matches text in any message, `TokenUsageTermination(...)` caps reported token usage, `TimeoutTermination(seconds)` caps wall clock, `HandoffTermination(target=...)` stops on a handoff, `ExternalTermination()` lets outside code stop the run. They compose with operators: `a | b` builds an OR condition that fires as soon as either fires, `a & b` an AND condition that fires only after all parts have fired at some point in the run. In production you nearly always OR a semantic condition with a hard cap.

go deeper

for a junior

Know that you pass a termination_condition when constructing a team, that MaxMessageTermination and TextMentionTermination are the two you will use first, and that run() returns a TaskResult.

for a middle

Explain when conditions are checked, what stop_reason tells you, how | and & compose, and why conditions carry state that is reset per run.

for a senior

Demonstrate the layered policy: an explicit success signal ORed with message, time and token fuses, plus monitoring on stop_reason so a run that was cut off is never mistaken for one that finished.

for a principal

Own the cost and reliability envelope: which fuse belongs in the team, which belongs at the model client or gateway, and what the organisation does when safety nets start firing routinely across a fleet of teams.

## Why termination is the interesting half Starting a multi-agent conversation is easy; stopping it is the engineering problem. Agents keep producing text as long as they are asked to, so an AutoGen team without an explicit stop rule is an unbounded loop with a credit card attached. That is why `termination_condition` is a first-class constructor argument on every team type in `autogen_agentchat.teams`. ## The evaluation model A termination condition is an object with a call interface that the group-chat manager invokes as messages are produced during a run. If it returns a stop signal, the manager schedules no further turns; the run unwinds and `await team.run(task=...)` returns a `TaskResult` with two fields you care about — `messages` (the full thread produced by this run) and `stop_reason` (a string describing which condition fired). Checks happen at message boundaries, not inside an agent's turn: an agent that makes five tool calls and a long completion inside one turn will finish that turn before any condition can cut it off. This matters for cost — a token cap is a coarse fuse, not a hard limiter. Separately, teams accept `max_turns`. That is not a condition object; it is a plain cap on how many agent turns a single run may take, and it applies whether or not you passed a condition. Treat the two as belonging to different layers: conditions express *policy*, `max_turns` is the last-resort fuse. ## The built-ins In `autogen_agentchat.conditions` (0.7.x) the ones worth knowing by name: - `MaxMessageTermination(max_messages)` — stops after a message count. - `TextMentionTermination(text)` — stops when a message contains the given text. - `TokenUsageTermination(max_total_token=..., max_prompt_token=..., max_completion_token=...)` — stops when reported usage crosses a budget; it depends on the model client actually reporting usage. - `TimeoutTermination(timeout_seconds)` — wall-clock bound. - `HandoffTermination(target=...)` — stops when a handoff to a given target (commonly `"user"`) is emitted. - `ExternalTermination()` — exposes `set()` so code outside the run can request a stop. - `SourceMatchTermination(sources=[...])` — stops after a specific agent has spoken. ## Composition with | and & Conditions overload the boolean operators. `cond_a | cond_b` produces an OR condition that stops the run as soon as *either* part fires. `cond_a & cond_b` produces an AND condition that stops only when *all* parts have fired at some point during the run — the AND remembers which parts have already been satisfied, so the parts need not fire on the same message. Chaining is allowed: `TextMentionTermination("DONE") | MaxMessageTermination(20) | TimeoutTermination(120)`. The production idiom is OR: one semantic condition that represents genuine success, plus one or more caps that represent failure to succeed. AND is much rarer and is easy to get wrong — an AND that includes a condition which never fires makes the whole thing never fire. ## Statefulness Conditions carry state — a message counter, an accumulated token total, the set of AND parts already satisfied. The team resets its condition at the start of a run, so consecutive `run()` calls on the same team each get a fresh budget rather than inheriting the previous run's counters. If you hold a condition object yourself and hand it to a second team or reuse it out of band, call its `reset()` before reuse, or it will fire immediately. ## The classic traps `TextMentionTermination` inspects messages generally, so a task string that itself contains the magic word terminates the run before any agent speaks. Pick a token that will not appear in user input, and make the completion signal explicit in the agent's system message rather than hoping the model volunteers it. A `TokenUsageTermination` against a model client that does not report usage never fires — silently. Always OR it with a message or turn cap. Finally, read `stop_reason` in production. A run that succeeded and a run that was guillotined by the cap both return a `TaskResult`; only `stop_reason` distinguishes them, and treating both as success is how teams ship half-finished output.

  • Why is a semantic condition alone, like TextMentionTermination, unsafe in production?
    It fires only if the model emits exactly that text. Any prompt drift, a model that paraphrases, or a conversation that stalls means it never fires and the run continues indefinitely. OR it with `MaxMessageTermination` or `TimeoutTermination` so the failure mode is a bounded, observable cut-off rather than an unbounded loop, and alert when the safety net is what actually fired.
  • Can a termination condition cut off an agent in the middle of its turn?
    No. Conditions are evaluated at message boundaries, so an agent's turn — including its tool calls and its final completion — runs to the end before the next check. That is why a token budget can be overshot within a single expensive turn, and why hard cost control also needs limits at the model-client or gateway layer, not just at the team layer.
  • What does & actually require, and why is it easy to misuse?
    An AND condition fires only after every part has been satisfied at some point in the run; it remembers parts already satisfied rather than requiring simultaneity. It is easy to misuse because one never-firing part disables the whole thing — an AND containing a text match the model never emits means the team has, effectively, no termination condition at all.
  • How do you stop a running team from outside the run?
    Compose an `ExternalTermination()` into the condition and call its `set()` from your supervising code; the run stops at the next check. For an immediate abort, pass a `CancellationToken` to `run()`/`run_stream()` and cancel it, which cancels the in-flight work rather than waiting for a clean message boundary.

saying these in an interview costs you the question

  • Thinks the team detects task completion on its own
  • Believes | requires both conditions to fire
  • Assumes a token cap stops an agent mid-turn
  • Ignores stop_reason and treats every TaskResult as success
  • Uses a common word like DONE that appears in the user's task

context