@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
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file betterdb_agent_memory-0.7.0.tar.gz.
File metadata
- Download URL: betterdb_agent_memory-0.7.0.tar.gz
- Upload date:
- Size: 66.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74373fde851912a5ce2908195606435707e50d305ea7541f26716c2ce6ffb2fc
|
|
| MD5 |
cfd33296a5de1a74d40d865924cac3d4
|
|
| BLAKE2b-256 |
e93dd3339167d7f3703ddd6577e2f4aee1a43bba9d63b04ed3697649a11ca607
|
Provenance
The following attestation bundles were made for betterdb_agent_memory-0.7.0.tar.gz:
Publisher:
agent-memory-py-release.yml on BetterDB-inc/monitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
betterdb_agent_memory-0.7.0.tar.gz -
Subject digest:
74373fde851912a5ce2908195606435707e50d305ea7541f26716c2ce6ffb2fc - Sigstore transparency entry: 2226097169
- Sigstore integration time:
-
Permalink:
BetterDB-inc/monitor@69d8073b2bd1810e8621612abe509220987104d5 -
Branch / Tag:
refs/tags/agent-memory-py-v0.7.0 - Owner: https://github.com/BetterDB-inc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
agent-memory-py-release.yml@69d8073b2bd1810e8621612abe509220987104d5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file betterdb_agent_memory-0.7.0-py3-none-any.whl.
File metadata
- Download URL: betterdb_agent_memory-0.7.0-py3-none-any.whl
- Upload date:
- Size: 38.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4ece7b5c4e3408d326f6b7fdd4f6d0e0b231cf5a92d42852a24993913886945
|
|
| MD5 |
ba0f94e2546051e1be80d9647f5e00a7
|
|
| BLAKE2b-256 |
65330475e85de3554bb4643b3ed998b20b8094f9917a036b9078ac35d0dee509
|
Provenance
The following attestation bundles were made for betterdb_agent_memory-0.7.0-py3-none-any.whl:
Publisher:
agent-memory-py-release.yml on BetterDB-inc/monitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
betterdb_agent_memory-0.7.0-py3-none-any.whl -
Subject digest:
a4ece7b5c4e3408d326f6b7fdd4f6d0e0b231cf5a92d42852a24993913886945 - Sigstore transparency entry: 2226097604
- Sigstore integration time:
-
Permalink:
BetterDB-inc/monitor@69d8073b2bd1810e8621612abe509220987104d5 -
Branch / Tag:
refs/tags/agent-memory-py-v0.7.0 - Owner: https://github.com/BetterDB-inc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
agent-memory-py-release.yml@69d8073b2bd1810e8621612abe509220987104d5 -
Trigger Event:
push
-
Statement type: