Skip to content

Agent Loop

The agent loop is Neo’s heartbeat. A user sends a message, the model answers, Neo runs any requested tools, then the model continues until it has a final answer.

Think of it like:

  1. User asks for work.
  2. Model decides what to do.
  3. Neo runs tools the model asked for.
  4. Tool results go back to the model.
  5. Repeat until the model is done.

Coding agents need more than one model response. A model might first need to inspect files, then run a command, then edit a file, then run tests. That means one user turn can contain several model/tool steps.

The tricky part is preserving the transcript correctly. If the model asks for a tool, the next provider request must include the matching tool result. Splitting those apart can break provider APIs and confuse the model.

The core loop lives in internal/agent. It is deliberately policy-free:

  • It stores messages.
  • It calls an llm.Provider.
  • It emits events for the TUI.
  • It runs injected tools.
  • It appends tool results before continuing.

It does not know about coding style, AGENTS.md, skills, permissions, or the terminal UI. Those are layered around it.

Every assistant tool_use must be followed by a matching user tool_result before the transcript is sent back to the provider.

Neo builds the assistant message and tool results together before committing them to the transcript. That keeps the conversation valid even when a tool fails.

Oversized tool output is capped at the agent boundary before it enters the transcript or session payload. The capped content includes a visible truncation marker with the original byte size and line count.

Add behavior around the loop, not inside it, unless the behavior is truly provider/tool-turn mechanics.

Good extensions:

  • Add a new tool to internal/tools and inject it through the registry.
  • Add a new provider that implements llm.Provider.
  • Add prompt context before constructing the agent.
  • Add a compactor through the compact.Compactor interface.

Risky extensions:

  • Teaching the loop about project files.
  • Putting UI behavior in the loop.
  • Making the loop decide permissions itself.
  • internal/agent/agent.go: the loop and event model.
  • internal/llm/provider.go: provider-neutral message and tool types.
  • internal/tools/: built-in tools the loop can run.