Autonomy
Enable agents to operate independently with doom-loop protection and safety controls
Autonomy lets agents operate independently — detecting doom loops, escalating when stuck, and optionally running in a full-auto iterative mode.
from praisonaiagents import Agent
# All four spellings enable the same 'full_auto' preset:
Agent(instructions="t", autonomy="full_auto")
Agent(instructions="t", autonomy="full-auto")
Agent(instructions="t", autonomy="FULL_AUTO")
Agent(instructions="t", autonomy=" full_auto ")
# Typo raises — no silent fallback to a disabled autonomy:
Agent(instructions="t", autonomy="fll_auto")
# ValueError: Unknown preset 'fll_auto' for parameter 'autonomy'.
# Did you mean 'full_auto'? Valid presets: auto_edit, full_auto, suggest| Call (Python) | Before PR #4186 | After PR #4186 |
|---|---|---|
Agent(autonomy="full_auto") | ✅ autonomy enabled | ✅ autonomy enabled |
Agent(autonomy="full-auto") | ⚠ validated → silently disabled | ✅ autonomy enabled |
Agent(autonomy=" full_auto ") | ⚠ validated → silently disabled | ✅ autonomy enabled |
Agent(autonomy="FULL_AUTO") | ⚠ validated → silently disabled | ✅ autonomy enabled |
Agent(autonomy="fll_auto") (typo) | ❌ ValueError with suggestion | ❌ ValueError with suggestion |
from praisonaiagents import Agent
agent = Agent(
name="Assistant",
instructions="You are an autonomous coding assistant.",
autonomy=True,
)
agent.start("Refactor the authentication module to use JWT tokens.")The user delegates a coding task; the agent works independently, detects doom loops, and escalates to a human when stuck.
Quick Start
- Level 1 — Bool (simplest)
Turn on autonomy with a single flag — defaults to the safe
suggestlevel.python from praisonaiagents import Agent agent = Agent( name="Coder", instructions="You are an autonomous task-completion agent.", autonomy=True, ) agent.start("Write and test a Python function to merge sorted arrays.") - Level 2 — String (pick a level)
Pass a level name to unlock more independence.
python from praisonaiagents import Agent agent = Agent( name="Coder", instructions="You are an autonomous coding agent.", autonomy="full_auto", ) agent.start("Build a REST API endpoint for user authentication.") - Level 3 — Config class (full control)
Use
AutonomyConfigto tune iteration caps, doom-loop detection, and escalation.python from praisonaiagents import Agent, AutonomyConfig agent = Agent( name="Coder", instructions="You are a precise autonomous agent.", autonomy=AutonomyConfig( level="auto_edit", max_iterations=30, doom_loop_threshold=5, auto_escalate=True, ), ) agent.start("Review and improve the test coverage for the payment module.")
Autonomy Levels
From YAML
When you set autonomy in agents.yaml, the wrapper accepts an integer 0-10 (validated by the Pydantic schema) and maps it onto the core preset before handing it to Agent(autonomy=…):
| YAML value | Core preset |
|---|---|
0 (or omitted) | off |
1 – 3 | suggest |
4 – 7 | auto_edit |
8 – 10 | full_auto |
framework: praisonai
roles:
refactor_bot:
role: "Refactor Bot"
goal: "Refactor code safely"
backstory: "Meticulous senior engineer"
autonomy: 5 # -> auto_edit preset
tasks:
refactor_module:
description: "Refactor auth.py to use JWT"
expected_output: "A cleaner auth.py"bool / str preset / dict / AutonomyConfig values in YAML are passed through unchanged, mirroring the Python API.
How It Works
| Phase | What happens |
|---|---|
| 1. Execute | Agent takes action toward the goal |
| 2. Safety check | Doom loop tracker monitors for repeated identical actions |
| 3. Escalate | If stuck, agent asks user for guidance instead of looping |
| 4. Complete | Iterative mode detects task completion signal |
Completion Signals
The loop can stop on several signals — ranked by how reliably they mean “really done”.
| Completion Signal | How It Works | Reliability |
|---|---|---|
Goal judge (run_goal) | Independent judge evaluates acceptance criteria after each iteration | ⭐⭐⭐⭐ Most reliable — explicit contract |
| Tool completion | Model stops calling tools after a substantive response | ⭐⭐⭐ Good for tool-driven tasks |
| Completion promise | Model emits the configured completion_promise signal text | ⭐⭐ Depends on the model following instructions |
| Keyword heuristic | Words like “done”/”finished” or 2 no-tool turns | ⭐ Prone to false positives |
Configuration Options
CardFull list of options, types, and defaults — AutonomyConfig
The most common options at a glance:
| Option | Type | Default | Description | |
|---|---|---|---|---|
level | str | "suggest" | "suggest", "auto_edit", or "full_auto" | |
max_iterations | int | 20 | Max iterations before stopping | |
doom_loop_threshold | int | 3 | Repeated actions before doom loop detection | |
auto_escalate | bool | True | Automatically escalate when stuck | |
completion_promise | `str \ | None` | None | Signal text that marks task completion |
max_budget_usd | `float \ | None` | None | Cumulative USD spend cap for the run. None = unlimited |
max_tokens | `int \ | None` | None | Cumulative token cap (input + output). None = unlimited |
budget_action | str | "pause" | "pause" (recoverable) or "stop" (terminal) when a cap is hit | |
snapshot | bool | False | Take a pre-run workspace snapshot in run_autonomous() so agent.undo() can restore it. Requires track_changes. Off by default because snapshotting walks the whole project. Needed for agent.undo() — see File Snapshot |
Common Patterns
Pattern 1 — Auto-edit mode for coding tasks
from praisonaiagents import Agent, AutonomyConfig
agent = Agent(
instructions="You are a senior software engineer.",
autonomy=AutonomyConfig(
level="auto_edit",
max_iterations=15,
doom_loop_threshold=3,
),
)
response = agent.start("Add input validation to all API endpoints in the users module.")
print(response)Pattern 2 — Full-auto iterative mode
from praisonaiagents import Agent, AutonomyConfig
agent = Agent(
instructions="You are an autonomous DevOps agent.",
autonomy=AutonomyConfig(
level="full_auto",
completion_promise="DEPLOYMENT_COMPLETE",
max_iterations=50,
),
)
agent.start("Deploy the application to staging and run smoke tests.")Pattern 3 — Budget-bounded autonomous runs
Cap an unattended run by money or tokens so it can’t burn dollars silently.
from praisonaiagents import Agent, AutonomyConfig
agent = Agent(
instructions="You are an autonomous research agent.",
autonomy=AutonomyConfig(
level="full_auto",
max_iterations=50,
max_budget_usd=2.00, # stop if this run crosses $2
max_tokens=500_000, # or 500k tokens, whichever trips first
budget_action="pause", # keep the partial result so we can resume
),
)
result = agent.run_autonomous("Research and summarise recent LLM safety papers.")
if result.completion_reason == "budget_exhausted":
print(f"Paused at ${result.metadata['spend_usd']:.2f}")
print("Partial output:", result.output)Caps are measured from a loop-start baseline, so reusing the same agent across runs never carries prior spend into a new run’s cap.
Choosing a Cap
Pick the cap that matches what you care about most for the run.
Handling budget_exhausted
When a cap trips, the run stops with completion_reason="budget_exhausted" and a metadata payload describing the spend.
The metadata dict carries the actual spend, the configured caps, and the status:
result = agent.run_autonomous("...")
if result.completion_reason == "budget_exhausted":
print("Status:", result.metadata["status"]) # "paused" or "stopped"
print("Spent USD:", result.metadata["spend_usd"])
print("Spent tokens:", result.metadata["tokens"])
print("Partial output so far:", result.output)
# Pause is recoverable — raise the cap and re-run:
agent.autonomy_config["max_budget_usd"] = 5.0
result = agent.run_autonomous("...")| Key | Type | Description | |
|---|---|---|---|
spend_usd | float | Actual USD spent this run (baseline-adjusted) | |
tokens | int | Actual tokens spent this run | |
max_budget_usd | `float \ | None` | The configured USD cap |
max_tokens | `int \ | None` | The configured token cap |
status | str | "paused" (recoverable) or "stopped" (terminal) |
Best Practices
Start with suggest level
Start with autonomy=True (level suggest) to see what the agent proposes before giving it permission to edit files or run in a full loop. Graduate to auto_edit or full_auto when you trust the agent’s behavior.
Set doom_loop_threshold conservatively
The default threshold of 3 means 3 identical actions trigger escalation. Lower this to 2 for high-stakes tasks, or raise it to 5 for tasks where retrying the same action is expected behavior (like polling).
Use completion_promise for iterative mode
In full_auto mode, the agent loops until it detects completion. Set completion_promise="TASK_COMPLETE" and instruct the agent to output this signal when done, giving you clean loop termination.
Cap unattended runs with max_budget_usd
For full_auto mode running unattended (nightly jobs, background workers), set max_budget_usd as a hard ceiling. Combine with budget_action="pause" so a hit cap preserves the partial output and lets you raise the cap and resume rather than restart from zero.
Pick pause vs stop deliberately
budget_action="pause" returns a recoverable result — the partial output is preserved and metadata["status"] is "paused". budget_action="stop" marks it terminal (status="stopped"). Pick pause when a human might raise the cap and continue; pick stop when the run should be killed unconditionally.
Don't rely on AutonomyConfig.sandbox for isolation
AutonomyConfig.sandbox is a forward-compat placeholder — no autonomy level auto-enables sandboxing and nothing reads the field. Use Agent(sandbox=…) to enable the explicit agent.execute_code() API, or AgentFlow(run_on="docker") to isolate a whole workflow in a real container. See Placement.