LangGraph
Check what each node of your graph reads, says and does, and pause the graph when a tool call needs a person.
Before you start
- If your model node calls a LangChain chat model, agentfox.auto() already checks that call and its tool calls. Use this page to add checks on retrieval and on tool nodes.
Install
bash pip install "agentfox[langgraph]"Wrap your nodes
graph.py from agentfox.frameworks.langgraph import AgentFoxGuard guard = AgentFoxGuard(agent="research-bot", intent="Answer from the knowledge base.") @guard.retrieval_node # checks retrieved text for planted instructions def retrieve(state): ... @guard.model_node # checks the messages going in and the reply coming out def model(state): ... @guard.tool_node(tool="tickets.create") # checks the call before the body runs def file_ticket(state): ...Add the guard's key to your state
The guard keeps the trace id and what earlier nodes read under
__agentfox__. Declare it, or LangGraph drops it between nodes.python class State(TypedDict, total=False): messages: Annotated[list, add_messages] __agentfox__: Annotated[dict, lambda old, new: {**(old or {}), **(new or {})}]Give the agent its tool
The first run registers the agent and refuses
tickets.create, because nobody has said what it does or that the agent may call it.bash agentfox declare tool tickets.create --impact write agentfox permit grant research-bot tickets.create --yesAsk a person first, if you want
Grant with
--requires-approvaland the graph pauses at that node. Compile it with a checkpointer, then resume once someone approves in Approvals:python out = graph.invoke(inputs, config) # paused: out["__interrupt__"] out = graph.invoke(Command(resume={"approved": True}), config)
What happens on a refusal
| Verdict | What the node does |
|---|---|
| Block | Raises agentfox.PolicyViolation. The node body does not run. |
| Needs approval | Calls LangGraph's interrupt() with the approval_id and the reason. Pass raise_on_escalate=False to keep going instead. |
| Redact | A model node's reply is rewritten with the personal data or secret hidden. |
If something goes wrong
| You see | Do this |
|---|---|
capability.denied | Grant the tool to the agent (step 4). |
| A limit refuses with "this call passed None" | The tool node found no arguments. Put the model's tool call in state["messages"], or pass arguments=. |
| A paused run cannot be resumed | Compile with a checkpointer and pass the same thread_id. |
| No trace id in the result | Declare __agentfox__ in your state (step 3). |