/** * Session Manager for Antigravity Cloud Code * * Handles session ID generation and caching for prompt caching continuity. * Mimics the Antigravity binary behavior: generates a session ID at startup * and keeps it for the process lifetime, scoped per account/connection. * * Reference: antigravity-claude-proxy/src/cloudcode/session-manager.js */ import crypto from "crypto"; import { MEMORY_CONFIG } from "../config/runtimeConfig.js"; // Runtime storage: Key = connectionId, Value = { sessionId, lastUsed } const runtimeSessionStore = new Map(); // Periodically evict entries that haven't been used within TTL const cleanupInterval = setInterval(() => { const now = Date.now(); for (const [key, entry] of runtimeSessionStore) { if (now - entry.lastUsed > MEMORY_CONFIG.sessionTtlMs) { runtimeSessionStore.delete(key); } } }, MEMORY_CONFIG.sessionCleanupIntervalMs); // Allow Node.js to exit even if interval is still active if (cleanupInterval.unref) cleanupInterval.unref(); /** * Get or create a session ID for the given connection. * * The binary generates a session ID once at startup: `rs() + Date.now()`. * Since 9router is long-running, we simulate this "per-launch" behavior by * storing a generated ID in memory for each connection. * * - If 9router restarts, the ID changes (matching binary restart behavior). * - Within a running instance, the ID is stable for that connection. * - This enables prompt caching while using the EXACT random logic of the binary. * * @param {string} connectionId - The connection identifier (email or unique ID) * @returns {string} A stable session ID string matching binary format */ export function deriveSessionId(connectionId) { if (!connectionId) { return generateBinaryStyleId(); } const existing = runtimeSessionStore.get(connectionId); if (existing) { existing.lastUsed = Date.now(); return existing.sessionId; } // Evict oldest entry if store exceeds max size (safety cap between cleanup cycles) const MAX_SESSIONS = 1000; if (runtimeSessionStore.size >= MAX_SESSIONS) { const oldest = runtimeSessionStore.keys().next().value; runtimeSessionStore.delete(oldest); } const sessionId = generateBinaryStyleId(); runtimeSessionStore.set(connectionId, { sessionId, lastUsed: Date.now() }); return sessionId; } /** * Generate a Session ID using the binary's exact logic. * Format: `rs() + Date.now()` where `rs()` is randomUUID * * @returns {string} A session ID in binary format */ export function generateBinaryStyleId() { return crypto.randomUUID() + Date.now().toString(); } /** * Clears all session IDs (e.g. useful for testing or explicit reset) */ export function clearSessionStore() { runtimeSessionStore.clear(); }