
Research
/Security News
Popular npm Packages in the keyv and Cacheable Namespaces Compromised in Active Supply Chain Attack
Popular npm packages keyv and cacheable compromised.
@three-ws/agent-memory
Advanced tools
Persistent, embeddings-backed memory for agents. Store facts and entities, recall them semantically, and surface a working context — over the three.ws Memory engine.
Persistent, embeddings-backed memory for agents — store facts and entities, recall them semantically, in one import.
Install · Quick start · API · How it works · three.ws
@three-ws/agent-memoryis the official client for the three.ws Memory engine — the durable, embeddings-backed memory that gives an agent continuity across sessions. Your agentremember()s a fact, thenrecall()s it later by meaning, not keyword: a real semantic search over stored vectors. It wraps the live/api/agent-memoryand/api/memory/*endpoints — a tiered store (working / recall / archival), free-first embeddings, and an auto-mined entity graph of the mints, tickers, wallets, people, and strategies your agent has seen. It pairs with the talking-agent runtime: the same memories that feed the Brain Memory node power your agent's replies.
Every "agent memory" you reach for is either an in-process array that dies with the process, or a raw vector DB that leaves embedding, tiering, entity extraction, ownership, and the cross-model "different vectors, different space" trap to you. Memory is the whole pipeline, done once:
remember('User prefers SOL over EVM') writes
a memory that's still there next session — and recall('which chain?')
finds it by meaning.nv-embedqa-e5-v5 (1024-dim,
free with one key); OpenAI text-embedding-3-small is the paid backstop. No
vector DB to stand up.This is the SDK twin of the three.ws Memory Studio — the same engine, exposed as plain functions instead of a UI.
npm install @three-ws/agent-memory
Zero runtime dependencies. Works in Node 18+ and the browser (uses fetch).
Writes require a signed-in three.ws account or a bearer token (see
Auth); reads are owner-only.
Bind a client to one agent, then remember and recall:
import { AgentMemory } from '@three-ws/agent-memory';
const memory = new AgentMemory({ agentId: AGENT_ID, token: process.env.THREE_WS_TOKEN });
await memory.remember('User prefers Solana over EVM chains', { tags: ['preference'] });
const hits = await memory.recall('which blockchain does the user like?');
console.log(hits[0].content); // → "User prefers Solana over EVM chains"
console.log(hits[0].score); // → 0.83 (real cosine; null on a lexical fallback)
Pin something to the always-in-context working core, then read what the agent carries into every reply:
await memory.remember('Never risk more than 2% per trade', {
tags: ['strategy'],
pinned: true, // → working tier, always in context
});
const ctx = await memory.context();
console.log(ctx.tokens, '/', ctx.budget, 'tokens in core'); // → 41 / 2000
Walk the entity graph the store mined for you:
const { nodes, edges } = await memory.graph();
// nodes: [{ kind: 'strategy', label: 'Never risk more than 2%…', mentions: 1 }, …]
new AgentMemory(options)| Option | Type | Default | Notes |
|---|---|---|---|
agentId | string | — | Required. The agent these memories belong to. |
token | string | — | Bearer token for writes (or use cookie session in-browser). |
baseUrl | string | https://three.ws | Override for self-host / preview. |
fetch | typeof fetch | global fetch | Inject a custom fetch (e.g. an x402 payer). |
remember(content, options?) → Promise<Memory>Store (or upsert) a memory. Wraps POST /api/agent-memory { agentId, entry }.
| Option | Type | Default | Notes |
|---|---|---|---|
type | 'user' | 'feedback' | 'project' | 'reference' | 'project' | Memory category. Invalid values fall back to project. |
tags | string[] | [] | Topic tags — also mined into entity/topic nodes. |
context | object | {} | Structured fields ({ mint, symbol, wallet }) extracted as entities. |
salience | number | 0.5 | Importance, 0..1. Drives ranking and tier. |
pinned | boolean | false | Pin to the working core (forces tier: 'working'). |
tier | 'working' | 'recall' | 'archival' | auto | Defaults: pinned → working, low-salience reference → archival, else recall. |
id | string | — | Pass to upsert an existing memory idempotently. |
expiresAt | number | string | — | Auto-expiry timestamp. |
Returns the stored Memory (see shape). Content is capped at
10,000 chars. Changing an existing memory's content resets its vector and mined
entities, so it re-indexes on the next read.
recall(query, options?) → Promise<Memory[]>Semantic search over the agent's memories. Wraps POST /api/memory/search.
| Option | Type | Default | Notes |
|---|---|---|---|
topK | number | 8 | Max results, clamped 1..50. |
minScore | number | 0.25 | Min cosine similarity, 0..1. |
tiers | string[] | all | Restrict to e.g. ['working', 'recall']. |
type | string | all | Restrict to one memory type. |
Each result carries a score (cosine, 4-dp) and match of 'semantic' or
'lexical'. Results are semantic-first, then back-filled with salience-ranked
substring hits so a query is never empty just because a provider is down.
Recalling a memory bumps its accessCount and salience slightly — the
recency/reinforcement loop the tiers rely on.
entities(options?) → Promise<Entity[]>The knowledge-graph nodes the agent's memories mention. Convenience over
graph() — returns nodes ranked by mention count.
graph() → Promise<{ nodes, edges, stats }>The full temporal knowledge graph. Wraps GET /api/memory/graph. nodes are
entities (kind ∈ mint | ticker | wallet | person | strategy | topic);
edges are co-occurrence links weighted by how often two entities share a
memory. Lazily mines any not-yet-processed memories on read.
memoriesFor(entityId, options?) → Promise<Memory[]>Memories that mention a given entity node. Wraps
GET /api/memory/graph?entityId=. Powers node drilldown ("what does my agent
remember about this mint?").
context() → Promise<Context>The "in-context now" working set: pinned + working-tier memories with a live
token budget. Wraps GET /api/memory/context.
type Context = {
entries: Memory[];
tokens: number; // estimated tokens in the working core
budget: number; // 2000 — the working-core token budget
overBudget: boolean; // tokens > budget
counts: { total, working, recall, archival, embedded };
};
list(options?) → Promise<Memory[]>Every memory for the agent (newest, salience-first). Wraps
GET /api/agent-memory?agentId=. Options: type, since (ms), limit
(≤ 500, default 200).
Owner-only edits over POST /api/memory/curate:
| Method | Op | Effect |
|---|---|---|
pin(id) / unpin(id) | pin / unpin | Move in/out of the working core. |
retier(id, tier) | tier | Set working | recall | archival. |
setSalience(id, n) | salience | Set importance, 0..1. |
edit(id, { content?, tags? }) | edit | Re-embeds + re-mines on content change. |
merge([target, ...dupes]) | merge | Fold duplicates into one; re-indexes. |
forget(id) | forget | Delete a memory. |
type Memory = {
id: string;
type: 'user' | 'feedback' | 'project' | 'reference';
content: string;
tags: string[];
context: object;
salience: number; // 0..1
tier: 'working' | 'recall' | 'archival';
pinned: boolean;
embedder: string | null; // e.g. "nvidia/nv-embedqa-e5-v5@1024"
hasEmbedding: boolean;
accessCount: number;
tokens: number; // ~chars/4
createdAt: number; updatedAt: number;
lastAccessedAt: number | null; expiresAt: number | null;
// recall() only:
score?: number | null; // cosine, or null for a lexical hit
match?: 'semantic' | 'lexical';
};
Three layers turn a string into durable, recall-able memory — a write path, a read-triggered indexing pass, and a query path:
remember(text) ──▶ POST /api/agent-memory ──▶ agent_memories (Postgres)
│
read of recall()/graph() triggers lazy indexing (best-effort, bounded)
▼
┌──────────────── embed ────────────────┐ ┌──────── mine ────────┐
│ NIM nv-embedqa-e5-v5 @1024 (free) │ │ deterministic entity │
│ → OpenAI text-embedding-3-small @256 │ │ extraction (no LLM) │
│ vector tagged with its embedder │ │ → entity nodes+links │
└────────────────────┬───────────────────┘ └──────────┬──────────┘
▼ ▼
recall(query) ──▶ cosine within the SAME vector space ──▶ ranked Memory[]
(lexical + salience fallback) graph(): nodes + edges
working is the small, always-in-context core
(pinned + active rules), token-budgeted at 2000 tokens. recall is recent,
searchable interactions. archival is the long-term store. A new memory's tier
is chosen for you unless you set it.nv-embedqa-e5-v5
(1024-dim, free with one NVIDIA_API_KEY); OpenAI text-embedding-3-small at
256 dims is the paid backstop. Embedding happens lazily on read, in bounded
batches, so no write blocks on a provider.0, never
a plausible-looking garbage similarity.$TICKER cashtags, wallet addresses, @handles, and trading
strategies. Entities become graph nodes; co-occurrence within a memory becomes
a weighted edge.Reads are owner-only: anonymous or non-owner requests get an empty result
(an empty array / zeroed context), never a leak and never a 401 that spams a
public embed console. Writes require auth and surface as a thrown
MemoryError with a code:
code | HTTP | Meaning | Recovery |
|---|---|---|---|
unauthorized | 401 | Write with no session / token. | Pass a token, or sign in. |
forbidden | 403 | Agent isn't yours. | Use an agentId you own. |
not_found | 404 | Agent or memory doesn't exist. | Check the id. |
id_conflict | 409 | Upsert id already used by another agent. | Omit id to mint a new one. |
validation_error | 400 | Missing agentId / content / bad field. | Fix the input. |
Browser writes also need a CSRF token (handled automatically by the three.ws
session cookie flow); server-to-server calls authenticate with a bearer
token.
Agent loop — remember every turn, recall before replying:
const memory = new AgentMemory({ agentId, token });
async function onUserMessage(text) {
const recalled = await memory.recall(text, { topK: 5 });
const reply = await llm(text, { memories: recalled.map((m) => m.content) });
await memory.remember(`User said: ${text}\nAgent: ${reply}`, { type: 'user' });
return reply;
}
Record a trade with structured context — it extracts the entities for you:
await memory.remember('Sniped a fresh launch, took profit at 3x', {
tags: ['trade', 'lesson'],
salience: 0.8,
context: { mint: 'THREEsynthetic1111111111111111111111111111', symbol: '$THREE' },
});
const { nodes } = await memory.graph(); // mint + ticker nodes now linked
Curate the working core so it stays under budget:
const ctx = await memory.context();
if (ctx.overBudget) {
// demote the least-salient working memory to recall
const weakest = ctx.entries.sort((a, b) => a.salience - b.salience)[0];
await memory.retier(weakest.id, 'recall');
}
@three-ws/forge — give your remembering agent a body: text/image → rig-ready 3D GLB.@three-ws/avatar — render and animate that agent in the browser.@three-ws/x402-fetch — inject a paying fetch for paid three.ws lanes.FAQs
Persistent, embeddings-backed memory for agents. Store facts and entities, recall them semantically, and surface a working context — over the three.ws Memory engine.
We found that @three-ws/agent-memory demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Popular npm packages keyv and cacheable compromised.

Security News
A misconfiguration gave three Anthropic models internet access, and one, believing it was in a simulation, shipped a credential-stealing package to PyPI.

Security News
/Company News
Socket has joined the new Composer and Packagist sponsorship program as a launch sponsor, supporting the team that keeps PHP's package ecosystem secure.