LangGraph
Connect LangGraph interrupts to durable ActionBox decisions without moving graph checkpoint state into ActionBox.
LangGraph owns graph checkpoints and paused-run state. ActionBox supplies the durable human request and typed response; your graph driver owns the side effect and its credentials.
Ownership boundary
| Concern | Owner |
|---|---|
| Graph state, checkpoint, and resume | LangGraph checkpointer |
Interrupt ID and stable thread_id | LangGraph |
| Reviewer inbox and typed response | ActionBox |
| The approved operation and its credentials | Your graph or tool adapter |
ActionBox does not replace the LangGraph checkpointer and does not execute the operation for you. Use a durable checkpointer when a human response can outlive the worker that first surfaced the interrupt.
Supported flow
- Run the graph with a stable
thread_idand a checkpointer. - Call
interrupt(...)inside the node with a bounded, JSON-serializable review payload. Do not create the ActionBox Action inside the node: LangGraph can re-execute the node when it resumes. - Let the graph driver observe
result["__interrupt__"], then create one ActionBox Action per surfaced interrupt using a stable idempotency key. - Wait for the typed response. A boolean response is the envelope
{"type":"boolean","value":true}orfalse. - Map the response to the value your node expects and resume the same
checkpoint with
Command(resume=...). - Run the side effect only after the resumed graph confirms approval. If you need an execution record, report its real result to ActionBox after it finishes.
The core resume helper looks like this after your driver has received a pending interrupt and resolved its ActionBox request:
from langgraph.types import Command
async def resume_interrupt(graph, pending, response, thread_id: str):
approved = (
isinstance(response, dict)
and response.get("type") == "boolean"
and response.get("value") is True
)
return await graph.ainvoke(
Command(resume={pending.id: {"approved": approved}}),
config={"configurable": {"thread_id": thread_id}},
)Install the public SDKs in the environment that runs the graph:
python -m pip install actionbox-sdk langgraphKeep the reviewed payload complete
Remove credentials and secret-bearing arguments before creating the Action. Reject an oversized payload instead of silently truncating it; the person must see the operation that the graph will resume.
Do not serialize framework-owned checkpoint state into an Action payload. Use a
stable external ID, the interrupt ID, and bounded context blocks to correlate
the Action with the graph run. Hash the stable thread_id and interrupt ID into
the idempotency key so a retried driver recovers the same human request.
When multiple interrupts surface, resolve every item and pass an interrupt-ID
map to Command(resume=...); do not assume the first item is the only one.
Treat rejection, expiry, timeout, and a malformed response as approved=False.
For a complete walkthrough, see LangGraph human-in-the-loop approval.