Skip to content

Memory Category Distribution โ€‹

SpektraBot remembers key facts about each child across conversations, so parents don't have to repeat themselves. This page explains how the memory system works, what categories exist, and how memories are managed over time.


Executive Overview โ€‹

What is it? โ€‹

When a parent chats with SpektraBot about their child, the system automatically picks up important facts from the conversation -- things like the child's diagnosis, their school, the name of their SENCO, or whether they have an EHCP. These facts are stored as memories and grouped into eight categories.

The Memory Category Distribution chart on the admin dashboard shows how these memories break down across the eight categories, giving administrators a quick visual summary of what SpektraBot knows about the children it supports.

Why does it matter? โ€‹

  • Continuity of support -- Parents don't have to explain their child's situation every time they start a new conversation. SpektraBot already knows the key facts.
  • Personalised advice -- Responses are tailored to the child's specific circumstances (e.g. knowing they attend a particular school means SpektraBot can reference that school's SEND policy).
  • Quality assurance -- Administrators can see the distribution of memory types to understand what kinds of information SpektraBot is capturing and whether any categories are underrepresented.
  • GDPR compliance -- Every memory has a defined retention period aligned with how quickly that type of information changes in a child's life. Stale memories are flagged for review.

The eight categories at a glance โ€‹

CategoryWhat it storesHow long it's kept
DiagnosisSEND conditions (e.g. autism, dyslexia, ADHD)Permanent
SchoolSchool name, year group, class2 years
ProfessionalKey contacts (SENCO name, therapist, caseworker)1 year
PreferenceChild's preferences, triggers, calming strategies1 year
HistoryKey events and dates (EHCP issued, tribunal date)Permanent
BehaviourBehavioural patterns, strengths, challenges6 months
EHCPEHCP status, sections, named provisions1 year
ProvisionCurrent therapies, support, interventions6 months

Retention periods are aligned with real-world SEND review cycles -- for example, EHCP memories last one year because EHCPs are reviewed annually, while behavioural patterns are kept for six months because they change more frequently.


Technical Architecture โ€‹

How memories are extracted โ€‹

Memory extraction is fully automatic and runs asynchronously after every AI response. The process is non-blocking -- failures never affect the user's conversation.

Extraction pipeline โ€‹

The MemoryExtractionService (packages/api/src/services/memory/memory-extraction.service.ts) performs the following steps:

  1. Rate limiting -- A Redis-based cooldown (60 seconds per conversation) prevents redundant extraction calls across multiple API pods.

  2. Message retrieval -- The last 10 messages from the conversation are fetched and formatted chronologically.

  3. Existing memory context -- Up to 30 active memories for the child are loaded and included in the prompt, enabling the LLM to detect contradictions (e.g. "changed school from X to Y").

  4. LLM extraction -- The formatted conversation is sent to GPT-4o with a structured prompt requesting category, fact, confidence score, and optional supersession of existing memories.

  5. Validation and filtering:

    • Category must be one of the 8 defined categories
    • Fact must be a non-empty string (max 200 characters)
    • Confidence score must be >= 0.6
    • Only facts explicitly stated or confirmed by the user are accepted
  6. Deduplication -- Each fact is hashed (SHA-256) and stored with a unique constraint per child, preventing duplicate storage.

  7. Supersession -- When a new fact contradicts an existing memory (e.g. a school change), the old memory is soft-deleted and the new one references it via the supersedes field.

The eight categories in detail โ€‹

All categories are defined in packages/api/src/services/memory/types.ts:

Diagnosis โ€‹

Category: "diagnosis"
TTL: Permanent (null)

Stores SEND diagnoses and conditions -- autism spectrum disorder, dyslexia, ADHD, speech and language difficulties, sensory processing disorder, etc. These are permanent because diagnoses rarely change; they are only superseded if the user explicitly reports a revised diagnosis.

Example memories:

  • "Child has a diagnosis of autism spectrum disorder"
  • "Recently diagnosed with dyslexia (November 2025)"
  • "Has ADHD, combined type"

School โ€‹

Category: "school"
TTL: 730 days (2 years)

School-related facts including the school name, year group, class, and type of setting (mainstream, special school, alternative provision). The 2-year TTL aligns with key stage transitions when school details are most likely to change.

Example memories:

  • "Attends Riverside Primary School"
  • "Currently in Year 4"
  • "In a mainstream class with 1:1 TA support"

Professional โ€‹

Category: "professional"
TTL: 365 days (1 year)

Names and roles of key professionals involved with the child -- SENCO, educational psychologist, speech and language therapist, social worker, paediatrician. The 1-year TTL reflects typical staff turnover cycles.

Example memories:

  • "SENCO is Mrs Thompson"
  • "Seeing Dr Patel at the child development centre"
  • "Has a speech and language therapist called Sarah"

Preference โ€‹

Category: "preference"
TTL: 365 days (1 year)

The child's personal preferences, sensory triggers, calming strategies, and communication preferences. These help SpektraBot tailor advice to the child's specific needs.

Example memories:

  • "Gets overwhelmed by loud noises in assembly"
  • "Responds well to visual timetables"
  • "Prefers written instructions over verbal"

History โ€‹

Category: "history"
TTL: Permanent (null)

Key events and dates in the child's SEND journey. These are permanent because historical events don't change -- an EHCP was issued on a specific date, a tribunal happened, etc.

Example memories:

  • "EHCP was issued in March 2025"
  • "Moved from mainstream to special school in September 2024"
  • "Tribunal hearing scheduled for June 2026"

