molroo docs
SDK Reference

MolrooPersona

Standalone single-entity client for direct 1:1 persona interactions.

MolrooPersona

MolrooPersona is a standalone client for direct 1:1 interactions with a single persona. Unlike MolrooWorld which manages multiple entities in a spatial world, MolrooPersona is designed for simple character chatbot scenarios.

Use MolrooWorld when you need spatial awareness, multi-entity interaction, event propagation, or phase progression. Use MolrooPersona when you need a single character with emotion-aware responses.

Quick start

import { MolrooPersona } from '@molroo-ai/sdk';
import { VercelAIAdapter } from '@molroo-ai/adapter-llm/vercel-ai';
import { openai } from '@ai-sdk/openai';

const llm = new VercelAIAdapter({ model: openai('gpt-4o-mini') });

// Create a new persona
const persona = await MolrooPersona.create(
  { baseUrl: 'https://api.molroo.io', apiKey: 'mk_live_xxx', llm },
  {
    identity: { name: 'Sera', role: 'barista', speakingStyle: 'warm and casual' },
    personality: { O: 0.7, C: 0.6, E: 0.8, A: 0.9, N: 0.3, H: 0.8 },
    goals: [
      { id: 'g1', content: 'Make every customer smile', priority: 1, status: 'active', mutable: false },
    ],
  },
);

// Chat (LLM generates text + appraisal, engine computes emotion)
const result = await persona.chat('Good morning! What do you recommend?');
console.log(result.text);                           // LLM-generated response
console.log(result.response.emotion.discrete);      // { primary: 'joy', intensity: 0.72 }

Properties

PropertyTypeDescription
idstringUnique persona instance ID
personaIdstringAlias for id
configPersonaConfigData | nullCached persona configuration

Static Factory Methods

MolrooPersona.create(config, personaConfig)

Create a new persona on the API and return a connected instance.

const persona = await MolrooPersona.create(
  { baseUrl: 'https://api.molroo.io', apiKey: 'mk_live_xxx', llm },
  {
    identity: { name: 'Sera', role: 'barista' },
    personality: { O: 0.7, C: 0.6, E: 0.8, A: 0.9, N: 0.3, H: 0.8 },
  },
);
ParameterTypeDescription
config.baseUrlstringAPI base URL
config.apiKeystringAPI key
config.llmLLMAdapterOptional LLM adapter for chat()
personaConfigPersonaConfigDataIdentity, personality, goals

Returns: Promise<MolrooPersona>

MolrooPersona.connect(config, personaId)

Connect to an existing persona by ID. Verifies the persona exists and fetches its config.

const persona = await MolrooPersona.connect(
  { baseUrl: 'https://api.molroo.io', apiKey: 'mk_live_xxx', llm },
  'persona_abc123',
);

Returns: Promise<MolrooPersona>

MolrooPersona.listPersonas(config)

List all personas for the authenticated tenant.

const { personas } = await MolrooPersona.listPersonas({
  baseUrl: 'https://api.molroo.io',
  apiKey: 'mk_live_xxx',
});

Returns: Promise<{ personas: PersonaSummary[]; nextCursor?: string }>

Chat Methods

persona.chat(message, options?)

High-level chat with LLM integration. The SDK:

  1. Calls getState() to get current emotional state
  2. Builds a system prompt from persona config + state
  3. Sends to the LLM adapter for text generation + appraisal
  4. Sends the appraisal to the API for emotion computation
  5. Returns combined result

Requires an LLM adapter. Without one, use perceive() directly.

const result = await persona.chat('How are you feeling today?', {
  from: 'Alex',
  history: [
    { role: 'user', content: 'Hey Sera!' },
    { role: 'assistant', content: 'Hi there! Welcome back!' },
  ],
});

console.log(result.text);                        // LLM-generated text
console.log(result.response.emotion.vad);        // { V: 0.6, A: 0.4, D: 0.3 }
console.log(result.response.emotion.discrete);   // { primary: 'joy', intensity: 0.72 }
console.log(result.state?.mood);                 // slow-moving baseline mood
ParameterTypeDescription
messagestringUser message
options.fromstring?Sender name (default: 'user')
options.historyChatMessage[]?Conversation history for LLM context

