stackbone.memory
Status: planned. This surface is already on the ambient
stackboneclient, but every method returnsnot_implementedfor now. The shape on this page is the contract you can type against today. The backend will be mem0 (MEM0_API_KEY, optionalMEM0_BASE_URL), and every method goes live once that wiring lands: no code change on your side.
stackbone.memory is the long-term memory store for an agent. You reach
it through the ambient stackbone client from any
deep-agent tool or durable
workflow step:
import { stackbone } from '@stackbone/sdk';
await stackbone.memory.add('Prefers dark mode and Spanish UI.', { userId: 'user_42' });The backend will be the external mem0 service, so the
store stands apart from the agent's own Postgres
(stackbone.database). It needs no platform
capability. The wiring reads a MEM0_API_KEY from the environment, and nothing
supplies one yet.
Memory vs. a deep-agent session
A deep agent already remembers a conversation across turns inside a single
session, and every agent session carries that
durable buffer without you asking for it. stackbone.memory
holds the explicit facts you want to persist across
sessions and across users ("this customer is on the Pro plan",
"prefers Spanish"). Use the session for the live conversation; use
stackbone.memory for what should outlive it.
Scopes
Every memory belongs to a scope:
| Scope | Lifetime | Use it for |
|---|---|---|
'user' |
Long-term (default). | Facts about a specific end-user of the agent. |
'session' |
Short-lived; collapsed by endSession. |
Conversation buffer while a single chat is in flight. |
'agent' |
Shared across every user of the agent. | Global facts the agent should know regardless of caller. |
scope: 'session' requires a sessionId. The other scopes do not.
API
Every method returns the standard Result<T> envelope
({ data, error: null } | { data: null, error: SdkError }). You call
them from inside a deep-agent tool or a workflow step, where the
ambient stackbone handle is in scope.
add(content, request)
Stores a new memory. content is either a string (ingested verbatim)
or an OpenAI-shaped ChatCompletionMessageParam[]: mem0 summarises
message arrays into one or more facts.
import { tool } from '@langchain/core/tools';
import { stackbone, z } from '@stackbone/sdk';
const rememberFact = tool(
async ({ userId, fact }: { userId: string; fact: string }) => {
const { error } = await stackbone.memory.add(fact, { userId });
return error ? 'Could not remember that.' : 'Remembered.';
},
{
name: 'remember_fact',
description: 'Remember a fact about the current user.',
schema: z.object({ userId: z.string(), fact: z.string() }),
},
);A message array, scoped to a single session:
await stackbone.memory.add(
[
{ role: 'user', content: 'I need to switch my plan to Pro' },
{ role: 'assistant', content: 'Sure, I will upgrade your account now.' },
],
{ userId: 'user_42', sessionId: 'sess_abc', scope: 'session' },
);search(query, options?)
Semantic search across the configured scopes. Returns hits sorted by
descending cosine similarity, capped at limit (default 10) and
filtered by threshold if provided.
const { data } = await stackbone.memory.search('What plan is the user on?', {
userId: 'user_42',
limit: 5,
threshold: 0.7,
});
for (const hit of data) {
console.log(hit.score.toFixed(2), hit.content);
}filters AND-merge metadata predicates onto the semantic match.
includeScopes restricts the search (omit to search every scope).
get(memoryId)
Returns a single memory by id.
list(request)
Paginated list of memories for a userId.
const { data } = await stackbone.memory.list({ userId: 'user_42', limit: 50 });update(memoryId, options)
Updates the content and/or metadata of a memory. mem0 shallow-merges the metadata.
await stackbone.memory.update('mem_123', { content: 'Prefers light mode now.' });delete(memoryId)
Deletes a single memory. Resolves to { id }: the id of the deleted
memory.
deleteAll(request)
Deletes every memory for a userId. Resolves to { deleted }: the
number of memories removed.
await stackbone.memory.deleteAll({ userId: 'user_42' });history(memoryId)
Returns the audit trail for a memory: every created, updated,
accessed or deleted event, with before and after content
snapshots where applicable.
const { data } = await stackbone.memory.history('mem_123');
for (const entry of data) {
console.log(entry.event, '@', entry.at, 'by', entry.actor);
}endSession(sessionId, options?)
Closes a session. By default, endSession promotes session-scoped
memories to long-term ('user') storage before it drops the session.
Pass { persist: false } to drop them outright.
const { data } = await stackbone.memory.endSession('sess_abc');
console.log(data.persisted, 'session facts promoted');Configuration
Nothing reads these yet. They are the keys the surface resolves once the mem0 wiring ships, and the runtime supplies them then: you will not wire a client by hand.
| Config key | Falls back to env | Required when… |
|---|---|---|
mem0ApiKey |
MEM0_API_KEY |
Any stackbone.memory.* call. |
mem0BaseUrl |
MEM0_BASE_URL |
Optional. Point at a self-hosted mem0 deployment. Defaults to the mem0 cloud when unset. |
Errors
| Code | Meaning |
|---|---|
not_implemented |
Returned by every call until the mem0 wiring ships. |
mem0_unconfigured |
mem0ApiKey / MEM0_API_KEY is missing. |
memory_not_found |
The memoryId does not exist or has been deleted. |
Today only not_implemented is reachable. The other two codes arrive with
the mem0 wiring.
Where to go next
stackbone.ai: the LLM client memories feed into via the conversation summarisation flow.requestApproval(): erasing a user's memory on request ("right to be forgotten") is a good fit for a workflow-level human approval gate rather than a fire-and-forgetdeleteAll. Seestackbone.approvalfor the underlying surface.stackbone.database: the Postgres the rest of the agent uses; mem0 lives outside it.- Concepts → Agents and sessions: how a deep agent's built-in session memory complements long-term memory.