stackbone.memory

Status: planned. This surface is already on the ambient stackbone client, but every method returns not_implemented for now. The shape on this page is the contract you can type against today. The backend will be mem0 (MEM0_API_KEY, optional MEM0_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-forget deleteAll. See stackbone.approval for 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.
BUILT WITH ❤️ FROM CANADA AND SPAIN