EQTY LabDocs

LangGraph

guardian_agent.langgraph: describe_graph, which describes a hand-built LangGraph graph as an agent that signs its own requests.

View as Markdown

Hand-built LangGraph graphs, as agents that sign their own requests.

Give describe_graph the function that builds your graph and the chat models it uses. It calls that function once, with each model routed through the proxy as the agent, describes the graph it built, and returns it:

python
from guardian_agent.langgraph import describe_graph

def build(llm):
    graph = StateGraph(MessagesState)
    ...  # your nodes call llm
    return graph.compile()

app = describe_graph(build, name="inventory", models={"llm": ChatOpenAI(...)})

Needs langgraph, which the langchain extra brings.

Functions:

  • describe_graph – Your LangGraph graph, built with routed models, described, as the agent name.

langgraph.describe_graph

python
describe_graph(build: Callable[..., Any], *, name: str, models: Mapping[str, BaseChatModel | str], tools: Sequence[BaseTool | Callable[..., Any] | dict[str, Any]] = (), instructions: Instruction | Sequence[Instruction] | None = None, description: str | None = None, version: str | None = None, sources: Iterable[Source] = (), exclude: Sequence[str] = (), guardian: Guardian | None = None) -> CompiledStateGraph[Any, Any, Any, Any]

Your LangGraph graph, built with routed models, described, as the agent name.

build is called once, with each of models routed through the proxy as the agent and passed by name, so every call its nodes make is signed as the agent. The definition records the models, the graph’s nodes and edges (a subgraph’s too, named outer:inner), each node’s and router’s code with the values it captured, and the tools of each ToolNode. Each request is checked as it’s built: one sending settings, or offering a tool, the definition doesn’t describe is refused before it’s sent.

Example:

python
def build(llm: ChatOpenAI):
    model = llm.bind_tools([inventory])

    def answer(state: MessagesState):
        return {"messages": [model.invoke(state["messages"])]}

    graph = StateGraph(MessagesState)
    graph.add_node("answer", answer)
    graph.add_edge(START, "answer")
    return graph.compile()

app = describe_graph(
    build, name="inventory", models={"llm": ChatOpenAI(model="gpt-4.1")}
)

Parameters:

  • build (Callable[..., Any]) – Builds your graph from the routed models, given by name, and returns it compiled, or as a StateGraph to compile as it is.
  • name (str) – The agent’s name, as enrolled with viper agent add.
  • models (Mapping[str, BaseChatModel | str]) – Each of build’s parameters that takes a chat model, and the model: a chat model, or a "provider:model" name built with init_chat_model (as create_agent takes one); in the definition in this order.
  • tools (Sequence[BaseTool | Callable[..., Any] | dict[str, Any]]) – Tools the graph’s models are offered besides those in its ToolNodes.
  • instructions (Instruction | Sequence[Instruction] | None) – Text for a system prompt, or a list of prompts, as guardian_agent.Definition takes them.
  • description (str | None) – What the agent is for.
  • version (str | None) – Your own label for this version of the agent.
  • sources (Iterable[Source]) – Source files to fingerprint, such as a module whose constants your nodes read.
  • exclude (Sequence[str]) – JSON Pointers to fields to leave out of the definition, such as /extensions/langgraph/nodes/answer for a node holding a value that can’t be recorded.
  • guardian (Guardian | None) – The proxy to use; Guardian() (VIPER_PROXY_URL) by default.

Returns:

  • CompiledStateGraph[Any, Any, Any, Any] – The compiled graph, whose models are routed as the agent. agent_of(graph) is the SDK’s agent.

Raises:

  • TypeError – models is empty, names a parameter build doesn’t take, or holds something bind() can’t route; build returned something other than a LangGraph graph; or a node or router holds a chat model that isn’t one of the routed models.
  • ValueError – A router’s destinations can’t be seen (give it a Literal return type or a path_map); a node holds a value that can’t be recorded; or a model sends a setting no definition can record.
  • DefinitionInvalid – The definition breaks a rule.
  • DefinitionContainsSecret – It holds what looks like a credential.