Returns: Promise<PersonaChatResult>

interface PersonaChatResult {
  text: string;              // LLM-generated response text
  response: AgentResponse;   // Emotion data, somatic markers, social updates
  state?: PersonaState;      // Persona state at time of interaction
}

persona.perceive(message, options?)

Low-level emotion processing without LLM. Send a message (or appraisal) directly to the emotion engine.

// With manual appraisal (emotion-only mode)
const response = await persona.perceive('You did a great job!', {
  from: 'Alex',
  appraisal: {
    goal_relevance: 0.8,
    goal_congruence: 0.9,
    expectedness: 0.3,
    controllability: 0.2,
    agency: -0.7,
    norm_compatibility: 0.9,
  },
});

console.log(response.emotion.discrete.primary); // 'joy'
ParameterTypeDescription
messagestringStimulus message
options.fromstring?Sender name
options.appraisalAppraisalVectorManual appraisal values

Returns: Promise<AgentResponse>

Time Methods

persona.tick(seconds)

Advance persona time. Triggers internal decay, mood drift, and pending event processing.

await persona.tick(3600); // Advance 1 hour

Returns: Promise<{ pendingEvents?: unknown[] }>

persona.setEmotion(vad)

Directly override the persona's emotion state in VAD space.

await persona.setEmotion({ V: -0.5, A: 0.8 }); // Set to anxious state
ParameterTypeDescription
vad.Vnumber?Valence (-1 to +1)
vad.Anumber?Arousal (0 to 1)
vad.Dnumber?Dominance (-1 to +1)

State Methods

persona.getState()

Get the current emotional and psychological state.

const state = await persona.getState();
console.log(state.emotion.vad);       // { V: 0.3, A: 0.2, D: 0.1 }
console.log(state.emotion.discrete);  // { primary: 'contentment', intensity: 0.45 }
console.log(state.mood?.vad);         // slow-changing mood baseline
console.log(state.somatic);           // ['warm cheeks', 'relaxed shoulders']

Returns: Promise<PersonaState>

interface PersonaState {
  emotion: {
    vad: { V: number; A: number; D: number };
    discrete?: { primary: string; secondary?: string; intensity: number };
  };
  mood?: { vad: { V: number; A: number; D: number } };
  somatic?: string[];
  narrative?: { tone: number; agency: number; coherence: number };
}

persona.getSnapshot()

Get a full snapshot of the persona's internal state for backup.

const snapshot = await persona.getSnapshot();
// Save snapshot externally...

Returns: Promise<PersonaSnapshot>

persona.putSnapshot(snapshot)

Restore the persona's state from a previously saved snapshot.

await persona.putSnapshot(savedSnapshot);

Config Methods

persona.patch(updates)

Update the persona's configuration (identity, personality, goals).

await persona.patch({
  config: {
    identity: { name: 'Sera', role: 'head barista' }, // promoted!
    personality: { O: 0.7, C: 0.7, E: 0.8, A: 0.9, N: 0.3, H: 0.8 },
  },
});

Lifecycle Methods

persona.destroy()

Soft-delete this persona. Can be restored with restore().

await persona.destroy();

persona.restore()

Restore a previously soft-deleted persona.

await persona.restore();

PersonaConfigData

Configuration data for creating or updating a persona.

interface PersonaConfigData {
  personality?: Record<string, number>;   // HEXACO factors
  identity?: Record<string, unknown>;     // name, role, speakingStyle, coreValues
  goals?: Array<Record<string, unknown>>; // active goals
  [key: string]: unknown;                 // extensible
}

HEXACO personality factors:

KeyFactorRange
OOpenness to Experience0 - 1
CConscientiousness0 - 1
EExtraversion0 - 1
AAgreeableness0 - 1
NNeuroticism0 - 1
HHonesty-Humility0 - 1

MolrooWorld vs MolrooPersona

FeatureMolrooWorldMolrooPersona
Multiple entitiesYesNo (single)
Spatial awareness (spaces, topology)YesNo
Event propagationYesNo
Phase progressionYesNo
Knowledge system (facts)YesNo
Group awarenessYesNo
Emotion computationYesYes
LLM chatYesYes
Snapshot/restoreYesYes
Plugin systemYesNo

On this page