All tutorials
Track 19·State & Control

max_total_primitive_calls and allow_break_continue

The two remaining DesignExecuteConfig knobs: a whole-plan call cap and a toggle for break/continue in loops.

intermediate8 min
Video coming soon
Browse this tutorial's folder in tutorials-pygithub.com/OpenSymbolicAI/tutorials-py/tree/main/19-design-execute-limits

Track 18 covered max_loop_iterations. DesignExecuteConfig has two more knobs: max_total_primitive_calls and allow_break_continue.

The agent#

A shopping cart with three primitives:

python
# cart.py
from opensymbolicai.blueprints import DesignExecute
from opensymbolicai.core import primitive

PRICES = {"apple": 0.99, "banana": 0.49, "book": 12.99,
          "notebook": 4.99, "pen": 1.49, "stapler": 8.99}

class Cart(DesignExecute):
    """A shopping cart agent."""

    @primitive(read_only=True)
    def item_total(self, name: str, qty: int) -> float:
        """Price for qty units of name."""
        return round(PRICES[name] * qty, 2)

    @primitive(read_only=True)
    def add(self, a: float, b: float) -> float:
        """Add two amounts."""
        return round(a + b, 2)

    @primitive(read_only=True)
    def format_total(self, total: float) -> str:
        """Format the grand total as a receipt line."""
        return f"Total: ${total:.2f}"

max_total_primitive_calls#

A cap on every primitive call in the plan, across all loops and branches. The default is 1000. The five-item loop plan makes 11 calls total (two per item, plus one format_total).

python
from opensymbolicai.models import DesignExecuteConfig

# Trips on the 4th call.
config = DesignExecuteConfig(max_total_primitive_calls=3)
agent = Cart(llm=llm, config=config)
result = agent.execute(LOOP_PLAN)
last = result.trace.steps[-1]
print(f"calls made before stop: {len(result.trace.steps)}")
print(f"error: {last.error}")

# All 11 calls fit.
config = DesignExecuteConfig(max_total_primitive_calls=15)
agent = Cart(llm=llm, config=config)
result = agent.execute(LOOP_PLAN)
print(f"calls made: {len(result.trace.steps)}")
print(f"result: {result.get_value()}")
text
calls made before stop: 4
error: Exceeded maximum total primitive calls (3). Plan may contain too many iterations.

calls made: 11
result: Total: $56.88

allow_break_continue#

Controls whether break and continue are legal in plans. The default is True. Set False to reject any plan that contains them at validation time, before a single primitive runs.

python
BREAK_PLAN = """\
total = 0.0
items = [('stapler', 1), ('pen', 2), ('notebook', 3)]
for name, qty in items:
    line = item_total(name, qty)
    total = add(total, line)
    if total > 10:
        break
return format_total(total)
"""

# True (default): break is allowed; loop stops early once total > $10.
config = DesignExecuteConfig(allow_break_continue=True)
agent = Cart(llm=llm, config=config)
result = agent.execute(BREAK_PLAN)
print(f"calls made: {len(result.trace.steps)}")
print(f"result: {result.get_value()}")

# False: validate_plan rejects the plan before any primitive runs.
config = DesignExecuteConfig(allow_break_continue=False)
agent = Cart(llm=llm, config=config)
try:
    agent.validate_plan(BREAK_PLAN)
except ValueError as e:
    print(f"allow_break_continue=False: {e}")
text
calls made: 5
result: Total: $11.97

allow_break_continue=False: Break statements are not allowed in plans