Clone
2
API Reference
Shinwoo PARK edited this page 2026-05-15 13:27:29 +09:00

API Reference

This reference describes the public exports visible from src/index.ts:

export * from './types';
export * from './memory';
export * from './schedule';
export * from './conversation';
export * from './persona';

Persona

Main framework class.

Constructors

new Persona(displayName: string, seedMessage: string, options?: PersonaOptions)
new Persona(spaceId: string, options?: PersonaOptions)

Create mode:

const persona = new Persona('Mina', 'Mina likes quiet cafes.', { memory, models });

Load mode:

const persona = new Persona(existingSpaceId, { memory, models });

Behavior:

  • Create mode calls memory.createSpace({ displayName, seedMessage, now }).
  • Load mode calls memory.getSpace(spaceId) and throws if missing.
  • Initialization starts immediately in the constructor and is awaited through ready().
  • If options.memory is omitted, an InMemoryMemoryStore is used.

ready()

ready(): Promise<MemorySpace>

Returns the created or loaded persona memory space.

createDailySchedule(datetime, message)

createDailySchedule(datetime: DateTimeInput, message: string): Promise<ScheduleEntry[]>

Creates tomorrow's 10-minute schedule.

If datetime is May 1, the schedule covers May 2 00:00 through May 3 00:00 and contains 144 entries.

Side effects:

  • saves entries through memory.saveScheduleEntries
  • refreshes the in-memory availability snapshot
  • emits persona.schedule.daily.generated

Default deterministic mapping:

  • message containing travel/trip/여행 -> daytime travel
  • message containing study/exam/공부/시험 -> daytime study
  • message containing job/취업/구직 -> daytime job-search
  • message containing work/일/회사 -> daytime work
  • otherwise daytime defaults to work

createMonthlySchedule(datetime, message)

createMonthlySchedule(datetime: DateTimeInput, message: string): Promise<ScheduleEntry[]>

Creates 30 day-level entries starting tomorrow.

Side effects:

  • saves entries through memory.saveScheduleEntries
  • refreshes availability
  • emits persona.schedule.monthly.generated

deleteSchedulesBefore(cutoffExclusive)

deleteSchedulesBefore(cutoffExclusive: DateTimeInput): Promise<number>

Deletes or marks schedule entries before a caller-provided cutoff.

Behavior depends on the memory store:

  • InMemoryMemoryStore physically removes entries whose endAt <= cutoffExclusive and returns the deleted count.
  • IdentityDbMemoryStore does not physically delete schedule facts through IdentityDB's public append-oriented API, so it returns 0 at the store layer.
  • The Persona layer always records a fact with topic persona.schedule.deleted and source boxbrain.schedule.prune.

deleteSchedulesOlderThan(datetime)

deleteSchedulesOlderThan(datetime: DateTimeInput): Promise<number>

Alias for deleteSchedulesBefore(datetime).

getTodayScheduledAvailability(datetime)

getTodayScheduledAvailability(datetime: DateTimeInput): Promise<ScheduledAvailabilitySnapshot>

Returns the cached schedule-derived availability snapshot.

Window rule:

  • start: UTC start of datetime's day
  • end: two UTC days later

If the snapshot is missing or the day changed, BoxBrain reloads schedule entries from memory and rebuilds the snapshot.

sendMessage(input)

sendMessage(input: {
  datetime: DateTimeInput;
  messageHistory: PersonaMessage[];
  getLatestMessageHistory?: () => Promise<PersonaMessage[]>;
}): Promise<OutgoingMessageDraft>

Generates a reply to the user's message history.

Requires:

options.models.conversation

Pipeline:

  1. Await persona readiness.
  2. Load active availability.
  3. Build mandatory conversation context:
    • formatted messageHistory
    • schedule entries from yesterday through tomorrow
    • availability snapshot
    • facts tagged with persona, the persona display name, or user
  4. Emit persona.conversation.context.loaded.
  5. Call models.conversation.generateReply with mode reply.
  6. Trim blank messages from the draft.
  7. If getLatestMessageHistory and models.rewrite are present, check whether a newer history arrived and optionally rewrite.
  8. Emit persona.conversation.reply.generated.
  9. Return OutgoingMessageDraft.

