LangGraph: hosted tools and human approval
Call an Anlyon hosted action from a LangGraph node, keep provider credentials outside the graph, and recover by invocation ID.
LangGraph manages graph execution. Anlyon executes the named external action. As of 2026-09-30, a LangGraph interrupt() runs in your process and does not hold credentials. It does not approve a pending Anlyon invocation.
Prerequisites
Complete the quickstart in a test environment. Define the hosted template action refund-order with charge and amount inputs and require approval. Configure the provider secret using an operator credential outside the graph. The graph runtime needs an Anlyon agent credential with actions:invoke and actions:read. It does not need the provider key or approvals:decide.
The following is a node integration pattern, not a complete persisted graph application. Install anlyon in your application and supply the prepared action. The host application must persist the operation key with the business request before running this node.
import os
from typing import TypedDict
from anlyon import Client
class RefundState(TypedDict):
charge: str
amount: int
operation_key: str
invocation_id: str
status: str
def submit_refund(state: RefundState) -> dict[str, str]:
with Client(api_key=os.environ["ANLYON_AGENT_KEY"]) as agent:
result = agent.actions.invoke(
"refund-order",
{"charge": state["charge"], "amount": state["amount"]},
idempotency_key=state["operation_key"],
)
if result.data is None:
raise RuntimeError("No invocation returned; recover with the same request identity")
return {
"invocation_id": result.data["id"],
"status": result.data["status"],
}
def read_refund(state: RefundState) -> dict[str, str]:
with Client(api_key=os.environ["ANLYON_AGENT_KEY"]) as agent:
result = agent.actions.invocation(state["invocation_id"])
if result.data is None:
raise RuntimeError("Invocation unavailable; do not submit a new refund")
return {"status": result.data["status"]}
Register these functions as nodes in your StateGraph. Initialize the state from trusted application data, use a durable checkpointer for restart recovery, and persist the returned invocation ID. After submission, return pending work to your application or resume at the read node. Do not repeatedly submit new operations while waiting.
Approval is not completion
| Status | Application behavior |
|---|---|
pending_approval |
Show the pending review. An authorized person decides in Anlyon |
running |
Read the same invocation later |
succeeded |
For this template action, report the recorded provider HTTP result |
unknown |
Request reconciliation. Do not generate another refund |
failed |
Inspect evidence and use the documented explicit retry path if appropriate |
denied or expired |
Stop. Do not resubmit to bypass the decision |
A resume payload such as approved: true is not an Anlyon decision. Authenticate reviewers in the application and keep decision credentials out of the graph. Never let model output supply reviewer authority.
Restarts and interrupts
Check LangGraph’s interrupt documentation for which code runs again when a graph resumes. Keep external writes out of code that runs before an interrupt. Once submitted, prefer reading the saved invocation. If submission was interrupted before its ID was persisted, the same template request and idempotency key recover its current state while the invocation exists.
For a new execution after a confirmed failure, follow explicit retry and resolution, including retryOf. Do not replace an unknown operation’s key to force a new call.
Governed actions
For an action with an adapter or a declaration, pass operation_key and retain effectId. An adapter action takes the adapter’s input schema. Follow governed-effect recovery, not the template invocation resolution path. Anlyon’s current beta is not for critical production workloads.
See framework and architecture choices, approval policies, and idempotency.

