Here's the query that breaks most of them:
Stored memory: "What payment methods do you support?" → *"We accept
Visa, Mastercard, and PayPal."*>
User asks: "Does your platform support two-factor authentication?"
A retrieve-and-inject pipeline finds the payment memory (it shares the word support), it's the top hit, and the answer about Visa and Mastercard goes into the prompt — or worse, straight back to the user. The memory system did exactly what it was built to do: retrieve. Nobody asked it whether the retrieval should be used.
I know this failure mode intimately because an early version of my own scoring had it. The top hit was normalized to a perfect 1.0, so any shared word replayed a stored answer verbatim at confidence 1.0. A question about two-factor auth got the PayPal answer, confidently. I fixed it, wrote adversarial cases into the eval suite so it can't come back — and then realized the fix is the product.
Memory needs a decision layer, not just a retriever
Retrieval answers "what did we store about this?". An agent needs a second question answered: "should I use it, and how much should I trust it?"
That's what Agent Memory
does. Every resolve() returns one of four explicit actions:
| Action | Meaning | When | |---|---|---| | replay | Return the stored answer verbatim | Exact/near-exact repeat, high trust | | restore | Inject the memory as context, let the LLM adapt it | Paraphrase, adjacent question | | verify | Surface the memory but validate before reuse | Stale or flagged facts | | none | Ignore memory entirely | Weak or coincidental matches |
The score behind the action combines similarity, recency, stored confidence,
and usage — and crucially, the non-similarity factors can lower it. A
memory stored with confidence=0.1 never replays verbatim, even on an exact
query match; it restores as context instead. A fact that keeps being
replayed doesn't get artificially fresher; it ages into verify.
And it shows its work:
>>> print(memory.resolve("Does the platform support 2FA?").explain())
action: none
confidence: 0.68
reasons:
- keyword match
- below restore threshold
scores:
semantic_score: 0.60
recency_score: 1.00
confidence_score: 1.00
policy_score: 0.68
When your agent answers wrongly, you can see *why the memory layer decided what it decided* — which is more than most of us can say about our RAG pipelines.
The numbers (reproducible, no synthetic baselines)
The eval suite includes the trap cases above. Current results, reproducible
with agent-memory eval from the repo:
- 25/25 decision-quality cases on both backends — lexical SQLite
- ~12ms per
resolve()at 5,000 memories — a local SQLite file, no
- The semantic extra is ONNX MiniLM via fastembed. No torch download.
Try it in 60 seconds
from agent_memory import Memory, MemoryActionmemory = Memory(persist_dir=".agent_memory")
memory.remember("What payment methods do you support?",
"We accept Visa, Mastercard, and PayPal.")
decision = memory.resolve("Does the platform support two-factor auth?")
assert decision.action == MemoryAction.NONE # the whole point
Or as an MCP server for Cursor / Claude Code — one config block:
{
"mcpServers": {
"agent-memory": {
"command": "agent-memory-mcp",
"env": { "AGENT_MEMORY_DIR": "~/.agent_memory" }
}
}
}
The repo is github.com/TheProdSDE/agent-memory-sdk
(pip install agent-memory-sdk). The adversarial eval dataset lives in
benchmarks/datasets/decision_traps.json — and I take PRs that add trap
cases the system fails. Breaking it is the most useful contribution you can
make.