Skip to content

* Cutting of agentic loop based on max_iterations configured.#2307

Open
printSamarth wants to merge 1 commit into
strands-agents:mainfrom
printSamarth:feat/max-iterations
Open

* Cutting of agentic loop based on max_iterations configured.#2307
printSamarth wants to merge 1 commit into
strands-agents:mainfrom
printSamarth:feat/max-iterations

Conversation

@printSamarth
Copy link
Copy Markdown

Description

Adds a max_iterations configuration to Agent that bounds the number of "model turn → tool call → tool result" cycles per invocation, with a dedicated MaxIterationsReachedException raised when the limit is exceeded.

Motivation. Today the event loop runs until the LLM decides to stop. In production this exposes two risks:

Infinite reasoning loops — a tool error or confusing prompt can send the model into a hallucination loop, calling tools repeatedly without ever reaching end_turn.
Unpredictable latency / cost — without an explicit depth limit, a single user request can trigger many model turns and burn unbounded tokens.

API:

agent = Agent(tools=[my_tool], max_iterations=5)
try:
    response = agent("Perform a complex multi-step task")
except MaxIterationsReachedException as e:
    log.warning("agent stopped", iterations=e.iterations, limit=e.max_iterations)

max_iterations is None by default (preserves existing behavior). Positive integers only; 0, negatives, non-ints, and booleans are rejected at construction time.

Implementation.

New MaxIterationsReachedException in strands.types.exceptions carrying iterations and max_iterations for structured logging.
New max_iterations constructor kwarg on Agent, validated to be a positive int or None.
The event loop tracks invocation_state["event_loop_iteration"] and the guard is enforced at the top of event_loop_cycle, before the next model call — so an over-limit cycle never consumes an additional model invocation. The exception is added to the bubble-up list so it isn't wrapped in EventLoopException.
Iteration semantics. One iteration = one model turn (not one tool call). Parallel tool use counts as a single iteration. This matches what the cap is intended to bound (reasoning depth / API calls), and avoids penalizing models that parallelize independent tool calls.

Related Issues

Resolves 2298

Documentation PR

N/A : happy to follow up with a docs PR once this merges.

Type of Change

New feature

Testing

Added the following coverage:

tests/strands/types/test_exceptions.py : construction, inheritance, and metadata propagation for MaxIterationsReachedException.
tests/strands/agent/test_agent.py : constructor validation (default None, positive int, rejection of 0 / -1 / 1.5 / "5" / True), plus end-to-end tests through the public API using MockedModelProvider:
runaway tool loop is bounded and raises with correct metadata
normal completion succeeds when within the budget
iteration counter resets between separate invocations
tests/strands/event_loop/test_event_loop.py : limit exceeded raises before the next model call (model.stream.call_count asserted), within-limit completes normally, None disables the check, and a pre-set counter trips the guard on the very first cycle.
A small number of existing tests that pinned the exact shape of invocation_state keys passed to callbacks were updated to include the new event_loop_iteration key consistent with how event_loop_cycle_id is already exposed.

Apart from this manualy tested by integrating it into a local project to verify end-to-end behavior.

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Add max_iterations control to the Agent execution loop

1 participant