AutoGen’s termination conditions stop conversations by turn count. RunGuard stops them by loop pattern.

Microsoft AutoGen (both v0.2 and the newer v0.4/AgentChat API) is a multi-agent conversation framework. You compose ConversableAgent instances — or AssistantAgent and UserProxyAgent wrappers around them — and orchestrate them via GroupChat and GroupChatManager or the newer RoundRobinGroupChat / SelectorGroupChat teams. Each agent can have registered tools (functions the LLM can call via tool-use), and the conversation proceeds until a termination condition is met. AutoGen provides built-in termination: MaxMessageTermination(10) stops after 10 agent turns, StopMessageTermination() stops when any agent says a keyword, ExternalTermination() accepts a programmatic signal. These termination conditions are turn-level instruments: they count how many times the conversation has cycled, or they check string content, or they respond to an external signal. What they do not do is analyze the tool-call signature sequence within each agent’s turns and detect whether the sequence has entered a repeating cycle. An AutoGen assistant that calls web_search("latest AI safety regulations") on turn 3, then again on turn 5, then again on turn 7 — same tool, same arguments, same results — will reach the MaxMessageTermination ceiling after however many turns you configured, not after the third repeated search. The cost of the four redundant searches (turns 5, 7, 9, and 11 in a 12-turn budget) is paid in full before the termination condition fires. RunGuard’s LoopDetector fires at the third repeated search, before turn 7’s search goes out, and throws an exception that your error handler routes to a graceful fallback rather than letting the conversation continue to the turn limit.

AutoGen’s termination conditions: what they catch and what they miss

Where to add RunGuard in an AutoGen v0.4 stack

AutoGen v0.4 (the AgentChat API) uses ChatCompletionClient implementations (OpenAIChatCompletionClient, AnthropicChatCompletionClient) as the model-calling layer. The agents pass their message history to the client and receive a completion back. The cleanest place to add RunGuard is at the model client call, not at the agent level. You wrap the async function that calls model_client.create(messages) with guard_async(), provide usd (computed from the token counts in the response) and sig (the name of the first tool call in the response, or "end_turn") in the return value, and the guard’s LoopDetector and BudgetTracker run before each model call. Because the guard is at the model-client level, it sees the full tool-call sequence across all agents in a GroupChat — not just the tool calls of a single agent — provided you share the guard instance across all agents that use the same model client. A shared guard instance across agents is the correct setup for detecting cross-agent loops (agent A calls search_tool, delegates to agent B, agent B calls search_tool with the same arguments, delegates back to A, A calls it again — a loop that spans multiple agents and is invisible to a per-agent guard).

Implementation: AutoGen v0.4 with AssistantAgent

GroupChat: sharing the guard instance across agents

When multiple agents in a GroupChat or RoundRobinGroupChat use the same model, sharing a single guard instance ensures the loop detector sees the full cross-agent tool-call sequence. If each agent has its own independent guard instance, a loop that spans two agents — researcher calls search("AI safety"), passes to writer, writer calls search("AI safety"), passes back to researcher, researcher calls search("AI safety") — would not be detected because each agent’s guard only sees one repetition in its own history (below the repeats: 3 threshold). A shared guard instance in the monkey-patched model client call sees all three search("AI safety") calls and fires on the third one. The monkey-patching approach in the examples above automatically shares the guard because it patches the global OpenAI or Anthropic client — all agents that use the same global client share the same guarded function, and therefore the same guard instance. If you are using per-agent client instances, instantiate the guard once outside the agent definitions and pass the guarded function to each agent’s patched client.

AutoGen’s tool registration and where RunGuard fits

What this is not

RunGuard is not an AutoGen plugin or an AutoGen-specific integration. It wraps the model-client call layer, below AutoGen’s agent abstraction, which means it works with any AutoGen version (v0.2, v0.3, v0.4) and any model client (OpenAI, Anthropic, Azure OpenAI, Ollama) without requiring AutoGen to expose a custom circuit-breaker hook. RunGuard does not understand AutoGen’s agent protocols, team structures, or message routing — it only sees the model-client calls that flow through the patched function. This is intentional: the loop detection algorithm works on tool-call signatures, which are model-level signals, not agent-level signals. A future AutoGen version that changes its agent protocol will not affect RunGuard’s loop detection as long as the model-client call is still the innermost LLM-calling layer. RunGuard is also not a replacement for AutoGen’s termination conditions. Use MaxMessageTermination as the outer ceiling and RunGuard as the pattern-aware inner guard. The CrewAI loop detection page, LangChain circuit breaker page, and LangGraph infinite loop guard page cover the same RunGuard integration pattern for other multi-agent frameworks. RunGuard ships as @runguard/sdk on npm and runguard on PyPI. The full API is in llms.txt.