Skip to content

feat(agents): add termination conditions for multi-agent workflows#5213

Open
davidmonterocrespo24 wants to merge 2 commits intogoogle:mainfrom
davidmonterocrespo24:feat/termination-conditions
Open

feat(agents): add termination conditions for multi-agent workflows#5213
davidmonterocrespo24 wants to merge 2 commits intogoogle:mainfrom
davidmonterocrespo24:feat/termination-conditions

Conversation

@davidmonterocrespo24
Copy link
Copy Markdown

Add a new google.adk.termination module with pluggable termination conditions
that stop a LoopAgent or the Runner mid-run when a configured criterion is met.

New termination conditions:

  • MaxIterationsTermination: stops after N events
  • TextMentionTermination: stops when a keyword appears in event content
  • TimeoutTermination: stops after a wall-clock duration
  • TokenUsageTermination: stops when token budgets are exceeded
  • FunctionCallTermination: stops when a specific function is called
  • ExternalTermination: stops on external signal (asyncio-based)
  • Composite OrTerminationCondition and AndTerminationCondition (also exposed via | and & operators)

Integration points:

  • LoopAgent.termination_condition field: checked after each sub-agent event; emits a synthetic escalation event with termination_reason set
  • Runner.run_async(..., termination_condition=...) parameter: checked after every event yielded by the root agent

The termination_reason field is added to EventActions to carry the human-readable reason on synthetic termination events.

All conditions implement reset(), which is called automatically at the start of each run so the same instance can be reused across invocations.

Cross-repo: aligned with adk-js implementation in google/adk-js#193.


Link to Issue or Description of Change

Problem:
In multi-agent workflows, agents can fall into infinite or long-running loops
with no built-in signal to indicate task completion. There is no simple
mechanism for agents to signal "task completed," which leads to runaway
conversations, wasted tokens, and stalled workflows.

Solution:
Introduce a pluggable TerminationCondition abstraction (modeled after
AutoGen's termination system) that integrates into LoopAgent and
Runner.run_async(). Conditions are composable via | (OR) and & (AND),
reset automatically between runs, and emit a synthetic event with
actions.termination_reason when triggered.


Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

pytest results summary:

pytest tests/unittests/termination/                        → 39 passed
pytest test_loop_agent.py           →  9 passed (3 new)
pytest test_runner_termination.py  →  5 passed (new)
pytest tests/unittests/agents/ tests/unittests/runners/    → 500 passed, 0 regressions

New test files:

  • tests/unittests/termination/test_termination_conditions.py — covers all 7 condition types, OrTerminationCondition, AndTerminationCondition, reset() behavior, and operator overloads
  • tests/unittests/agents/test_loop_agent.py — 3 new tests for LoopAgent.termination_condition: stops loop, text keyword detection, resets between runs
  • tests/unittests/runners/test_runner_termination.py — 5 new tests for Runner.run_async(..., termination_condition=...): baseline without condition, stops run, text mention, keyword absent, resets between runs

Manual End-to-End (E2E) Tests:

Example usage verified locally:

from google.adk.agents import LoopAgent
from google.adk.termination import TextMentionTermination, MaxIterationsTermination

loop = LoopAgent(
    name="my_loop",
    sub_agents=[planner, executor],
    termination_condition=TextMentionTermination("TERMINATE") | MaxIterationsTermination(10),
)
# Via Runner
async for event in runner.run_async(
    user_id=..., session_id=..., new_message=...,
    termination_condition=TextMentionTermination("DONE"),
):
    print(event)

When the condition fires, the loop/runner emits a final event with:

  • event.actions.escalate = True
  • event.actions.termination_reason = "Text 'TERMINATE' mentioned"

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

@google-cla
Copy link
Copy Markdown

google-cla bot commented Apr 8, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Add a new google.adk.termination module with pluggable termination
conditions that stop a LoopAgent or the Runner mid-run when a configured
criterion is met.

New termination conditions:
- MaxIterationsTermination: stops after N events
- TextMentionTermination: stops when a keyword appears in event content
- TimeoutTermination: stops after a wall-clock duration
- TokenUsageTermination: stops when token budgets are exceeded
- FunctionCallTermination: stops when a specific function is called
- ExternalTermination: stops on external signal (asyncio-based)
- Composite OrTerminationCondition and AndTerminationCondition
  (also exposed via | and & operators)

Integration points:
- LoopAgent.termination_condition field: checked after each sub-agent
  event; emits a synthetic escalation event with 	ermination_reason set
- Runner.run_async(..., termination_condition=...) parameter: checked
  after every event yielded by the root agent

The 	ermination_reason field is added to EventActions to carry the
human-readable reason on synthetic termination events.

All conditions implement 
eset(), which is called automatically at the
start of each run so the same instance can be reused across invocations.

Cross-repo: aligned with adk-js implementation in google/adk-js#193.

Closes google#5211
@davidmonterocrespo24 davidmonterocrespo24 force-pushed the feat/termination-conditions branch from 29ceadc to 3037c2c Compare April 8, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add Explicit Termination Mechanism for Multi-Agent Workflows (Similar to AutoGen "TERMINATE")

1 participant