Skip to main content
This example is a support agent built with LangGraph and a LangChain chat model. The graph loops between the model and its tools. Before it runs a refund call, the tools node calls interrupt(): AgentOS asks a person, and the graph continues with the approval, the edited arguments or the rejection, in whichever container answers the resume. The SDK’s langgraph adapter does the work: the graph’s checkpoints live in run state instead of a database of your own, an interrupt() becomes one hold, and the resume continues the graph with Command(resume=…). See Agent frameworks.
Tested with langgraph 1.2.15, langchain-openai 1.7.3 and Python 3.13, using the conformance kit: 22 checks passed, including an approved, an edited and a rejected refund.

The bundle

The SDK wheel goes in the bundle’s vendor/ folder and is installed with its langgraph extra; see SDKs.

How the model is wired

chat_model() builds a LangChain ChatOpenAI from the invocation that is running (agentos.current()): the gateway’s base URL, the model from config.models.main, the run token in the x-agentos-run-token header, and HTTP clients from inv.llm.httpx_client() that never send the token anywhere else. The model name reaches the gateway exactly as written in agentos.yaml (anthropic/claude-sonnet-4-5). The graph’s structure is built once, at module level. The model and the compiled graph are made per invocation, because the token belongs to one invocation and the checkpointer belongs to one run: builder.compile(checkpointer=langgraph.checkpointer()) in the handler. When a guardrail blocks a model call, ChatOpenAI raises an error that carries the gateway’s answer. agentos.guardrail_block(error) finds the block in it, and raising that block fails the run with blocked_by_guardrail and the guardrail’s message. See Guardrails.

How the approval works

1

The graph interrupts

The model asks for refund. The tools node calls interrupt() with a value shaped like an AgentOS ask (intent, actions, items), so the adapter asks it as it is: one item per refund call, its id the tool call id, its data the call’s arguments, with approve, edit and reject. The graph’s checkpoints are kept in run state.
2

A person decides

The run is held until someone decides in the Review queue or through the Holds API. An edit changes the call’s arguments, for example a smaller amount.
3

The graph continues

On the resume the adapter loads the checkpoints and continues the graph. interrupt() returns the decision (items, each with id, action, data and comment). The node runs approved and edited calls (an edit with the reviewer’s data), answers a rejected one with the reviewer’s comment, and the model answers the customer.
LangGraph runs a node again from its start when it resumes, so keep code before interrupt() free of side effects. Here the node only reads the tool calls before it asks; every tool runs after the decision.

Run it

1

Zip and deploy

Put the SDK wheel in vendor/ (see SDKs), set config.models.main to a model from your Models page, then zip the folder’s contents and upload them:
2

Ask for a refund

The run is held: the refund waits in the Review queue. Decide it there, or through the Holds API. The item’s id is the model’s tool call id: read it from the hold (GET …/holds/h_12). An edit carries the item’s full data:

Test it before you deploy

The conformance kit builds the bundle and runs it against a mock platform whose model follows call:<tool> {arguments} in a message, so these cases drive the tools and every decision without a real model:
conformance.yaml

Things to know

  • Checkpoints travel in run state. A value there can be at most 1 MiB, and the checkpoints hold the whole message history; keep very long conversations short.
  • One interrupt per step, if it is a whole ask. An interrupt() whose value is shaped like an ask must be the only interrupt of its step. Other values become one item each, and each interrupt() then returns its own item’s decision.

Next steps

Human approvals

Everything an ask can carry: several items, details, files, an expiry.

More frameworks

The same agent in other frameworks and languages.