molroo docs
Guides

Memory

Give your persona memory: external history management or advanced MemoryAdapter.

Memory

Memory lets a persona remember past interactions and use those memories to inform future responses.

Two modes

For most applications, manage conversation history yourself. The chat() method returns updatedHistory which you store and pass back:

import { Molroo } from '@molroo-io/sdk';
import { createOpenAI } from '@ai-sdk/openai';

const molroo = new Molroo({ apiKey: 'mk_live_...' });
const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY! });

const sera = await molroo.createPersona(
  { identity: { name: 'Sera' }, personality: { O: 0.7, C: 0.6, E: 0.8, A: 0.9, N: 0.3, H: 0.8 } },
  { llm: openai('gpt-4o-mini') },
);

// Manage history externally
let history: Message[] = [];

const result1 = await sera.chat('Hi, my name is Alice!', { history });
history = result1.updatedHistory;

const result2 = await sera.chat('What was my name again?', { history });
history = result2.updatedHistory;
// -> The persona knows "Alice" from the conversation history

You are responsible for persisting history between sessions (e.g., in a database, localStorage, or session store).

Memory is fully optional. Without it, the persona still works -- it just won't recall past conversations beyond what you pass in history.

2. Advanced mode: MemoryAdapter

For advanced features like semantic search, emotion-aware storage, and reflections, implement the MemoryAdapter interface:

import type { MemoryAdapter } from '@molroo-io/sdk';

class MyMemoryAdapter implements MemoryAdapter {
  async saveEpisode(episode) { /* save to your DB */ }
  async recall(query) { /* query your DB */ }

  // Optional methods for richer features:
  async semanticRecall(query, options?) { /* vector search */ }
  async saveReflection(reflection) { /* save reflection */ }
  async getReflections(sourceEntity?) { /* get reflections */ }
}

const sera = await molroo.createPersona('Barista Sera', {
  llm: openai('gpt-4o-mini'),
  memory: new MyMemoryAdapter(),
});

When a MemoryAdapter is configured, the SDK automatically recalls relevant episodes before each chat() call and injects them into the LLM prompt.

How it works

persona.chat('Remember our picnic?', { history })
    |
    +-- 1. Episodic recall (from MemoryAdapter, if configured)
    +-- 2. Semantic recall (if semanticRecall is implemented)
    +-- 3. Reflection recall (if getReflections is implemented)
         |
         v
    Memory block injected into system prompt
         |
         v
    LLM generates response with memory + history context
         |
         v
    New episode saved automatically (if MemoryAdapter configured)
    Returns PersonaChatResult with updatedHistory

Each chat() call:

  1. Before the LLM call -- recalls episodic + semantic + reflections in parallel (if MemoryAdapter is configured), injects into prompt along with the provided history
  2. After the API response -- saves the new episode (fire-and-forget), generates reflections if triggered
  3. Returns updatedHistory -- always returned regardless of MemoryAdapter

Reflections

Reflections are natural-language self-observations the persona generates when significant emotional shifts occur. They are stored via the MemoryAdapter and recalled as context.

Example reflections:

  • "I need to be more empathetic when others share difficult experiences"
  • "I've been more confident in conversations lately"

Reflections are generated automatically by the SDK when the API response includes a reflectionPrompt -- requires a MemoryAdapter with saveReflection and getReflections implemented.

Event memory

Beyond chat, molroo can process game events, simulation actions, and other non-chat stimuli as emotional experiences that become memories.

Use event() to send a non-chat event with a required appraisal vector:

// A goblin attacks the persona
await persona.event('attack', 'goblin attacks with sword', {
  from: 'goblin',
  appraisal: {
    goal_relevance: 0.8,
    goal_congruence: -0.9,
    expectedness: 0.3,
    controllability: 0.4,
    agency: -0.6,
    norm_compatibility: -0.5,
    internal_standards: 0,
    adjustment_potential: 0.3,
    urgency: 0.9,
  },
});

// Later, during chat, the persona recalls the event (if MemoryAdapter is configured)
let history: Message[] = [];
const result = await persona.chat('How are you feeling?', { history });
history = result.updatedHistory;

event() requires an appraisal vector because emotion impact is the core value -- without appraisal, the event wouldn't affect the persona's feelings.

Next steps

On this page