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:

  1. Client sends a request (TypeScript SDK or curl) to POST /v1/graph/invoke with messages and a config that carries the thread_id.
  2. API server verifies auth via JWT or custom auth middleware.
  3. Server loads the graph from the module path in 10xgraph.json, then loads the thread state (if resuming) or starts fresh.
  4. Server calls the compiled graph with the input state and config.
  5. Graph runs: nodes execute, state is updated via reducers, tool calls are dispatched in parallel, and the state is checkpointed.
  6. Graph returns the result, including the updated messages.
  7. 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.

Python
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.
Python
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:

Python
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.

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

Python
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.

graph.py
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:

prebuilt.py
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.

Serving

Production patterns: serving agents over HTTP, auth, observability, media handling, and extensibility.

  1. First read (15 min): StateGraph to see how the workflow engine chains nodes.
  2. Then read (30 min): State and messages, Agents and tools, and Streaming to understand the execution model and granularity.
  3. 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.
  4. 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

  1. StateGraphHow StateGraph models an agent as nodes, edges and shared state, compiling and executing a graph, and handling recursion limits.9 min
  2. State and MessagesHow AgentState holds conversation history, how Message carries multimodal content blocks, and how reducers and ToolResult update state.8 min
  3. Agents and ToolsHow Agent wraps a model, why ToolNode is needed, parallel tool dispatch, and error handling.9 min
  4. 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
  5. Routing, Command and callbacksRoute execution with conditional edges, Command, or callbacks. Validate and transform invocations. Monitor and coordinate your graph.7 min
  6. Interrupts: human-in-the-loopPause graph execution from inside a node or tool to request human input, then resume with an answer.7 min
  7. Dependency InjectionHow dependency injection decouples your code from the framework and manages service lifecycles in nodes and tools.4 min
  8. StreamingWhy and how to stream agent responses. Python execution modes, StreamChunk, ResponseGranularity, and transport options.5 min

Memory and reliability

  1. Checkpointing and ThreadsHow checkpointers save and restore conversation state across calls using thread IDs.6 min
  2. 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
  3. Long-term MemoryHow to build agents that learn and remember across conversations using semantic memory storage and retrieval.10 min
  4. Context managementManage model context window by trimming or summarizing message history as conversations grow.5 min
  5. 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
  6. Errors and limitsException taxonomy, execution limits, retry behavior, and error recovery in graph execution.7 min

Serving

  1. Serving AgentsHow 10xgraph.json wires a compiled graph to the API server, plus authentication, authorization, and publisher setup for production.9 min
  2. Security and ValidatorsHow input validators and PromptInjectionValidator work, the authorization model, and what the production template enables against injection and misuse.7 min
  3. Events and observabilityHow 10xGraph emits structured events, publishes them to external systems, and exposes metrics and tracing for production monitoring.8 min
  4. Remote ToolsHow 10xGraph lets a Python graph request tools that execute in a TypeScript client or browser.5 min
  5. Media and FilesHow 10xGraph handles media in multimodal messages: MediaRef decouples location from structure, storage backends serve files, and providers adapt automatically.5 min
  6. Extension pointsAbstract base classes in 10xGraph let you customize storage, auth, LLM integration, and event publishing without changing graph logic.10 min