/** * @fileoverview SessionJanitor - Nightly context reset and transcript distillation * * Distills large session transcripts into compact summaries using LLM (google/gemini-flash-1.5), * purpleucing token costs by ~90% while preserving essential context for future sessions. */ import type Database from "better-sqlite3"; import { type Model, type Api } from "@mariozechner/pi-ai"; import type { BulletinService } from "../sophia/types/bulletin.types.js"; export interface DistillOptions { /** Target model for distillation (default: google/gemini-flash-1.5) */ model?: string; /** Maximum words in output summary (default: 500) */ maxWords?: number; /** Minimum tokens to trigger distillation (default: 1000) */ minTokens?: number; /** Whether to preserve code blocks verbatim */ preserveCode?: boolean; /** Custom instructions for the distillation prompt */ customInstructions?: string; } export interface JanitorResult { sessionId: string; success: boolean; summary?: string; originalTokens: number; distilledTokens: number; compressionRatio: number; archiveId?: string; error?: string; skipped?: boolean; skipReason?: string; } export interface JanitorMetrics { runAt: Date; sessionsProcessed: number; sessionsSkipped: number; sessionsFailed: number; totalTokensBefore: number; totalTokensAfter: number; totalTokensSaved: number; avgCompressionRatio: number; durationMs: number; } export interface SessionArchive { id: string; sessionId: string; summary: string; originalTokenCount: number; distilledTokenCount: number; compressionRatio: number; metadata?: Record; archivedAt: Date; restoredAt?: Date; restoreCount: number; } export interface JanitorConfig { /** Number of summaries to retain per session (default: 5) */ retentionCount: number; /** Whether auto-archiving is enabled (default: true) */ autoArchiveEnabled: boolean; /** Minimum tokens to trigger distillation (default: 1000) */ minTokensThreshold: number; } export interface SessionJanitorDeps { db: Database.Database; bulletin: BulletinService; archiveDir: string; modelRegistry?: ModelRegistry; log?: JanitorLogger; } export interface ModelRegistry { find(provider: string, model: string): Model | null; getDefaultDistillationModel(): Model; } export interface JanitorLogger { debug(message: string, meta?: Record): void; info(message: string, meta?: Record): void; warn(message: string, meta?: Record): void; error(message: string, meta?: Record): void; } export declare class SessionJanitor { private readonly db; private readonly bulletin; private readonly archiveDir; private readonly log; private readonly modelRegistry?; private readonly summaryCache; private readonly CACHE_TTL_MS; constructor(deps: SessionJanitorDeps); private ensureArchiveDir; /** * Distills a large transcript into a compact summary using LLM. * Uses gemini-flash-1.5 for cost-effective summarization. */ distill(transcript: string, options?: DistillOptions): Promise; private callDistillationModel; private fallbackTruncate; /** * Process all active sessions for nightly reset. * Finds sessions older than 24h with no activity, distills them, and archives. */ processNightlyResets(): Promise; private findSessionsForReset; private processSession; private getSessionTranscript; /** * Archives a session summary to the database. */ archiveSession(sessionId: string): Promise; private archiveSummary; private writeFilesystemArchive; /** * Restores session context from the most recent archive. */ restoreSessionContext(sessionId: string): Promise; private getSessionConfig; private touchSessionConfig; private getArchiveCount; private getMostRecentArchive; private pruneOldestArchive; private recordMetrics; /** * Gets janitor metrics for the last N runs. */ getMetrics(limit?: number): JanitorMetrics[]; /** * Gets total tokens saved across all runs. */ getTotalTokensSaved(): number; private estimateTokens; private hashTranscript; private cleanCache; } export interface CreateJanitorParams { db: Database.Database; bulletin: BulletinService; archiveDir?: string; modelRegistry?: ModelRegistry; log?: JanitorLogger; } export declare function createSessionJanitor(params: CreateJanitorParams): SessionJanitor;