Throws if no conversation model is configured.

startConversation(input)

startConversation(input: {
  datetime: DateTimeInput;
  messageHistory: PersonaMessage[];
}): Promise<OutgoingMessageDraft>

Generates a proactive opener from the persona.

Requires:

options.models.conversation

Uses the same mandatory context pipeline as sendMessage, but passes mode: 'start-conversation' to the model.

Emits persona.conversation.started.

sleepMemory(input)

sleepMemory(input: {
  datetime: DateTimeInput;
  messageHistory: PersonaMessage[];
}): Promise<FactDraft[]>

Extracts durable facts from a period of messages and persists them.

Requires:

options.models.memoryExtraction

Pipeline:

  1. Find relevant context facts tagged with persona, the persona display name, or user.
  2. Format the provided message history.
  3. Call models.memoryExtraction.extract with the objectivization instruction.
  4. Persist each returned fact through memory.addFact.
  5. Add the topic sleepMemory to each persisted fact.
  6. Use source boxbrain.sleepMemory if the draft did not specify a source.
  7. Emit persona.memory.sleep.persisted.
  8. Return the extracted drafts.

Recommended cadence: daily around midnight, passing the previous day's messages.

Options and models

PersonaOptions

interface PersonaOptions {
  memory?: BoxBrainMemoryStore;
  models?: PersonaModels;
  debug?: DebugHook;
  now?: DateTimeInput;
}
  • memory: storage adapter. Defaults to InMemoryMemoryStore.
  • models: provider-agnostic LLM adapters.
  • debug: optional async event hook.
  • now: deterministic initialization time for tests or replay.

PersonaModels

interface PersonaModels {
  initialization?: PersonaInitializationModel;
  conversation?: ConversationModel;
  rewrite?: RewriteModel;
  memoryExtraction?: MemoryExtractionModel;
}

PersonaInitializationModel

interface PersonaInitializationModel {
  extractInitialFacts(input: {
    displayName: string;
    seedMessage: string;
    now: string;
  }): Promise<FactDraft[]>;
}

Called during persona creation. If omitted, BoxBrain stores a default seed fact. If it returns [], BoxBrain stores no fallback fact.

ConversationModel

interface ConversationModel {
  generateReply(input: ReplyGenerationInput): Promise<OutgoingMessageDraft>;
}

ReplyGenerationInput

interface ReplyGenerationInput {
  persona: MemorySpace;
  now: string;
  mode: 'reply' | 'start-conversation';
  context: MandatoryConversationContext;
  userMessage?: string;
  instruction: string;
}

OutgoingMessageDraft

interface OutgoingMessageDraft {
  messages: string[];
  reasoning?: string;
}

The host app should deliver each messages[] item as a separate messenger message.

RewriteModel

interface RewriteModel {
  decide(input: RewriteDecisionInput): Promise<RewriteDecision>;
}
interface RewriteDecision {
  rewrite: boolean;
  draft?: OutgoingMessageDraft;
  reason?: string;
}

MemoryExtractionModel

interface MemoryExtractionModel {
  extract(input: MemoryExtractionInput): Promise<FactDraft[]>;
}
interface MemoryExtractionInput {
  persona: MemorySpace;
  now: string;
  formattedMessageHistory: string;
  contextFacts: StoredFact[];
  instruction: string;
}

Memory stores

BoxBrainMemoryStore

interface BoxBrainMemoryStore {
  createSpace(input: { displayName: string; seedMessage: string; now: string }): Promise<MemorySpace>;
  getSpace(spaceId: string): Promise<MemorySpace | null>;
  addFact(spaceId: string, fact: FactDraft): Promise<StoredFact>;
  listFacts(spaceId: string): Promise<StoredFact[]>;
  findFacts(spaceId: string, topics: string[]): Promise<StoredFact[]>;
  saveScheduleEntries(spaceId: string, entries: ScheduleEntry[]): Promise<void>;
  listScheduleEntries(spaceId: string, fromInclusive: string, toExclusive: string): Promise<ScheduleEntry[]>;
  deleteScheduleEntriesBefore(spaceId: string, cutoffExclusive: string): Promise<number>;
}

