docs: refresh wiki for current runtime structure
193
API-Reference.md
193
API-Reference.md
@@ -1,32 +1,41 @@
|
|||||||
# API Reference
|
# API Reference
|
||||||
|
|
||||||
This page documents the current public surface exported from the BoxBrain package root.
|
This page documents the **current public surface exported from the BoxBrain package root**.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export * from './adapters';
|
export * from './core/adapters';
|
||||||
|
export * from './core/types';
|
||||||
export * from './availability';
|
export * from './availability';
|
||||||
export * from './conversation';
|
export * from './conversation';
|
||||||
export * from './grok';
|
|
||||||
export * from './memory';
|
export * from './memory';
|
||||||
export * from './persona';
|
export * from './persona';
|
||||||
|
export * from './providers/grok';
|
||||||
export * from './schedule';
|
export * from './schedule';
|
||||||
export * from './timing';
|
export * from './timing';
|
||||||
export * from './types';
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Public API shape
|
||||||
|
|
||||||
|
The package root exposes both:
|
||||||
|
|
||||||
|
- **functional helpers** for direct use in applications
|
||||||
|
- **class-based service entrypoints** for clearer domain grouping in stateful integrations
|
||||||
|
|
||||||
## `persona`
|
## `persona`
|
||||||
|
|
||||||
|
### `PersonaService`
|
||||||
|
|
||||||
|
Class-based entrypoint for persona initialization.
|
||||||
|
|
||||||
### `initializePersona(db, input)`
|
### `initializePersona(db, input)`
|
||||||
|
|
||||||
Creates and persists a new persona runtime profile.
|
Creates and persists a new persona runtime profile.
|
||||||
|
|
||||||
**Signature**
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
initializePersona(db: IdentityDB, input: InitializePersonaInput): Promise<InitializedPersona>
|
initializePersona(db: IdentityDB, input: InitializePersonaInput): Promise<InitializedPersona>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Important input fields**
|
Important input fields:
|
||||||
|
|
||||||
- `displayName: string`
|
- `displayName: string`
|
||||||
- `seedText?: string`
|
- `seedText?: string`
|
||||||
@@ -42,36 +51,18 @@ initializePersona(db: IdentityDB, input: InitializePersonaInput): Promise<Initia
|
|||||||
- `generateProfileImage?: boolean`
|
- `generateProfileImage?: boolean`
|
||||||
- `reuseExistingSpace?: boolean`
|
- `reuseExistingSpace?: boolean`
|
||||||
|
|
||||||
`seedText` is the preferred initialize input shape: a single long freeform string that may already include personality, history, values, preferences, dislikes, and relationships. Structured fields remain available as optional supplemental hints and for backward compatibility.
|
`seedText` is the preferred initialization input shape: one long freeform string containing the persona's personality, history, values, preferences, and relationships when available.
|
||||||
|
|
||||||
**Behavior**
|
|
||||||
|
|
||||||
- generates a biography through `structuredModel`, using `seedText` as the primary source when provided
|
|
||||||
- extracts fact drafts through `structuredModel`
|
|
||||||
- writes biography facts into the persona space
|
|
||||||
- optionally generates a profile image and writes a profile-image fact
|
|
||||||
- creates a collision-resistant persona ID if one is not provided
|
|
||||||
|
|
||||||
**Returns**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface InitializedPersona {
|
|
||||||
id: string;
|
|
||||||
spaceName: string;
|
|
||||||
displayName: string;
|
|
||||||
biography: string;
|
|
||||||
profileImageUrl?: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `schedule`
|
## `schedule`
|
||||||
|
|
||||||
|
### `ScheduleService`
|
||||||
|
|
||||||
|
Class-based entrypoint for schedule generation, listing, and pruning.
|
||||||
|
|
||||||
### `generateSchedule(db, input)`
|
### `generateSchedule(db, input)`
|
||||||
|
|
||||||
Generates and persists schedule events, then derives schedule-backed availability entries.
|
Generates and persists schedule events, then derives schedule-backed availability entries.
|
||||||
|
|
||||||
**Signature**
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
generateSchedule(
|
generateSchedule(
|
||||||
db: IdentityDB,
|
db: IdentityDB,
|
||||||
@@ -79,38 +70,18 @@ generateSchedule(
|
|||||||
): Promise<{ events: BoxBrainScheduleEvent[]; availabilityEntries: BoxBrainAvailabilityEntry[] }>
|
): Promise<{ events: BoxBrainScheduleEvent[]; availabilityEntries: BoxBrainAvailabilityEntry[] }>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Important input fields**
|
|
||||||
|
|
||||||
- `spaceName: string`
|
|
||||||
- `displayName?: string`
|
|
||||||
- `currentDate: string`
|
|
||||||
- `scope: 'day' | 'week' | 'month'`
|
|
||||||
- `timezone?: string`
|
|
||||||
- `structuredModel: StructuredModelAdapter`
|
|
||||||
- `specialDateProvider?: SpecialDateProvider`
|
|
||||||
|
|
||||||
### `listScheduleEvents(db, input)`
|
### `listScheduleEvents(db, input)`
|
||||||
|
|
||||||
Lists persisted schedule events, excluding ones hidden by deletion markers.
|
Lists persisted schedule events, excluding ones hidden by deletion markers.
|
||||||
|
|
||||||
**Signature**
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
listScheduleEvents(db: IdentityDB, input: ListScheduleEventsInput): Promise<BoxBrainScheduleEvent[]>
|
listScheduleEvents(db: IdentityDB, input: ListScheduleEventsInput): Promise<BoxBrainScheduleEvent[]>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Filters**
|
|
||||||
|
|
||||||
- `spaceName`
|
|
||||||
- optional `from`
|
|
||||||
- optional `until`
|
|
||||||
|
|
||||||
### `pruneExpiredSchedule(db, input)`
|
### `pruneExpiredSchedule(db, input)`
|
||||||
|
|
||||||
Marks schedule events as deleted when they ended before `referenceTime` minus an optional grace window.
|
Marks schedule events as deleted when they ended before `referenceTime` minus an optional grace window.
|
||||||
|
|
||||||
**Signature**
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
pruneExpiredSchedule(db: IdentityDB, input: PruneExpiredScheduleInput): Promise<SchedulePruneResult>
|
pruneExpiredSchedule(db: IdentityDB, input: PruneExpiredScheduleInput): Promise<SchedulePruneResult>
|
||||||
```
|
```
|
||||||
@@ -119,58 +90,27 @@ pruneExpiredSchedule(db: IdentityDB, input: PruneExpiredScheduleInput): Promise<
|
|||||||
|
|
||||||
Marks schedule events as deleted when they start before a cutoff timestamp.
|
Marks schedule events as deleted when they start before a cutoff timestamp.
|
||||||
|
|
||||||
**Signature**
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
pruneScheduleBefore(db: IdentityDB, input: PruneScheduleBeforeInput): Promise<SchedulePruneResult>
|
pruneScheduleBefore(db: IdentityDB, input: PruneScheduleBeforeInput): Promise<SchedulePruneResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Common types**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
type BoxBrainScheduleScope = 'day' | 'week' | 'month';
|
|
||||||
type BoxBrainScheduleEventKind = 'routine' | 'special';
|
|
||||||
|
|
||||||
interface BoxBrainScheduleEvent {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
description?: string;
|
|
||||||
startAt: string;
|
|
||||||
endAt: string;
|
|
||||||
availabilityMode: BoxBrainAvailabilityMode;
|
|
||||||
availabilityReason?: string;
|
|
||||||
kind: BoxBrainScheduleEventKind;
|
|
||||||
topics: BoxBrainTopicDraft[];
|
|
||||||
metadata?: JsonValue | null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `availability`
|
## `availability`
|
||||||
|
|
||||||
|
### `AvailabilityService`
|
||||||
|
|
||||||
|
Class-based entrypoint for availability writes, listing, and snapshot queries.
|
||||||
|
|
||||||
### `setAvailabilityStatus(db, input)`
|
### `setAvailabilityStatus(db, input)`
|
||||||
|
|
||||||
Persists an explicit availability entry.
|
Persists an explicit availability entry.
|
||||||
|
|
||||||
**Signature**
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
setAvailabilityStatus(db: IdentityDB, input: SetAvailabilityStatusInput): Promise<BoxBrainAvailabilityEntry>
|
setAvailabilityStatus(db: IdentityDB, input: SetAvailabilityStatusInput): Promise<BoxBrainAvailabilityEntry>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Important input fields**
|
|
||||||
|
|
||||||
- `spaceName: string`
|
|
||||||
- `mode: 'online' | 'do_not_disturb' | 'offline'`
|
|
||||||
- `reason?: string`
|
|
||||||
- `effectiveFrom: string`
|
|
||||||
- `until?: string`
|
|
||||||
- `sourceType?: 'schedule' | 'manual' | 'tool'`
|
|
||||||
- `eventId?: string`
|
|
||||||
- `metadata?: JsonValue | null`
|
|
||||||
|
|
||||||
### `listAvailabilityEntries(db, input)`
|
### `listAvailabilityEntries(db, input)`
|
||||||
|
|
||||||
Lists explicit availability entries in chronological order.
|
Lists availability entries in chronological order.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
listAvailabilityEntries(db: IdentityDB, input: ListAvailabilityEntriesInput): Promise<BoxBrainAvailabilityEntry[]>
|
listAvailabilityEntries(db: IdentityDB, input: ListAvailabilityEntriesInput): Promise<BoxBrainAvailabilityEntry[]>
|
||||||
@@ -184,32 +124,19 @@ Returns the active availability state at a timestamp plus the next transition.
|
|||||||
getAvailabilitySnapshot(db: IdentityDB, input: GetAvailabilitySnapshotInput): Promise<BoxBrainAvailabilitySnapshot>
|
getAvailabilitySnapshot(db: IdentityDB, input: GetAvailabilitySnapshotInput): Promise<BoxBrainAvailabilitySnapshot>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Important types**
|
Important types:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type BoxBrainAvailabilityMode = 'online' | 'do_not_disturb' | 'offline';
|
type BoxBrainAvailabilityMode = 'online' | 'do_not_disturb' | 'offline';
|
||||||
type BoxBrainAvailabilitySourceType = 'default' | 'schedule' | 'manual' | 'tool';
|
type BoxBrainAvailabilitySourceType = 'default' | 'schedule' | 'manual' | 'tool';
|
||||||
|
|
||||||
interface BoxBrainAvailabilityEntry {
|
|
||||||
id: string;
|
|
||||||
mode: BoxBrainAvailabilityMode;
|
|
||||||
reason?: string;
|
|
||||||
effectiveFrom: string;
|
|
||||||
until?: string;
|
|
||||||
sourceType: BoxBrainAvailabilitySourceType;
|
|
||||||
eventId?: string;
|
|
||||||
createdAt?: string;
|
|
||||||
metadata?: JsonValue | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BoxBrainAvailabilitySnapshot {
|
|
||||||
current: BoxBrainAvailabilityEntry;
|
|
||||||
next: BoxBrainAvailabilityEntry | null;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## `conversation`
|
## `conversation`
|
||||||
|
|
||||||
|
### `ConversationService`
|
||||||
|
|
||||||
|
Class-based entrypoint for inbound replies, proactive openings, and entry listing.
|
||||||
|
|
||||||
### `replyToConversation(db, input)`
|
### `replyToConversation(db, input)`
|
||||||
|
|
||||||
Persists an inbound message and generates a DM-style response turn.
|
Persists an inbound message and generates a DM-style response turn.
|
||||||
@@ -234,41 +161,29 @@ Lists stored conversation entries for a persona, optionally filtered by counterp
|
|||||||
listConversationEntries(db: IdentityDB, input: ListConversationEntriesInput): Promise<BoxBrainConversationEntry[]>
|
listConversationEntries(db: IdentityDB, input: ListConversationEntriesInput): Promise<BoxBrainConversationEntry[]>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Required model roles for turn generation**
|
Required model roles for turn generation:
|
||||||
|
|
||||||
Both `replyToConversation` and `startConversation` require:
|
|
||||||
|
|
||||||
- `mandatoryMemoryModel: StructuredModelAdapter`
|
- `mandatoryMemoryModel: StructuredModelAdapter`
|
||||||
- `contextualMemoryModel: StructuredModelAdapter`
|
- `contextualMemoryModel: StructuredModelAdapter`
|
||||||
- `responseModel: StructuredModelAdapter`
|
- `responseModel: StructuredModelAdapter`
|
||||||
|
|
||||||
**Turn result**
|
## `memory`
|
||||||
|
|
||||||
|
### `FactDraftMemoryStore`
|
||||||
|
|
||||||
|
Class-based entrypoint for persisting extracted fact drafts into IdentityDB.
|
||||||
|
|
||||||
|
### `persistFactDrafts(db, input)`
|
||||||
|
|
||||||
|
Low-level helper for writing BoxBrain fact drafts into IdentityDB.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
interface ConversationTurnResult {
|
persistFactDrafts(db: IdentityDB, input: PersistFactDraftsInput): Promise<Fact[]>
|
||||||
blocked: boolean;
|
|
||||||
blockedReason?: string;
|
|
||||||
blockedUntil?: string;
|
|
||||||
messages: BoxBrainMessage[];
|
|
||||||
usedMemories: BoxBrainMemoryReference[];
|
|
||||||
toolCallsExecuted: ConversationToolCall[];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Message type**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface BoxBrainMessage {
|
|
||||||
text: string;
|
|
||||||
typingDelaySeconds: number;
|
|
||||||
replyDelaySeconds: number;
|
|
||||||
totalDelaySeconds: number;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## `timing`
|
## `timing`
|
||||||
|
|
||||||
### Availability constants
|
### Constants
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
ONLINE_AVAILABILITY
|
ONLINE_AVAILABILITY
|
||||||
@@ -276,6 +191,10 @@ DND_AVAILABILITY
|
|||||||
OFFLINE_AVAILABILITY
|
OFFLINE_AVAILABILITY
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `TimingProfile`
|
||||||
|
|
||||||
|
Class-based entrypoint for timing calculations.
|
||||||
|
|
||||||
### `createTypingDelay(message, options?)`
|
### `createTypingDelay(message, options?)`
|
||||||
|
|
||||||
Computes a per-message typing delay based on message length.
|
Computes a per-message typing delay based on message length.
|
||||||
@@ -346,6 +265,10 @@ interface SpecialDateProvider {
|
|||||||
|
|
||||||
## `grok`
|
## `grok`
|
||||||
|
|
||||||
|
### `GrokApiClient`
|
||||||
|
|
||||||
|
Class-based xAI runtime client used by the Grok adapter helpers.
|
||||||
|
|
||||||
### `createGrokTextModelAdapter(options)`
|
### `createGrokTextModelAdapter(options)`
|
||||||
|
|
||||||
Creates a `TextModelAdapter` that uses xAI chat completions.
|
Creates a `TextModelAdapter` that uses xAI chat completions.
|
||||||
@@ -370,21 +293,9 @@ createGrokAdapters(options: GrokAdapterBundleOptions): {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## `memory`
|
|
||||||
|
|
||||||
### `persistFactDrafts(db, input)`
|
|
||||||
|
|
||||||
Low-level helper for writing BoxBrain fact drafts into IdentityDB.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
persistFactDrafts(db: IdentityDB, input: PersistFactDraftsInput): Promise<Fact[]>
|
|
||||||
```
|
|
||||||
|
|
||||||
Useful when extending BoxBrain with your own runtime modules.
|
|
||||||
|
|
||||||
## `types`
|
## `types`
|
||||||
|
|
||||||
Selected important domain types:
|
Selected important domain types include:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type BoxBrainFactDomain =
|
type BoxBrainFactDomain =
|
||||||
|
|||||||
@@ -1,48 +1,50 @@
|
|||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
## Current setup assumptions
|
## Setup options
|
||||||
|
|
||||||
At the current stage, BoxBrain is a local TypeScript/Bun framework that depends on a sibling checkout of IdentityDB.
|
BoxBrain now consumes the published `identitydb` package from npm, so **a sibling checkout of IdentityDB is no longer required** for normal usage or local verification.
|
||||||
|
|
||||||
The package configuration currently points to:
|
### Use BoxBrain in your own project
|
||||||
|
|
||||||
```json
|
```bash
|
||||||
"identitydb": "file:../IdentityDB"
|
bun add boxbrain identitydb
|
||||||
```
|
```
|
||||||
|
|
||||||
So a practical local setup looks like this:
|
### Work on the BoxBrain repository itself
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://git.psw.kr/p-sw/BoxBrain.git
|
git clone https://git.psw.kr/p-sw/BoxBrain.git
|
||||||
git clone https://git.psw.kr/p-sw/IdentityDB.git
|
|
||||||
```
|
|
||||||
|
|
||||||
with both repositories living next to each other.
|
|
||||||
|
|
||||||
## Install and verify
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd BoxBrain
|
cd BoxBrain
|
||||||
bun install
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verify the repository
|
||||||
|
|
||||||
|
```bash
|
||||||
bun run test
|
bun run test
|
||||||
bun run check
|
bun run check
|
||||||
bun run build
|
bun run build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Minimal dependencies
|
If you hit a `better-sqlite3` native module / `NODE_MODULE_VERSION` mismatch after environment changes, reset the install so Bun can re-run trusted lifecycle scripts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf node_modules bun.lock
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Runtime requirements
|
||||||
|
|
||||||
You need:
|
You need:
|
||||||
|
|
||||||
- Node.js 20+
|
- Node.js 20+
|
||||||
- Bun
|
- Bun
|
||||||
- IdentityDB available at `../IdentityDB`
|
- an initialized IdentityDB database connection at runtime
|
||||||
|
|
||||||
## Create an IdentityDB instance
|
## Create an IdentityDB instance
|
||||||
|
|
||||||
BoxBrain uses IdentityDB as the persistence layer.
|
BoxBrain uses IdentityDB as the persistence layer.
|
||||||
|
|
||||||
A minimal in-memory setup:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { IdentityDB } from 'identitydb';
|
import { IdentityDB } from 'identitydb';
|
||||||
|
|
||||||
@@ -58,7 +60,7 @@ For a persistent local database, replace `':memory:'` with a file path.
|
|||||||
|
|
||||||
## Create model adapters
|
## Create model adapters
|
||||||
|
|
||||||
BoxBrain runtime code expects provider adapters instead of hard-coding a specific vendor inside the core functions.
|
BoxBrain expects provider adapters instead of hard-coding a vendor into the core runtime.
|
||||||
|
|
||||||
### Provider-agnostic contracts
|
### Provider-agnostic contracts
|
||||||
|
|
||||||
@@ -84,7 +86,9 @@ const grok = createGrokAdapters({
|
|||||||
|
|
||||||
## Initialize a persona
|
## Initialize a persona
|
||||||
|
|
||||||
This is the first major BoxBrain workflow.
|
You can use either the functional helper or the class-based service entrypoint.
|
||||||
|
|
||||||
|
### Functional helper
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { IdentityDB } from 'identitydb';
|
import { IdentityDB } from 'identitydb';
|
||||||
@@ -109,18 +113,32 @@ const persona = await initializePersona(db, {
|
|||||||
imageModel: grok.image,
|
imageModel: grok.image,
|
||||||
generateProfileImage: true,
|
generateProfileImage: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(persona);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### What initialization does
|
### Class-based service
|
||||||
|
|
||||||
- generates a detailed biography
|
```ts
|
||||||
- can start from a single long freeform persona seed string
|
import { IdentityDB } from 'identitydb';
|
||||||
- extracts IdentityDB-ready facts
|
import { createGrokAdapters, PersonaService } from 'boxbrain';
|
||||||
- creates or reuses an IdentityDB space (depending on options)
|
|
||||||
- optionally generates a profile image
|
const db = await IdentityDB.connect({ client: 'sqlite', filename: ':memory:' });
|
||||||
- persists biography and image facts
|
await db.initialize();
|
||||||
|
|
||||||
|
const grok = createGrokAdapters({
|
||||||
|
apiKey: process.env.XAI_API_KEY!,
|
||||||
|
textModel: 'grok-4.3-mini',
|
||||||
|
structuredModel: 'grok-4.3',
|
||||||
|
imageModel: 'grok-imagine-image-quality',
|
||||||
|
});
|
||||||
|
|
||||||
|
const personas = new PersonaService(db);
|
||||||
|
|
||||||
|
const persona = await personas.initialize({
|
||||||
|
displayName: 'Mina',
|
||||||
|
seedText: 'Mina is a thoughtful, witty Seoul product designer who loves quiet cafés.',
|
||||||
|
structuredModel: grok.structured,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Generate a schedule
|
## Generate a schedule
|
||||||
|
|
||||||
@@ -151,14 +169,6 @@ console.log(schedule.events);
|
|||||||
console.log(schedule.availabilityEntries);
|
console.log(schedule.availabilityEntries);
|
||||||
```
|
```
|
||||||
|
|
||||||
### What schedule generation does
|
|
||||||
|
|
||||||
- reads persona facts and recent schedule continuity
|
|
||||||
- optionally loads external special-date context
|
|
||||||
- generates realistic events for a day/week/month window
|
|
||||||
- stores schedule facts in IdentityDB
|
|
||||||
- automatically emits schedule-derived availability entries
|
|
||||||
|
|
||||||
## Read or override availability
|
## Read or override availability
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
@@ -226,8 +236,6 @@ console.log(reply.toolCallsExecuted);
|
|||||||
|
|
||||||
## Timing helpers
|
## Timing helpers
|
||||||
|
|
||||||
If you want to inspect or reuse BoxBrain’s timing rules directly:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import {
|
import {
|
||||||
ONLINE_AVAILABILITY,
|
ONLINE_AVAILABILITY,
|
||||||
@@ -245,9 +253,9 @@ const typingDelay = createTypingDelay('지금 뭐해?', {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Caveats
|
## Important caveats
|
||||||
|
|
||||||
### 1. BoxBrain is currently a library, not an HTTP service
|
### 1. BoxBrain is a library, not an HTTP service
|
||||||
|
|
||||||
You call the exported TypeScript APIs directly.
|
You call the exported TypeScript APIs directly.
|
||||||
|
|
||||||
@@ -255,10 +263,10 @@ You call the exported TypeScript APIs directly.
|
|||||||
|
|
||||||
The framework assumes IdentityDB is available and initialized.
|
The framework assumes IdentityDB is available and initialized.
|
||||||
|
|
||||||
### 3. Current local development uses a sibling checkout
|
### 3. Internal source folders are a repository concern
|
||||||
|
|
||||||
Because the package currently depends on `file:../IdentityDB`, a standalone `npm install boxbrain` style flow is not the current development path yet.
|
The repository is organized by domain folders under `src/`, but the published package is still consumed through the package root exports.
|
||||||
|
|
||||||
### 4. `better-sqlite3` native rebuilds may be needed in local dev
|
### 4. Clean Bun installs depend on trusted lifecycle scripts
|
||||||
|
|
||||||
If you hit a native module mismatch through the local IdentityDB dependency, rebuilding `better-sqlite3` from the IdentityDB workspace may be required.
|
The repository keeps `trustedDependencies` for `better-sqlite3` and `esbuild` so native/runtime build steps succeed during clean installs.
|
||||||
|
|||||||
120
Home.md
120
Home.md
@@ -2,85 +2,79 @@
|
|||||||
|
|
||||||
BoxBrain is an IdentityDB-backed TypeScript framework for building **synthetic personas that feel like real DM contacts**.
|
BoxBrain is an IdentityDB-backed TypeScript framework for building **synthetic personas that feel like real DM contacts**.
|
||||||
|
|
||||||
It is not a finished chatbot product. It is a **framework for persona runtime design**: a reusable harness for turning long-term memory, schedules, availability, and multi-step LLM orchestration into believable human-like messaging behavior.
|
It is not a finished chatbot product. It is a **framework-first runtime library** for composing persona memory, schedules, availability, and multi-step LLM orchestration into believable messaging behavior.
|
||||||
|
|
||||||
## Why BoxBrain exists
|
## What BoxBrain currently provides
|
||||||
|
|
||||||
Most LLM chat systems are optimized for correctness, utility, or task completion. BoxBrain exists for a different goal:
|
|
||||||
|
|
||||||
- make a persona feel like a **specific person**, not a generic assistant
|
|
||||||
- preserve continuity through **IdentityDB facts** instead of a short rolling prompt only
|
|
||||||
- let that persona have a **life outside the chat**
|
|
||||||
- make conversation timing and availability feel **human**, not instant and mechanical
|
|
||||||
- keep the whole system **framework-first**, so applications can compose their own transports and product UX on top
|
|
||||||
|
|
||||||
In short: BoxBrain is a harness for building personas that have memory, history, schedules, contactability, and DM-style messaging behavior.
|
|
||||||
|
|
||||||
## What the framework currently provides
|
|
||||||
|
|
||||||
- provider-agnostic adapter contracts for text, structured-output, image, and special-date retrieval
|
- provider-agnostic adapter contracts for text, structured-output, image, and special-date retrieval
|
||||||
- a ready-made xAI Grok adapter set for text, structured-output, and image generation
|
- a ready-made xAI Grok adapter set
|
||||||
- one IdentityDB **space** per persona as the primary isolation boundary
|
- one IdentityDB space per persona as the main isolation boundary
|
||||||
- persona initialization from a long freeform seed string that the LLM breaks into biography-ready detail and IdentityDB facts
|
- persona initialization from a long freeform seed string, with optional supplemental structured hints
|
||||||
- LLM-generated biography creation followed by fact extraction into IdentityDB
|
- biography generation and fact extraction into IdentityDB
|
||||||
- optional profile image generation during persona initialization
|
- optional profile image generation during persona initialization
|
||||||
- realistic schedule generation for day, week, and month scopes
|
- schedule generation for `day`, `week`, and `month` scopes
|
||||||
- schedule persistence, listing, and pruning
|
- schedule persistence, listing, and pruning
|
||||||
- availability state persistence with schedule, manual, and tool-driven overrides
|
- availability persistence with schedule/manual/tool overrides
|
||||||
- availability snapshots with current and next transition resolution
|
- availability snapshots with current and next-transition resolution
|
||||||
- DM-style conversation orchestration for inbound replies and proactive openings
|
- DM-style conversation orchestration for inbound replies and proactive openings
|
||||||
- two-stage memory retrieval for conversation turns: mandatory memories first, contextual memories second
|
- human-like first-reply and typing delay helpers
|
||||||
- human-like first-reply delay and per-message typing delay helpers
|
|
||||||
- refusal / farewell flows that can trigger an availability-changing tool call
|
|
||||||
|
|
||||||
## What is still planned
|
## What is still planned
|
||||||
|
|
||||||
These are **not** implemented as part of the core library yet:
|
These are **not** implemented as part of the core library yet:
|
||||||
|
|
||||||
- HTTP/RPC wrappers around the runtime APIs
|
- HTTP/RPC wrappers around the runtime APIs
|
||||||
- additional ready-made vendor adapter packages beyond Grok
|
- additional ready-made provider adapter packages beyond Grok
|
||||||
- production-focused runtime/persistence integrations beyond the in-process core library
|
- production-focused runtime integrations beyond the in-process core library
|
||||||
|
|
||||||
## Recommended reading order
|
## Current project status
|
||||||
|
|
||||||
1. [Purpose and Architecture](Purpose-and-Architecture)
|
|
||||||
2. [Getting Started](Getting-Started)
|
|
||||||
3. [API Reference](API-Reference)
|
|
||||||
4. [xAI Grok Adapter](xAI-Grok-Adapter)
|
|
||||||
|
|
||||||
## BoxBrain mental model
|
|
||||||
|
|
||||||
A BoxBrain persona works like this:
|
|
||||||
|
|
||||||
1. **Initialize a persona** from a long freeform seed string, optionally with extra structured hints.
|
|
||||||
2. Generate a detailed biography.
|
|
||||||
3. Extract biography facts and store them in the persona's IdentityDB space.
|
|
||||||
4. Generate schedules anchored to time and external special dates.
|
|
||||||
5. Derive availability from schedule or explicit overrides.
|
|
||||||
6. Run conversations by retrieving mandatory/contextual memories, generating a turn plan, and emitting DM-style messages with delays.
|
|
||||||
|
|
||||||
## Current code surface
|
|
||||||
|
|
||||||
The package root currently exports:
|
|
||||||
|
|
||||||
- `./adapters`
|
|
||||||
- `./availability`
|
|
||||||
- `./conversation`
|
|
||||||
- `./grok`
|
|
||||||
- `./memory`
|
|
||||||
- `./persona`
|
|
||||||
- `./schedule`
|
|
||||||
- `./timing`
|
|
||||||
- `./types`
|
|
||||||
|
|
||||||
## Development status
|
|
||||||
|
|
||||||
Repository status at the time of writing:
|
|
||||||
|
|
||||||
- package/runtime: **Bun**
|
- package/runtime: **Bun**
|
||||||
- language: **TypeScript**
|
- language: **TypeScript**
|
||||||
- tests: **Vitest**
|
- tests: **Vitest**
|
||||||
- build: **tsup**
|
- build: **tsup**
|
||||||
- storage/memory dependency: **IdentityDB**
|
- persistence dependency: published **`identitydb@0.2.0`** from npm
|
||||||
|
- release automation: tag-triggered **Gitea Actions** workflow for npm publishing
|
||||||
|
|
||||||
See [Getting Started](Getting-Started) for a working local setup pattern.
|
## Recommended reading order
|
||||||
|
|
||||||
|
1. [Purpose and Architecture](Purpose-and-Architecture)
|
||||||
|
2. [Getting Started](Getting-Started)
|
||||||
|
3. [Source Layout](Source-Layout)
|
||||||
|
4. [API Reference](API-Reference)
|
||||||
|
5. [Release Workflow](Release-Workflow)
|
||||||
|
6. [xAI Grok Adapter](xAI-Grok-Adapter)
|
||||||
|
|
||||||
|
## Mental model
|
||||||
|
|
||||||
|
A BoxBrain persona works like this:
|
||||||
|
|
||||||
|
1. **Initialize a persona** from a long freeform seed string.
|
||||||
|
2. Generate a detailed biography.
|
||||||
|
3. Extract biography facts and store them in the persona's IdentityDB space.
|
||||||
|
4. Generate schedules anchored to time and optional special-date context.
|
||||||
|
5. Derive availability from schedule or explicit overrides.
|
||||||
|
6. Run conversations by retrieving memories, planning a turn, and emitting DM-style messages with delays.
|
||||||
|
|
||||||
|
## Public surface at a glance
|
||||||
|
|
||||||
|
The package root currently re-exports:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export * from './core/adapters';
|
||||||
|
export * from './core/types';
|
||||||
|
export * from './availability';
|
||||||
|
export * from './conversation';
|
||||||
|
export * from './memory';
|
||||||
|
export * from './persona';
|
||||||
|
export * from './providers/grok';
|
||||||
|
export * from './schedule';
|
||||||
|
export * from './timing';
|
||||||
|
```
|
||||||
|
|
||||||
|
That means consumers can use both:
|
||||||
|
|
||||||
|
- functional helpers like `initializePersona`, `generateSchedule`, and `replyToConversation`
|
||||||
|
- class-based entrypoints like `PersonaService`, `ScheduleService`, `AvailabilityService`, `ConversationService`, `FactDraftMemoryStore`, `TimingProfile`, and `GrokApiClient`
|
||||||
|
|
||||||
|
See [Getting Started](Getting-Started) for local setup and [API Reference](API-Reference) for the current exported runtime surface.
|
||||||
|
|||||||
85
Release-Workflow.md
Normal file
85
Release-Workflow.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# Release Workflow
|
||||||
|
|
||||||
|
BoxBrain uses a **tag-triggered Gitea Actions workflow** to publish the package to npm.
|
||||||
|
|
||||||
|
## Trigger
|
||||||
|
|
||||||
|
Creating and pushing either of these tag forms starts the release workflow:
|
||||||
|
|
||||||
|
- `vX.Y.Z`
|
||||||
|
- `X.Y.Z`
|
||||||
|
|
||||||
|
The workflow file lives at:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.gitea/workflows/npm-release.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verify stage
|
||||||
|
|
||||||
|
Before publishing, the workflow performs a full verification pass on the tagged source.
|
||||||
|
|
||||||
|
At a high level it:
|
||||||
|
|
||||||
|
1. installs release tooling in the CI container
|
||||||
|
2. clones the tagged BoxBrain source
|
||||||
|
3. verifies that the tag name matches `package.json` version
|
||||||
|
4. runs the full verify pipeline:
|
||||||
|
- `bun install --frozen-lockfile`
|
||||||
|
- `bun run test`
|
||||||
|
- `bun run check`
|
||||||
|
- `bun run build`
|
||||||
|
|
||||||
|
## Publish stage
|
||||||
|
|
||||||
|
Only after verify succeeds, the workflow:
|
||||||
|
|
||||||
|
1. clones the tagged source again
|
||||||
|
2. installs dependencies with Bun
|
||||||
|
3. builds the package
|
||||||
|
4. publishes to npm with `NODE_AUTH_TOKEN`
|
||||||
|
|
||||||
|
## IdentityDB dependency model
|
||||||
|
|
||||||
|
BoxBrain now depends on the published npm package:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"identitydb": "0.2.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
That means the release workflow **does not need a sibling IdentityDB checkout** anymore.
|
||||||
|
|
||||||
|
## Trusted Bun dependencies
|
||||||
|
|
||||||
|
The repository keeps these entries in `trustedDependencies`:
|
||||||
|
|
||||||
|
- `better-sqlite3`
|
||||||
|
- `esbuild`
|
||||||
|
|
||||||
|
This matters because clean Bun installs must allow the necessary lifecycle scripts for native/runtime build steps.
|
||||||
|
|
||||||
|
## Local verification before tagging
|
||||||
|
|
||||||
|
A normal local verification pass is:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run test
|
||||||
|
bun run check
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to simulate a clean release-style clone:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf /tmp/boxbrain-release-check
|
||||||
|
git clone https://git.psw.kr/p-sw/BoxBrain.git /tmp/boxbrain-release-check
|
||||||
|
cd /tmp/boxbrain-release-check
|
||||||
|
bun install
|
||||||
|
bun run test && bun run check && bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Current published version
|
||||||
|
|
||||||
|
At the time of writing, BoxBrain has already been published as:
|
||||||
|
|
||||||
|
- `boxbrain@0.1.0`
|
||||||
52
Source-Layout.md
Normal file
52
Source-Layout.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Source Layout
|
||||||
|
|
||||||
|
The repository is now organized by **domain folders** under `src/` instead of a flat list of top-level runtime files.
|
||||||
|
|
||||||
|
## Current `src/` structure
|
||||||
|
|
||||||
|
- `src/core/` — shared adapter interfaces, common types, and fact helpers
|
||||||
|
- `src/persona/` — persona initialization runtime
|
||||||
|
- `src/schedule/` — schedule generation, listing, and pruning
|
||||||
|
- `src/availability/` — availability persistence and snapshot resolution
|
||||||
|
- `src/conversation/` — DM-style conversation orchestration
|
||||||
|
- `src/memory/` — fact-draft persistence into IdentityDB
|
||||||
|
- `src/timing/` — timing constants, delay helpers, and timing profile class
|
||||||
|
- `src/providers/grok/` — xAI-specific runtime client and adapter helpers
|
||||||
|
|
||||||
|
## Why the structure changed
|
||||||
|
|
||||||
|
The repository moved to domain folders to make the runtime easier to navigate as BoxBrain grew beyond a few flat modules.
|
||||||
|
|
||||||
|
This structure now makes it clearer where to look for:
|
||||||
|
|
||||||
|
- public entrypoints for a domain
|
||||||
|
- internal helpers related to that domain
|
||||||
|
- class-based service abstractions for stateful integrations
|
||||||
|
- provider-specific code that should stay separate from the provider-agnostic core
|
||||||
|
|
||||||
|
## Class-oriented runtime surface
|
||||||
|
|
||||||
|
The current repository also leans more heavily on class-based entrypoints while still keeping the existing functional helpers.
|
||||||
|
|
||||||
|
Notable exported classes:
|
||||||
|
|
||||||
|
- `PersonaService`
|
||||||
|
- `ScheduleService`
|
||||||
|
- `AvailabilityService`
|
||||||
|
- `ConversationService`
|
||||||
|
- `FactDraftMemoryStore`
|
||||||
|
- `TimingProfile`
|
||||||
|
- `GrokApiClient`
|
||||||
|
|
||||||
|
That means consumers can choose between:
|
||||||
|
|
||||||
|
- **functional usage** for quick direct calls
|
||||||
|
- **service-class usage** for cleaner composition inside larger applications
|
||||||
|
|
||||||
|
## Important packaging note
|
||||||
|
|
||||||
|
The folder layout described on this page is the **repository source structure**.
|
||||||
|
|
||||||
|
The published package is still consumed through the **package root exports**, not through documented public subpath exports.
|
||||||
|
|
||||||
|
See [API Reference](API-Reference) for the supported root-level public surface.
|
||||||
@@ -3,5 +3,7 @@
|
|||||||
- [Home](Home)
|
- [Home](Home)
|
||||||
- [Purpose and Architecture](Purpose-and-Architecture)
|
- [Purpose and Architecture](Purpose-and-Architecture)
|
||||||
- [Getting Started](Getting-Started)
|
- [Getting Started](Getting-Started)
|
||||||
|
- [Source Layout](Source-Layout)
|
||||||
- [API Reference](API-Reference)
|
- [API Reference](API-Reference)
|
||||||
|
- [Release Workflow](Release-Workflow)
|
||||||
- [xAI Grok Adapter](xAI-Grok-Adapter)
|
- [xAI Grok Adapter](xAI-Grok-Adapter)
|
||||||
|
|||||||
Reference in New Issue
Block a user