Prerequisites
Install and initialize the TypeScript SDK or Python SDK. The examples use that client asfw. Set OPENAI_API_KEY for the OpenAI model examples.
Add the callback handler
- TypeScript
- Python
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 distinctmetadata.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 initializedfw, configured chat model, tools
array or list, and a caller-generated conversationId or conversation_id for
this agent sequence.
- TypeScript
- Python
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.