diff --git a/API-Reference.md b/API-Reference.md new file mode 100644 index 0000000..8179a33 --- /dev/null +++ b/API-Reference.md @@ -0,0 +1,420 @@ +# API Reference + +This page documents the current public surface exported from the BoxBrain package root. + +```ts +export * from './adapters'; +export * from './availability'; +export * from './conversation'; +export * from './grok'; +export * from './memory'; +export * from './persona'; +export * from './schedule'; +export * from './timing'; +export * from './types'; +``` + +## `persona` + +### `initializePersona(db, input)` + +Creates and persists a new persona runtime profile. + +**Signature** + +```ts +initializePersona(db: IdentityDB, input: InitializePersonaInput): Promise +``` + +**Important input fields** + +- `displayName: string` +- `personality: string` +- `history?: string` +- `values?: string[]` +- `likes?: string[]` +- `dislikes?: string[]` +- `relationships?: PersonaRelationshipInput[]` +- `currentDate?: string` +- `structuredModel: StructuredModelAdapter` +- `imageModel?: ImageModelAdapter` +- `generateProfileImage?: boolean` +- `reuseExistingSpace?: boolean` + +**Behavior** + +- generates a biography through `structuredModel` +- 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` + +### `generateSchedule(db, input)` + +Generates and persists schedule events, then derives schedule-backed availability entries. + +**Signature** + +```ts +generateSchedule( + db: IdentityDB, + input: GenerateScheduleInput, +): 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)` + +Lists persisted schedule events, excluding ones hidden by deletion markers. + +**Signature** + +```ts +listScheduleEvents(db: IdentityDB, input: ListScheduleEventsInput): Promise +``` + +**Filters** + +- `spaceName` +- optional `from` +- optional `until` + +### `pruneExpiredSchedule(db, input)` + +Marks schedule events as deleted when they ended before `referenceTime` minus an optional grace window. + +**Signature** + +```ts +pruneExpiredSchedule(db: IdentityDB, input: PruneExpiredScheduleInput): Promise +``` + +### `pruneScheduleBefore(db, input)` + +Marks schedule events as deleted when they start before a cutoff timestamp. + +**Signature** + +```ts +pruneScheduleBefore(db: IdentityDB, input: PruneScheduleBeforeInput): Promise +``` + +**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` + +### `setAvailabilityStatus(db, input)` + +Persists an explicit availability entry. + +**Signature** + +```ts +setAvailabilityStatus(db: IdentityDB, input: SetAvailabilityStatusInput): Promise +``` + +**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)` + +Lists explicit availability entries in chronological order. + +```ts +listAvailabilityEntries(db: IdentityDB, input: ListAvailabilityEntriesInput): Promise +``` + +### `getAvailabilitySnapshot(db, input)` + +Returns the active availability state at a timestamp plus the next transition. + +```ts +getAvailabilitySnapshot(db: IdentityDB, input: GetAvailabilitySnapshotInput): Promise +``` + +**Important types** + +```ts +type BoxBrainAvailabilityMode = 'online' | 'do_not_disturb' | 'offline'; +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` + +### `replyToConversation(db, input)` + +Persists an inbound message and generates a DM-style response turn. + +```ts +replyToConversation(db: IdentityDB, input: ReplyToConversationInput): Promise +``` + +### `startConversation(db, input)` + +Generates a proactive outbound opening turn with no inbound user message. + +```ts +startConversation(db: IdentityDB, input: StartConversationInput): Promise +``` + +### `listConversationEntries(db, input)` + +Lists stored conversation entries for a persona, optionally filtered by counterpart and time range. + +```ts +listConversationEntries(db: IdentityDB, input: ListConversationEntriesInput): Promise +``` + +**Required model roles for turn generation** + +Both `replyToConversation` and `startConversation` require: + +- `mandatoryMemoryModel: StructuredModelAdapter` +- `contextualMemoryModel: StructuredModelAdapter` +- `responseModel: StructuredModelAdapter` + +**Turn result** + +```ts +interface ConversationTurnResult { + 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` + +### Availability constants + +```ts +ONLINE_AVAILABILITY +DND_AVAILABILITY +OFFLINE_AVAILABILITY +``` + +### `createTypingDelay(message, options?)` + +Computes a per-message typing delay based on message length. + +```ts +createTypingDelay(message: string, options?: TypingDelayOptions): number +``` + +Default per-character range: + +- minimum: `0.05` seconds +- maximum: `0.08` seconds + +### `createReplyDelay(availability, options)` + +Computes the initial reply delay for the first message in an exchange. + +```ts +createReplyDelay(availability: BoxBrainAvailability, options: ReplyDelayOptions): number | null +``` + +Behavior summary: + +- `offline` -> `null` +- not first reply in exchange -> `0` +- `do_not_disturb` -> probabilistic reply or `null` +- `online` -> short randomized delay + +## `adapters` + +### `TextModelAdapter` + +```ts +interface TextModelAdapter { + provider: string; + model: string; + generateText(request: TextGenerationRequest): Promise; +} +``` + +### `StructuredModelAdapter` + +```ts +interface StructuredModelAdapter { + provider: string; + model: string; + generateObject(request: StructuredGenerationRequest): Promise; +} +``` + +### `ImageModelAdapter` + +```ts +interface ImageModelAdapter { + provider: string; + model: string; + generateImage(request: ImageGenerationRequest): Promise; +} +``` + +### `SpecialDateProvider` + +```ts +interface SpecialDateProvider { + listSpecialDates(request: SpecialDateRequest): Promise; +} +``` + +## `grok` + +### `createGrokTextModelAdapter(options)` + +Creates a `TextModelAdapter` that uses xAI chat completions. + +### `createGrokStructuredModelAdapter(options)` + +Creates a `StructuredModelAdapter` that uses xAI chat completions with `response_format` configured as JSON object or JSON schema. + +### `createGrokImageModelAdapter(options)` + +Creates an `ImageModelAdapter` that uses xAI image generation. + +### `createGrokAdapters(options)` + +Convenience bundle creator. + +```ts +createGrokAdapters(options: GrokAdapterBundleOptions): { + text: TextModelAdapter; + structured: StructuredModelAdapter; + image: ImageModelAdapter; +} +``` + +## `memory` + +### `persistFactDrafts(db, input)` + +Low-level helper for writing BoxBrain fact drafts into IdentityDB. + +```ts +persistFactDrafts(db: IdentityDB, input: PersistFactDraftsInput): Promise +``` + +Useful when extending BoxBrain with your own runtime modules. + +## `types` + +Selected important domain types: + +```ts +type BoxBrainFactDomain = + | 'persona.biography' + | 'persona.profile_image' + | 'persona.schedule' + | 'persona.schedule.deleted' + | 'persona.availability' + | 'persona.conversation' + | 'persona.relationship' + | (string & {}); +``` + +```ts +interface BoxBrainPersonaProfile { + id: string; + spaceName: string; + displayName: string; + profileImageUrl?: string; +} +``` + +```ts +interface BoxBrainConversationEntry { + id: string; + turnId: string; + direction: 'inbound' | 'outbound'; + text: string; + occurredAt: string; + createdAt?: string; + counterpartId: string; + counterpartDisplayName?: string; + proactive: boolean; + metadata?: JsonValue | null; +} +``` diff --git a/Getting-Started.md b/Getting-Started.md new file mode 100644 index 0000000..b82d1c8 --- /dev/null +++ b/Getting-Started.md @@ -0,0 +1,273 @@ +# Getting Started + +## Current setup assumptions + +At the current stage, BoxBrain is a local TypeScript/Bun framework that depends on a sibling checkout of IdentityDB. + +The package configuration currently points to: + +```json +"identitydb": "file:../IdentityDB" +``` + +So a practical local setup looks like this: + +```bash +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 +bun install +bun run test +bun run check +bun run build +``` + +## Minimal dependencies + +You need: + +- Node.js 20+ +- Bun +- IdentityDB available at `../IdentityDB` + +## Create an IdentityDB instance + +BoxBrain uses IdentityDB as the persistence layer. + +A minimal in-memory setup: + +```ts +import { IdentityDB } from 'identitydb'; + +const db = await IdentityDB.connect({ + client: 'sqlite', + filename: ':memory:', +}); + +await db.initialize(); +``` + +For a persistent local database, replace `':memory:'` with a file path. + +## Create model adapters + +BoxBrain runtime code expects provider adapters instead of hard-coding a specific vendor inside the core functions. + +### Provider-agnostic contracts + +The package exports these adapter interfaces: + +- `TextModelAdapter` +- `StructuredModelAdapter` +- `ImageModelAdapter` +- `SpecialDateProvider` + +### Quick start with Grok + +```ts +import { createGrokAdapters } from 'boxbrain'; + +const grok = createGrokAdapters({ + apiKey: process.env.XAI_API_KEY!, + textModel: 'grok-4.3-mini', + structuredModel: 'grok-4.3', + imageModel: 'grok-imagine-image-quality', +}); +``` + +## Initialize a persona + +This is the first major BoxBrain workflow. + +```ts +import { IdentityDB } from 'identitydb'; +import { createGrokAdapters, initializePersona } from 'boxbrain'; + +const db = await IdentityDB.connect({ client: 'sqlite', filename: ':memory:' }); +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 persona = await initializePersona(db, { + displayName: 'Mina', + personality: 'Thoughtful, witty, introverted, and emotionally observant.', + history: 'Raised in Busan, later moved to Seoul to work in product design.', + values: ['loyalty', 'self-respect', 'quiet consistency'], + likes: ['late-night walks', 'indie music', 'quiet cafés'], + dislikes: ['performative networking', 'loud restaurants'], + relationships: [ + { + name: 'Jisoo', + relationship: 'older brother', + description: 'protective but teasing', + }, + ], + currentDate: '2026-05-11', + structuredModel: grok.structured, + imageModel: grok.image, + generateProfileImage: true, +}); + +console.log(persona); +``` + +### What initialization does + +- generates a detailed biography +- extracts IdentityDB-ready facts +- creates or reuses an IdentityDB space (depending on options) +- optionally generates a profile image +- persists biography and image facts + +## Generate a schedule + +```ts +import { generateSchedule } from 'boxbrain'; + +const schedule = await generateSchedule(db, { + spaceName: persona.spaceName, + displayName: persona.displayName, + currentDate: '2026-05-11', + scope: 'week', + timezone: 'Asia/Seoul', + structuredModel: grok.structured, + specialDateProvider: { + async listSpecialDates() { + return [ + { + date: '2026-05-15', + title: 'Teacher’s Day', + description: 'A recurring Korean commemorative day.', + }, + ]; + }, + }, +}); + +console.log(schedule.events); +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 + +```ts +import { getAvailabilitySnapshot, setAvailabilityStatus } from 'boxbrain'; + +await setAvailabilityStatus(db, { + spaceName: persona.spaceName, + mode: 'do_not_disturb', + reason: 'studying for an exam', + effectiveFrom: '2026-05-11T19:00:00.000Z', + until: '2026-05-11T22:00:00.000Z', + sourceType: 'manual', +}); + +const snapshot = await getAvailabilitySnapshot(db, { + spaceName: persona.spaceName, + at: '2026-05-11T20:00:00.000Z', +}); + +console.log(snapshot.current); +console.log(snapshot.next); +``` + +## Run a conversation turn + +BoxBrain separates memory retrieval and response planning into three structured model roles: + +- `mandatoryMemoryModel` +- `contextualMemoryModel` +- `responseModel` + +You can point all three at the same underlying model if you want. + +```ts +import { replyToConversation, startConversation } from 'boxbrain'; + +const proactive = await startConversation(db, { + spaceName: persona.spaceName, + counterpartId: 'user:shinwoo', + counterpartDisplayName: 'Shinwoo', + currentTime: '2026-05-11T12:00:00.000Z', + mandatoryMemoryModel: grok.structured, + contextualMemoryModel: grok.structured, + responseModel: grok.structured, +}); + +console.log(proactive.messages); + +const reply = await replyToConversation(db, { + spaceName: persona.spaceName, + counterpartId: 'user:shinwoo', + counterpartDisplayName: 'Shinwoo', + currentTime: '2026-05-11T12:05:00.000Z', + message: 'Are you free tonight?', + mandatoryMemoryModel: grok.structured, + contextualMemoryModel: grok.structured, + responseModel: grok.structured, +}); + +console.log(reply.blocked); +console.log(reply.messages); +console.log(reply.usedMemories); +console.log(reply.toolCallsExecuted); +``` + +## Timing helpers + +If you want to inspect or reuse BoxBrain’s timing rules directly: + +```ts +import { + ONLINE_AVAILABILITY, + createReplyDelay, + createTypingDelay, +} from 'boxbrain'; + +const replyDelay = createReplyDelay(ONLINE_AVAILABILITY, { + isFirstReplyInExchange: true, +}); + +const typingDelay = createTypingDelay('지금 뭐해?', { + minSecondsPerCharacter: 0.05, + maxSecondsPerCharacter: 0.08, +}); +``` + +## Caveats + +### 1. BoxBrain is currently a library, not an HTTP service + +You call the exported TypeScript APIs directly. + +### 2. IdentityDB is a required runtime dependency + +The framework assumes IdentityDB is available and initialized. + +### 3. Current local development uses a sibling checkout + +Because the package currently depends on `file:../IdentityDB`, a standalone `npm install boxbrain` style flow is not the current development path yet. + +### 4. `better-sqlite3` native rebuilds may be needed in local dev + +If you hit a native module mismatch through the local IdentityDB dependency, rebuilding `better-sqlite3` from the IdentityDB workspace may be required. diff --git a/Home.md b/Home.md index e69de29..e38266d 100644 --- a/Home.md +++ b/Home.md @@ -0,0 +1,86 @@ +# BoxBrain + +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. + +## Why BoxBrain exists + +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 +- a ready-made xAI Grok adapter set for text, structured-output, and image generation +- one IdentityDB **space** per persona as the primary isolation boundary +- persona initialization from personality, history, values, likes, dislikes, and relationships +- LLM-generated biography creation followed by fact extraction into IdentityDB +- optional profile image generation during persona initialization +- realistic schedule generation for day, week, and month scopes +- schedule persistence, listing, and pruning +- availability state persistence with schedule, manual, and tool-driven overrides +- availability snapshots with current and next transition resolution +- 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 delay and per-message typing delay helpers +- refusal / farewell flows that can trigger an availability-changing tool call + +## What is still planned + +These are **not** implemented as part of the core library yet: + +- HTTP/RPC wrappers around the runtime APIs +- additional ready-made vendor adapter packages beyond Grok +- production-focused runtime/persistence integrations beyond the in-process core library + +## Recommended reading order + +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 structured traits and history. +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** +- language: **TypeScript** +- tests: **Vitest** +- build: **tsup** +- storage/memory dependency: **IdentityDB** + +See [Getting Started](Getting-Started) for a working local setup pattern. diff --git a/Purpose-and-Architecture.md b/Purpose-and-Architecture.md new file mode 100644 index 0000000..020948d --- /dev/null +++ b/Purpose-and-Architecture.md @@ -0,0 +1,226 @@ +# Purpose and Architecture + +## Existence and design intent + +BoxBrain exists to answer a specific question: + +> What does an LLM runtime need in order to feel less like a chatbot and more like an actual person in a DM thread? + +Its answer is: memory alone is not enough. + +A believable persona also needs: + +- a persistent personal history +- preferences and values that survive across turns +- relationships with named people +- a time-aware schedule +- changing availability +- conversation-specific memory retrieval +- message timing that feels human + +This is why BoxBrain is not just a prompt template or a single conversation function. It is a small framework that coordinates multiple model calls and stores their outcomes in IdentityDB. + +## Core principles + +### 1. Framework-first, not app-first + +BoxBrain intentionally stops at the runtime/library layer. + +It gives you primitives for: + +- persona initialization +- schedule generation +- availability control +- conversation orchestration +- provider adapters + +It does **not** currently ship with its own HTTP server, frontend, or transport product. + +### 2. IdentityDB space = one persona + +Each persona is isolated into its own IdentityDB space. + +That means: + +- biography facts belong to one persona space +- schedule facts belong to that same persona space +- availability facts belong to that same persona space +- conversation history belongs to that same persona space + +This is the main boundary that prevents one persona's memories from bleeding into another persona. + +### 3. Structured generation before persistence + +BoxBrain does not trust raw free-form LLM output for important state transitions. + +It prefers: + +- structured biography generation +- structured fact extraction +- structured schedule generation +- structured memory selection +- structured conversation turn planning + +This makes the runtime more deterministic, testable, and safer to persist into IdentityDB. + +### 4. A persona should have a life outside the chat + +A BoxBrain persona is not assumed to be available all the time. + +Instead: + +- schedules create time-bound events +- schedule events can create availability windows +- manual or tool-driven overrides can supersede schedule-derived states +- conversations can be blocked or delayed depending on availability + +This is the mechanism that makes a persona feel like it has its own life rhythm. + +## Runtime architecture + +## 1. Persona initialization + +Initialization takes explicit seed attributes such as: + +- display name +- personality +- history +- values +- likes / dislikes +- relationships + +Then BoxBrain: + +1. asks a structured model to generate a detailed biography +2. asks a structured model to split that biography into IdentityDB-ready facts +3. persists those facts into the persona's IdentityDB space +4. optionally generates a profile image through an image adapter + +The result is a persona profile with a stable `id`, `spaceName`, `displayName`, biography, and optional profile image URL. + +## 2. Schedule runtime + +Schedules are generated for a `day`, `week`, or `month` scope. + +The schedule generator combines: + +- existing persona facts +- recent schedule continuity +- optional external special-date context +- the anchor date and optional timezone + +Generated events are stored as `persona.schedule` facts. + +Each event includes: + +- title +- optional description +- `startAt` +- `endAt` +- `availabilityMode` +- optional `availabilityReason` +- `kind` (`routine` or `special`) +- topics / metadata + +Schedule pruning does not mutate old facts directly. Instead, BoxBrain writes `persona.schedule.deleted` marker facts so the runtime can treat old events as deleted while keeping an append-only fact history. + +## 3. Availability runtime + +Availability facts represent whether the persona is: + +- `online` +- `do_not_disturb` +- `offline` + +Availability can come from different sources: + +- `schedule` +- `manual` +- `tool` +- `default` + +`default` is implicit and resolves to online when no explicit entry applies. + +A snapshot query returns: + +- the **current** active availability state at a timestamp +- the **next** availability transition, if one exists + +This gives upstream applications enough information to render presence and decide whether to send or defer a conversation turn. + +## 4. Conversation runtime + +A BoxBrain conversation turn is intentionally multi-stage. + +### Stage A: availability check + +Before generating a response, BoxBrain checks the persona's current availability snapshot. + +If the persona is offline, the turn is blocked. + +### Stage B: mandatory memory retrieval + +A structured retrieval model chooses memories that must always be considered, especially: + +- yesterday / today / tomorrow schedule context +- recent conversation context +- stable persona or counterpart facts + +### Stage C: contextual memory retrieval + +A second structured retrieval model chooses additional relevant memories based on the specific user message or proactive context. + +### Stage D: turn planning + +A response model generates a structured turn plan: + +- `mode: 'reply' | 'refuse'` +- `messages: string[]` +- optional `toolCalls` + +### Stage E: human-like timing + +BoxBrain calculates: + +- first-reply delay based on availability mode and whether this is the first reply in the active exchange +- typing delay per message based on message length + +### Stage F: persistence + +Inbound and outbound messages are stored as `persona.conversation` facts. + +## 5. Adapter boundary + +BoxBrain separates provider-specific API mechanics from runtime logic. + +The framework itself expects abstract adapters for: + +- plain text generation +- structured-object generation +- image generation +- special-date retrieval + +That means the persona runtime can stay largely unchanged while different model providers are swapped underneath. + +## Conversation realism rules encoded in the runtime + +The current runtime already supports several behaviors that matter for realism: + +- first replies can be delayed +- follow-up messages in the same exchange can skip that initial reply delay +- typing time depends on message length +- `do_not_disturb` can probabilistically fail to reply at all +- `offline` blocks the turn entirely +- a refusal plan can still emit a short farewell sequence and trigger a tool-driven availability change + +## What BoxBrain is not + +BoxBrain is not currently: + +- a SaaS product +- an HTTP API server +- a complete social simulation world model +- a universal provider SDK +- a frontend chat application + +It is the runtime foundation you would build those things on top of. diff --git a/_Sidebar.md b/_Sidebar.md new file mode 100644 index 0000000..ac1cfff --- /dev/null +++ b/_Sidebar.md @@ -0,0 +1,7 @@ +# BoxBrain Wiki + +- [Home](Home) +- [Purpose and Architecture](Purpose-and-Architecture) +- [Getting Started](Getting-Started) +- [API Reference](API-Reference) +- [xAI Grok Adapter](xAI-Grok-Adapter) diff --git a/xAI-Grok-Adapter.md b/xAI-Grok-Adapter.md new file mode 100644 index 0000000..e532056 --- /dev/null +++ b/xAI-Grok-Adapter.md @@ -0,0 +1,106 @@ +# xAI Grok Adapter + +BoxBrain ships with a ready-made xAI Grok adapter set so you can get started without writing your own provider glue first. + +## What it includes + +- `createGrokTextModelAdapter` +- `createGrokStructuredModelAdapter` +- `createGrokImageModelAdapter` +- `createGrokAdapters` + +Provider identifier used by the adapter: + +```ts +'xai-grok' +``` + +Default base URL: + +```ts +https://api.x.ai/v1 +``` + +## Bundle setup + +```ts +import { createGrokAdapters } from 'boxbrain'; + +const grok = createGrokAdapters({ + apiKey: process.env.XAI_API_KEY!, + textModel: 'grok-4.3-mini', + structuredModel: 'grok-4.3', + imageModel: 'grok-imagine-image-quality', +}); +``` + +## Text adapter + +The text adapter sends requests to: + +```text +POST /chat/completions +``` + +It builds a standard message array from: + +- optional `system` +- required `prompt` + +## Structured-output adapter + +The structured adapter also uses: + +```text +POST /chat/completions +``` + +Behavior: + +- if `request.schema` exists, it sends `response_format: { type: 'json_schema', ... }` +- otherwise, it falls back to `response_format: { type: 'json_object' }` +- the returned message content is parsed as JSON + +This is the adapter used by the current BoxBrain persona, schedule, memory-selection, and conversation-plan flows. + +## Image adapter + +The image adapter sends requests to: + +```text +POST /images/generations +``` + +It maps BoxBrain-neutral aspect ratios to xAI payload values like this: + +| BoxBrain | xAI | +|---|---| +| `square` | `1:1` | +| `portrait` | `3:4` | +| `landscape` | `16:9` | + +## Advanced options + +Both the per-capability factories and the bundle helper support: + +- `apiKey` +- model name(s) +- `baseUrl?` +- `fetch?` +- `extraHeaders?` + +That makes the adapter easy to test or route through custom gateways. + +## Testing approach used in BoxBrain + +The adapter is tested with injected `fetch` functions instead of a vendor SDK. The test suite asserts: + +- URL +- HTTP method +- auth headers +- model selection +- chat messages +- JSON-schema response format +- image aspect-ratio mapping + +This keeps the adapter lightweight and deterministic.