Client initialization
apiKey
explicitly. Requests carry no state between calls, so a single client can be shared
across your whole application.
fetch is injectable, which is useful for tests or a custom transport:
Methods
Response objects keep the API’s field names, so they are
snake_case:
memory_id, relevance_score, space_id, job_ids.
record
background: true to queue the write instead of waiting on extraction. The call
then returns job_id with status: "processing" and memory_id: null, so poll it with
getJob.
userId, agentId and sessionId scope the memory inside the space, so one space can
serve many end users without their memories mixing: only a retrieve carrying the same
scope sees it. See Scoping.
recordBatch
Up to 100 memories in one call, always queued.retrieve
relevance_score is a composite of four factors, not a normalized probability, so it can
exceed 1.0. It is null for memories returned outside a ranked recall.mode: "fast" skips the neural rerank pass for lower latency, at some cost to relevance
quality. See Latency modes.
Retrieval collapses a consolidated memory and the raw facts behind it into one result by
default. Pass preferObservations: false to see both layers. Other filters:
memoryType, tags, tagsMatch, minScore, asOf.
asOf restricts the search to memories recorded at or before an ISO 8601 instant,
so you get what the space knew then. queryTimestamp is not a filter. It moves the
“now” that recency scoring and relative dates in the query are measured against, and
never removes a result. See
Searching over time.
retrieveReceipt, getReceipt and explain
retrieve returns a plain array, which has nowhere to carry the id of the
receipt for that search. retrieveReceipt is the same search and returns both.
receiptDetail: "full" also asks the search to account for its own cuts, so the
receipt can explain memories that were ranked and dropped before limit or a
relevance floor ever applied. It can cost latency on the first call for a given
query, so leave it "basic" for production traffic.
receipt_id is null only when the receipt could not be stored. A receipt is a
debugging aid and never load-bearing, so the search itself still succeeded and
memories is complete either way.
explain answers the question the receipt cannot: why one specific memory is
not in your results.
not_retrieved is the one to act on: nothing matched the memory at all, so a
bigger limit or a lower floor will not bring it back, and the query wording or
the scope you searched is what to change. arms shows which kind of matching
found it, and how well: found by keyword but not semantic usually means your
query shares words with the memory but not meaning.
Every search builds a receipt whether or not you asked for one, so getReceipt
and explain also work on a request id from your own logs. See
Context receipts.
reason
usage is available alongside insights.
getUserProfile and askAboutUser
Everything a space has learned about one end user, and a question answered from that user’s memories only. Both needuserId to be the same value your writes
are scoped with.
userId nobody has recorded under is not an error: it comes back with
memory_count: 0 and an empty memories, because a user is a scope tag created
by the first write naming it rather than a resource you register. An unknown
space is still a 404.
memory_count can also go down between two reads, since consolidation folds
several raw facts into one note and the default view counts the note. Read it as
how many distinct things are currently known about this user, not as an
ingestion counter. See User profiles.
updateMemory
Correct a memory, or retire it without losing it.state: "invalidated" drops the memory out of retrieve, consolidation and
reasoning while keeping it for audit; "active" puts it back. That is a
supersession, not a delete, so prefer it over deleteMemory, which is permanent.
Editable fields: text, context, occurredStart, occurredEnd,
memoryType, entities, state, reason. At least one is required. A call
with nothing to change fails locally, before any request. reason is kept on
the memory’s history so an audit shows why it changed, not merely that it did.
Memories the system synthesised from your raw facts cannot be edited. They are
derived, so the API rejects the attempt rather than letting a synthesis drift
away from the evidence under it.
getMemoryHistory
{ memory_id, history }, where each entry carries the previous content
and when it changed.
history is frequently empty. It reflects supersession inside the memory
layer, not edits you make with updateMemory. A memory you have just edited
will still report an empty history. Treat it as a view onto how the system’s
own understanding evolved, not as an audit log of your writes; for the latter,
the reason you pass to updateMemory is what gets retained.uploadFiles
Uploads files into a space so retrieval can draw on their content. Ingestion is asynchronous and returnsjob_ids, so poll each with getJob.
data accepts a Blob, File, ArrayBuffer, or Uint8Array. A Node Buffer works
unchanged. There is no filesystem-path overload, which is what keeps the package usable
on edge runtimes.
All three limits are enforced before anything is sent, so an oversized upload fails
instantly rather than after transferring the body:
Supported formats are PDF, DOCX, DOC, PPTX, PPT, XLSX, XLS, HTML, TXT, Markdown,
CSV, JPEG/PNG images, MP3/WAV audio and MP4/MOV/WEBM/MKV video. Images, audio
and video are read into text. See Documents.
Vercel AI SDK
Wrap any model to give it memory. Relevant memories are recalled before the call and the turn is recorded after it.ai v5 or newer. Recording is fire-and-forget by default so memory never adds
latency to a response; pass await: true to block until the write lands, or
record: false to recall without writing. Streaming is supported, and the turn is recorded
when the stream completes, not at the first token.
Memory failures never break the model call. If recall or recording fails, the request
proceeds without it.
OpenAI Agents SDK
Exposes memory as two tools the model can call:remember and recall.
Error handling
429 and 5xx are retried automatically with jittered backoff. 4xx is never retried,
it means the request itself was wrong.
A
503 arriving without a requestId may be a gateway timeout whose body was stripped
in transit. Report it with a timestamp rather than treating it as a malformed response.Browser usage
The package runs in the browser so it can be used in trusted contexts such as an internal tool behind auth, or a browser extension. For a public web app, keep the key on your server:Next steps
Python SDK
The same surface, for Python.
API overview
Every endpoint, request shape, and error code.