Concepts
In this sectionUnderstand how 10xGraph works, from its three-layer architecture to request flow, the execution model, and production patterns.
- 20 pages
- About 139 min to read all
The Concepts section explains how 10xGraph works: the three-layer architecture (library, server, client), how a request flows from client through the server to your graph, the execution model (state, messages, nodes, edges), and advanced patterns for memory, reliability, and production deployments. Read this section to understand the mental model before building.
Why graphs?
10xGraph uses a graph-based execution model instead of a linear pipeline or free-form function calls. This model gives you:
- Reproducibility: The workflow is an explicit graph, so the same state takes the same route. Tool calls are replay-safe, so if a tool runs and the process crashes, resuming the same thread does not re-execute the finished call.
- Durability: Intermediate state is checkpointed at each step, so you can pause an agent for human approval, resume it later, and it continues from exactly where it left off.
- Observability: Execution emits events you can stream, log, or send to tracing systems (see Events and observability).
- Control: You route between nodes using conditional logic you define, so complex multi-step and multi-agent workflows are explicit and testable.
- Concurrency: Tools run in parallel by default, and the graph engine scales across stateless servers with per-thread durability.
Three-layer architecture
10xGraph is built in three independent layers. You can use just the Python library for agents in a script, or add the API server and TypeScript client to serve agents over HTTP.
flowchart TB
subgraph "Python library (10xgraph)"
Graph[StateGraph · Agent · ToolNode]
Storage[Checkpointer · Memory Store · Media Store]
end
subgraph "API and CLI (10xgraph-api)"
CLI["10xgraph CLI"]
API[FastAPI Server]
end
subgraph "TypeScript client (10xgraph-client)"
SDK[TenxGraphClient]
end
SDK -->|HTTP / SSE / WS| API
CLI --> API
API --> Graph
Graph <--> Storage
| Layer | Package | What it does |
|---|---|---|
| Core library | 10xgraph (import tenxgraph) |
Graph engine, agents, tools, state, checkpointing, memory stores, media handling, publishers. Use this to build agents locally or embed graphs in your own apps. |
| API server & CLI | 10xgraph-api (import tenxgraph_api, command 10xgraph) |
FastAPI server that wraps your compiled graph, REST and WebSocket endpoints, auth, authorization, rate limiting, thread management. Use this to serve agents over HTTP. |
| TypeScript client | 10xgraph-client (npm 10xgraph-client) |
Typed HTTP wrapper for browser and Node.js, handles auth, streaming, thread management, file uploads. Use this to call the server from your frontend or backend. |
Python code imports from tenxgraph, for example from tenxgraph.core.graph import StateGraph. The deprecated alias agentflow still works until 2.0. The TypeScript class is named TenxGraphClient.
How a request flows through the system
When you call an agent over HTTP, here is what happens:
- Client sends a request (TypeScript SDK or curl) to
POST /v1/graph/invokewithmessagesand aconfigthat carries thethread_id. - API server verifies auth via JWT or custom auth middleware.
- Server loads the graph from the module path in
10xgraph.json, then loads the thread state (if resuming) or starts fresh. - Server calls the compiled graph with the input state and config.
- Graph runs: nodes execute, state is updated via reducers, tool calls are dispatched in parallel, and the state is checkpointed.
- Graph returns the result, including the updated messages.
- Server returns the response to the client (as one JSON body, or as a stream).
For streaming, the graph emits StreamChunk objects as it runs. Each chunk has an event of state, message, error or updates. POST /v1/graph/stream sends them as server-sent events (text/event-stream), and the /v1/graph/ws WebSocket endpoint sends them over a socket. See Streaming for the details.
The execution model
Four core concepts form the foundation of every 10xGraph agent.
Message
Message is the unit of all communication. Every piece of information flowing through a graph is a Message: user questions, assistant responses, tool calls, tool results, and errors.
from tenxgraph.core.state import Message
# Create a user message
Message.text_message("What is the weather?", role="user")
# Create an assistant response
Message.text_message("Let me check...", role="assistant")A message carries one or more content blocks, such as TextBlock, ToolCallBlock, ToolResultBlock, ImageBlock, AudioBlock, VideoBlock, DocumentBlock, DataBlock, ReasoningBlock, AnnotationBlock and ErrorBlock. Nodes read the content blocks to decide what to do next.
AgentState
AgentState is the container passed from node to node. It has three built-in fields; subclass it and add your own.
| Field | Type | Purpose |
|---|---|---|
context |
list[Message] |
Live message list; appended to by every node via the add_messages reducer. |
context_summary |
str | None |
Optional summary written by SummaryContextManager when old messages are trimmed. |
execution_meta |
ExecMeta |
Internal runtime bookkeeping (current node, step count, status, interrupt details, thread ID), managed by the framework. |
from tenxgraph.core.state import AgentState
from pydantic import Field
class MyState(AgentState):
# context, context_summary, and execution_meta are already defined
user_name: str = "Guest"
order_data: dict = Field(default_factory=dict)Fields use annotated reducers to control how new values merge with old. The context field uses add_messages, which appends new messages and deduplicates by ID:
from typing import Annotated
from tenxgraph.core.state import add_messages, Message
context: Annotated[list[Message], add_messages]Node
A node is any Python function that receives AgentState and returns a message or a state update. Nodes are the unit of work.
# Registered with graph.add_node("GREET", my_node)
async def my_node(state: MyState) -> Message:
# The graph injects state, config, and any Inject[T] dependencies
return Message.text_message(f"Hello {state.user_name}", role="assistant")You do not call nodes yourself. The graph injects dependencies and calls them in the order the edges define.
Node execution cycle
In each step a node receives the full state, does its work, and returns a message or partial state update. The graph merges the result via reducers, saves a checkpoint, then routes to the next node.
flowchart LR
START["START\n(entry point)"]
NODE1["Node\n(e.g., Agent)"]
ROUTE{"Routing\n(condition?)"}
NODE2["Node\n(e.g., Tool)"]
END["END\n(exit)"]
START --> NODE1
NODE1 --> ROUTE
ROUTE -->|yes| NODE2
ROUTE -->|no| END
NODE2 --> NODE1
The key insight: state is immutable during a single step. Each node receives a consistent snapshot, returns an update, and the graph applies all updates (via reducers) before the next step. This isolation enables replay-safety and resumability.
Edge and routing
Edges connect nodes. A static edge always goes to one node, and a conditional edge calls a function that returns where to go next:
graph.add_edge("TOOL", "MAIN") # static
graph.add_conditional_edges("MAIN", route_fn) # route_fn returns a node name
# or
graph.add_conditional_edges("MAIN", route_fn, { # route_fn returns a key in this map
"tool": "TOOL",
"done": END,
})Building and running a graph
Every graph has three stages: define (add nodes and edges), compile (attach a checkpointer and other services), and run (invoke, stream, or resume). The example below is complete once you install pip install "10xgraph[openai]" and set your OpenAI API key.
from tenxgraph.core.graph import Agent, StateGraph, ToolNode
from tenxgraph.core.state import AgentState, Message
from tenxgraph.storage.checkpointer import InMemoryCheckpointer
from tenxgraph.utils import END, START
def get_weather(location: str) -> str:
"""Get the current weather for a location."""
return f"The weather in {location} is sunny"
# Define nodes: a tool node and an agent that can call its tools
tool_node = ToolNode([get_weather])
agent = Agent(model="gpt-4o", tool_node=tool_node)
# Routing: go to tools when the assistant asked for one, otherwise finish
def route(state: AgentState) -> str:
last = state.context[-1]
if last.role == "assistant" and last.tools_calls:
return "TOOL"
return END
# Define edges
graph = StateGraph()
graph.add_node("MAIN", agent)
graph.add_node("TOOL", tool_node)
graph.add_edge(START, "MAIN")
graph.add_conditional_edges("MAIN", route, {"TOOL": "TOOL", END: END})
graph.add_edge("TOOL", "MAIN")
# Compile with a checkpointer so threads can resume
compiled = graph.compile(checkpointer=InMemoryCheckpointer())
# Run: the thread_id lives in config
result = compiled.invoke(
{"messages": [Message.text_message("What is the weather in Paris?")]},
config={"thread_id": "abc"},
)
print(result["messages"][-1])Or use a prebuilt agent to skip graph definition:
from tenxgraph.prebuilt.agent import ReactAgent
from graph import get_weather # the tool from the example above
compiled = ReactAgent(model="gpt-4o", tools=[get_weather]).compile()Calling invoke again with the same thread_id resumes that thread from its last checkpoint, and finished tool calls are not re-run. See Checkpointing and threads and Choosing a building block.
What’s in this section
The Concepts section is organized into three groups:
Foundations
Start here to understand the execution model in depth: state graphs, messages, agents, tools, routing, dependency injection, and streaming.
- StateGraph: The core workflow engine, how compile() wires everything, and recursion limits.
- State and messages: Message structure, content blocks, state reducers, and the message catalog.
- Agents and tools: Why Agent exists, how ToolNode dispatches (parallel by default), MCP, and tool errors.
- Choosing a building block: When to use a plain node vs Agent vs prebuilt agent vs custom graph.
- Routing, Command and callbacks: Conditional edges, the Command API, and callback handling.
- Interrupts: Human-in-the-loop: pausing execution, saving checkpoints, and resuming.
- Dependency injection: Why DI vs globals, and the injectable parameters you can request.
- Streaming: Python streaming granularity, why stream, and transport summary.
Memory and reliability
Build robust agents: checkpointing threads, long-term memory stores, context trimming, error handling, and tool replay safety.
- Checkpointing and threads: Threads, checkpoints, and choosing a checkpointer (in-memory, SQLite, Postgres+Redis).
- How PgCheckpointer works: The dual-layer write and read paths, versioning, and recovery.
- Long-term memory: Store vs checkpointer, retrieval, scoping, and when to use memory tools.
- Context management: Why context grows, message trimming vs summarization, and trade-offs.
- Replay-safe tools: How tool ledgers prevent duplicate execution on resume.
- Errors and limits: Exception types, recursion limits, timeouts, and retry policies.
Serving
Production patterns: serving agents over HTTP, auth, observability, media handling, and extensibility.
- Serving agents: How the API server loads graphs, request lifecycle, workers, and config vs code.
- Security and validators: Input validation, authorization models, and isolation scopes.
- Events and observability: The event model, publishers, metrics, and tracing.
- Remote tools: When to use remote tool execution.
- Media and files: Media refs, offload policies, storage backends, and provider file APIs.
- Extension points: The base classes you can subclass: BaseAgent, BaseCheckpointer, BaseStore, BaseAuth, and more.
Recommended reading order
- First read (15 min): StateGraph to see how the workflow engine chains nodes.
- Then read (30 min): State and messages, Agents and tools, and Streaming to understand the execution model and granularity.
- Go build in the Get started section. Build a graph in Python, serve it with
10xgraph api, and call it from TypeScript. The tutorial is more hands-on. - Return here to dive deeper: checkpointing, memory, context management, error handling, auth, observability.
Next steps
- Get started: Build your first agent, step by step.
- Build agents: Task guides for everything from custom nodes to prebuilt agents to production patterns.
- API server: Serve agents over HTTP with auth, rate limiting, and observability.
- TypeScript client: Call the server from your app with the typed client.
- Reference: API signatures, CLI flags, environment variables, and error codes.
All pages in Concepts
Foundations
- StateGraphHow StateGraph models an agent as nodes, edges and shared state, compiling and executing a graph, and handling recursion limits.9 min
- State and MessagesHow AgentState holds conversation history, how Message carries multimodal content blocks, and how reducers and ToolResult update state.8 min
- Agents and ToolsHow Agent wraps a model, why ToolNode is needed, parallel tool dispatch, and error handling.9 min
- Choosing a building blockDecide between a prebuilt agent, the Agent node in a StateGraph, and a plain function node, based on your pattern and how much control you need.7 min
- Routing, Command and callbacksRoute execution with conditional edges, Command, or callbacks. Validate and transform invocations. Monitor and coordinate your graph.7 min
- Interrupts: human-in-the-loopPause graph execution from inside a node or tool to request human input, then resume with an answer.7 min
- Dependency InjectionHow dependency injection decouples your code from the framework and manages service lifecycles in nodes and tools.4 min
- StreamingWhy and how to stream agent responses. Python execution modes, StreamChunk, ResponseGranularity, and transport options.5 min
Memory and reliability
- Checkpointing and ThreadsHow checkpointers save and restore conversation state across calls using thread IDs.6 min
- How PgCheckpointer worksThe internal mechanisms of PgCheckpointer's two-layer storage model, the write path, read path, and optimistic concurrency control for thread state.7 min
- Long-term MemoryHow to build agents that learn and remember across conversations using semantic memory storage and retrieval.10 min
- Context managementManage model context window by trimming or summarizing message history as conversations grow.5 min
- Replay-safe toolsReplay-safe tools let a resumed 10xGraph run skip tool calls that already finished, so a crash does not charge a card or send an email twice.4 min
- Errors and limitsException taxonomy, execution limits, retry behavior, and error recovery in graph execution.7 min
Serving
- Serving AgentsHow 10xgraph.json wires a compiled graph to the API server, plus authentication, authorization, and publisher setup for production.9 min
- Security and ValidatorsHow input validators and PromptInjectionValidator work, the authorization model, and what the production template enables against injection and misuse.7 min
- Events and observabilityHow 10xGraph emits structured events, publishes them to external systems, and exposes metrics and tracing for production monitoring.8 min
- Remote ToolsHow 10xGraph lets a Python graph request tools that execute in a TypeScript client or browser.5 min
- Media and FilesHow 10xGraph handles media in multimodal messages: MediaRef decouples location from structure, storage backends serve files, and providers adapt automatically.5 min
- Extension pointsAbstract base classes in 10xGraph let you customize storage, auth, LLM integration, and event publishing without changing graph logic.10 min