> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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 |

<Info>
  `autonomy=True` now defaults to **caller mode** — one `chat()` call wrapped in `AutonomyResult`. No wasteful iteration loop. Use `mode="iterative"` or `level="full_auto"` for multi-turn autonomous loops.
</Info>

## Execution Flow Comparison

### Caller Mode (default for `autonomy=True`)

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent as agent.start()
    participant Chat as chat()
    participant Tools as Tool Executor

    User->>Agent: agent.start(prompt)
    Note over Agent: mode="caller"
    Agent->>Chat: Single chat(prompt)
    Chat->>Tools: Execute tool calls
    Tools-->>Chat: Tool results
    Chat-->>Agent: LLM response
    Agent-->>User: AutonomyResult(reason="caller_mode", iterations=1)
```

### Iterative Mode (default for `full_auto`)

When `mode="iterative"`, the agent runs a multi-turn loop with safety infrastructure:

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent as agent.start()
    participant Auto as run_autonomous()
    participant Chat as chat()
    participant Inner as Inner Tool Loop
    participant LLM as LLM

    User->>Agent: agent.start(prompt)
    Note over Agent: mode="iterative"
    Agent->>Auto: Route to autonomous loop
    Auto->>Chat: chat(prompt)
    Chat->>Inner: _chat_completion(messages, tools)
    
    loop Model decides what tools to call
        Inner->>LLM: prompt + tools
        LLM-->>Inner: tool_calls=[search, write_file]
        Inner->>Inner: Execute tools, collect results
    end
    
    Inner->>LLM: tool results
    LLM-->>Inner: Summary response (no more tools)
    Note over Inner: Model stopped calling tools
    Inner-->>Chat: Final response
    Chat-->>Auto: Response text
    Note over Auto: Tools used + response produced = done
    Auto-->>User: ✅ AutonomyResult(reason="tool_completion")
```

<Tip>
  **Key insight**: All three modes use the same inner tool loop. The difference is what wraps it — nothing (interactive), an AutonomyResult wrapper (caller), or a multi-turn retry loop (iterative).
</Tip>

### Interactive Mode Flow

In interactive mode, the **human drives the loop** — each message is a single-turn `chat()` call:

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant TUI as TUI / CLI
    participant Agent as Agent
    participant Chat as chat()
    participant Tools as Tool Executor

    User->>TUI: Start interactive session
    TUI->>TUI: Load tools (ACP + LSP + Basic)
    TUI->>Agent: Create Agent(tools=[...])
    loop Human-driven loop
        User->>TUI: Type message
        TUI->>TUI: Expand @file mentions
        TUI->>Agent: agent.start(prompt)
        Agent->>Chat: Single chat(prompt)
        Chat->>Tools: Execute tool calls
        Tools-->>Chat: Tool results
        Chat-->>Agent: LLM response
        Agent-->>TUI: Response string
        TUI-->>User: Stream response
    end
    User->>TUI: /exit
```

<Note>
  **The Loop Driver Distinction**:

  * **Interactive Mode**: The **human** provides the prompt, the agent responds once, and the human decides the next prompt.
  * **Iterative Mode**: The **agent** provides its own prompts to itself in a loop until it detects the task is complete.
  * **Caller Mode**: A simplified "one-shot" interaction that returns rich metadata.
</Note>

## 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 |

<Tip>
  **Key insight**: Caller mode gives you `AutonomyResult` metadata (`.success`, `.iterations`, `.duration_seconds`) without the overhead of the iterative loop — ideal for most use cases.
</Tip>

## 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` |

<Info>
  With `autonomy=True` (defaults), init overhead is **\< 5ms** since `track_changes=False` and `observe=False` by default.
</Info>

### 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

<Warning>
  **Return type**: `AutonomyResult.__str__()` returns `.output`, so `print(result)` works the same. But code that does `if result:` or `len(result)` may break — `AutonomyResult` is always truthy and has no `__len__`. Use `str(result)` or `result.output`.
</Warning>

