Skip to content

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 ChatOpenAI or 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.