InMemoryMemoryStore

Test/demo store backed by maps:

  • spaces: Map<string, MemorySpace>
  • facts: Map<string, StoredFact[]>
  • schedules: Map<string, ScheduleEntry[]>

Useful for unit tests and demos. Not persistent.

IdentityDbMemoryStore

Persistent store backed by IdentityDB.

import { IdentityDB } from 'identitydb';
import { IdentityDbMemoryStore } from 'boxbrain';

const db = await IdentityDB.connect({ client: 'sqlite', filename: '.data/personas.sqlite' });
await db.initialize();
const memory = new IdentityDbMemoryStore({ db });

createSqliteIdentityMemoryStore(filename)

createSqliteIdentityMemoryStore(filename: string): Promise<IdentityDbMemoryStore>

Convenience helper that connects and initializes an IdentityDB SQLite database.

Core types

DateTimeInput

type DateTimeInput = Date | string | number;

All datetime inputs are converted through new Date(...). Invalid dates throw.

MemorySpace

interface MemorySpace {
  id: string;
  displayName: string;
  createdAt: string;
  metadata: Record<string, unknown>;
}

FactDraft

interface FactDraft {
  statement: string;
  topics: string[];
  confidence?: number;
  source?: string;
  metadata?: Record<string, unknown>;
}

StoredFact

interface StoredFact extends FactDraft {
  id: string;
  createdAt: string;
}

PersonaMessage

interface PersonaMessage {
  sender: 'persona' | 'user';
  time: DateTimeInput;
  content: string;
}

ScheduleActivity

type ScheduleActivity =
  | 'sleep'
  | 'rest'
  | 'meal'
  | 'commute'
  | 'work'
  | 'study'
  | 'job-search'
  | 'travel'
  | 'exercise'
  | 'social'
  | 'errand'
  | 'free-time';

ScheduleEntry

interface ScheduleEntry {
  id: string;
  spaceId: string;
  startAt: string;
  endAt: string;
  activity: ScheduleActivity;
  title: string;
  description?: string;
  granularity: 'day' | 'ten-minute';
  sourceMessage?: string;
  metadata: Record<string, unknown>;
}

AvailabilityMode

type AvailabilityMode = 'online' | 'do-not-disturb' | 'offline';

AvailabilityRange

interface AvailabilityRange {
  startAt: string;
  endAt: string;
  mode: AvailabilityMode;
  sourceScheduleIds: string[];
  reason: string;
}

ScheduledAvailabilitySnapshot

interface ScheduledAvailabilitySnapshot {
  generatedAt: string;
  windowStartAt: string;
  windowEndAt: string;
  ranges: AvailabilityRange[];
}

MandatoryConversationContext

interface MandatoryConversationContext {
  formattedMessageHistory: string;
  conversationWindowLabel: string;
  memorySummary: string;
  personaAndUserFacts: StoredFact[];
  scheduleEntries: ScheduleEntry[];
  availability: ScheduledAvailabilitySnapshot;
}

Schedule helper exports

The following helpers are exported for applications and tests:

toDate(input)
toIso(input)
startOfUtcDay(input)
addUtcDays(input, days)
scheduleTargetDay(now)
createTenMinuteDailySchedule(input)
createMonthlyScheduleEntries(input)
availabilityModeForEntry(entry)
buildAvailabilitySnapshot(input)
dateKeysAround(input)

Conversation helper exports

formatMessageHistory({ personaName, messages })
conversationInstruction()
memoryExtractionInstruction(now)
buildMandatoryConversationContext(input)

formatMessageHistory converts structured messages into model-readable text:

Mina@2026-04-30T23:00:00.000Z: See you later.
user@2026-05-01T12:00:00.000Z: What are you doing?