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

Terminal
pip install "10xgraph[google-genai]" 10xgraph-api
export GOOGLE_API_KEY="your-gemini-api-key"

OpenAI

Terminal
pip install "10xgraph[openai]" 10xgraph-api
export OPENAI_API_KEY="your-openai-api-key"

Anthropic

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

  1. 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())

    ReactAgent builds 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 a CompiledGraph, the object you run and the server loads.

  2. Test the agent locally

    Create run.py next to agent.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.py

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

  3. Create the server config file

    The API server finds your graph by reading 10xgraph.json. Create this file in the same directory as agent.py:

    10xgraph.json
    {
      "agent": "agent:app",
      "env": ".env",
      "auth": null
    }

    The agent field points to the app variable in the agent module. The server loads and compiles it once at startup.

  4. Start the API server

    Terminal
    10xgraph api

    Expected output:

    Text
    INFO: Uvicorn running on http://127.0.0.1:8000

    The server listens on 127.0.0.1:8000 by default. Use --host 0.0.0.0 to accept connections from other machines and --port to 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.

  5. 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) and metadata (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:

Terminal
npm install 10xgraph-client

Create a file named client.ts:

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:

Terminal
npx tsx client.ts

The 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:

stream.ts
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:

TypeScript
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.
Last updated for v0.10.0Edit this page on GitHubReport an issue