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
| Property | Type | Description |
|---|---|---|
id | string | Unique persona instance ID |
personaId | string | Alias for id |
config | PersonaConfigData | null | Cached 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 },
},
);| Parameter | Type | Description |
|---|---|---|
config.baseUrl | string | API base URL |
config.apiKey | string | API key |
config.llm | LLMAdapter | Optional LLM adapter for chat() |
personaConfig | PersonaConfigData | Identity, 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:
- Calls
getState()to get current emotional state - Builds a system prompt from persona config + state
- Sends to the LLM adapter for text generation + appraisal
- Sends the appraisal to the API for emotion computation
- 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| Parameter | Type | Description |
|---|---|---|
message | string | User message |
options.from | string? | Sender name (default: 'user') |
options.history | ChatMessage[]? | 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'| Parameter | Type | Description |
|---|---|---|
message | string | Stimulus message |
options.from | string? | Sender name |
options.appraisal | AppraisalVector | Manual 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 hourReturns: 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| Parameter | Type | Description |
|---|---|---|
vad.V | number? | Valence (-1 to +1) |
vad.A | number? | Arousal (0 to 1) |
vad.D | number? | 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:
| Key | Factor | Range |
|---|---|---|
O | Openness to Experience | 0 - 1 |
C | Conscientiousness | 0 - 1 |
E | Extraversion | 0 - 1 |
A | Agreeableness | 0 - 1 |
N | Neuroticism | 0 - 1 |
H | Honesty-Humility | 0 - 1 |
MolrooWorld vs MolrooPersona
| Feature | MolrooWorld | MolrooPersona |
|---|---|---|
| Multiple entities | Yes | No (single) |
| Spatial awareness (spaces, topology) | Yes | No |
| Event propagation | Yes | No |
| Phase progression | Yes | No |
| Knowledge system (facts) | Yes | No |
| Group awareness | Yes | No |
| Emotion computation | Yes | Yes |
| LLM chat | Yes | Yes |
| Snapshot/restore | Yes | Yes |
| Plugin system | Yes | No |