Autonomy vs Interactive
Understand how autonomy and interactive modes differ, their tool systems, and the recommended architecture
PraisonAI provides two primary execution approaches: Autonomy (agent-driven results) and Interactive (human-driven sessions). Understanding the distinction between Iterative (autonomous loop) and Interactive (manual loop) is key to building complex workflows.
At a Glance: Iterative vs. Interactive
While the names sound similar, they represent the two sides of “who drives the loop”:
| Term | Driver | Paradigm | Best For |
|---|---|---|---|
| Interactive | π€ Human | Chat / TUI | Exploratory work, manual guidance |
| Iterative | π§ Agent | Autonomy (mode=”iterative”) | Self-correction, multi-step automation |
| Caller | β | Single-turn response | Quick actions, direct pipelines |
Execution Mode
AutonomyConfig has a mode field that controls execution behavior:
| Level | Default Mode | Behavior |
|---|---|---|
"suggest" (default) | "caller" | Single chat() β AutonomyResult |
"auto_edit" | "caller" | Single chat() + auto-approve edits |
"full_auto" | "iterative" | run_autonomous() loop with completion detection |
Execution Flow Comparison
Caller Mode (default for autonomy=True)
Iterative Mode (default for full_auto)
When mode="iterative", the agent runs a multi-turn loop with safety infrastructure:
Interactive Mode Flow
In interactive mode, the human drives the loop β each message is a single-turn chat() call:
Feature Comparison
| Dimension | Caller Mode (autonomy=True) | Iterative Mode (full_auto) | Interactive (no autonomy) |
|---|---|---|---|
| Primary Driver | Application Code | π§ Agent (Internal Loop) | π€ Human (External Loop) |
| Turns | 1 (single chat()) | Up to max_iterations | Single turn per interaction |
| Complexity Mgt | Simple pipelines | Automated self-correction | Manual refinement |
| Return type | AutonomyResult | AutonomyResult | str |
| Self-correction | β | β Doom loop + recovery | β (Human corrects) |
| Session persistence | Manual | Auto-saves each iteration | Manual |
| Observability | Standard | Built-in event emission | Standard |
Speed Profile
Init Overhead (one-time)
| Component | Cost | Notes |
|---|---|---|
AutonomyConfig() | ~0ms | Simple dataclass |
AutonomyTrigger() | ~1-2ms | Lazy imports EscalationTrigger |
DoomLoopTracker() | ~1ms | Lazy imports DoomLoopDetector |
FileSnapshot | ~50-200ms | Only if track_changes=True |
ObservabilityHooks | ~1ms | Only if observe=True |
Per-Iteration Overhead
| Operation | Cost |
|---|---|
| Timeout check | ~0ΞΌs |
| Doom-loop check | ~0.1ms |
| Action recording | ~0.1ms |
| Completion detection | ~0.1ms |
| Session auto-save | 0-5ms |
| Total | ~0.5ms |
Per-iteration overhead is ~0.5ms β negligible compared to LLM API calls (typically 1-30 seconds each). The real speed difference is the number of LLM calls, not framework overhead.
End-to-End Comparison
| Metric | Non-Autonomy | Autonomy |
|---|---|---|
| Minimum LLM calls | 1 | 1 (if completion detected on first turn) |
| Maximum LLM calls | 1 | 20 (default max_iterations) |
| Typical for multi-step task | 1 (all tools in one turn) | 1-3 (re-injects if not “done”) |
| Overhead per call | 0 | ~0.5ms |
Important Behavioral Differences
Two-Layer Tool Architecture
Tools are provisioned at two independent layers. The CLI wrapper assembles tool lists and passes them as tools=[...] to the SDK’s Agent() constructor:
What each layer provides
13 tools via get_interactive_tools(): – ACP (4): create/edit/delete files, execute commands (disabled by default in autonomy) – LSP (4): symbols, definitions, references, diagnostics – Basic (5): read/write files, list, execute, search
Used by: praisonai tui, praisonai "prompt"
16 tools when autonomy=True via AUTONOMY_PROFILE: – file_ops (7): read/write/list/copy/move/delete/info – shell (3): execute_command, list_processes, get_system_info – web (3): internet_search, search_web, web_crawl – code_intelligence (3): ast_grep search/rewrite/scan
Used by: Agent(autonomy=True) in Python
Built-in ToolProfiles
The SDK ships with composable profiles in tools/profiles.py:
| Profile | Tools | Description |
|---|---|---|
code_intelligence | 3 | ast-grep search, rewrite, scan |
file_ops | 7 | read, write, list, copy, move, delete, get_file_info |
shell | 3 | execute_command, list_processes, get_system_info |
web | 3 | internet_search, search_web, web_crawl |
code_exec | 4 | execute_code, analyze_code, format_code, lint_code |
schedule | 3 | schedule_add, schedule_list, schedule_remove |
autonomy | 16 | Composite: file_ops + shell + web + code_intelligence |
Tools by entry point
| Entry Point | Tools Available | Source |
|---|---|---|
praisonai tui | 13 (ACP + LSP + Basic) | CLI wrapper |
praisonai "prompt" | 13 + autonomy (16) | CLI wrapper + SDK |
praisonai tracker run | 30 (expanded set) | tracker.py |
Agent(autonomy=True) in Python | 16 (AUTONOMY_PROFILE) | Core SDK |
Agent() in Python | 0 (user-provided only) | β |
Design Principles
The current architecture follows a layered separation pattern:
- Core SDK stays minimal
The
praisonaiagentspackage provides the agent runtime, tool execution, and LLM integration β but does not bundle default tools. This keeps the SDK lightweight and avoids opinionated defaults. - CLI wrapper adds batteries
The
praisonaiwrapper package adds ACP, LSP, file operations, and search tools for CLI users. It assembles toolsets and passes them astools=[...]to the Agent constructor. - Tools are data, not hardcoded
Interactive tools are defined as groups in
interactive_tools.pywith aTOOL_GROUPSdictionary. New tools are added to a group, and all consumers automatically get them.
Why this is the best approach
SDK independence
The Core SDK has zero dependency on the CLI wrapper. Users embedding praisonaiagents in their own applications bring exactly the tools they need β no surprise defaults, no bloat.
Composable toolsets
Each entry point assembles its own toolset. praisonai tui loads ACP + LSP + Basic. praisonai tracker run loads a broader set. SDK users pass their own tools. This is intentional β different contexts need different capabilities.
Single source of truth
interactive_tools.py with get_interactive_tools() is the canonical provider. Both tui/app.py and main.py call this single function. Adding a new interactive tool means editing one file.
When to Use Each Mode
| Mode | Best For | Example Prompt | What Happens |
|---|---|---|---|
| No autonomy | Questions, explanations, advice | “Explain authentication patterns” | Agent answers from knowledge β doesn’t touch files or run tools |
| Caller (default) | Single-shot automation, pipelines | “Search for X and save results to file” | Agent uses tools in one turn, returns AutonomyResult with metadata |
| Iterative | Multi-step self-correction, buildβtestβfix | “Refactor auth module and verify tests pass” | Agent loops until task is complete, with doom loop protection |
Fastest β agent explains but doesn’t act.
agent = Agent(
instructions="Help with coding"
)
agent.start("Explain this function")One turn β agent acts immediately with tools.
agent = Agent(
instructions="You are a research assistant",
autonomy=True
)
result = agent.start("Search and save to file")
print(result.success)Multi-turn β agent self-corrects until done.
agent = Agent(
instructions="Build and test features",
autonomy={"mode": "iterative"}
)
result = agent.start("Refactor the auth module")
print(result.iterations)Extending Tools
Using ToolProfiles (recommended)
Combine built-in profiles or register custom ones:
from praisonaiagents.tools.profiles import (
resolve_profiles, register_profile, ToolProfile
)
# Combine built-in profiles
tools = resolve_profiles("file_ops", "web", "shell")
agent = Agent(tools=tools)
# Register a custom profile (e.g., from CLI wrapper)
register_profile(ToolProfile(
name="acp",
tools=["acp_create_file", "acp_edit_file",
"acp_delete_file", "acp_execute_command"],
description="Agentic Change Plan tools",
))
# Now use it alongside built-in profiles
tools = resolve_profiles("autonomy", "acp", "lsp")Adding tools for CLI users
Add tools to interactive_tools.py:
# In praisonai/cli/features/interactive_tools.py
TOOL_GROUPS = {
"basic": [read_file, write_file, ...],
"acp": [acp_create_file, ...],
"lsp": [lsp_list_symbols, ...],
"my_group": [my_custom_tool], # Add new group
}Adding tools for SDK users
Pass tools directly β the SDK is tool-agnostic:
from praisonaiagents import Agent
def my_tool(query: str) -> str:
"""My custom tool."""
return "result"
agent = Agent(
instructions="Use tools wisely",
tools=[my_tool],
autonomy=True # Gets 16 AUTONOMY_PROFILE tools + your tools
)