feat: bootstrap BoxBrain framework
Some checks failed
CI / verify (push) Failing after 3s

This commit is contained in:
2026-05-14 19:30:34 +09:00
commit c047c5a23d
16 changed files with 1846 additions and 0 deletions

64
src/conversation.ts Normal file
View File

@@ -0,0 +1,64 @@
import type {
BoxBrainMemoryStore,
DateTimeInput,
MandatoryConversationContext,
MemorySpace,
PersonaMessage,
ScheduledAvailabilitySnapshot,
} from './types';
import { addUtcDays, buildAvailabilitySnapshot, dateKeysAround, startOfUtcDay, toIso } from './schedule';
export function formatMessageHistory(input: { personaName: string; messages: PersonaMessage[] }): string {
return input.messages
.map((message) => {
const sender = message.sender === 'persona' ? input.personaName : 'user';
return `${sender}@${toIso(message.time)}: ${message.content}`;
})
.join('\n');
}
export function conversationInstruction(): string {
return [
'You are controlling the persona, not a generic assistant.',
'Use the send_message tool conceptually: return one or more outgoing messages.',
'Unless the persona strongly prefers otherwise, keep each outgoing message to at most one sentence.',
'Prefer short, natural, chat-like wording and allow splitting one thought into multiple messages.',
'If mandatory memory says "기억이 없음", the persona may naturally wonder about missing context instead of pretending to remember.',
].join('\n');
}
export function memoryExtractionInstruction(now: string): string {
return [
`Current objective time: ${now}.`,
'Read the message history and extract durable facts worth remembering.',
'Objectivize subjective statements before storage.',
'Example: "I started TypeScript in 2025" becomes "The user started TypeScript in 2025."',
'Prefer facts about the persona, the user, their relationship, preferences, history, schedule-relevant events, and stable traits.',
].join('\n');
}
export async function buildMandatoryConversationContext(input: {
persona: MemorySpace;
now: DateTimeInput;
memory: BoxBrainMemoryStore;
messages: PersonaMessage[];
availability: ScheduledAvailabilitySnapshot;
}): Promise<MandatoryConversationContext> {
const now = startOfUtcDay(input.now);
const from = addUtcDays(now, -1).toISOString();
const to = addUtcDays(now, 2).toISOString();
const scheduleEntries = await input.memory.listScheduleEntries(input.persona.id, from, to);
const personaAndUserFacts = await input.memory.findFacts(input.persona.id, ['persona', input.persona.displayName, 'user']);
const memorySummary = personaAndUserFacts.length === 0
? '기억이 없음'
: personaAndUserFacts.map((fact) => `- ${fact.statement}`).join('\n');
return {
formattedMessageHistory: formatMessageHistory({ personaName: input.persona.displayName, messages: input.messages }),
conversationWindowLabel: `Required conversation window: yesterday/today. Schedule dates: ${dateKeysAround(input.now).join(', ')}.`,
memorySummary,
personaAndUserFacts,
scheduleEntries,
availability: input.availability,
};
}