Skip to content

Protect a LangGraph agent

Install with the LangGraph extra:

pip install "nullrun[langgraph]" langgraph langchain-openai

nullrun.init() auto-instruments LangGraph — it attaches NullRunCallback to any compiled graph once init() runs. No manual callback wiring needed (the old from nullrun.instrumentation.langgraph import NullRunCallback import still works but is discouraged).

from langchain_openai import ChatOpenAI
from langgraph.graph import END, MessagesState, StateGraph

from nullrun import init

init(api_key="nr_live_...")

llm = ChatOpenAI(model="gpt-4o-mini")

def chat(state: MessagesState):
    return {"messages": [llm.invoke(state["messages"])]}

# `StateGraph(MessagesState)` replaces the deprecated
# `langgraph.graph.MessageGraph` (removed in langgraph 1.0).
graph = StateGraph(MessagesState)
graph.add_node("chat", chat)
graph.add_edge("chat", END)
graph.set_entry_point("chat")
app = graph.compile()

result = app.invoke([{"role": "user", "content": "Hi"}])

Every LLM call inside the graph is now cost-attributed and gated by your workspace policy. The same auto-instrumentation path works for any LangChain Runnable and most LangGraph node types.

Manual wrapper (advanced)

If you need to attach the callback manually — e.g. inside a library that re-compiles graphs after init() ran — the canonical wrapper is:

from nullrun.toolbox.langgraph import wrapper

app = wrapper(graph.compile())

This is preferred over NullRunCallback() because it also wires the control-plane kill/pause subscription for the wrapped graph.

See also