DSPM — memory for LLM conversations that keeps your constraints
Dynamic Semantic Patch Memory, by Dhruv Dubey · Python package: dspm-memory · Repo: Kernl
pip install dspm-memory
Long chats drop the rule from turn 3 that everything else depends on. DSPM turns each turn into typed patches, protects constraints, decisions and revised values, and renders them under a fixed token budget. Training-free: no fine-tuning, just prompts and Python rules. Works with any OpenAI-compatible endpoint.
Headline numbers (v0.2.1, verified on live data)
24-turn fintech conversation, 648 raw tokens, 3 revisions tracked (JWT 15→30min, S3 1h→15min, CPU 70→60%), real Groq LLM:
| Budget | CRR | TRR | Context tokens |
|---|---|---|---|
| 60 | 100% | 93.1% | 45 |
| 100 | 100% | 81.9% | 117 |
| 250 | 100% | 59.3% | 264 |
| 400 | 100% | 36.1% | 414 |
| 800 | 100% | 0.6% | 644 |
CRR = Critical Retention Rate. TRR = Token Reduction Rate (conversation-based). CRR = 100% is a structural guarantee, verified across budgets 59 to 5000 tokens.
Offline benchmark (v0.1.17, 7 hand-authored 40-turn dialogues, same model for extraction and judging):
| Budget | TRR | CRR |
|---|---|---|
| 150 | 66.8% | 100% |
| 250 | 82.8% | 100% |
| 400 | 72.4% | 100% |
Recognition: Poster accepted at CAICS 2026 (Indo-US Workshop on AI & Cybersecurity), organized by IISc Bengaluru and Argonne National Laboratory, funded by the U.S. Department of State.
Savings depend on conversation length. Short conversations compress very little. Recommended budget: 250–400 for best readability + compression balance.
Who it's for: agents and chatbots whose long conversations must not lose a constraint, a decision, or a revised value (support bots, coding agents, assistants that remember a user's hard rules across sessions).
Who it's not for: summarizing or answering questions over documents. See Known Limitations.
Quickstart
from openai import OpenAI
from dspm import DSPMMemory
llm = OpenAI(api_key="sk-...") # any OpenAI-compatible endpoint
mem = DSPMMemory(budget=250, llm_client=llm, model="gpt-4o-mini")
mem.add_turn("user", "Always return JSON. Use POST /v1/items. Max fee 0.5%.")
mem.add_turn("assistant", "Webhook timeout set to 30 seconds.")
# Later: the webhook timeout is revised
mem.add_turn("user", "Webhook timeout updated to 10 seconds.")
print(mem.get_context(query="What must the contract remember?"))
print(mem.stats)
Illustrative output (exact wording varies by extraction model):
[DEC] Webhook timeout updated to 10 seconds (was 30)
[CON] Max fee 0.5%
[DEC] Use POST /v1/items
[CON] Always return JSON output.
No paid key? Use a free Groq tier or a local Ollama model:
# Groq (free tier available at console.groq.com)
llm = OpenAI(base_url="https://api.groq.com/openai/v1", api_key="gsk_...")
# Ollama (local, no key needed)
llm = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
# Together AI
llm = OpenAI(base_url="https://api.together.xyz/v1", api_key="...")
Why it's different
- Constraints and decisions are protected.
[CON]and[DEC]patches are never dropped by dedup, fusion or pruning, and are selected first at render time. - Revisions supersede old values. Change a value mid-chat and the current one survives, with the lineage baked in as
(was X). - Memory persists across chats. Save at the end of one chat, load at the start of the next, with no API cost for recall.
- Fixed budget, predictable cost. You set the token budget; the rendered context stays inside it.
- Universal CRR guarantee. CRR = 100% at any budget above the floor. Below the floor, raises
BudgetTooSmallErrorinstead of silently dropping criticals.
Universal CRR guarantee
from dspm.engine import DSPMEngine, BudgetTooSmallError
# Find the minimum safe budget for N critical patches
floor = DSPMEngine.min_budget_for_crr(22) # → 59 tokens for 22 criticals
# Below the floor, raises a clear error instead of silently dropping
try:
mem.set_budget(10)
mem.get_context()
except BudgetTooSmallError as e:
print(e) # Budget 10 is below the absolute floor (59 tokens for 22 criticals)
5-stage compression ladder, which escalates only as needed:
| Stage | When triggered | What it does |
|---|---|---|
| 1. Numeric-trim | Always | Keeps numbers, units, acronyms; drops filler words |
| 2. Iterative-trim | Budget pressure | Trims the longest critical one word at a time |
| 3. Ultra-compact | Tight budget | Reduces each critical to key numbers only |
| 4. Dense-merge | Very tight | Merges all criticals into one line |
| 5. Ultra-dense | Extreme | Single line of space-separated tokens |
Persistence: memory across chats and sessions
# Chat 1 — Monday
mem = DSPMMemory(budget=250, llm_client=llm, model="gpt-4o-mini")
mem.add_turn("user", "Building a budgeting app. Hard rules: must work offline, deadline Oct 20.")
mem.save("user_42_memory.json")
# Chat 2 — Thursday, new process
mem2 = DSPMMemory(budget=250, llm_client=llm, model="gpt-4o-mini")
mem2.load("user_42_memory.json")
mem2.get_context(query="What were my hard rules?")
# → [CON] must work offline
# → [CON] deadline Oct 20 ← recalled from Chat 1, zero API cost
mem2.add_turn("user", "The deadline moved to November 5.")
# → Oct 20 is superseded. November 5 replaces it.
Persistence safety: writes are atomic, and load(path, strict=True) raises CorruptNotebookError on corrupt files.
How it works
Raw conversation (648 tokens, 24 turns)
↓
Semantic extraction → 39 patches, 20 critical
↓
7-stage compression pipeline
↓
Compressed context (264 tokens @ budget 250) — 100% of criticals selected
Pipeline: fingerprint dedup → slot fusion → delta encoding → causal pruning → utility scoring → shadow selection → adaptive budget allocation.
Patch types
| Type | Tag | Critical? | Description |
|---|---|---|---|
| constraint | [CON] |
Yes | Non-negotiable requirements (deadlines, limits, compliance rules) |
| decision | [DEC] |
Yes | Speaker value directives ("set timeout to 30 seconds") |
| code | [CODE] |
No | Implementation detail |
| equation | [EQ] |
No | Formulas and numeric results |
| entity | [ENT] |
No | Named things |
| structure | [STR] |
No | Schemas and workflows |
Regulatory and compliance requirements (PCI-DSS, HIPAA, GDPR, SOC 2, ISO 27001, FedRAMP) are classified as constraints by the extractor prompt.
Stats and metrics
print(mem.stats)
| Key | Description |
|---|---|
turns |
Number of conversation turns added |
total_patches |
Active patches in the store |
critical_total |
Constraint + decision patches (protected) |
critical_selected |
Critical patches delivered in the last get_context() |
crr |
Critical Retention Rate: % of extracted criticals delivered |
trr_by_conversation |
Token Reduction Rate, conversation-based. Use this for savings |
budget |
Current token budget |
conversation_tokens |
Raw turn text fed to add_turn() |
patch_tokens |
Tokens in the extracted patches |
context_tokens |
Tokens in the delivered context |
llm_calls |
Total LLM calls made |
llm_errors |
Total LLM errors |
Testing
Run offline tests (no API key needed):
python tests/verify_crr.py
python tests/test_universal_budgets.py
Run live tests (API key required):
# Windows PowerShell
$env:GROQ_API_KEY = "gsk_..."
python tests/small_live_test_budgets.py # 10-turn REST API conversation
python tests/large_live_test_budgets.py # 24-turn fintech + 3 revisions
See tests/README.md for expected output and reproduction instructions.
API reference
DSPMMemory(budget, llm_client, model)
| Parameter | Type | Default | Description |
|---|---|---|---|
budget |
int | 400 | Maximum tokens in the compressed output |
llm_client |
OpenAI-compatible | None | Any sync OpenAI-compatible client |
model |
str | "gpt-4o-mini" |
Model used for patch extraction |
Methods
| Method | Description |
|---|---|
add_turn(role, text) |
Add a conversation turn. Returns extracted patches. |
get_context(query="") |
Returns compressed context string. |
set_budget(budget) |
Update the token budget. |
save(path) |
Persist memory to JSON (atomic write). |
load(path, strict=False) |
Load a saved memory file. |
reset() |
Clear all memory. |
Properties
| Property | Description |
|---|---|
memory.stats |
Dict with token counts, patch counts, CRR, TRR and LLM telemetry |
memory.critical_patches |
List of critical patches in memory |
memory.all_patches |
List of every patch in memory |
Advanced API
from dspm import DSPMEngine, extract_patches, merge_into_memory, SemanticPatch
from dspm.engine import BudgetTooSmallError
Repository layout
.
├── dspm/
│ ├── __init__.py # public API
│ ├── patch.py # SemanticPatch structure
│ ├── engine.py # DSPMEngine v4.5 — 7-stage pipeline + CRR guarantee
│ ├── extractor.py # LLM-based patch extraction
│ ├── client.py # LLMClient + provider auto-detection
│ └── memory.py # DSPMMemory high-level wrapper
├── tests/
│ ├── verify_crr.py # quick CRR check
│ ├── test_universal_budgets.py # offline sweep, 17 budgets
│ ├── small_live_test_budgets.py # 10-turn live test
│ ├── large_live_test_budgets.py # 24-turn live test with 3 revisions
│ └── README.md # reproduction instructions
├── pyproject.toml
├── README.md
└── LICENSE
Known Limitations
- Small budgets under-deliver readability. At budget 60, context is trimmed to bare numbers. CRR = 100% but human readability suffers. Recommended minimum for readable output: budget 100.
- Per-turn extraction cap. The extraction prompt allows at most 1 constraint and 1 decision per turn. If a single message states several hard rules, split them across turns.
- Revision matching is rule-based. Numeric, day-name and acronym-bridged revisions are handled. Other free-text revisions may coexist with stale values.
- Extraction depends on the LLM. Quality varies by model and domain. A constraint the extractor misses is not protected.
- No async support yet.
add_turn()is synchronous. Planned for v0.3.0. - Document QA. DSPM is designed for conversations, not document compression.
- Self-judged offline benchmark. Same model family for extraction and judging; not independently replicated. Run live tests with your own data using
tests/large_live_test_budgets.py.
Paper
DSPM: A Critical-Retention Approach to Long-Context Memory Compression for LLM Conversations Dhruv Dubey, 2026 · Zenodo: 10.5281/zenodo.19438636
Recognition: Poster accepted at CAICS 2026 (Indo-US Workshop on AI & Cybersecurity), jointly organized by IISc Bengaluru and Argonne National Laboratory, funded by the U.S. Department of State.
Feedback
Found a case where a constraint or revision is lost? Open an issue with the conversation and the budget you used.
License
MIT © 2026 Dhruv Dubey
Metadata
Release files for dspm-memory 0.2.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 | Provenance | Actions |
|---|---|---|---|---|
| dspm_memory-0.2.1.tar.gz | 30.7 kB | Without provenance | Details for dspm_memory-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| dspm_memory-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for dspm_memory-0.2.1-py3-none-any.whl |
Total release size: 54.8 kB
Release files / dspm_memory-0.2.1.tar.gz
| Download URL | dspm_memory-0.2.1.tar.gz |
|---|---|
| Size | 30.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
65809ba253f12170a806b9ab6a7067479ddd0e01e77b3abfcc919b3cb787bed0
|
|
BLAKE2b-256 checksum How to use checksums |
d934e722c0fe33a290d29862b1ce147c91dafafcb0e873214aee5716a009c204
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.8
|
Release files / dspm_memory-0.2.1-py3-none-any.whl
| Download URL | dspm_memory-0.2.1-py3-none-any.whl |
|---|---|
| Size | 24.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2f663c07cb376b8bcf8066a56a0d221c5e8bd85a55908ebc5255d1b82b3e4961
|
|
BLAKE2b-256 checksum How to use checksums |
c76bbacb7ee0c13d678ed8530aa29b955278659fd990fc335856a52f3eaf0eeb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.8
|
Security for dspm-memory 0.2.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.