Behaviour โ€‹

Category: "behaviour"
TTL: 180 days (6 months)

Behavioural patterns, strengths, and challenges. This has the shortest TTL because children's behaviour evolves quickly, especially with appropriate support in place.

Example memories:

  • "Has meltdowns during transitions between activities"
  • "Reading has improved significantly this term"
  • "Struggles with unstructured break times"

EHCP โ€‹

Category: "ehcp"
TTL: 365 days (1 year)

Education, Health and Care Plan specific information -- application status, named provisions, section contents, annual review outcomes. The 1-year TTL matches the statutory annual EHCP review cycle.

Example memories:

  • "EHCP names 20 hours of 1:1 support"
  • "Annual review is due in February"
  • "Section F includes speech and language therapy"

Provision โ€‹

Category: "provision"
TTL: 180 days (6 months)

Current support, therapies, and interventions the child is receiving. A 6-month TTL reflects that interventions are frequently adjusted based on progress and need.

Example memories:

  • "Receives occupational therapy twice a week"
  • "Has a social skills group on Wednesdays"
  • "Using Colourful Semantics programme for language"

Database schema โ€‹

Memories are stored in the child_memories table:

sql
CREATE TABLE child_memories (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    child_id    UUID NOT NULL REFERENCES children(id),
    category    VARCHAR(50) NOT NULL,
    fact        VARCHAR(1000) NOT NULL,
    confidence  FLOAT DEFAULT 0.8,
    fact_hash   VARCHAR(64) NOT NULL,
    is_active   BOOLEAN DEFAULT true,
    deleted_at  TIMESTAMPTZ,            -- GDPR soft-delete
    created_at  TIMESTAMPTZ DEFAULT now(),
    updated_at  TIMESTAMPTZ,
    UNIQUE(child_id, fact_hash)         -- Prevent duplicate facts per child
);

CREATE INDEX idx_child_memory_category ON child_memories(child_id, category);

Key design decisions:

  • fact_hash (SHA-256) ensures the same fact is never stored twice for the same child, even if mentioned across multiple conversations.
  • is_active + deleted_at supports GDPR soft-deletion -- memories are logically removed but retained for audit until the 90-day hard-delete cycle runs.
  • confidence (0.0 -- 1.0) reflects how certain the extraction LLM was that this is a genuine fact, not a hypothetical or question.

Memory staleness โ€‹

The MemoryService (packages/api/src/services/memory/memory.service.ts) provides staleness checking:

typescript
isMemoryStale(memory: { category: string; createdAt: Date }): boolean {
  const ttlDays = MEMORY_TTL_DAYS[memory.category as MemoryCategory];
  if (ttlDays === null) return false;  // Permanent categories never go stale
  const ageDays = (Date.now() - memory.createdAt.getTime()) / (1000 * 60 * 60 * 24);
  return ageDays > ttlDays;
}

Stale memories are not automatically deleted -- they are deprioritised when building the child's context for the LLM, and flagged on the admin dashboard for review. A parent can refresh a stale memory simply by mentioning the updated information in conversation.

How memories are used in responses โ€‹

When generating an AI response, the Agentic RAG pipeline (packages/api/src/chat/agentic-rag.ts) retrieves up to 30 active memories for the child and groups them by category:

CHILD CONTEXT:
DIAGNOSIS: Child has a diagnosis of autism spectrum disorder
SCHOOL: Attends Riverside Primary School; Currently in Year 4
EHCP: EHCP names 20 hours of 1:1 support; Annual review is due in February
PROVISION: Receives occupational therapy twice a week

This structured context is prepended to the system prompt, allowing GPT-4o to reference the child's specific circumstances in every response without the parent needing to repeat themselves.

Admin dashboard โ€‹

The Memory Category Distribution pie chart is displayed on the System Health page (/admin/system-health) and is powered by the /api/admin/system-health/memory-stats endpoint.

The endpoint aggregates active memories using Prisma's groupBy:

typescript
const memoriesByCategory = await prisma.childMemory.groupBy({
  by: ["category"],
  where: { isActive: true, deletedAt: null },
  _count: { category: true },
});

The result is a simple count per category, rendered as an interactive pie chart showing administrators the overall distribution of what SpektraBot knows about the children it supports.

API endpoints โ€‹

EndpointMethodDescription
/api/children/:childId/memoriesGETList memories (filterable by category)
/api/children/:childId/memories/countGETGet total memory count for a child
/api/children/:childId/memories/staleGETList stale memories
/api/children/:childId/memories/:memoryIdDELETESoft-delete a specific memory
/api/children/:childId/memoriesDELETESoft-delete all memories for a child
/api/admin/system-health/memory-statsGETAggregated category distribution (admin)

Data flow diagram โ€‹

GDPR considerations โ€‹

  • Retention: Each category has a defined TTL aligned with real-world SEND cycles. Stale memories are flagged but not auto-deleted, allowing parental review.
  • Right to erasure: The DELETE endpoints support both individual and bulk memory deletion per child.
  • Soft-delete: Memories are logically deleted (is_active = false, deleted_at timestamped) and physically purged by the 90-day GDPR cleanup job.
  • Data minimisation: Only facts the user explicitly stated are extracted. SpektraBot's own suggestions and hypotheticals are excluded.
  • Transparency: Parents can view all stored memories for their child through the UI.

Confidential ยท Spectrum Dynamics CIC