Memories — top-level API
Reference for recall.remember, recall.search, recall.correct, recall.explain, recall.forget, and the recall.memory CRUD escape hatch.
remember()
recall.remember(input: RememberInput, options?: TransportRequestOptions): Promise<RememberResult>;
recall.remember(input: RememberInput & { stream: true }, options?: TransportRequestOptions): Promise<RecallStream<PipelineEvent, RememberResult>>;Send conversation turns, raw observations, or structured events into the seven-stage write pipeline. The server runs pre_filter → extract → resolve_refs → dedupe → conflict → persist, and (when an idempotency key replays) skips straight to replay.
Input — discriminated union
messagesArray<{ role: 'user' | 'assistant'; content: string }>optionalConversation turns. The pipeline runs full extraction and may produce multiple memories per turn.
observationsstring[]optionalPlain pre-distilled facts. Each becomes a single user turn before extraction.
eventsArray<{ description: string; at?: string; tags?: string[] }>optionalStructured events with explicit timestamps. Useful for system events (logins, settings changes).
idempotencyKeystringoptionalOptional client-generated key that lets the server deduplicate replays. When omitted, the SDK auto-generates one per request.
Exactly one of messages, observations, or events is required.
Returns
storedMemoryId[]alwaysmergedArray<{ existingId: MemoryId; sourceTurnId: string }>alwayssupersededArray<{ newId: MemoryId; oldId: MemoryId }>alwaysdiscardednumberalwaysflaggednumberalwaystraceIdstringalwayslatencyMsnumberalwaysllmCostUsdnumberalwaysExample
const result = await recall.remember({
messages: [
{ role: 'user', content: 'I prefer dark mode.' },
{ role: 'user', content: 'I live in Berlin.' },
],
});
console.log(`stored=${result.stored.length} merged=${result.merged.length}`);
console.log(`traceId=${result.traceId}`);When to use
Reach for messages for chat applications. Reach for observations when an upstream system has already distilled facts and you only want extraction + dedup. Reach for events when timestamps matter — login events, settings changes, anything log-flavoured.
Common pitfalls
idempotencyKey is one-shot — the same key + same scope returns the cached result without re-running the pipeline. Do not reuse a key across different bodies; the server will return the original outcome regardless of your new input.
When the pipeline is still running for a previous request with the same key, the server returns 409 REQUEST_IN_FLIGHT. The SDK throws RecallConflictError with retryAfterMs: 1000 so callers can wait and retry safely.
search()
recall.search(input: SearchInput, options?: TransportRequestOptions): Promise<SearchResult>;
recall.search(input: SearchInput & { stream: true }, options?: TransportRequestOptions): Promise<RecallStream<PipelineEvent, SearchResult>>;Run a hybrid retrieval query. The four-stage read pipeline — understand → retrieve → rank → filter — returns a list of MemoryWithScore, in descending relevance order. See Search for the deep dive; this section is a fast reference.
Input
querystringrequiredlimitnumberoptional[1, 100]).filters.memoryTypeMemoryTypeoptionalfact | preference | event | entity | relation | convention | constraint.filters.minConfidencenumberoptionalReturns
SearchResult with memories: MemoryWithScore[], totalBeforePolicy, traceId, latencyMs, and plan?. See Search for full field semantics.
Example
const hits = await recall.search({
query: 'where does the user live?',
limit: 5,
filters: { memoryType: 'preference', minConfidence: 0.6 },
});
for (const m of hits.memories) console.log(m.score, m.content);correct()
recall.correct(
id: MemoryId,
correction: string | { content: string; reason?: string },
options?: TransportRequestOptions,
): Promise<CorrectResult>;Replace a memory's content. The server creates a new memory carrying the corrected content, supersedes the old one (old.supersededBy = new.id), and persists reason to the audit log. The old memory is not deleted — its history is still queryable.
Input
idMemoryIdrequiredcorrectionstring | CorrectionInputrequiredA bare string is the new content. Pass an object to include an optional reason for the audit log.
Returns
supersededIdMemoryIdalwaysnewMemoryIdMemoryIdalwaystraceIdstringalwayslatencyMsnumberalwaysExample
await recall.correct(memoryId, 'user actually lives in Hamburg');
await recall.correct(memoryId, {
content: 'user lives in Hamburg',
reason: 'updated via settings page',
});See Correct & feedback for the supersession chain, audit-log shape, and how this differs from recall.memory.patch.
explain()
recall.explain(id: MemoryId, options?: TransportRequestOptions): Promise<MemoryExplanation>;Provenance-focused view of a single memory. Returns the content plus where it came from, how often it has been retrieved, and whether it has been superseded.
Returns
idMemoryIdalwaystypeMemoryTypealwayscontentstringalwaysconfidencenumberalways[0, 1].tagsstring[]alwaysprovenance.accessCountnumberalwaysprovenance.createdAtstringalwaysprovenance.updatedAtstringalwaysprovenance.supersededByMemoryIdWhen to use
explain() is the right call when you want the why of a memory — for dashboards, "where did this come from?" tooltips, and supersession-chain traversal. For mutating operations use recall.memory.patch().
forget()
recall.forget(input: ForgetInput, options?: TransportRequestOptions): Promise<ForgetResult>;Soft-delete one or more memories with an audit reason. Pass hard: true for an irreversible delete. Both forms persist reason to the audit log for compliance / GDPR records.
Input — discriminated union
idMemoryIdoptionalfilter.typeMemoryTypeoptionalfilter.tagsstring[]optionalreasonstringoptionalhardbooleanoptionaltrue, hard-delete (not recoverable). Default false.Returns
deletednumberalwaystraceIdstringalwayslatencyMsnumberalwaysExample
await recall.forget({ id: memoryId, reason: 'user requested via settings' });
await recall.forget({ filter: { type: 'preference' }, hard: true });recall.memory — CRUD escape hatch
The recall.memory resource exposes direct CRUD against /v1/memories. Use it for dashboards, admin scripts, and any time you want stable cursor-based pagination instead of ranked search.
get(id)
recall.memory.get(id: MemoryId, options?: TransportRequestOptions): Promise<MemoryDetail>;Returns the full MemoryDetail: content, confidence, optional predicate and object (for typed memories), tags, the bound scope, accessCount, createdAt, updatedAt, and supersededBy? if the memory has been replaced. Throws RecallNotFoundError for unknown IDs.
list(opts)
recall.memory.list(opts?: ListMemoryOptions, options?: TransportRequestOptions): PagedRequest<MemorySummary>;Returns a PagedRequest<MemorySummary> — await it for the first page, or for await it to auto-paginate through every memory in scope. See Pagination for the full pattern.
typeMemoryTypeoptionallimitnumberoptional[1, 100]).cursorstringoptional// First page only
const page = await recall.memory.list({ type: 'preference', limit: 50 });
console.log(page.items.length, page.hasMore);
// Auto-paginate everything
for await (const m of recall.memory.list()) {
console.log(m.id, m.content);
}patch(id, patch)
recall.memory.patch(id: MemoryId, patch: MemoryPatch, options?: TransportRequestOptions): Promise<MemoryDetail>;Mutate an existing memory in place — content, confidence, or tag additions. This bypasses the supersession-chain semantics of correct(): the audit log records a patch, not a supersede, and there is no newMemoryId.
contentstringoptionalconfidencenumberoptional[0, 1].addTagsstring[]optionalWhen to use patch vs correct
Use correct() when the memory's meaning changed — the user updated their address, a preference was wrong, a fact became outdated. The supersession chain preserves history.
Use patch() for mechanical fixups — a typo in content, a confidence score the application now wants to revise, an extra tag for a UI feature. There is no semantic "this replaces that" relationship.
Was this page helpful?