One isolated memory environment (e.g. prod vs staging).
Customer (customer_id)
Passed per call on B2B instances; auto-resolved on B2C
Your B2B tenant. Memories are visible to all users in that customer.
User (user_id)
Passed on every call
Your end-user. Memories stay private to that user.
Conversation (conversation_id)
Passed on conversation-scoped calls; must be a valid UUID
A single chat thread. Registered only by record_message (see below).
B2C vs B2B: B2C instances need only user_id (customer_id is auto-resolved); B2B instances pass user_id under a customer_id. The shape is set per-Instance by the User Relationship setting in the Dashboard. See Memory scopes.
Passing conversation_id inside memories.create(metadata=...) does not register the conversation — metadata is stored but not indexed for scope resolution. Only record_message creates the conversation row that conversation.context.fetch reads from.
Which do I use?
Turn-by-turn chat history → record_message
Long-term knowledge (a document, a profile, an imported fact) → memories.create
Production chat agent → both: record_message for the transcript, memories.create for durable knowledge. See the cost & dedup note in Ingestion.
Fetching a brand-new or never-ingested scope returns an emptyContextResponse (facts == [], etc.), not an error — this is the normal cold-start path. A malformed (non-UUID) conversation_id raises InvalidInputError. See Error handling.
Two different mode= axes — label which one you mean:
Axis
Values
What changes
Retrieval (...context.fetch(mode=...))
fast (default) · accurate
fast = vector + graph, no LLM decomposition. accurate = vector + graph + LLM subquery decomposition + reranking (more compute, wider/higher-quality results). Both pull from the same memory. See Retrieval modes.