/** * Session Pool - Claude CLI Session Reuse Manager * * Manages Claude CLI session IDs per channel to enable conversation continuity. * Instead of creating new sessions for each message, reuses existing sessions * so Claude CLI maintains its own conversation history. * * Benefits: * - 6x token reduction (no manual history injection needed) * - Natural conversation flow (Claude remembers context) * - Automatic summarization by Claude when context fills up */ /** * Session entry with metadata */ interface SessionEntry { /** Claude CLI session ID */ sessionId: string; /** Last activity timestamp */ lastActive: number; /** Message count in this session */ messageCount: number; /** Creation timestamp */ createdAt: number; /** Whether session is currently in use (locked) */ inUse: boolean; /** Legacy context occupancy field; durable runtimes own compaction, so this stays zero */ totalInputTokens: number; } /** * Session Pool configuration */ export interface SessionPoolConfig { /** Session timeout in milliseconds (default: 30 minutes) */ sessionTimeoutMs?: number; /** Maximum sessions to keep in pool (default: 100) */ maxSessions?: number; /** Cleanup interval in milliseconds (default: 5 minutes) */ cleanupIntervalMs?: number; } /** * Session Pool for Claude CLI session management * * Key design: * - Channel key format: "{source}:{channelId}" (e.g., "discord:123456") * - Sessions expire after timeout (default 30 min) * - Automatic cleanup of stale sessions */ export declare class SessionPool { private sessions; private config; private cleanupTimer; constructor(config?: SessionPoolConfig); /** * Get or create session ID for a channel * * With --no-session-persistence flag, Claude CLI doesn't lock session IDs. * This allows session reuse for conversation continuity. * * Durable backends own model-aware context compaction. This pool rotates only * for explicit resets and session-lifecycle expiry. * If session is in use, returns busy=true immediately (no waiting). * * @param channelKey - Channel identifier (format: "{source}:{channelId}") * @returns Object with sessionId, isNew flag, and busy status */ getSession(channelKey: string): { sessionId: string; isNew: boolean; busy: boolean; }; /** * Read-only check for session busy status * Does NOT modify session state (no lock, no messageCount increment) * * @param channelKey - Channel identifier * @returns Object with sessionId (if exists) and busy status */ peekSession(channelKey: string): { sessionId?: string; busy: boolean; }; /** * Preserve the legacy token-status interface without interpreting billing * usage as context occupancy. Claude Code, Codex app-server, and Cline Hub * each compact from their own model-aware request state. * * @param channelKey - Channel identifier * @param _inputTokens - Usage telemetry from this run; recorded separately by AgentLoop * @param _backend - Runtime that owns the durable session * @returns Zero occupancy because the host has no authoritative context-size signal */ updateTokens(channelKey: string, _inputTokens: number, _backend?: 'claude' | 'codex' | 'cline'): { totalTokens: number; nearThreshold: boolean; }; /** * Get current token usage for a session */ getTokenUsage(channelKey: string): number; /** * Legacy method for backward compatibility * @deprecated Use getSession() instead */ getSessionId(channelKey: string): string; /** * Release a session after use * This allows the session to be reused by future requests */ releaseSession(channelKey: string, expectedSessionId?: string): void; /** * Override session ID for a channel (e.g., when backend returns its own thread ID) */ setSessionId(channelKey: string, sessionId: string): void; /** * Create a new session for a channel */ private createSession; /** * Force create a new session (for /clear command) */ resetSession(channelKey: string): string; /** * Remove a session without creating a replacement. * * Use this after a failed reset attempt: the next request must observe a * genuinely new session and rebuild its complete policy prompt. */ invalidateSession(channelKey: string, expectedSessionId?: string): void; /** * Check if a session exists and is active */ hasActiveSession(channelKey: string): boolean; /** * Get session info for a channel */ getSessionInfo(channelKey: string): SessionEntry | null; /** * Get all active sessions (for debugging/monitoring) */ listSessions(): Map; /** * Get active session count */ getActiveSessionCount(): number; /** * Evict the oldest (least recently used) session */ private evictOldestSession; /** * Clean up expired sessions and force-release stuck inUse sessions */ cleanup(): number; /** * Start periodic cleanup timer */ private startCleanupTimer; /** * Stop cleanup timer and clear all sessions */ dispose(): void; } /** * Get global session pool instance */ export declare function getSessionPool(): SessionPool; /** * Set global session pool instance (for testing) */ export declare function setSessionPool(pool: SessionPool): void; /** * Build channel key from source and channel ID */ export declare function buildChannelKey(source: string, channelId: string): string; export {}; //# sourceMappingURL=session-pool.d.ts.map