Patterns

Reflection loops

Scheduled or triggered reflect jobs.

Reflection is Spectron'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 Spectron moves from storing individual facts to producing understanding.

A reflection request takes a query, a scope, and optional parameters, then:

  1. Retrieves relevant memory items across the scope.

  2. Sends them to a reasoning model alongside your query.

  3. Returns a synthesised response.

  4. 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.

from spectron import Spectron

client = Spectron(api_key="sk-...")
memory = client.memory(context_id="support")

result = await memory.reflect(
scope={"org": "acme", "user": "alice"},
query="What are Alice's most frequently reported frustrations?",
persist=False,
)

print(result.synthesis)
import { Spectron } from "spectron";

const client = new Spectron({ apiKey: "sk-..." });
const memory = client.memory({ contextId: "support" });

const result = await memory.reflect({
scope: { org: "acme", user: "alice" },
query: "What are Alice's most frequently reported frustrations?",
persist: false,
});

console.log(result.synthesis);

The synthesis 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.

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(
scope={"org": "acme", "user": "alice"},
query="Summarise this customer's product preferences and risk of churn.",
persist=True,
target_entity_type="Customer",
target_entity_name="alice",
target_attribute_key="churn_risk_summary",
)
const result = await memory.reflect({
scope: { org: "acme", user: "alice" },
query: "Summarise this customer's product preferences and risk of churn.",
persist: true,
targetEntityType: "Customer",
targetEntityName: "alice",
targetAttributeKey: "churn_risk_summary",
});

The persisted attribute appears in future profile() and context() calls, enriching responses with synthesised understanding rather than just raw facts.

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 = client.memory(
context_id="support",
api_key="supervisor_sk_...",
)

result = await supervisor_memory.reflect(
scope={"org": "acme"}, # No user – reflects across all users in the org
query="What are the most common product complaints this week?",
persist=True,
target_entity_type="Organisation",
target_entity_name="acme",
target_attribute_key="weekly_complaint_summary",
)
const supervisorMemory = client.memory({
contextId: "support",
apiKey: "supervisor_sk_...",
});

const result = await supervisorMemory.reflect({
scope: { org: "acme" },
query: "What are the most common product complaints this week?",
persist: true,
targetEntityType: "Organisation",
targetEntityName: "acme",
targetAttributeKey: "weekly_complaint_summary",
});

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.

import asyncio
from datetime import datetime, timezone

async def nightly_reflection(memory, org_id: str):
"""Run nightly reflection for all users in an org."""
entities = await memory.entities.list(
scope={"org": org_id},
entity_type="Customer",
)

for customer in entities:
await memory.reflect(
scope={"org": org_id, "user": customer.name},
query="Update this customer's satisfaction score and churn risk based on recent interactions.",
persist=True,
target_entity_type="Customer",
target_entity_name=customer.name,
target_attribute_key="satisfaction_score",
)
# 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> {
const entities = await memory.entities.list({
scope: { org: orgId },
entityType: "Customer",
});

for (const customer of entities) {
await memory.reflect({
scope: { org: orgId, user: customer.name },
query: "Update this customer's satisfaction score and churn risk based on recent interactions.",
persist: true,
targetEntityType: "Customer",
targetEntityName: customer.name,
targetAttributeKey: "satisfaction_score",
});

await new Promise(r => setTimeout(r, 500));
}

console.log(`Nightly reflection complete for ${entities.length} customers.`);
}
Use caseQuery
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?"
context() / recall()reflect()
What it doesRetrieves existing factsReasons across facts to produce new conclusions
OutputRanked memory itemsFree-form synthesis (+ optional persisted attributes)
CostLow (retrieval only)Higher (LLM reasoning pass)
When to useBefore every LLM callPeriodically or on specific events

Was this page helpful?