<Warning>
  **Early completion risk**: If the LLM says `"I'm done searching"` mid-task, keyword-based detection might stop early. For multi-step tasks, the **tool completion** signal is the primary mechanism — the model naturally stops calling tools when done. For explicit control, use structured completion signals:

  ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  Agent(autonomy={"completion_promise": "COMPLETED"})
  ```
</Warning>

<Note>
  **Approval with autonomy=True**: Default level is `"suggest"`, which does NOT auto-approve tools. Only `level="full_auto"` auto-wires `AutoApproveBackend`.
</Note>

## 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:

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    subgraph SDK["Core SDK (praisonaiagents)"]
        PROFILES["tools/profiles.py<br/>ToolProfile system<br/>6 built-in profiles"]
        AUTONOMY["AUTONOMY_PROFILE<br/>16 tools (composite)"]
        MAPPINGS["tools/__init__.py<br/>TOOL_MAPPINGS: 50+ tools<br/>(lazy-load registry)"]
        INJECT["agent.py<br/>autonomy default injection"]
        RESOLVE["_resolve_tool_names()<br/>(string → function)"]
        PROFILES --> AUTONOMY
        INJECT --> AUTONOMY
        RESOLVE -.->|"uses"| MAPPINGS
    end

    subgraph WRAPPER["CLI Wrapper (praisonai)"]
        IT["interactive_tools.py<br/>TOOL_GROUPS: 13 tools"]
        TK["tracker.py<br/>AUTONOMY_DEFAULT_TOOLS: 30 tools"]
        REG["register_profile()<br/>ACP + LSP profiles"]
    end

    IT -->|"tools=[...]"| SDK
    TK -->|"tools=[...]"| SDK
    REG -.->|"extends"| PROFILES

    classDef sdk fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef wrap fill:#F59E0B,stroke:#7C90A0,color:#fff

    class PROFILES,AUTONOMY,MAPPINGS,INJECT,RESOLVE sdk
    class IT,TK,REG wrap
```

### What each layer provides

<Warning>
  **ACP Tools Performance**: ACP tools (`acp_edit_file`, `acp_execute_command`) go through a complex orchestration flow and can be **slow (174s+ per operation)**. In autonomy mode (`--autonomy full_auto`), ACP tools are **disabled by default** for speed. Use `--acp` flag to explicitly enable them when needed.
</Warning>

<CardGroup cols={2}>
  <Card title="CLI Wrapper (praisonai)" icon="terminal">
    **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"`
  </Card>

  <Card title="Core SDK (praisonaiagents)" icon="microchip">
    **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
  </Card>
</CardGroup>

### 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:

<Steps>
  <Step title="Core SDK stays minimal">
    The `praisonaiagents` package provides the agent runtime, tool execution, and LLM integration — but **does not bundle default tools**. This keeps the SDK lightweight and avoids opinionated defaults.
  </Step>

  <Step title="CLI wrapper adds batteries">
    The `praisonai` wrapper package adds ACP, LSP, file operations, and search tools for CLI users. It assembles toolsets and passes them as `tools=[...]` to the Agent constructor.
  </Step>

  <Step title="Tools are data, not hardcoded">
    Interactive tools are defined as groups in `interactive_tools.py` with a `TOOL_GROUPS` dictionary. New tools are added to a group, and all consumers automatically get them.
  </Step>
</Steps>

### Why this is the best approach

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>
</AccordionGroup>

## 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 |

<CardGroup cols={3}>
  <Card title="No Autonomy" icon="message">
    **Fastest** — agent explains but doesn't act.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    agent = Agent(
        instructions="Help with coding"
    )
    agent.start("Explain this function")
    ```
  </Card>

  <Card title="Caller Mode" icon="bolt">
    **One turn** — agent acts immediately with tools.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    agent = Agent(
        instructions="You are a research assistant",
        autonomy=True
    )
    result = agent.start("Search and save to file")
    print(result.success)
    ```
  </Card>

  <Card title="Iterative Mode" icon="rotate">
    **Multi-turn** — agent self-corrects until done.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    agent = Agent(
        instructions="Build and test features",
        autonomy={"mode": "iterative"}
    )
    result = agent.start("Refactor the auth module")
    print(result.iterations)
    ```
  </Card>
</CardGroup>

## Extending Tools

### Using ToolProfiles (recommended)

Combine built-in profiles or register custom ones:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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`:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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
)
```

## Related

<CardGroup cols={2}>
  <Card title="Autonomy Concepts" icon="robot" href="/docs/concepts/autonomy">
    Configuration, stages, and doom loop detection
  </Card>

  <Card title="Autonomous Loops" icon="rotate" href="/docs/features/autonomy-loop">
    Execution loop details and async support
  </Card>

  <Card title="Interactive Tools" icon="toolbox" href="/docs/cli/interactive-tools">
    ACP, LSP, and basic tool reference
  </Card>

  <Card title="Autonomy Modes" icon="sliders" href="/docs/cli/autonomy-modes">
    Suggest, auto-edit, and full-auto modes
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.