Audit log for LangChain agents
Add the middleware to a LangChain agent, or wrap the tools you hand it, and every tool call is written as a signed, chained record: a decision before the tool runs and an outcome after it. Python and TypeScript.
Full steps: Python quickstart, TypeScript quickstart. What recording covers and where it stops: Tool coverage.
Python: the middleware #
langchain-signafaide is a LangChain agent middleware. Add it to create_agent and every tool call the agent makes is recorded, without wrapping each tool.
pip install langchain-signafaidefrom langchain.agents import create_agent
from langchain_signafaide import SignafaideMiddleware
tools = [lookup_order, refund]
agent = create_agent(
model,
tools=tools,
middleware=[SignafaideMiddleware(agent="support-bot", tools=tools)],
)agentnames the record chain: one name per running agent instance in production.toolsdeclares every tool the agent can call as recorded, sosignafaide verifycan say that all of them are covered. Without it, a tool is declared when it is first called.strict=Trueruns a tool only once the witness has confirmed its record;store_content=Truealso sends inputs and outputs, encrypted.- It works with
invokeandainvoke. A tool that raises is recorded with its error, and the error is raised unchanged.
Use the middleware or wrap_tools for an agent's tools, not both, or each call is recorded twice. The package needs Python 3.10 or later and LangChain 1.x; its source is in the SDK repository.
Wrapping the tools #
One call around the tools you already have. wrap_tools takes @tool functions and BaseTool instances; wrapTools takes tool(), DynamicStructuredTool and StructuredTool instances. The copies still work with bind_tools and bindTools, and LangChain is not a dependency of the SDK.
Python
import signafaide
from langchain.agents import create_agent
tools = signafaide.wrap_tools(
[lookup_order, refund], agent="support-bot"
)
agent = create_agent(model, tools=tools)TypeScript
import { wrapTools } from "signafaide";
import { createAgent } from "langchain";
const tools = wrapTools([lookupOrder, refund], {
agent: "support-bot",
});
const agent = createAgent({ model, tools });A verify run #
Run the agent once, then signafaide verify (npx signafaide verify in a TypeScript project). This is a local run in which the agent called refund once: three records for the tool list, one decision and one outcome.
$ signafaide verify
local state: /home/dev/support-agent/.signafaide
1. Envelope schema PASS 5 records
2. Record hashes NOT CHECKED 0 records; 5 not yet shipped (no receipt); nothing co-signed yet
3. Client signatures PASS 5 records
4. Agent chains PASS 5 records
5. Merkle proofs NOT CHECKED 0 records; nothing co-signed yet
6. Batch hashes and signatures NOT CHECKED 0 batches; nothing co-signed yet
7. Batch chain NOT CHECKED 0 batches; nothing co-signed yet
8. Signed heads NOT CHECKED 0 heads; nothing co-signed yet
9. drand rounds NOT CHECKED 0 rounds
10. Anchors NOT CHECKED 0 anchors; local state holds no anchors
11. OpenTimestamps NOT CHECKED 0 proofs
12. Content hashes PASS 5 records
coverage: _pending/nokey/support-bot: all 2 declared tools are recorded
checked here: signatures, chain links and content hashes of all 5 records, using this machine's keys
co-signature, public timestamp: not yet. Run `signafaide init` to send hashes, or self-host (SIGNAFAIDE_URL)
PASS: 4 of 12 checks passed, 8 not checked (nothing co-signed yet)What is recorded and what is not #
- Recorded. Every tool call that goes through the middleware, and every
invokeof a wrapped tool (andainvokein Python), including the calls the model asks for: the tool name and input, then the tool's own return value or its error. Inputs and outputs stay in.signafaide/on your machine. Nothing is sent until you runsignafaide init, and then only salted hashes. - Not recorded. A tool you did not wrap, and a call your code makes around the agent or the wrapped copy, leaves no record. Give the full list to
declare_toolsordeclareToolsandsignafaide verifynames the tools that are not recorded. - Evidence, not certification. Records prove integrity and timing, not that a decision was right. The eight checks not run above need a witness: the co-signature and the public timestamp come after
signafaide init.
Next: install, wrap, verify and send hashes, step by step. LangChain quickstart