RECALL — the memory primitive
MnemoPay's recall surface is the agent-side equivalent of a query layer on top of vector + scalar memory. Three things make it different from "RAG on a Pinecone index":
- Compounding scores. Memories have an
importance×recency×frequencyscore that gets adjusted automatically as the agent references them. Useful memories drift up. Stale ones decay. - Reinforcement loop.
rlFeedback(ids, reward)lets the agent signal which recalled memories were actually useful — that adjusts the score so the next recall returns better candidates. - DID-signed anchors. Optional. Every
remember()can mint a portable, signed receipt (aMemoryAnchor) so the memory is verifiable by any third party without trusting MnemoPay.
This page covers all three.
remember()
import MnemoPay from "@mnemopay/sdk";
const agent = MnemoPay.quick("agent-1");
// Simple
const id = await agent.remember("User prefers monthly billing");
// With metadata
await agent.remember("User churned on $99 tier", {
importance: 0.9, // 0-1, higher = surfaces more often
factType: "experience", // "world" | "experience" | "opinion" | "observation"
tags: ["billing", "churn"],
entityIds: ["user:42"],
});
// Opinion (drives confidence updates when reinforced)
await agent.remember("Stripe is the best rail for SaaS", {
factType: "opinion",
confidence: 0.75,
});
factType |
When to use |
|---|---|
world |
Objective facts. Default. ("Paris is in France.") |
experience |
First-person events. ("Agent paid $49 for Pro last Tuesday.") |
opinion |
Subjective stances. Drives confidence reinforcement on overlap. |
observation |
Agent-generated summaries. Emitted by the observation pipeline, not callers. |
Receipt mode
For audit-grade workflows, ask remember() for the receipt instead of just the id:
const { id, anchor } = await agent.remember("Charged $25 for May invoice", {
returnReceipt: true,
});
if (anchor) {
// anchor.proofValue is a base58btc Multibase Ed25519 signature
// anchor.payload is the canonical JSON that was signed
console.log(anchor.signerDid); // "did:mp:..."
}
anchor is only minted when the instance has anchoring enabled (agent.enableAnchoring(wallet)) or when opts.anchor === true is passed and a wallet is attached.
recall()
// Top-K by score (no query)
const latest = await agent.recall(5);
// Semantic search
const billing = await agent.recall("billing preferences", 5);
// Format for the Anthropic 1-hour prompt cache (single call)
const cacheBlock = await agent.recall("user context", 10, {
formatForClaudeCache: true,
});
// → { type: "text", text: "...", cache_control: { type: "ephemeral", ttl: 3600 } }
Memory returned by recall():
interface Memory {
id: string;
content: string;
importance: number; // 0-1
score: number; // ranked score at recall time
createdAt: Date;
lastAccessed: Date;
accessCount: number;
tags: string[];
factType?: "world" | "experience" | "opinion" | "observation";
confidence?: number; // opinions only
entityIds?: string[];
anchor?: MemoryAnchor; // present iff anchoring was on at write time
}
Reinforcement (the part most teams skip)
After the agent acts on recalled memories, tell MnemoPay which ones were useful. This is the loop that compounds:
const memories = await agent.recall("billing", 5);
const answer = await yourLLM({ memories });
const usefulIds = memories.filter(m => answer.cited(m.id)).map(m => m.id);
// +1 = useful, -1 = misleading. EWMA-weighted update on importance.
await agent.rlFeedback(usefulIds, +1.0);
Forgetting (when an old memory contradicts a new one):
await agent.forget(oldMemoryId);
Consolidation (auto-prune low-importance memories at scale):
const pruned = await agent.consolidate();
console.log(pruned.removed, pruned.kept);
Hosted vs local
Two ways to talk to the recall surface:
| Mode | Class | Storage | Identity |
|---|---|---|---|
| Local | MnemoPay.quick(id) → MnemoPayLite |
In-memory or SQLite | Optional did:mp:… |
| Hosted | new MnemoPayClient({ baseUrl, token }) |
Postgres / pgvector | Server-issued, signed |
Local mode is the fastest path for prototyping and dogfooding. Hosted mode is what you want when memories must be portable across processes or verifiable by counter-parties.
// Hosted
import { MnemoPayClient } from "@mnemopay/sdk/client";
const client = new MnemoPayClient({
baseUrl: "https://mnemopay-landing.fly.dev",
token: process.env.MNEMOPAY_TOKEN,
});
await client.remember("User prefers monthly billing");
const memories = await client.recall("billing");
Performance
MnemoPayLite.remember() end-to-end (including Ed25519 anchor mint) measures p50 1.0 ms / p95 1.7 ms / p99 2.5 ms on an Intel i5-1035G1 dev box — see the governance latency table in the README. The path is intentionally cheap so it can sit inside the LLM's tool-call loop without budget anxiety.
Reproduce: npm run bench:governance.