A turn is a single message in a conversational thread. After a session is open, every message - whether from the user, the assistant, the system, or a tool - is recorded as a turn. SurrealDB Agent Memory processes each turn synchronously through an extraction pipeline and returns a structured diff of everything that was learned or changed.
Writing a turn
A turn is written with the /facts endpoint. Pass the session id as session_id and the speaker as role:
POST /api/v1/{context_id}/facts
Content-Type: application/json
{
"text": "I just got promoted to CTO",
"session_id": "01hx7…",
"role": "user"
}role defaults to user. When session_id is left out, SurrealDB Agent Memory creates a new session for the write and returns its id as sessionId in the response.
The request blocks until extraction is complete, then returns the structured result. Extraction is synchronous by design: the caller can use the returned diff to update application state, drive real-time UI, or trigger downstream logic without polling.
Roles
| Role | When to use |
|---|---|
user | Messages from the human participant. Extraction is most active on user turns. |
assistant | Responses generated by the LLM. Recording assistant turns preserves the full conversational context and allows SurrealDB Agent Memory to track what the assistant has stated or committed to. |
system | System prompt or instruction turns. SurrealDB Agent Memory extracts behavioural instructions and constraints from system turns. |
tool | Results returned from tool calls. SurrealDB Agent Memory extracts factual content from tool results and attributes it to the tool source. |
All four roles participate in provenance. Each turn is stored with its role, and every fact extracted from it carries a source_turn reference regardless of role.
Extraction pipeline
When a turn arrives, SurrealDB Agent Memory runs the following steps synchronously before returning:
Named entity recognition - identifies people, organisations, locations, products and the other entity types in the fixed set. A type outside that set is stored as
other.Attribute extraction - extracts scalar properties of entities (job title, location, preference, status, and so on).
Relation extraction - identifies directed relationships between entities.
Instruction detection - recognises statements that express user preferences, behavioural instructions, or explicit requests about how the agent should behave.
Uncertainty flagging - marks statements that are speculative, negated, or otherwise of low confidence.
Reconciliation - compares newly extracted facts against existing memory. Facts that contradict prior records are resolved and a correction record is produced. See Reconciliation and supersession for the full correction model.
Python SDK
result = await memory.remember("I just got promoted to CTO", session_id=session.id, role="user")JavaScript SDK
const result = await memory.remember("I just got promoted to CTO", { sessionId: session.id, role: "user" });Extraction result
The response to a write contains the session and turn ids, and an extraction object with the full diff for that turn.
{
"mode": "full",
"sessionId": "01hx7…",
"turnId": "01hy2…",
"extraction": {
"turnId": "01hy2…",
"entities": [
{
"id": "['person', 'alice']",
"name": "Alice",
"entityType": "person",
"memoryCategory": "identity",
"isNew": false
}
],
"attributes": [
{
"id": "attr_01hy2b",
"entityId": "['person', 'alice']",
"key": "job_title",
"value": "CTO",
"memoryCategory": "identity"
}
],
"relations": [],
"actions": [],
"instructions": [],
"uncertainties": [],
"corrections": [
{
"entityId": "['person', 'alice']",
"key": "job_title",
"oldValue": "Head of Platform",
"newValue": "CTO"
}
]
},
"preview": false
} turnId
The stable identifier for this turn. Store it to correlate later reads - for example to label a /state snapshot taken immediately after the turn.
entities
Entities named or implied in the turn content. Each entity carries:
id- stable record identifiername- the canonical display nameentityType- entity type (e.g.person,organisation,project)memoryCategory-identity,knowledge, orcontextisNew-truewhen this turn created the entity,falsewhen it matched an existing one
An entity record is created once and then referenced by subsequent attributes and relations. If an entity was already known, the existing record is returned rather than a duplicate.
attributes
Scalar facts about entities. Each attribute carries:
id- the attribute record identifierentityId- the entity the attribute belongs tokey- the attribute name (e.g.job_title,location,preference)value- the extracted valuememoryCategory- the category the attribute was filed under
Attributes are versioned. If the same key already exists for an entity and the new value differs, the prior attribute is superseded rather than overwritten. The supersession chain is preserved so the history of a fact is always queryable. Validity times and provenance are stored on the attribute record and returned by /state and GET /entities/{type}/{name}/history/{key}.
relations
Directed relationships between two entities. Each relation carries:
subject- source entitylabel- relationship type (e.g.works_at,manages,owns)object- target entitymemoryCategory- the category the relation was filed under
actions
Events the turn describes: who did what, and when. Each action carries actor, verb, object (the thing acted on, as the extraction named it, or null), a one-line summary, occurredAt when the turn gave a time, and memoryCategory.
instructions
Behavioural directives extracted from the turn. These are statements where the user or system is expressing a persistent preference or rule, such as "always reply in French" or "never mention competitors by name." Instructions are surfaced in the context payload and injected into prompts automatically when using the managed chat loop.
Each instruction carries:
id- the instruction record identifierlabel- a short name for the directivedescription- the normalised instruction text
uncertainties
Statements extracted from the turn that SurrealDB Agent Memory cannot assert with confidence - negated claims, speculative language, conflicting signals, or information that requires human verification. Each carries about and reason. These are stored separately from confirmed attributes and are surfaced in the state under unknowns.
corrections
When reconciliation finds that a newly extracted fact contradicts an existing attribute, a correction record is produced. Each correction carries:
entityId- the entity whose attribute changedkey- the attribute nameoldValue- the value that was supersedednewValue- the value from this turn
Corrections are the mechanism through which SurrealDB Agent Memory handles conversational drift - for example, when a user corrects a name, updates their role, or revises a stated preference. See Reconciliation and supersession for how the supersession chain works.
Using the extraction result for real-time UI
Because the extraction result returns synchronously with the turn response, you can use it to drive application state immediately after each message is submitted.
A common pattern is to compare the returned arrays against your local state and highlight changes in the UI:
result = await memory.remember("Actually I moved to Berlin last month", session_id=session.id, role="user")
for attr in result.extraction.attributes:
ui.render_attribute(attr["entityId"], attr["key"], attr["value"])
for correction in result.extraction.corrections:
ui.strike_through(correction["oldValue"])
ui.highlight_new(correction["newValue"])const result = await memory.remember("Actually I moved to Berlin last month", { sessionId: session.id, role: "user" });
for (const attr of result.extraction?.attributes ?? []) {
ui.renderAttribute(attr.entityId, attr.key, attr.value);
}
for (const correction of result.extraction?.corrections ?? []) {
ui.strikeThrough(correction.oldValue);
ui.highlightNew(correction.newValue);
}Recording assistant turns
When you are driving the LLM loop yourself (as opposed to using chat()), record the assistant's response as a turn after each generation:
user_result = await memory.remember(user_message, session_id=session.id, role="user")
context = await memory.sessions.context(session.id, user_message)
reply = your_llm.generate(system=context.context, user=user_message)
assistant_result = await memory.remember(reply, session_id=session.id, role="assistant")Recording assistant turns preserves the full conversational record and allows SurrealDB Agent Memory to extract any facts the assistant stated - commitments, stated knowledge, or preferences expressed on behalf of the agent. Omitting assistant turns is permitted, but the resulting memory will have gaps that could reduce context quality on subsequent retrieval.
Listing turns
To retrieve all turns recorded in a session:
GET /api/v1/{context_id}/sessions/{session_id}/turnsturns = await memory.sessions.turns(session.id)const turns = await session.turns();The response is a list of turns, oldest first, with their roles, content, and timestamps. It is paginated: limit defaults to 100 and is capped at 500, and page.nextCursor gives the next page. Extraction results are not re-included in this listing; use the /state endpoint to query the facts that were produced.