Skip to content

Building Agents

Latent ships a production-grade agent runtime: a streaming, async, tool-calling ReAct loop with first-class guardrails, context management, and a stable wire protocol that any platform can consume. This page is the map — each feature has a dedicated page linked below.

What is a Latent agent?

An agent takes a conversation history (list[Message]) and produces a stream of typed events as it reasons, calls tools, and responds. The standard implementation is the ReActAgent: it runs the ReAct loop — the model thinks, optionally calls a tool, observes the result, and iterates until it produces a final answer or hits max_iterations.

messages ReAct loop think call tool (optional) observe repeat until done final text guardrails · pre guardrails · post every step emits events · stream() observes them live

Every agent satisfies one contract — AgentProtocol — exposing stream() (per-event) and invoke() (per-step, buffered). All entry points are async (async-only since 5.0.0).

import asyncio
from latent.agents import ReActAgent
from latent.protocol import Message

async def main():
    agent = ReActAgent(name="assistant", model="gpt-4o")
    result = await agent.invoke([Message(role="user", content="What is 2+2?")])
    print(result.text)            # "4"

asyncio.run(main())

Feature map

Feature Page What it gives you
The agent ReAct Agent Construction, the ReAct loop, structured output, lifecycle, max-iteration fallback, thinking config
Wire contract Agent Protocol Message, the AgentEvent hierarchy, Step / InvokeResult, stream() vs invoke()
Tool calling Tools & Retrievers @tool functions and methods, @retriever + retrieval events, the end_call tool
Safety rules Guardrails The @guardrail decorator, GuardrailMiddleware, observability sinks
Scanning units Scanners Built-in input/output scanners, the scan protocol, custom scanners
Context window Context Engineering @context_check, token-budget auditing, compaction, review_context()
Deterministic routing Pipeline Agents Phase-based agents where code decides transitions
Guided behavior (experimental) Guided Agents Guideline/journey-driven context narrowing and tool gating
Simulation Simulators Drive agents through multi-turn conversations for eval (HumanAgent, ConversationSimulator)
Evaluation Judges & Scoring Judge / Classifier — structured LLM-as-judge scoring
Recipes Agent Cookbook Class-based skeletons for every agent type above

What's in the box vs. extras

The agent runtime — ReAct loop, tools, the protocol, and the @guardrail machinery — works on the minimal install. Some scanners and surfaces need an extra:

pip install latent                  # ReAct agent, tools, protocol, guardrail engine
pip install "latent[guardrails]"    # LanguageScanner (langdetect)
pip install "latent[guardrails-llmguard]"  # ML scanners (PII, toxicity, ...)
pip install "latent[chat]"          # interactive TUI: latent chat <agent>
pip install "latent[eval]"          # Judges/Classifiers inside flows, statistics
Capability Extra
ReAct agent, @tool, @retriever, latent.protocol, @guardrail engine (none — base install)
LanguageScanner guardrails
ML scanners (LLM Guard) guardrails-llmguard
Hebrew scanner locale guardrails-hebrew
latent chat TUI chat
Judges / scoring inside flows eval

Composing the pieces

A typical production agent stacks several features:

from latent.agents import ReActAgent, tool
from latent.guardrails import guardrail
from latent.guardrails.scanners.builtin import TokenLimitScanner

@tool
async def lookup_order(order_id: str) -> str:
    """Look up an order by its ID."""
    return await db.fetch_order(order_id)

class SupportAgent(ReActAgent):
    # tool methods are auto-discovered — see Tools & Retrievers
    @tool
    async def refund(self, order_id: str) -> str:
        """Issue a refund for an order."""
        return await payments.refund(order_id)

    # guardrail methods are auto-discovered — see Guardrails
    @guardrail(timing="pre", outcome="active", message="Prompt too long")
    def token_cap(self):
        return TokenLimitScanner(max_tokens=8000)

agent = SupportAgent(name="support", model="gpt-4o", tools=[lookup_order])

From here, dig into each feature: