Reflection is SurrealDB Agent Memory's mechanism for synthesising higher-order insights from accumulated memory. Unlike retrieval - which surfaces facts that already exist - reflection runs an LLM reasoning pass over a scope's memory and produces new insights that can be persisted back as experiential memory attributes. It is how SurrealDB Agent Memory moves from storing individual facts to producing understanding.
Spectron was the project name for SurrealDB Agent Memory. These type names
will be renamed in a future release.
What reflection does
A reflection request takes a query, a scope, and optional parameters, then:
Retrieves relevant memory items across the scope.
Sends them to a reasoning model alongside your query.
Returns a synthesised response.
If
persist: true, stores the synthesised insights as new attributes on the relevant entities.
This is different from context(), which retrieves and ranks existing facts. Reflection reasons across facts to produce conclusions that are not explicitly stored anywhere.
Basic reflection call
from surrealdb import Spectron
memory = Spectron(context="support", api_key="sk-...")
result = await memory.reflect(
query="What are Alice's most frequently reported frustrations?",
persist=False)
print(result.reflection)import { Spectron } from "@surrealdb/spectron";
const memory = new Spectron({ context: "support", apiKey: "sk-..." });
const result = await memory.reflect({
query: "What are Alice's most frequently reported frustrations?",
persist: false });
console.log(result.reflection);The reflection field is a free-form text response from the reasoning model. When persist: false, nothing is written back to memory - useful for exploratory analysis or generating one-off summaries.
Persisting synthesised insights
Set persist: true to write the insights back as experiential memory attributes. The reasoning model produces structured attribute suggestions which are reconciled against the existing memory state before being committed.
result = await memory.reflect(
query="Summarise this customer's product preferences and risk of churn.",
persist=True)const result = await memory.reflect({
query: "Summarise this customer's product preferences and risk of churn.",
persist: true });persist is the only routing control: reflect writes back against the entities its
own evidence names, and returns them in persistedAttributes. There is notarget_entity_type / target_attribute_key - you cannot pin the write to a
chosen attribute. The persisted attributes appear in future profile() andcontext() calls, enriching responses with synthesised understanding rather than
just raw facts.
Cross-user reflection with supervisor keys
Supervisor API keys have broader scope access - they can reflect across multiple users or the entire organisation scope. This enables pattern analysis across your user base.
supervisor_memory = Spectron(
context="support",
api_key="supervisor_sk_...",
)
result = await supervisor_memory.reflect( # No user - reflects across all users in the org
query="What are the most common product complaints this week?",
persist=True)const supervisorMemory = new Spectron({
context: "support",
apiKey: "supervisor_sk_...",
});
const result = await supervisorMemory.reflect({
// no user segment - reflects across everything the key can read
query: "What are the most common product complaints this week?",
persist: true,
});When to run reflections
Reflection is a compute-intensive operation. Appropriate trigger points:
End of session - after a conversation closes, reflect to produce a session summary and update the user's churn risk or sentiment attributes.
Daily batch - run a nightly reflection across all active users to update aggregate attributes.
Event-triggered - run a targeted reflection when a specific event occurs (a complaint, a high-value purchase, an escalation).
Weekly insights - broader organisational reflections that surface cross-user patterns.
Scheduling as a background job
import asyncio
from datetime import datetime, timezone
async def nightly_reflection(memory, org_id: str):
"""Run nightly reflection for all users in an org."""
# GET /entities filters on type only - the key's read region bounds the rest
entities = await memory.entities.list(type="Customer")
for customer in entities:
await memory.reflect(
query="Update this customer's satisfaction score and churn risk based on recent interactions.",
persist=True)
# Respect rate limits between requests
await asyncio.sleep(0.5)
print(f"[{datetime.now(timezone.utc).isoformat()}] Nightly reflection complete for {len(entities)} customers.")async function nightlyReflection(memory: Memory, orgId: string): Promise<void> {
// GET /entities filters on type only - the key's read region bounds the rest
const entities = await memory.entities.list({ type: "Customer" });
for (const customer of entities) {
await memory.reflect({
query: "Update this customer's satisfaction score and churn risk based on recent interactions.",
persist: true });
await new Promise(r => setTimeout(r, 500));
}
console.log(`Nightly reflection complete for ${entities.length} customers.`);
}Example reflection queries
| Use case | Query |
|---|---|
| Session summary | "Summarise this conversation and any commitments the agent made." |
| Customer health | "Rate this customer's satisfaction and likelihood to renew (1-10)." |
| Project risk | "What risks or blockers have been mentioned about this project?" |
| Complaint patterns | "What product issues have been raised most frequently this month?" |
| Learning trajectory | "What topics has this learner mastered and what gaps remain?" |
Reflection versus retrieval
context() / recall() | reflect() | |
|---|---|---|
| What it does | Retrieves existing facts | Reasons across facts to produce new conclusions |
| Output | Ranked memory items | Free-form synthesis (+ optional persisted attributes) |
| Cost | Low (retrieval only) | Higher (LLM reasoning pass) |
| When to use | Before every LLM call | Periodically or on specific events |