@betterdb/agent-memory (Python)
betterdb-agent-memory is the long-term memory tier for AI agents, backed by
Valkey Search. It is the Python port of
@betterdb/agent-memory
and pairs with betterdb-agent-cache
(the short-term llm/tool/session cache tiers).
Where the cache tiers are exact-match and ephemeral, the memory tier is semantic and durable: it embeds content, stores it in an HNSW vector index, and recalls it by meaning with a composite score that blends similarity, recency (half-life decay), and importance.
See it live in BetterDB Monitor
BetterDB Monitor auto-discovers every betterdb-agent-memory instance on your Valkey - zero configuration, the library already registers itself - and turns its stats into live dashboards:
- AI Cache & Memory - hit rate, cost saved, evictions, and index size across all your caches and memory stores, with history.
- AI Traces - OpenTelemetry waterfalls for each request, correlated with live Valkey state to explain every cache hit and miss.
Run it self-hosted (docker run -p 3001:3001 betterdb/monitor), or use BetterDB Cloud - which can also provision a managed, TLS-enabled Valkey instance with the Search module in one click - exactly what this library needs.
Features
- Semantic recall — KNN vector search with a tunable composite score.
- Scoping — memories carry
thread_id/agent_id/namespace/tags; recall, forget, and consolidation all filter by scope. - Reinforcement — recalled memories bump
last_accessed_at+access_count, so frequently-used memories stay recallable. - Capacity eviction —
max_items_per_scopeevicts the lowest-scoring memories (importance + recency) once a scope exceeds its cap. - Consolidation — fold a set of older/low-importance memories into a single summary memory.
- Live config — re-read
recall.threshold/ weights /halfLifeSeconds/maxItemsPerScopefrom a Valkey hash without a restart. - Observability — OpenTelemetry spans + Prometheus metrics.
- Discovery — registers a marker so BetterDB Monitor can enumerate the tier.
Installation
pip install betterdb-agent-memory
You also need a Valkey server with the Search module loaded (e.g.
valkey/valkey-bundle) and the valkey
async client.
Quick start
import valkey.asyncio as valkey
from betterdb_agent_memory import AgentMemory, AgentMemoryOptions
async def embed(text: str) -> list[float]:
# Replace with a real embedding model (OpenAI, sentence-transformers, ...).
...
async def main() -> None:
client = valkey.Valkey(host="localhost", port=6379)
agent = AgentMemory(AgentMemoryOptions(client=client, embed_fn=embed))
await agent.initialize()
await agent.memory.remember(
"User prefers dark mode and concise answers.",
importance=0.8,
tags=["preference", "ui"],
thread_id="t1",
)
hits = await agent.memory.recall("what UI settings does the user like?", thread_id="t1")
for hit in hits:
print(hit.score, hit.item.content)
# Short-term cache tiers remain available:
# agent.llm, agent.tool, agent.session
await agent.close()
Using the memory tier standalone
If you only need the memory tier, construct MemoryStore directly:
from betterdb_agent_memory import MemoryStore
store = MemoryStore(client=client, name="myapp", embed_fn=embed)
await store.ensure_index()
await store.remember("hello", thread_id="t1")
hits = await store.recall("hi", thread_id="t1")
API
MemoryStore
await ensure_index()— create the{name}:mem:idxHNSW index if absent.await remember(content, *, importance=None, tags=None, source=None, ttl=None, thread_id=None, agent_id=None, namespace=None) -> strawait recall(query, *, k=None, threshold=None, tags=None, weights=None, reinforce=None, thread_id=None, agent_id=None, namespace=None) -> list[MemoryHit]await forget(id) -> boolawait forget_by_scope(*, thread_id=None, agent_id=None, namespace=None, tags=None) -> intawait consolidate(*, mode, summarize=None, extract_facts=None, older_than_seconds=None, max_importance=None, delete_sources=None, summary_importance=None, fact_importance=None, tags=None, thread_id=None, agent_id=None, namespace=None) -> ConsolidateResult | ConsolidateFactsResult- one method, two explicit modes; select candidates by scope, tags,older_than_seconds, ormax_importance:mode="summary"- accumulation.summarize(items)folds the candidates into one new digest memory, optionally deleting the sources. Lossy - use it to compress volume. Items are passed oldest→newest with their dates, so the summarizer can respect recency. It does not resolve updates; for a corpus where later statements supersede earlier ones, usemode="facts"or you may get conflated/stale summaries.mode="facts"- updates/supersession. Anextract_facts(items)LLM seam returnslist[Fact](subject,statement, optionaldate, optionaltombstone); facts are reconciled bysubject(newestdatewins, tombstones drop a subject), written additively keeping the source memories (recall preserved), and each fact's date is preserved in its content. Reconciliation is stateful across runs: a re-run over unchanged sources rewrites nothing (idempotent), a newer statement supersedes (deletes) the prior fact memory, and a tombstone retracts it. A tombstone that matches no live fact is surfaced inunmatched_tombstones(and a metric) rather than silently dropped. The result reportscreated,deleted,facts, andunmatched_tombstones; prior fact memories are excluded from the source scan so a run never re-distills its own output. Customize the factsourcetag / default importance via the store'sconsolidationoption (ConsolidationConfig(fact_source=..., fact_importance=...)).
await consolidate_facts(*, extract_facts, ...) -> ConsolidateFactsResult- deprecated thin alias forconsolidate(mode="facts", ...); prefer the merged method.current_config() -> MemoryConfigSnapshotawait refresh_config()await ensure_discovery_ready()await close()
AgentMemory
The batteries-included facade: an AgentCache (llm/tool/session) plus a
MemoryStore sharing one client and name. initialize() creates the index and
readies discovery for both tiers; close() tears both down.
Scoring
composite_score = w.similarity * similarity + w.recency * recency + w.importance * importance
where similarity = 1 - distance / 2 (cosine distance → 0..1) and recency
decays with a true half-life (0.5 at one half_life_seconds). Default weights
are {similarity: 0.6, recency: 0.25, importance: 0.15}, default threshold
0.33 (similarity ≥ ~0.835 — loose enough to admit mainstream embedding models,
whose correct matches can land near ~0.3), default half-life 7 days. When a recall
returns zero hits but the nearest candidate sat just past the threshold
(within 2×), the store flags a near-miss (a one-time warning + the
..._recall_near_miss_total metric) so a mis-set threshold surfaces instead of
silently yielding nothing.
License
MIT
Metadata
Release files for betterdb-agent-memory 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| betterdb_agent_memory-0.7.0.tar.gz | 66.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| betterdb_agent_memory-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 105.0 kB
Release files / betterdb_agent_memory-0.7.0.tar.gz
| Download URL | betterdb_agent_memory-0.7.0.tar.gz |
|---|---|
| Size | 66.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
74373fde851912a5ce2908195606435707e50d305ea7541f26716c2ce6ffb2fc
|
|
BLAKE2b-256 checksum How to use checksums |
e93dd3339167d7f3703ddd6577e2f4aee1a43bba9d63b04ed3697649a11ca607
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.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 Jul 23, 2026.
Transparency logRelease files / betterdb_agent_memory-0.7.0-py3-none-any.whl
| Download URL | betterdb_agent_memory-0.7.0-py3-none-any.whl |
|---|---|
| Size | 38.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a4ece7b5c4e3408d326f6b7fdd4f6d0e0b231cf5a92d42852a24993913886945
|
|
BLAKE2b-256 checksum How to use checksums |
65330475e85de3554bb4643b3ed998b20b8094f9917a036b9078ac35d0dee509
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.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 Jul 23, 2026.
Transparency log