Quickstart
In shortInstall 10xGraph, build a support agent in Python, serve it with the API server, then call it with curl and the TypeScript client.
- 7 min read
- 6 sections
- Updated
- v0.10.0
- Markdown
To build your first 10xGraph agent, install the packages, define a ReactAgent with two tools, run it from Python, serve it with 10xgraph api, and call it with curl and the TypeScript client. This page takes you through all of it with one support agent.
You need Python 3.12 or newer and an API key for your chosen model provider (Google, OpenAI, or Anthropic).
Install the packages
Choose your model provider and install the matching extra:
Google Gemini
pip install "10xgraph[google-genai]" 10xgraph-api
export GOOGLE_API_KEY="your-gemini-api-key"OpenAI
pip install "10xgraph[openai]" 10xgraph-api
export OPENAI_API_KEY="your-openai-api-key"Anthropic
pip install "10xgraph[anthropic]" 10xgraph-api
export ANTHROPIC_API_KEY="your-anthropic-api-key"The 10xgraph package is the framework. The 10xgraph-api package adds the server and the 10xgraph CLI. The provider extra (google-genai, openai, or anthropic) lets 10xGraph call your chosen model. For details on API keys and other providers, see Installation.
Build and run the agent locally
You will create two Python files: one that defines the agent, and one that runs it.
-
Define tools and create the agent
Create a file named
agent.py. Tools are plain Python functions. Their docstrings and type hints become the schema that the model sees, so write them clearly.Google Gemini
agent.py from tenxgraph.prebuilt.agent import ReactAgent from tenxgraph.storage.checkpointer import InMemoryCheckpointer def lookup_order(order_id: str) -> dict: """Look up an order by id and return its status and total.""" return {"order_id": order_id, "status": "delivered", "total": 59.0} def refund_order(order_id: str, amount: float) -> str: """Refund an order. This moves money, so it must run once per request.""" return f"Refunded {amount:.2f} for order {order_id}" agent = ReactAgent( model="google/gemini-2.5-flash", provider="google", system_prompt=[ { "role": "system", "content": "You are a concise support agent for an online shop.", } ], tools=[lookup_order, refund_order], ) app = agent.compile(checkpointer=InMemoryCheckpointer())OpenAI
agent.py from tenxgraph.prebuilt.agent import ReactAgent from tenxgraph.storage.checkpointer import InMemoryCheckpointer def lookup_order(order_id: str) -> dict: """Look up an order by id and return its status and total.""" return {"order_id": order_id, "status": "delivered", "total": 59.0} def refund_order(order_id: str, amount: float) -> str: """Refund an order. This moves money, so it must run once per request.""" return f"Refunded {amount:.2f} for order {order_id}" agent = ReactAgent( model="gpt-4o", provider="openai", system_prompt=[ { "role": "system", "content": "You are a concise support agent for an online shop.", } ], tools=[lookup_order, refund_order], ) app = agent.compile(checkpointer=InMemoryCheckpointer())Anthropic
agent.py from tenxgraph.prebuilt.agent import ReactAgent from tenxgraph.storage.checkpointer import InMemoryCheckpointer def lookup_order(order_id: str) -> dict: """Look up an order by id and return its status and total.""" return {"order_id": order_id, "status": "delivered", "total": 59.0} def refund_order(order_id: str, amount: float) -> str: """Refund an order. This moves money, so it must run once per request.""" return f"Refunded {amount:.2f} for order {order_id}" agent = ReactAgent( model="claude-haiku-4-5", provider="anthropic", system_prompt=[ { "role": "system", "content": "You are a concise support agent for an online shop.", } ], tools=[lookup_order, refund_order], ) app = agent.compile(checkpointer=InMemoryCheckpointer())ReactAgentbuilds a standard reason-and-act graph for you: it has an agent node that calls the model, a tool node that runs tools, and conditional routing between them.compile()returns aCompiledGraph, the object you run and the server loads. -
Test the agent locally
Create
run.pynext toagent.py. It sends two requests on the same thread:run.py from tenxgraph.core.state import Message from agent import app config = {"thread_id": "quickstart-1"} # First turn: the agent calls lookup_order result = app.invoke( {"messages": [Message.text_message("Where is order 1042?")]}, config=config, ) print(result["messages"][-1].text()) # Second turn on the same thread: the agent calls refund_order result = app.invoke( {"messages": [Message.text_message("Refund order 1042 for 59.00")]}, config=config, ) print(result["messages"][-1].text())Run it:
Terminal python run.pyThe exact wording varies by model. The first reply gives the order status and total, and the second confirms the refund. Both turns use thread
quickstart-1, so the checkpointer keeps the first conversation available to the second. -
Create the server config file
The API server finds your graph by reading
10xgraph.json. Create this file in the same directory asagent.py:10xgraph.json { "agent": "agent:app", "env": ".env", "auth": null }The
agentfield points to theappvariable in theagentmodule. The server loads and compiles it once at startup. -
Start the API server
Terminal 10xgraph apiExpected output:
Text INFO: Uvicorn running on http://127.0.0.1:8000The server listens on
127.0.0.1:8000by default. Use--host 0.0.0.0to accept connections from other machines and--portto use a different port. The server needs the same provider API key in its environment, so run it from the shell where you exported the key. -
Call the agent over HTTP
In a second terminal, invoke the agent with curl. Notice the message format: content is a list of typed blocks.
Terminal curl -X POST http://127.0.0.1:8000/v1/graph/invoke \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": [{"type": "text", "text": "Where is order 1042?"}] } ], "config": {"thread_id": "quickstart-2"} }'The response is a JSON object with
data(the result) andmetadata(request id and timestamp):JSON { "data": { "messages": [ {"role": "user", "content": [{"type": "text", "text": "Where is order 1042?"}]}, {"role": "assistant", "content": [{"type": "text", "text": "Order 1042 is delivered. The total is $59.00."}]} ], "state": null, "context": null, "summary": null, "meta": null }, "metadata": { "request_id": "550e8400-e29b-41d4-a716-446655440000", "timestamp": "2026-10-08T12:30:45.123Z", "message": "OK" } }The assistant message is the last item in
data.messages.
Call the agent from TypeScript
The 10xGraph client for TypeScript wraps the HTTP API with types and helper methods. It handles graph execution, thread management, long-term memory, and file uploads. It requires Node.js 18 or newer.
Install the client:
npm install 10xgraph-clientCreate a file named client.ts:
import { TenxGraphClient, Message } from "10xgraph-client";
const client = new TenxGraphClient({
baseUrl: "http://127.0.0.1:8000",
});
async function main() {
// Send one user message on thread quickstart-3
const result = await client.invoke(
[Message.text_message("Where is order 1042?")],
{
config: { thread_id: "quickstart-3" },
recursion_limit: 10,
}
);
console.log(result.messages.at(-1)?.text());
}
main();Run it with a TypeScript runner such as tsx:
npx tsx client.tsThe client wraps the HTTP request, parses the response, and returns a typed object.
Stream the agent response
To see the agent reasoning in real time, use stream() instead of invoke(). It returns an async iterable of stream events:
import { TenxGraphClient, Message, StreamEventType } from "10xgraph-client";
const client = new TenxGraphClient({ baseUrl: "http://127.0.0.1:8000" });
async function main() {
const stream = client.stream(
[Message.text_message("Refund order 1042 for 59.00")],
{ config: { thread_id: "quickstart-4" } }
);
// Print each message chunk as it arrives
for await (const chunk of stream) {
if (chunk.event === StreamEventType.MESSAGE && chunk.message) {
process.stdout.write(chunk.message.text());
}
}
}
main();Authentication
If your API server has authentication enabled, pass auth to the client constructor:
import { TenxGraphClient, bearerAuth } from "10xgraph-client";
const client = new TenxGraphClient({
baseUrl: "http://127.0.0.1:8000",
auth: bearerAuth("your-api-token"),
});The client also exports basicAuth(username, password) and headerAuth(name, value) for other auth schemes.
Understanding the request and response
When you call /v1/graph/invoke, you send a GraphInputSchema and get back a GraphInvokeOutputSchema.
Request fields (POST body):
| Field | Type | Default | Meaning |
|---|---|---|---|
messages |
Message[] | [] |
List of messages. Required unless resume is set. |
config |
object | null | Run settings. thread_id selects which thread (conversation) to run. |
initial_state |
object | null | Initial values for custom state fields. |
recursion_limit |
number | 25 | Maximum steps the graph can take. Allowed: 1 to 100. |
response_granularity |
string | low |
Response detail level: low (messages only), partial (messages, context and summary), or full (messages and full state). |
resume |
any | null | Answer for a paused thread. Send it (even as null) only to resume an interrupted run. |
Response fields (in data):
| Field | Type | Meaning |
|---|---|---|
messages |
Message[] | Final message list after the run. |
state |
object | Full state (only when response_granularity is full). |
context |
Message[] | Context window (only when response_granularity is partial). |
summary |
string | Conversation summary (only when response_granularity is partial). |
meta |
object | Custom metadata from your agent. |
Message format: A message is an object with role (user, assistant, or tool) and content (a list of typed blocks). A text block is {"type": "text", "text": "..."}. Images, audio, and documents use other types (see Send media).
Next steps
You now have a working agent, API server, and TypeScript client. Here is what to read next:
Frequently asked questions
- Do I need ReactAgent, or should I write a StateGraph myself?
- Start with ReactAgent. It builds the standard reason-and-act graph for you (one agent node, one tool node, a conditional edge between them) and returns a normal compiled graph. Move to StateGraph when you need custom routing or several agents.
- Can I use OpenAI or Anthropic instead of Google?
- Yes. Change the model string and the provider argument, and install the matching extra. The graph, the tools and the API server stay the same.
- Which Node.js version does the TypeScript client need?
- Node.js 18 or newer. Install the client with npm and point TenxGraphClient at the baseUrl of your running 10xgraph api server.
- How do I authenticate the TypeScript client?
- Pass an auth option to the TenxGraphClient constructor, for example bearerAuth("your-token"). The client also exports basicAuth(username, password) and headerAuth(name, value).
- Why does the second curl call remember the first one?
- Both calls send the same thread_id, and the compiled graph has a checkpointer. The checkpointer stores the conversation per thread, so the next call on that thread continues it.