import type { AgentOrchestrator } from '../backends/native/orchestrator.js'; import type { Message } from '../models/types.js'; import { getMessageText } from '../models/media.js'; import type { MemoryStore } from '../memory/store.js'; import type { ModelTier } from '../models/router.js'; export interface SessionEndSummaryConfig { enabled: boolean; tier: ModelTier; maxMessages: number; maxInputChars: number; maxTokens: number; writeToMemory: boolean; memoryNamespace: string; } export interface SessionEndSummaryResult { summary: string; namespace?: string; } const SESSION_END_SUMMARY_PROMPT = [ 'Summarize this completed conversation for future continuity.', 'Focus on durable facts, decisions, preferences, unresolved tasks, and next steps.', 'Be concise and structured with short bullets.', 'Do not include private secrets.', ].join(' '); function sanitizeSessionId(sessionId: string): string { return sessionId .replace(/:/g, '/') .replace(/[^a-zA-Z0-9/_-]+/g, '_') .replace(/_+/g, '_'); } function formatHistory(messages: Message[], maxInputChars: number): string { const text = messages .map((msg) => `${msg.role}: ${getMessageText(msg)}`) .join('\n\n'); if (text.length <= maxInputChars) { return text; } return text.slice(text.length - maxInputChars); } export async function summarizeSessionOnEnd(opts: { agent: AgentOrchestrator; sessionId: string; history: Message[]; config: SessionEndSummaryConfig; memoryStore?: MemoryStore; }): Promise { if (!opts.config.enabled || opts.history.length === 0) { return null; } const selected = opts.history.slice(-opts.config.maxMessages); const conversation = formatHistory(selected, opts.config.maxInputChars); if (!conversation.trim()) { return null; } const result = await opts.agent.delegate({ tier: opts.config.tier, systemPrompt: SESSION_END_SUMMARY_PROMPT, message: conversation, maxTokens: opts.config.maxTokens, }); const summary = result.content.trim(); if (!summary) { return null; } let namespace: string | undefined; if (opts.memoryStore && opts.config.writeToMemory) { namespace = `${opts.config.memoryNamespace}/${sanitizeSessionId(opts.sessionId)}`; const block = `## ${new Date().toISOString()}\n\n${summary}\n\n`; opts.memoryStore.write(namespace, block, 'append'); } return { summary, namespace }; } export const sessionEndSummaryInternals = { sanitizeSessionId, formatHistory, };