npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@betterdb/agent-memory

v0.6.1

Published

Standalone agent memory: agent-cache short-term tiers plus a semantic long-term MemoryStore over valkey-search

Readme

@betterdb/agent-memory

npm version total downloads license: MIT types GitHub stars

Standalone agent memory for Valkey: the short-term caching tiers from @betterdb/agent-cache plus a semantic long-term MemoryStore backed by Valkey Search (FT.*). Store memories with remember(), retrieve the most relevant ones with recall() (semantic similarity blended with recency and importance), and keep stores bounded with TTLs, capacity eviction, and consolidate().

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.

AI Cache & Memory tab in BetterDB Monitor

AI Traces waterfall in BetterDB Monitor

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.

Installation

npm install @betterdb/agent-memory iovalkey

Requires a Valkey server with the Valkey Search module loaded (for the FT.* commands), and an embedding function you provide.

Quick start

The AgentMemory facade wires the short-term cache tiers and the long-term memory store together over a single client and name:

import Valkey from 'iovalkey';
import { AgentMemory } from '@betterdb/agent-memory';

const client = new Valkey('redis://localhost:6379');

const agent = new AgentMemory({
  client,
  name: 'my_agent',
  embedFn: async (text) => embed(text), // returns number[]
});

// Create the vector index and register discovery markers (idempotent).
await agent.initialize();

// Long-term memory:
await agent.memory.remember('User prefers dark mode', {
  agentId: 'assistant',
  importance: 0.8,
  tags: ['preferences'],
});

const hits = await agent.memory.recall('what theme does the user like?', {
  agentId: 'assistant',
  k: 5,
});

// Short-term cache tiers (from @betterdb/agent-cache):
agent.llm;
agent.tool;
agent.session;

await agent.close();

You can also use the MemoryStore directly, without the cache tiers:

import { MemoryStore } from '@betterdb/agent-memory';

const memory = new MemoryStore({ client, name: 'my_agent', embedFn });
await memory.ensureIndex();

MemoryStore API

  • ensureIndex() — create the {name}:mem:idx vector index if absent (idempotent). Resolves the vector dimension from embedFn.
  • remember(content, options?) — embed and store a memory; returns its id. Options: importance (0..1), tags, ttl (seconds), and scope (threadId, agentId, namespace).
  • recall(query, options?) — semantic search scoped by threadId/agentId/namespace/tags, ranked by a composite of similarity, recency (half-life decay), and importance. Returns MemoryHit[]. Recalled memories are reinforced (last-access + access-count bumped) unless reinforce: false.
  • forget(id) — delete a single memory by id.
  • forgetByScope(scope) — delete all memories matching a scope and/or tags.
  • consolidate(options) — summarize a set of memories (via a summarize callback) into one new memory and optionally delete the sources. Select candidates by scope, tags, olderThanSeconds, or maxImportance.
  • consolidateFacts(options) — distill a set of memories into atomic, deduplicated facts and write each as its own memory, keeping the source memories (additive, so recall is preserved). You supply an extractFacts(items) LLM seam that returns Fact[] (subject, statement, optional date, optional tombstone); the store reconciles them by subject (newest date wins, tombstones drop a subject) and preserves each fact's date in its content. Reconciliation is stateful across runs: each fact memory persists its subject, so a later run loads the stored facts and reconciles against them — a re-run over unchanged sources rewrites nothing (idempotent), a newer statement supersedes (deletes) the prior fact memory, and a tombstone retracts it. The result reports created (ids written) and deleted (prior fact memories superseded or retracted). Off by default — construct the store with consolidation: true (or { enabled: true, factSource?, factImportance? }) to enable it, otherwise it throws. Select sources by scope, tags, olderThanSeconds, or maxImportance; prior fact memories are excluded from the source scan so a run never re-distills its own output.
  • currentConfig() / refreshConfig() — read the live recall/eviction tunables; with configRefresh enabled the store periodically re-reads them from {name}:__mem_config.
  • close() — stop the config-refresh timer and tear down discovery heartbeats.

Scoring & capacity

Recall ranks by compositeScore — a weighted blend of similarity, recency (true half-life decay), and importance. Defaults are tunable via MemoryStoreOptions (weights, halfLifeSeconds, defaultThreshold) or live via config refresh. Set maxItemsPerScope to cap memories per scope; over-capacity writes evict the lowest-scoring items (importance + recency).

recall only returns candidates whose cosine distance is within a threshold (default 0.25, i.e. similarity ≥ ~0.875) — tuned for real semantic embeddings, where a relevant memory lands well inside it. A weak or non-semantic embedFn can push every candidate past the threshold and yield no hits; raise it per call (recall(query, { threshold })) or globally (defaultThreshold) if that happens.

Observability

Set telemetry: { registry } to register Prometheus metrics (agent_memory_*: items, recall total/hits/empty/latency, embedding calls, evictions, consolidations) and OpenTelemetry spans for each operation. With discovery enabled (default in the facade), the store publishes a marker to the shared __betterdb:caches registry so Monitor can auto-discover it.

License

MIT