langchain-fairseal
LangSmith tells you what the agent did. FairSeal proves it actually happened — on-chain.
langchain-fairseal is a LangChain callback handler that notarizes every tool call
on FairSeal: a cryptographic receipt layer anchored to Base mainnet.
Receipts are independently verifiable at verify.fairseal.io
by any party without trusting LangChain, AWS, or your infrastructure.
Quick Start
pip install langchain-fairseal
import os
from langchain_fairseal import FairSealCallbackHandler
# Handler: notarize every tool call, write receipt to LangSmith spans
handler = FairSealCallbackHandler(
api_key=os.environ["FAIRSEAL_NOTARY_API_KEY"], # fsn_... key
agent_id="my-agent/prod-v1", # stable agent identifier
sample_rate=1.0, # 100% notarized; 0.1 = 10% sampled
fail_open=True, # notarize failures never block agent
attach_to_langsmith=True, # write receipt_id to LangSmith spans
)
# Pass to any LangChain chain / agent / tool via config
result = my_chain.invoke(
{"input": "What is the weather in Taipei?"},
config={"callbacks": [handler]},
)
# Inspect receipts
print(handler.summary())
# {'total_notarized': 2, 'successful': 2, 'failed': 0, 'receipt_ids': ['nr_...', 'nr_...']}
last = handler.last_receipt
print(f"Latest receipt: {last.receipt_id}")
print(f"Verify: {last.verify_url}")
Architecture
LangChain Agent / Chain
│
▼
on_tool_start() ──────────────────────────────────────────────────────┐
│ │
│ sha256(inputs) → input_hash │
│ (raw inputs NEVER leave agent runtime) │
▼ │
[tool executes] │
│ │
▼ │
on_tool_end() │
│ │
│ sha256(output) → decision_hash │
│ │
▼ │
POST api.fairseal.io/v1/notarize │
{ schema: "agent_decision", │
metadata: { agent_id, input_hash, decision_hash, decided_at } } │
│ │
▼ │
receipt_id = "nr_..." ◄──────────────────────────────────────────────┘
│
├──► LangSmith run span metadata (fairseal_receipt_id)
└──► handler.receipts [in-memory list]
verify.fairseal.io/nr_... ← independent verification, no LangChain/AWS trust
Extension Point Note (LangChain 0.3.30)
The LangChain/AgentCore Payments blog post (2026-08-18) refers to an
AgentMiddleware.wrap_tool_call interface. This class does not exist in LangChain
0.3.30 / langchain-core 0.3.86 (confirmed by import inspection).
This package uses the stable, documented callback system:
BaseCallbackHandler.on_tool_start— capture tool name + input hashBaseCallbackHandler.on_tool_end— capture output hash + fire notarizeBaseCallbackHandler.on_tool_error— fail-open cleanup + error notarize
When/if AgentMiddleware ships as a stable API, the handler can be refactored
to use it without changing the public interface.
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str | env FAIRSEAL_NOTARY_API_KEY |
FairSeal notary key (fsn_...) |
agent_id |
str | env FAIRSEAL_AGENT_ID or "langchain-agent" |
Stable agent identifier |
sample_rate |
float | 1.0 |
Fraction of tool calls to notarize (0.0–1.0) |
fail_open |
bool | True |
If True, notarize errors never block the agent |
attach_to_langsmith |
bool | True |
Write receipt to LangSmith run span metadata |
model |
str | None | Optional model tag in receipt metadata |
operator |
str | None | Optional operator tag in receipt metadata |
Environment Variables
FAIRSEAL_NOTARY_API_KEY=fsn_... # Primary auth key
FAIRSEAL_API_KEY=fsn_... # Fallback (also accepted)
FAIRSEAL_AGENT_ID=my-agent/prod # Default agent_id
FAIRSEAL_API_URL=https://api.fairseal.io # Override API base (for testing)
FAIRSEAL_TIMEOUT_S=10 # HTTP timeout in seconds
LANGCHAIN_API_KEY=ls_... # For LangSmith span attachment
PII Safety
Only SHA-256 hashes of tool inputs and outputs are transmitted to FairSeal.
Raw payload text never leaves the agent runtime. This is enforced in
langchain_fairseal.notarize.sha256_of() and tested in tests/test_notarize.py.
LangSmith Integration
When attach_to_langsmith=True and LANGCHAIN_API_KEY is set, each successful
receipt is written to the LangSmith run span as:
{
"fairseal_receipt_id": "nr_...",
"fairseal_verify_url": "https://verify.fairseal.io/nr_...",
"fairseal_tool_name": "search_tool",
"fairseal_agent_id": "my-agent/prod-v1"
}
Visible in the LangSmith trace UI under run metadata.
Development
pip install -e ".[dev]"
pytest -v # unit tests (mocked HTTP)
pytest tests/test_e2e.py -v # e2e (requires FAIRSEAL_NOTARY_API_KEY)
Positioning
| Concern | LangSmith | FairSeal |
|---|---|---|
| What did the agent do? | ✅ Full trace | ❌ Not designed for this |
| Prove it actually happened? | ❌ Internal log only | ✅ On-chain, third-party verifiable |
| Third-party verification? | ❌ Requires LangChain trust | ✅ Independent, no trust needed |
| Real-time observability? | ✅ | ❌ Batch anchoring (~2 min) |
Use both: LangSmith for debugging and observability, FairSeal for compliance and non-repudiation.
License
MIT © 2026 FairSeal
Metadata
Release files for langchain-fairseal 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| langchain_fairseal-0.1.1.tar.gz | 18.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langchain_fairseal-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.3 kB
Release files / langchain_fairseal-0.1.1.tar.gz
| Download URL | langchain_fairseal-0.1.1.tar.gz |
|---|---|
| Size | 18.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bbd64d85b7ec6785965e33bee8bcb87439f593116e1ed2e562b0a6d066f49c84
|
|
BLAKE2b-256 checksum How to use checksums |
c62a06f9d60f6fcb37e43e129218de73d80bcc7ad62f297d347dcdfceb51d6da
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / langchain_fairseal-0.1.1-py3-none-any.whl
| Download URL | langchain_fairseal-0.1.1-py3-none-any.whl |
|---|---|
| Size | 13.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bc9aefd7d8a2e00b0660ae8b393420817d3c414ac87c4687768c7fd79ec60944
|
|
BLAKE2b-256 checksum How to use checksums |
e97aea01bf357f40079e40672789ca5a5e22b58a281aa2285e77f1a125176299
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|