import type { ISdk } from "iii-sdk"; import type { CompressedObservation, EnrichedChunk, MemoryProvider, } from "../types.js"; import { KV, generateId } from "../state/schema.js"; import type { StateKV } from "../state/kv.js"; import { recordAudit } from "./audit.js"; import { logger } from "../logger.js"; const SLIDING_WINDOW_SYSTEM = `You are a contextual enrichment engine. Given a primary observation and its surrounding context window (previous and next observations from the same session), produce an enriched version. Your tasks: 1. ENTITY RESOLUTION: Replace all pronouns, implicit references ("that framework", "the file", "it", "he/she") with the explicit entity names found in the context window. 2. PREFERENCE MAPPING: Extract any user preferences, constraints, or opinions expressed directly or indirectly. 3. CONTEXT BRIDGES: Add brief contextual links that make this chunk self-contained without reading adjacent chunks. Output EXACTLY this XML: The fully enriched, self-contained text with all references resolved extracted user preference or constraint contextual link to adjacent information Rules: - The enriched content MUST be understandable in complete isolation - Resolve ALL ambiguous references using the context window - Do not hallucinate entities not present in the window - Preserve factual accuracy while adding clarity`; function buildWindowPrompt( primary: CompressedObservation, before: CompressedObservation[], after: CompressedObservation[], ): string { const parts: string[] = []; if (before.length > 0) { parts.push("=== PRECEDING CONTEXT ==="); for (const obs of before) { parts.push(`[${obs.type}] ${obs.title}: ${obs.narrative}`); if (obs.facts.length > 0) parts.push(`Facts: ${obs.facts.join("; ")}`); if (obs.concepts.length > 0) parts.push(`Concepts: ${obs.concepts.join(", ")}`); } } parts.push("\n=== PRIMARY OBSERVATION (enrich this) ==="); parts.push(`Type: ${primary.type}`); parts.push(`Title: ${primary.title}`); if (primary.subtitle) parts.push(`Subtitle: ${primary.subtitle}`); parts.push(`Narrative: ${primary.narrative}`); if (primary.facts.length > 0) parts.push(`Facts: ${primary.facts.join("; ")}`); if (primary.concepts.length > 0) parts.push(`Concepts: ${primary.concepts.join(", ")}`); if (primary.files.length > 0) parts.push(`Files: ${primary.files.join(", ")}`); if (after.length > 0) { parts.push("\n=== FOLLOWING CONTEXT ==="); for (const obs of after) { parts.push(`[${obs.type}] ${obs.title}: ${obs.narrative}`); if (obs.facts.length > 0) parts.push(`Facts: ${obs.facts.join("; ")}`); } } return parts.join("\n"); } function parseEnrichedXml(xml: string): { content: string; resolvedEntities: Record; preferences: string[]; contextBridges: string[]; } | null { const contentMatch = xml.match(/([\s\S]*?)<\/content>/); if (!contentMatch) return null; const resolvedEntities: Record = {}; const entityRegex = //g; let match; while ((match = entityRegex.exec(xml)) !== null) { resolvedEntities[match[1]] = match[2]; } const preferences: string[] = []; const prefRegex = /([^<]+)<\/preference>/g; while ((match = prefRegex.exec(xml)) !== null) { preferences.push(match[1]); } const contextBridges: string[] = []; const bridgeRegex = /([^<]+)<\/bridge>/g; while ((match = bridgeRegex.exec(xml)) !== null) { contextBridges.push(match[1]); } return { content: contentMatch[1].trim(), resolvedEntities, preferences, contextBridges, }; } export function registerSlidingWindowFunction( sdk: ISdk, kv: StateKV, provider: MemoryProvider, ): void { sdk.registerFunction("mem::enrich-window", async (data: { observationId: string; sessionId: string; lookback?: number; lookahead?: number; }) => { if ( !data || typeof data.sessionId !== "string" || !data.sessionId.trim() || typeof data.observationId !== "string" || !data.observationId.trim() ) { return { success: false, error: "sessionId and observationId are required" }; } const sessionId = data.sessionId.trim(); const observationId = data.observationId.trim(); const hprev = data.lookback ?? 3; const hnext = data.lookahead ?? 2; const allObs = await kv.list( KV.observations(sessionId), ); allObs.sort( (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(), ); const primaryIdx = allObs.findIndex((o) => o.id === observationId); if (primaryIdx === -1) { return { success: false, error: "Observation not found" }; } const primary = allObs[primaryIdx]; const before = allObs.slice(Math.max(0, primaryIdx - hprev), primaryIdx); const after = allObs.slice(primaryIdx + 1, primaryIdx + 1 + hnext); if (before.length === 0 && after.length === 0) { return { success: true, enriched: null, reason: "No adjacent context available", }; } try { const prompt = buildWindowPrompt(primary, before, after); const response = await provider.compress( SLIDING_WINDOW_SYSTEM, prompt, ); const parsed = parseEnrichedXml(response); if (!parsed) { logger.warn("Failed to parse enrichment XML", { obsId: data.observationId, }); return { success: false, error: "parse_failed" }; } const enriched: EnrichedChunk = { id: generateId("ec"), originalObsId: observationId, sessionId, content: parsed.content, resolvedEntities: parsed.resolvedEntities, preferences: parsed.preferences, contextBridges: parsed.contextBridges, windowStart: Math.max(0, primaryIdx - hprev), windowEnd: Math.min(allObs.length - 1, primaryIdx + hnext), createdAt: new Date().toISOString(), }; await kv.set( KV.enrichedChunks(sessionId), observationId, enriched, ); await recordAudit(kv, "observe", "mem::enrich-window", [enriched.id], { action: "persist_enriched_chunk", sessionId, observationId, }); logger.info("Observation enriched via sliding window", { obsId: observationId, entitiesResolved: Object.keys(parsed.resolvedEntities).length, preferencesFound: parsed.preferences.length, bridges: parsed.contextBridges.length, }); return { success: true, enriched }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); logger.error("Sliding window enrichment failed", { error: msg }); return { success: false, error: msg }; } }, ); sdk.registerFunction("mem::enrich-session", async (data: { sessionId: string; lookback?: number; lookahead?: number; minImportance?: number; }) => { if (!data || typeof data.sessionId !== "string" || !data.sessionId.trim()) { return { success: false, error: "sessionId is required" }; } const sessionId = data.sessionId.trim(); const allObs = await kv.list( KV.observations(sessionId), ); const minImp = data.minImportance ?? 4; const toEnrich = allObs.filter((o) => o.importance >= minImp); let enriched = 0; let failed = 0; for (const obs of toEnrich) { try { const result = (await sdk.trigger({ function_id: "mem::enrich-window", payload: { observationId: obs.id, sessionId, lookback: data.lookback ?? 3, lookahead: data.lookahead ?? 2, } })) as { success?: boolean } | undefined; if (result?.success) enriched++; else failed++; } catch { failed++; } } logger.info("Session enrichment complete", { sessionId, total: toEnrich.length, enriched, failed, }); return { success: true, total: toEnrich.length, enriched, failed }; }, ); }