Skip to content

LangChain / LangGraph

Full working examples:

Auto-patch (simplest)

python
import gavrun

gavrun.configure(
    api_key="gavrun_live_...",
    agent_manager_url="https://api.gavrun.ai",
    auto_patch=True,   # default — patches BaseTool.invoke and BaseChatModel.invoke
)

# Every @tool call is now governed automatically
from langchain_core.tools import tool

@tool
def delete_order(order_id: str) -> str:
    """Delete an order from the database."""
    return db.delete(order_id)

Manual guard

For tools that need approval polling, guard manually to control execution flow:

python
from langchain_core.tools import tool
from gavrun.client import GavrunDecisionDenied

@tool
def refund_order(order_id: str) -> str:
    """Refund an order."""
    client = gavrun.get_client()

    result = client.guard(
        action="refund_order",
        execute=lambda: None,   # deferred
        tools=["refund_order"],
        prompt=f"Refund order {order_id}",
    )

    if result.denied:
        raise GavrunDecisionDenied("Refund denied by governance policy.")

    if result.requires_human_review:
        approval_id = result.decision.get("approval_id")
        while True:
            status = client.get_approval_status(approval_id=approval_id)
            if status["status"] == "approved":
                return process_refund(order_id)
            elif status["status"] == "denied":
                raise GavrunDecisionDenied("Refund denied by reviewer.")
            time.sleep(3)

    return process_refund(order_id)

LangGraph StateGraph

python
from langgraph.graph import StateGraph
from langgraph.prebuilt import ToolNode

graph = StateGraph(State)
graph.add_node("agent", agent_node)
graph.add_node("tools", ToolNode(tools, handle_tool_errors=True))
# ToolNode catches GavrunDecisionDenied and passes the message to the LLM

Use handle_tool_errors=True so denied tool calls become tool-error messages the LLM can read rather than crashing the graph.

Apache 2.0 License