Skip to main content

langchain-fathom

A coherence read for LangChain agents, as an agent middleware.

A long-running agent loses coherence with its own decisions. It renames a field at one step, then writes the old name at a later one. It marks a record done that it never wrote. The run reports success, and the contradiction ships. langchain-fathom watches the agent run and, when it finishes, names the step where a later action contradicts an earlier commitment.

The middleware observes the agent and does not change what it does. It maps the tool calls in the message history to a committed-state op stream, sends that stream to the Fathom read, and reports the findings. The read is deterministic and needs no model access.

Install

pip install langchain-fathom

Use

from langchain.agents import create_agent
from langchain_fathom import FathomMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[...],
    middleware=[FathomMiddleware()],
)

result = agent.invoke({"messages": [...]})

By default the middleware logs any findings through the fathom logger. Two other modes fit a test suite or a pipeline.

FathomMiddleware(on_finding="raise")   # raise FathomCoherenceError when a run is not coherent
FathomMiddleware(on_finding="store")   # put the verdict on agent state under the "fathom" key

Under store, the verdict arrives on the result.

result = agent.invoke({"messages": [...]})
verdict = result["fathom"]
verdict["coherent"], verdict["findings"]

The middleware declares that key in its own state schema, so a graph that carries a state schema of its own keeps the verdict rather than dropping it. Version 0.1.0 declared nothing, and an orchestrator such as a deepagents agent dropped the verdict before the caller saw it.

If the run is a rename or a migration, tell the read which token replaced which, so it also reports records left on the old value at the end.

FathomMiddleware(supersede=[("guest_id", "customer_id")])

What it finds

Finding The agent...
stale_reference acts on a record it already removed or renamed away
superseded_value writes a value it already replaced
residual ends the run with a record still carrying a value it replaced elsewhere
duplicate_commit adds an entity a collection already holds
post_commit_mutation changes a record after committing it

A coherent run returns coherent and the middleware reports nothing else.

Agents that delegate

The middleware reads the calls of the agent it rides. An orchestrator that hands work to sub-agents runs each sub-agent as its own agent with its own message history, so an orchestrator-level middleware sees the delegation and the orchestrator's own tools, and not what the sub-agents did. Give each sub-agent its own FathomMiddleware to cover the whole run. On one deepagents research run we measured, the orchestrator's middleware alone returned 3 of the 9 findings a trace across every sub-agent returned.

Your own tool names

The read knows common state-writing tool names. For tools with your own names, map them once and pass the file.

FathomMiddleware(mapping_path="tools.json")
{"save_decision": {"op": "set", "kind": "decision", "key": "topic", "value": "text"},
 "confirm_booking": {"op": "commit", "kind": "flight", "key": "booking"}}

The repair

FathomMiddleware watches. FathomRepairMiddleware acts. It sits between the model and its tools, sends the actions the model just proposed together with what the run has already committed, and gets back one of three decisions.

from langchain_fathom import FathomRepairMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[...],
    middleware=[FathomRepairMiddleware()],
)

On proceed every proposed action is consistent with what the agent already committed and nothing changes. On filter the agent keeps its own consistent alternatives and the contradicting calls never reach the tools. On reground none of them survive, so the committed facts go back in front of the model as a system-role message and the model is asked again, once by default.

The repair needs a free key. Get one with fathom key you@example.com from the fathom-read package and set FATHOM_API_KEY, or pass key=. The middleware checks for it when you construct it, so a run fails at setup rather than twenty steps in. The two reads stay free without a key.

This middleware changes what your agent does, which is why it carries its own class rather than a flag on the read. Two settings cover the cases where that matters.

FathomRepairMiddleware(on_error="raise")  # stop the run rather than skip the repair
FathomRepairMiddleware(max_reasks=0)      # never re-ask; filter and proceed only

on_error defaults to "proceed", so an unreachable service or a spent daily limit logs a warning and lets the agent act on its own proposal. A coherence repair should not take down a running agent. Pass "raise" when you are measuring a before-and-after, since a silently skipped repair would contaminate the result.

Every repaired step appends an entry to agent state under fathom_repair, carrying the decision, the proposals evaluated, the finding kinds of anything dropped, and the re-asks spent. That is the log a run needs to report what the repair did.

result = agent.invoke({"messages": [...]})
for step in result["fathom_repair"]:
    print(step["decision"], step["dropped"])

What it costs, in two places. A repair call counts double against the 2,000 calls a day a free key carries. A reground decision spends one extra model call, billed by your own provider. A model turn with no tool calls, and a tool the mapping does not name, cost nothing and pass through untouched.

What we measured

On DBOS's own Hacker News research agent, vendored unchanged and run on gpt-4o-mini through OpenRouter across five topics at ten iterations each, the agent as published repeated 14 of 50 searches and re-read 42 percent of the threads it fetched. With the repair in front of the one step where it proposes its next queries, repeats fell to 0 of 50, re-reads to 12 percent, and distinct threads covered rose 35 percent at the same model and the same iteration count. Across 45 follow-up steps the repair let 23 through untouched, filtered 21, and regrounded 1. Every run, the trace, and the command sit in the coherence census.

Those numbers come from an agent that hands out its proposed next queries explicitly. Your mileage depends on how much of your agent's state the tool mapping can see.

MIT licensed.

Metadata

Release files for langchain-fathom 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for langchain-fathom 0.2.0
File Size Uploaded
langchain_fathom-0.2.0.tar.gz 18.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for langchain-fathom 0.2.0
File Interpreter ABI Platform
langchain_fathom-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 32.5 kB

Release files / langchain_fathom-0.2.0.tar.gz

Download URL langchain_fathom-0.2.0.tar.gz
Size 18.1 kB
Tags Source
SHA-256 checksum
How to use checksums
afa293eb762e7147c4a174796f37d97f8c9ce692dbc276b9bf64f72ffc20ad2b
BLAKE2b-256 checksum
How to use checksums
4257d7715e713c8247490ea9c11002b1b7786b1910be10d71802c0f4bc395c12
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release files / langchain_fathom-0.2.0-py3-none-any.whl

Download URL langchain_fathom-0.2.0-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f399075d9c3edaf2ffc9549c6e072e2c601f993e2c9899a1f1ca9c844ab0c66e
BLAKE2b-256 checksum
How to use checksums
1946442f8fbd6944cc4ac90963b86ea05aae7fcd0600414ff1864af35cd30913
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.0

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page