Agentic AI Atlasby a5c.ai
OverviewWikiGraphFor AgentsEdgesSearchWorkspace
/
GitHubDocsDiscord
iiRecord
Agentic AI Atlas · Agent Loop Internals
page:docs-hermes-research-raw-agent-loopa5c.ai
Search record views/
Record · tabs

Available views

II.Record viewspp. 1 - 1
overviewarticlejsongraph
II.
Page JSON

page:docs-hermes-research-raw-agent-loop

Structured · live

Agent Loop Internals json

Inspect the normalized record payload exactly as the atlas UI reads it.

File · wiki/docs/hermes-research/raw/agent-loop.mdCluster · wiki
Record JSON
{
  "id": "page:docs-hermes-research-raw-agent-loop",
  "_kind": "Page",
  "_file": "wiki/docs/hermes-research/raw/agent-loop.md",
  "_cluster": "wiki",
  "attributes": {
    "nodeKind": "Page",
    "sourcePath": "docs/hermes-research/raw/agent-loop.md",
    "sourceKind": "repo-docs",
    "title": "Agent Loop Internals",
    "displayName": "Agent Loop Internals",
    "slug": "docs/hermes-research/raw/agent-loop",
    "articlePath": "wiki/docs/hermes-research/raw/agent-loop.md",
    "article": "\n# Agent Loop Internals\n\n> Source: https://hermes-agent.nousresearch.com/docs/developer-guide/agent-loop\n\n## Core Responsibilities\n\nThe `AIAgent` class in `run_agent.py` (~4,400 lines) orchestrates the agent's core operations:\n\n- Assembling system prompts and tool schemas via `prompt_builder.py`\n- Selecting the appropriate provider/API mode\n- Making interruptible model calls with cancellation support\n- Executing tool calls sequentially or concurrently\n- Maintaining conversation history in OpenAI message format\n- Handling compression, retries, and fallback model switching\n- Tracking iteration budgets across parent and child agents\n- Flushing persistent memory before context loss\n\n## Two Entry Points\n\n```python\n# Simple interface -- returns final response string\nresponse = agent.chat(\"Fix the bug in main.py\")\n\n# Full interface -- returns dict with messages, metadata, usage stats\nresult = agent.run_conversation(\n    user_message=\"Fix the bug in main.py\",\n    system_message=None,           # auto-built if omitted\n    conversation_history=None,      # auto-loaded from session if omitted\n    task_id=\"task_abc123\")\n```\n\n`chat()` wraps `run_conversation()` and extracts the `final_response` field.\n\n## API Modes\n\nThree execution modes resolve from provider selection, explicit arguments, and base URL heuristics:\n\n| API Mode | Used For | Client Type |\n|----------|----------|-------------|\n| `chat_completions` | OpenAI-compatible endpoints | `openai.OpenAI` |\n| `codex_responses` | OpenAI Codex/Responses API | `openai.OpenAI` |\n| `anthropic_messages` | Native Anthropic API | `anthropic.Anthropic` |\n\n**Resolution order:**\n1. Explicit `api_mode` constructor arg (highest priority)\n2. Provider-specific detection\n3. Base URL heuristics\n4. Default: `chat_completions`\n\n## Turn Lifecycle\n\nEach iteration follows this sequence:\n\n```\n1. Generate task_id if not provided\n2. Append user message to conversation history\n3. Build or reuse cached system prompt\n4. Check if preflight compression needed (>50% context)\n5. Build API messages from conversation history\n6. Inject ephemeral prompt layers (budget warnings, context pressure)\n7. Apply prompt caching markers if on Anthropic\n8. Make interruptible API call\n9. Parse response:\n   - Tool calls: execute, append results, loop back to step 5\n   - Text response: persist session, flush memory, return\n```\n\n### Message Format\n\nAll messages use OpenAI-compatible format internally:\n\n```json\n{\"role\": \"system\", \"content\": \"...\"}\n{\"role\": \"user\", \"content\": \"...\"}\n{\"role\": \"assistant\", \"content\": \"...\", \"tool_calls\": [...]}\n{\"role\": \"tool\", \"tool_call_id\": \"...\", \"content\": \"...\"}\n```\n\nReasoning content is stored in `assistant_msg[\"reasoning\"]` and displayed via callbacks.\n\n### Message Alternation Rules\n\n- After system message: `User -> Assistant -> User -> Assistant -> ...`\n- During tool calling: `Assistant (with tool_calls) -> Tool -> Tool -> ... -> Assistant`\n- Never two consecutive assistant messages\n- Never two consecutive user messages\n- Only `tool` role can have consecutive entries (parallel results)\n\n## Interruptible API Calls\n\nAPI requests run in background threads while monitoring interrupt events:\n\n```\nMain Thread          API Thread\n  |-- wait on:     -> HTTP POST\n  |  - response      to provider\n  |  - interrupt\n  |  - timeout\n```\n\nWhen interrupted:\n- The API thread is abandoned\n- Agent processes new input or shuts down cleanly\n- No partial response injected into history\n\n## Tool Execution\n\n### Sequential vs Concurrent\n\n- **Single tool call**: executed directly in main thread\n- **Multiple tool calls**: executed via `ThreadPoolExecutor`\n  - Interactive tools (e.g., `clarify`) force sequential execution\n  - Results reinserted in original tool call order\n\n### Execution Flow\n\n```\nFor each tool_call:\n  1. Resolve handler from tools/registry.py\n  2. Fire pre_tool_call plugin hook\n  3. Check if dangerous command\n     - If dangerous: invoke approval_callback\n  4. Execute handler with args + task_id\n  5. Fire post_tool_call plugin hook\n  6. Append tool result to history\n```\n\n### Agent-Level Tools\n\nThese are intercepted before reaching `handle_function_call()`:\n\n| Tool | Why Intercepted |\n|------|-----------------|\n| `todo` | Reads/writes agent-local task state |\n| `memory` | Writes to persistent memory files |\n| `session_search` | Queries session history via agent DB |\n| `delegate_task` | Spawns subagents with isolated context |\n\n## Callback Surfaces\n\n| Callback | Fired When | Used By |\n|----------|-----------|---------|\n| `tool_progress_callback` | Before/after tool execution | CLI spinner, gateway |\n| `thinking_callback` | Model starts/stops thinking | CLI indicator |\n| `reasoning_callback` | Model returns reasoning | CLI display, gateway |\n| `clarify_callback` | `clarify` tool called | CLI prompt, gateway |\n| `step_callback` | After complete agent turn | Gateway, ACP |\n| `stream_delta_callback` | Each streaming token | CLI streaming display |\n| `tool_gen_callback` | Tool call parsed from stream | CLI tool preview |\n| `status_callback` | State changes | ACP updates |\n\n## Budget and Fallback Behavior\n\n### Iteration Budget\n\n- Default: 90 iterations (configurable via `agent.max_turns`)\n- Each agent gets independent budget; subagents capped at `delegation.max_iterations` (default 50)\n- At 100%, agent stops and returns work summary\n\n### Fallback Model\n\nWhen primary model fails (rate limit, server error, auth error):\n1. Check `fallback_providers` list\n2. Try each fallback in order\n3. Continue conversation with new provider on success\n4. Attempt credential refresh on 401/403 before failing over\n\nAuxiliary tasks have independent fallback chains via `auxiliary.*` config.\n\n## Compression and Persistence\n\n### When Compression Triggers\n\n- **Preflight**: Before API call if conversation exceeds 50% of context window\n- **Gateway auto-compression**: If exceeds 85% (more aggressive, runs between turns)\n\n### During Compression\n\n1. Memory flushed to disk first\n2. Middle conversation turns summarized\n3. Last N messages preserved intact (`compression.protect_last_n` default: 20)\n4. Tool call/result pairs kept together\n5. New session lineage ID generated\n\n### Session Persistence\n\nAfter each turn:\n- Messages saved to session store (SQLite via `hermes_state.py`)\n- Memory changes flushed to `MEMORY.md` / `USER.md`\n- Session resumable via `/resume` or `hermes chat --resume`\n\n## Key Source Files\n\n| File | Purpose |\n|------|---------|\n| `run_agent.py` | AIAgent class -- complete agent loop |\n| `agent/prompt_builder.py` | System prompt assembly |\n| `agent/context_engine.py` | ContextEngine ABC -- pluggable context management |\n| `agent/context_compressor.py` | Default engine -- lossy summarization |\n| `agent/prompt_caching.py` | Anthropic prompt caching markers |\n| `agent/auxiliary_client.py` | Auxiliary LLM client for side tasks |\n| `model_tools.py` | Tool schema collection, dispatch |\n",
    "documents": []
  },
  "outgoingEdges": [],
  "incomingEdges": [
    {
      "from": "page:docs-hermes-research",
      "to": "page:docs-hermes-research-raw-agent-loop",
      "kind": "contains_page"
    }
  ]
}

Shortcuts

Back to overview
Open graph tab