ExecutionConfig

Configure agent execution limits including iterations, rate limits, and timeouts

Next

Control agent execution behavior with limits on iterations, rate limiting, timeouts, and retries.

Diagram

Execution Limits

OK

Limit

⚡ Start

Check Limits

🔄 Execute

🛑 Stop

Quick Start

  1. Using Presets

    Use string presets for common configurations:

    python
    from praisonaiagents import Agent
    
    # Fast execution (fewer iterations)
    agent = Agent(
        name="Fast Agent",
        instructions="Quick tasks",
        execution="fast"
    )
    
    # Thorough execution (more iterations)
    agent = Agent(
        name="Thorough Agent",
        instructions="Complex analysis",
        execution="thorough"
    )
  2. With Configuration

    Fine-grained control:

    python
    from praisonaiagents import Agent
    from praisonaiagents.config import ExecutionConfig
    
    agent = Agent(
        name="Custom Agent",
        instructions="Custom execution limits",
        execution=ExecutionConfig(
            max_iter=50,
            max_rpm=100,
            max_execution_time=300,
            max_retry_limit=5,
            max_tool_calls_per_turn=10
        )
    )

Configuration Options

python
from praisonaiagents.config import ExecutionConfig

config = ExecutionConfig(
    # Iteration limits
    max_iter=20,

    # Rate limiting: positive int auto-builds a live RateLimiter
    max_rpm=None,

    # Time limits (seconds)
    max_execution_time=None,

    # Retry settings
    max_retry_limit=2,

    # Tool call limits (loop protection)
    max_tool_calls_per_turn=10
)
ParameterTypeDefaultDescription
max_iterint20Maximum tool-calling iterations. Now propagated to the LLM instance, so it controls every internal loop (previously some loops were hardcoded to 5/10/20/50). Both the ExecutionConfig default and the LLM-direct-construction default are 20 (aligned as of PR #1898). When the loop reaches this cap, the agent performs one bounded LLM call with tools disabled to synthesise a wrap-up summary instead of returning the old "Task completed." placeholder (as of PR #2577).
max_rpm`int \None`NoneMax requests per minute. When set to a positive int with no explicit rate_limiter, the Agent auto-builds RateLimiter(requests_per_minute=max_rpm). Explicit rate_limiter takes precedence. max_rpm <= 0 raises ValueError at construction (validated before precedence, so max_rpm=0 still raises even with a rate_limiter). See Rate Limiter.
max_execution_time`int \None`NoneMax execution time in seconds
max_retry_limitint2Max retries for retryable tool failures and guardrail validation failures. Total attempts = 1 + max_retry_limit. For tools, this feeds the same effective RetryPolicy as ToolConfig(retry_policy=...); an explicit retry_policy takes precedence. Retries use exponential backoff with jitter (see retry_initial_delay, retry_backoff_factor, retry_jitter).
retry_initial_delayfloat1.0First retry delay in seconds. Subsequent delays grow exponentially. Must be > 0.
retry_backoff_factorfloat2.0Multiplier applied each attempt (base = initial × factor^(attempt−1)). Must be >= 1.0.
retry_jitterfloat0.1Random jitter added as a fraction of the base delay. Must be >= 0.
max_tool_calls_per_turnint10Maximum tool calls allowed in a single chat turn. When exceeded, execution stops with a clear message instead of looping forever.
context_compaction`bool \ContextCompactionPolicy`FalseProactive context-overflow protection. True uses the BALANCED_POLICY preset. Pass a ContextCompactionPolicy instance for custom routing. Default flips to True in the next release — a DeprecationWarning is emitted today when left at False. See Context Compaction Policy.
compaction_strategy`CompactionStrategy \None`NoneWhich strategy the compactor uses when context_compaction is on. None defaults to CompactionStrategy.TRUNCATE. Set to CompactionStrategy.LLM_SUMMARIZE for summary-based compaction. Import: from praisonaiagents import CompactionStrategy.
max_context_tokens`int \None`None (auto-detect from model window)Trigger for the in-run compaction hook. When unset, derived from the active model’s context window via budgeter.get_model_limit at 80% minus get_output_reserve (headroom for completion); an explicit int wins unchanged. Falls back to a static 8000 only for offline / unknown-model cases. See Context Compaction → Auto-sized trigger.
max_budget`float \None`NoneHard USD cap per agent run. None = no limit.
on_budget_exceeded`str \callable`"stop"Action when limit is hit after an LLM call returns. "stop" raises BudgetExceededError. "warn" logs a warning and continues. callable(total_cost, max_budget) is invoked; return value is ignored.

Execution Presets

Presetmax_iterDescription
"fast"10Quick tasks, fewer iterations
"balanced"20Default, balanced approach
"thorough"50Complex tasks, more iterations
"unlimited"1000Long-running tasks

Iteration Propagation

ExecutionConfig.max_iter is now the single source of truth for iteration limits, replacing previously hardcoded internal caps.

Diagram

Unified Iteration Control

📋 ExecutionConfig.max_iter

🤖 Agent

⚙️ LLM

🔄 All Internal Tool Loops

Before: Internal LLM loops were hardcoded to different limits (5, 10, 20, 50)

After: All loops respect the configured max_iter value

python
from praisonaiagents import Agent
from praisonaiagents.config import ExecutionConfig

# This now controls ALL iteration loops, not just agent-level loops
agent = Agent(
    name="Unified Control",
    instructions="Respect iteration limits everywhere",
    execution=ExecutionConfig(max_iter=15)
)
# The agent's LLM will respect 15 iterations in all internal loops

When the limit is reached

When the tool-calling loop reaches max_iter, the agent performs one final LLM call with tool_choice="none" and every advertised tool stripped, asking the model to summarise what it accomplished, what remains unfinished, and any suggested next steps using the tool results already in context. That synthesised text becomes the final answer.

The extra call is bounded to exactly one non-tool completion and is routed through the same retry / failover wrappers as every other completion, so a transient rate-limit error doesn’t drop straight to a placeholder. If the call still fails, the agent falls back to the last-turn text, then to "Reached the step limit before finishing this task." — behaviour never regresses.

There is no opt-out. To avoid truncation, increase max_iter so the agent can finish normally.


Tool Retry & Exponential Backoff

Tool and guardrail retries use exponential backoff with jitter so transient failures recover without hammering APIs.

Diagram
ToolAgentToolAgentwait delay₁ (~1.0s)wait delay₂ (~2.0s)CallRetryable failureRetryRetryable failureRetrySuccess

Delay formula: delay = min(initial_delay × factor^(attempt−1), 60s) + random(0, jitter × base).

With defaults (retry_initial_delay=1.0, retry_backoff_factor=2.0), three retries wait roughly 1.0s, 2.0s, 4.0s (plus up to 10% jitter).

For tools, max_retry_limit / retry_* are translated into the same effective RetryPolicy as ToolConfig(retry_policy=...). An explicit retry_policy (or per-tool @tool(retry_policy=...)) wins over these fields. Users who never set retry_policy= see no behaviour change. The guardrail-retry backoff continues to use these fields regardless.

See Tool Retry & Backoff for retry classification and patterns.


Proactive Context Compaction

Diagram

Context Protection Flow

📋 ExecutionConfig

🛡️ Policy

📊 Routes

🤖 LLM Call

Context compaction proactively prevents overflow before LLM calls instead of reacting after errors.

python
from praisonaiagents import Agent, ExecutionConfig, BALANCED_POLICY

agent = Agent(
    name="Researcher",
    execution=ExecutionConfig(
        max_iter=30,
        context_compaction=BALANCED_POLICY,  # explicit preset
    ),
)

See Context Compaction Policy for detailed configuration options.


Persistence

Save an ExecutionConfig to a dict for YAML/JSON storage and restore it later — every field round-trips.

python
from praisonaiagents import Agent, ExecutionConfig, CompactionStrategy

config = ExecutionConfig(
    max_iter=30,
    retry_initial_delay=3.0,
    retry_backoff_factor=4.0,
    retry_jitter=0.25,
    context_compaction=True,
    compaction_strategy=CompactionStrategy.LLM_SUMMARIZE,
)

# Save
saved = config.to_dict()

# Restore
restored = ExecutionConfig.from_dict(saved)

agent = Agent(name="Persisted Agent", instructions="...", execution=restored)

Common Patterns

Pattern 1: Rate-Limited Agent

python
from praisonaiagents import Agent
from praisonaiagents.config import ExecutionConfig

agent = Agent(
    name="Rate Limited Agent",
    instructions="Respect API limits",
    execution=ExecutionConfig(
        max_rpm=60,  # auto-builds a live RateLimiter(requests_per_minute=60)
        max_retry_limit=3
    )
)

Pattern 2: Time-Bounded Agent

python
from praisonaiagents import Agent
from praisonaiagents.config import ExecutionConfig

agent = Agent(
    name="Timed Agent",
    instructions="Complete within time limit",
    execution=ExecutionConfig(
        max_execution_time=60,  # 60 seconds max
        max_iter=100
    )
)

Pattern 3: Resilient Agent

python
from praisonaiagents import Agent
from praisonaiagents.config import ExecutionConfig

agent = Agent(
    name="Resilient Agent",
    instructions="Handle failures gracefully",
    execution=ExecutionConfig(
        max_retry_limit=5,
        retry_initial_delay=0.5,
        retry_backoff_factor=2.0,
        retry_jitter=0.2,
    )
)

Pattern 4: Loop-Protected Agent

python
from praisonaiagents import Agent
from praisonaiagents.config import ExecutionConfig

agent = Agent(
    name="Protected Agent",
    instructions="Agent with experimental tools",
    execution=ExecutionConfig(
        max_tool_calls_per_turn=5,  # Lower limit for potentially noisy tools
        max_iter=20
    )
)

Best Practices

Set Iteration Limits

Always set max_iter to prevent runaway agents consuming resources.

Use Rate Limiting for APIs

Set max_rpm when calling external APIs to avoid rate limit errors. Setting max_rpm now enforces the limit — the Agent auto-builds a live RateLimiter, so no separate rate_limiter object is required for simple RPM throttling.

Set Timeouts for Production

Use max_execution_time in production to prevent hung processes.

Configure Loop Protection

Adjust max_tool_calls_per_turn based on your tools: lower for experimental tools (3-5), higher for complex multi-tool workflows (20-30).


Related