docs: add BoxBrain wiki

2026-05-11 17:22:59 +09:00
parent 030b550e3d
commit 9fb2ec4d47
6 changed files with 1118 additions and 0 deletions

420
API-Reference.md Normal file

@@ -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<InitializedPersona>
```
**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<BoxBrainScheduleEvent[]>
```
**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<SchedulePruneResult>
```
### `pruneScheduleBefore(db, input)`
Marks schedule events as deleted when they start before a cutoff timestamp.
**Signature**
```ts
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`
### `setAvailabilityStatus(db, input)`
Persists an explicit availability entry.
**Signature**
```ts
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)`
Lists explicit availability entries in chronological order.
```ts
listAvailabilityEntries(db: IdentityDB, input: ListAvailabilityEntriesInput): Promise<BoxBrainAvailabilityEntry[]>
```
### `getAvailabilitySnapshot(db, input)`
Returns the active availability state at a timestamp plus the next transition.
```ts
getAvailabilitySnapshot(db: IdentityDB, input: GetAvailabilitySnapshotInput): Promise<BoxBrainAvailabilitySnapshot>
```
**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<ConversationTurnResult>
```
### `startConversation(db, input)`
Generates a proactive outbound opening turn with no inbound user message.
```ts
startConversation(db: IdentityDB, input: StartConversationInput): Promise<ConversationTurnResult>
```
### `listConversationEntries(db, input)`
Lists stored conversation entries for a persona, optionally filtered by counterpart and time range.
```ts
listConversationEntries(db: IdentityDB, input: ListConversationEntriesInput): Promise<BoxBrainConversationEntry[]>
```
**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<string>;
}
```
### `StructuredModelAdapter`
```ts
interface StructuredModelAdapter<TSchema = unknown> {
provider: string;
model: string;
generateObject<TOutput>(request: StructuredGenerationRequest<TSchema>): Promise<TOutput>;
}
```
### `ImageModelAdapter`
```ts
interface ImageModelAdapter {
provider: string;
model: string;
generateImage(request: ImageGenerationRequest): Promise<ImageGenerationResult>;
}
```
### `SpecialDateProvider`
```ts
interface SpecialDateProvider {
listSpecialDates(request: SpecialDateRequest): Promise<SpecialDateContext[]>;
}
```
## `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<Fact[]>
```
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;
}
```

273
Getting-Started.md Normal file

@@ -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: 'Teachers 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 BoxBrains 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.

86
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.

226
Purpose-and-Architecture.md Normal file

@@ -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.

7
_Sidebar.md Normal file

@@ -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)

106
xAI-Grok-Adapter.md Normal file

@@ -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.