Metadata-Version: 2.4
Name: diffledger
Version: 0.1.0
Summary: Diff-triggered retrieval for compression-resilient agent sessions
Project-URL: Homepage, https://github.com/benolenick/context-ledger
Project-URL: Paper, https://github.com/benolenick/context-ledger/blob/main/paper/context_ledger_paper_v2.md
License: MIT
Keywords: agent,compression,context,llm,memory,rag
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Provides-Extra: consolidation
Requires-Dist: anthropic>=0.25; extra == 'consolidation'
Description-Content-Type: text/markdown

# diffledger

**Diff-triggered retrieval for compression-resilient agent sessions.**

Standard RAG fires on the wrong trigger after a context compression event. It asks "what is similar to this message?" The right question is "what is the user referring to that the agent no longer holds?" These fail differently — especially on anaphoric references like "how does it work again" or "the first thing we set up."

diffledger maintains an external ledger of what the agent has been told this session. Before each message, it extracts the concepts being referenced, diffs them against the ledger, and fills any gaps via vector retrieval before the agent responds.

**29% → 96%** on post-compression turns (5 constructed cases, keyword-presence scoring).

## Install

```bash
pip install diffledger
```

Requires [Ollama](https://ollama.ai) with `qwen3:1.7b`:
```bash
ollama pull qwen3:1.7b
```

## CLI

```bash
diffledger status                          # show current ledger state
diffledger inject "how does it work again" # run gap detection for a message
diffledger crunch                          # simulate a compression event
diffledger reset                           # clear the ledger
diffledger extract "your message here"     # dry-run concept extraction
```

## Python API

```python
from diffledger import Ledger, detect_gaps, fill_gaps, detect_crunch

ledger = Ledger("my-session")

# after a compression event
if detect_crunch():
    ledger.mark_all_stale()

# for each incoming message
gaps   = detect_gaps("how does it work again", ledger)
fills  = fill_gaps(gaps, ledger)   # queries your vector store, injects results
ledger.advance_turn()
ledger.save()

# fills is a list of {"concept": str, "text": str}
# inject these into the agent's context before it sees the message
```

## Environment variables

| Variable | Default | Description |
|---|---|---|
| `DIFFLEDGER_SESSION` | `"default"` | Session ID for ledger file |
| `DIFFLEDGER_HYPHAE_URL` | `http://127.0.0.1:8100` | Vector store `/recall` endpoint |
| `DIFFLEDGER_OLLAMA_URL` | `http://127.0.0.1:11434` | Ollama endpoint |
| `DIFFLEDGER_MODEL` | `qwen3:1.7b` | Concept extraction model |
| `DIFFLEDGER_STALE_TURNS` | `30` | Turns before an entry is re-injectable |
| `DIFFLEDGER_GAP_MAX` | `2` | Max gap fills per turn |
| `DIFFLEDGER_JACCARD` | `0.50` | Jaccard threshold for fuzzy concept matching |

## How it works

1. **Ledger**: a JSON file per session tracking which concepts have been injected, at which turn, and with what reference count.
2. **Extraction**: `qwen3:1.7b` via Ollama reads the incoming message and extracts named concepts (~1s on CPU).
3. **Diff**: extracted concepts are checked against the live ledger entries. Anything missing is a gap.
4. **Fill**: each gap triggers a vector search against your retrieval backend. Results are injected into the prompt and recorded in the ledger.
5. **Crunch handling**: when a compression event is detected (via transcript scan or manual call), all entries are marked stale. Post-crunch turns use **resolution mode**: the model picks from a numbered list of stale concepts, handling ordinals and pronouns ("the first thing", "how does it work") that carry no embedding signal.

## Vector store interface

diffledger expects a `/recall` POST endpoint:
```
POST /recall
{"query": "concept name", "top_k": 1}
→ {"results": [{"text": "..."}]}
```

Compatible with [Hyphae](https://github.com/benolenick/hyphae) and anything with the same interface.

## Paper

[Diff, Don't Retrieve: A Context Ledger for Compression-Resilient Agent Sessions](https://github.com/benolenick/context-ledger/blob/main/paper/context_ledger_paper_v2.md)

## License

MIT
