Skip to content

Bounded Execution: Preventing Runaway Agents

Overview

Resources are finite. Unbounded execution leads to runaway agents, high costs, and system crashes.


Resource Bounds

class BoundedAgent:
    def __init__(self):
        self.limits = {
            'max_iterations': 10,      # Max reasoning steps
            'max_tool_calls': 50,      # Max tools invoked
            'timeout_sec': 60,         # Max execution time
            'max_tokens': 10000,       # Max output tokens
            'max_cost': 1.0            # Max cost in dollars
        }

    def execute(self, task):
        self.iterations = 0
        self.tool_calls = 0
        self.start_time = time.time()
        self.cost = 0

        while True:
            if self.iterations >= self.limits['max_iterations']:
                return {"error": "Max iterations exceeded"}

            if self.tool_calls >= self.limits['max_tool_calls']:
                return {"error": "Max tool calls exceeded"}

            elapsed = time.time() - self.start_time
            if elapsed > self.limits['timeout_sec']:
                return {"error": "Timeout exceeded"}

            if self.cost > self.limits['max_cost']:
                return {"error": "Cost limit exceeded"}

            # Execute one step
            self.iterations += 1
            result = self.step(task)

            if result.is_terminal():
                return result

Timeout Patterns

import signal

class TimeoutHandler:
    def call_with_timeout(self, func, timeout_sec):
        def timeout_handler(signum, frame):
            raise TimeoutError()

        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(timeout_sec)

        try:
            result = func()
            signal.alarm(0)  # Cancel alarm
            return result
        except TimeoutError:
            return {"error": "Operation timed out"}

Cost Control

class CostAwareLLMCaller:
    def __init__(self, max_cost_usd=1.0):
        self.max_cost = max_cost_usd
        self.current_cost = 0

    def call(self, prompt: str) -> str:
        # Estimate cost before calling
        estimated_cost = self.estimate_cost(prompt)

        if self.current_cost + estimated_cost > self.max_cost:
            return {"error": "Cost limit exceeded"}

        # Call LLM
        response = self.llm.generate(prompt)

        # Track actual cost
        actual_cost = self.get_actual_cost(response)
        self.current_cost += actual_cost

        return response

3 Warnings ⚠️

Warning 1: Too Tight Bounds

# ❌ WRONG
limits = {
    'max_iterations': 1,      # Too few!
    'timeout_sec': 5,         # Too short!
}
# Most tasks can't complete

# ✅ RIGHT
limits = {
    'max_iterations': 10,     # Reasonable
    'timeout_sec': 60,        # Realistic
}

Warning 2: Not Monitoring Bounds

# ❌ WRONG
set_limits()
# Hope they work

# ✅ RIGHT
set_limits()
monitor_bounds()  # Log when near limit
alert_on_boundary()  # Warn before hitting

Warning 3: Single Point Failure

# ❌ WRONG: Only timeout protection
if time.time() - start > 60:
    stop()

# But what if tool call hangs?
# Or infinite loop in reasoning?

# ✅ RIGHT: Multiple safeguards
timeout_handler()  # Global timeout
iteration_limit()  # Step-based timeout
tool_timeout()     # Per-tool timeout
resource_monitor() # CPU/memory watch

Last Updated: August 9, 2026