LangGraph Compatibility
This tutorial validates ReplayLab with a LangGraph StateGraph workflow.
It is a compatibility scenario, not a native LangGraph adapter.
The goal is to prove that provider calls made inside graph nodes can still be captured, replayed, compared, viewed, and converted into pytest provider replay guards through the normal ReplayLab workflow.
Why This Matters
Graph frameworks often hide provider calls behind nodes, compiled graphs, and invoke(...) calls.
ReplayLab should not need to understand the graph runtime to capture supported provider boundaries.
It only needs startup provider instrumentation and a capture scope around the graph invocation.
This scenario follows the documented LangGraph shape: define a StateGraph, add nodes, connect
START and END, compile the graph, and run graph.invoke(...).
Run The Scenario
Run:
python scripts/run_scenario.py run langgraph-local --keep-workspace
Expected ending:
ReplayLab scenario passed.
Scenario: langgraph-local
Tier: loopback
Boundaries: 2
Providers: requests, openai
ReplayLab creates a clean temporary virtual environment, installs the current checkout plus
langgraph, requests, openai, and pytest, starts loopback HTTP and OpenAI Responses endpoints
only for capture, then stops both endpoints before replay and generated pytest.
App Shape
The generated scenario app uses startup instrumentation and normal provider calls inside graph nodes:
import openai
import replaylab
import requests
from langgraph.graph import END, START, StateGraph
from replaylab import CapturePayloadPolicy
handle = replaylab.init(
project_name="langgraph-local",
auto_patch_integrations="auto",
capture_payload_policy=CapturePayloadPolicy.FULL,
)
def fetch_ticket(state):
response = requests.get(f"{HTTP_BASE_URL}/provider/tickets/{state['ticket_id']}", timeout=5)
response.raise_for_status()
return {**state, "provider": response.json()["provider"]}
def classify_ticket(state):
client = openai.OpenAI(base_url=f"{OPENAI_BASE_URL}/v1", api_key="scenario-key")
response = client.responses.create(
model="gpt-5-mini",
input=f"Classify ticket {state['ticket_id']} from {state['provider']}.",
)
return {**state, "priority": response.output_text.strip()}
graph = StateGraph(dict)
graph.add_node("fetch_ticket", fetch_ticket)
graph.add_node("classify_ticket", classify_ticket)
graph.add_edge(START, "fetch_ticket")
graph.add_edge("fetch_ticket", "classify_ticket")
graph.add_edge("classify_ticket", END)
compiled = graph.compile()
with handle.capture("langgraph_ticket_graph"):
result = compiled.invoke({"ticket_id": "123", "provider": "", "priority": ""})
ReplayLab captures the provider calls made by the node functions. The graph itself stays normal.
When safe callsite metadata is available, the local app groups the provider boundaries under inferred
graph nodes such as Graph node fetch_ticket and Graph node classify_ticket. The breadcrumbs store
module/function-style identifiers only; they do not store raw arguments, local variables, source
bodies, raw command arguments, secrets, or absolute paths.
What ReplayLab Captures
The scenario expects two full-payload provider boundaries in sequence:
1. provider=requests operation=GET
2. provider=openai resource=openai.responses
Replay succeeds with both loopback providers stopped. That proves the graph invocation is served from the capsule rather than calling live dependencies.
In replaylab app, a provider-backed LangGraph trace should show:
Project run
Workflow step
Graph node fetch_ticket
API call
Graph node classify_ticket
LLM call
Provider-free LangGraph runs are different. ReplayLab may still record run/step metadata, but the
local app labels those captures as No replayable evidence and disables replay, live experiment, and
generated-guard actions until the workflow crosses a supported provider boundary.
What Is Not Yet Supported
- LangChain
ChatOpenAIor Chat Completions model wrappers. - Streaming graph/model calls.
- LangGraph-native semantic trace visualization or graph-edge replay semantics beyond provider-backed inferred grouping.
- Framework-specific node or edge replay semantics beyond provider boundary replay.
Those remain future work. The current guarantee is provider-level capture/replay for supported
requests and OpenAI Responses calls inside LangGraph nodes.