> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inference.net/llms.txt
> Use this file to discover all available pages before exploring further.

# LangGraph Traces

> Trace LangGraph workflows while preserving graph and node parent-child spans.

Catalyst uses the LangChain callback path for LangGraph workflows. A compiled
graph emits a graph-level CHAIN span and node-level CHAIN spans parented under
the graph run.

If the graph is the implementation of a product agent, wrap `graph.invoke()`
with `agentSpan()` / `agent_span()` and set a stable `agent.id` so executions
group in the Agents dashboard.

## Install

<CodeGroup>
  <Metadata text="integrations/traces/langgraph-install-typescript" />

  ```bash TypeScript theme={"system"}
  bun add @inference/tracing @langchain/core @langchain/langgraph
  ```

  <Metadata text="integrations/traces/langgraph-install-python" />

  ```bash Python theme={"system"}
  pip install 'inference-catalyst-tracing[langgraph]'
  ```
</CodeGroup>

## TypeScript State Graph

<Metadata text="integrations/traces/langgraph-state-ts" />

```typescript TypeScript theme={"system"}
import { agentSpan, setup } from "@inference/tracing";
import * as CallbackManagerModule from "@langchain/core/callbacks/manager";
import { Annotation, END, START, StateGraph } from "@langchain/langgraph";

const tracing = await setup({
  serviceName: "counter-graph",
  modules: { langchainCallbacksManager: CallbackManagerModule },
});

const State = Annotation.Root({
  count: Annotation<number>({
    reducer: (_left, right) => right,
    default: () => 0,
  }),
});

const graph = new StateGraph(State)
  .addNode("increment", (state) => ({ count: state.count + 1 }))
  .addNode("double", (state) => ({ count: state.count * 2 }))
  .addEdge(START, "increment")
  .addEdge("increment", "double")
  .addEdge("double", END)
  .compile();

const result = await agentSpan(
  {
    agentId: "counter-graph-agent",
    agentName: "Counter Graph Agent",
    spanName: "counter-graph.run",
    sessionId: "conversation-counter-1",
    role: "workflow",
    system: "langgraph",
  },
  async (span) => {
    const input = { count: 1 };
    span.setInput(input);
    const output = await graph.invoke(input);
    span.setOutput(output);
    return output;
  },
);
console.log(result);

await tracing.shutdown();
```

## Python State Graph

<Metadata text="integrations/traces/langgraph-state-python" />

```python Python theme={"system"}
from inference_catalyst_tracing import agent_span, setup
from langgraph.graph import END, START, StateGraph
from typing_extensions import TypedDict

class GraphState(TypedDict):
    count: int

tracing = setup(service_name="counter-graph")

def increment(state: GraphState) -> GraphState:
    return {"count": state["count"] + 1}

def double(state: GraphState) -> GraphState:
    return {"count": state["count"] * 2}

builder = StateGraph(GraphState)
builder.add_node("increment", increment)
builder.add_node("double", double)
builder.add_edge(START, "increment")
builder.add_edge("increment", "double")
builder.add_edge("double", END)

graph = builder.compile()
with agent_span(
    tracing.tracer,
    agent_id="counter-graph-agent",
    agent_name="Counter Graph Agent",
    span_name="counter-graph.run",
    session_id="conversation-counter-1",
    agent_role="workflow",
    system="langgraph",
) as span:
    input_state = {"count": 1}
    span.set_input(input_state)
    result = graph.invoke(input_state)
    span.set_output(result)
    print(result)

tracing.shutdown()
```

## What To Look For

* A graph span named `LangGraph`
* Node spans named after graph nodes
* `openinference.span.kind=CHAIN` on graph and node spans
* Node spans parented under the graph span
* An outer AGENT span with your stable `agent.id` when you wrap agent-style
  graph invocations

For agent-style graphs, model and tool spans created inside node functions
appear below the active graph or node context.
