Skip to main content

Prerequisites

Install and initialize the TypeScript SDK or Python SDK. The examples use that client as fw. Set OPENAI_API_KEY for the OpenAI model examples.

Add the callback handler

LangGraph.js can use the same LangChain callback handler through graph invocation config.
graph and state belong to the LangGraph application. Shadow-mode overrides for this handler are on the TypeScript SDK page.

Expected result

Callback handlers enable model-start, tool-start, and tool-end checks by default; retriever hooks are opt-in. They inspect the latest user message on model start without rescanning prior tool messages. Each classification has a distinct metadata.silmaril.request_id; the LangChain run ID is correlation metadata at metadata.langgraph.run_id. Pass conversationId (TypeScript) or conversation_id (Python) to the handler when the backend should correlate a sequence; the SDK sends it as metadata.conversationId. In Block mode, callbacks raise a blocking exception. Shadow and Warn report the decision and let execution continue.

Deep Agents

Deep Agents creates its own subagent graphs. Use the protected constructor to cover the root, its general-purpose subagent, and declarative subagents. In the examples below, supply your initialized fw, configured chat model, tools array or list, and a caller-generated conversationId or conversation_id for this agent sequence.
For a compiled subagent, use the verified factory before creating the parent:
For a compiled subagent, use createProtectedCompiledSubagent in TypeScript or create_protected_compiled_subagent in Python. These helpers install Silmaril middleware before compiling the graph. Pass the returned spec through protectedCompiledSubagents or protected_compiled_subagents, respectively. The parent constructor verifies the exact graph and Firewall client and rejects an arbitrary compiled runnable. Root custom middleware does not automatically reach every subagent. Classification errors allow execution by default. Set silmaril: { failOpen: false } in TypeScript or middleware_options={"fail_open": False} in Python when execution requires a successful classification. The middleware checks user input before model use, tool calls before execution, tool results before the next model call, and non-streamed model output before the graph consumes it. In Block mode, denied tool calls and results become a fixed safe tool message with the original call ID. The agent may choose an allowed alternative; repeated denials end with a fixed safe response. Denied model output is replaced before it enters graph messages. Shadow and Warn report decisions without replacing content. Already emitted streaming text cannot be recalled. TypeScript SDK 0.7.3 applies the repeated-denial cap only in effective Block mode. Genuine earlier Block denials remain counted, but do not halt Warn or Shadow continuation. For direct classification, Python, TypeScript, and Go accept typed governance context on single and batch calls. Batch calls remain stateless. Each item keeps its own metadata, including metadata.conversationId, and current Cascade treats each input independently and neither reads nor updates conversation history. Giving items the same conversationId does not connect them into a sequence. See TypeScript, Python, and Go. In effective Block mode, Python and Go raise a blocking error for a malicious prediction or explicit governance block. TypeScript direct calls return a result: inspect prediction and governance.action, then deny the action in your code when either indicates a block. Responses from older backends can omit governance. See the Go SDK for its direct classification API.