tasq/node_modules/agentic-flow/dist/sdk/session-manager.js

181 lines
5.0 KiB
JavaScript

/**
* SDK Session Manager - Manages Claude Agent SDK session lifecycle
*
* Provides session ID capture, resume capability, and session forking
* for maintaining context across multiple queries.
*/
import { logger } from "../utils/logger.js";
// Session TTL: 30 minutes of inactivity
const SESSION_TTL_MS = 30 * 60 * 1000;
// In-memory session storage
const activeSessions = new Map();
// Current session for quick access
let currentSessionId = null;
// Cleanup stale sessions periodically
function cleanupStaleSessions() {
const now = Date.now();
for (const [id, session] of activeSessions.entries()) {
if (now - session.lastActivity > SESSION_TTL_MS) {
activeSessions.delete(id);
if (currentSessionId === id) {
currentSessionId = null;
}
}
}
}
// Run cleanup every 5 minutes
setInterval(cleanupStaleSessions, 5 * 60 * 1000).unref();
/**
* Capture session ID from SDK init message
* Call this for every message received from query()
*/
export function captureSessionId(message) {
if (message.type === 'system' &&
message.subtype === 'init' &&
message.session_id) {
const sessionId = message.session_id;
// Store session info
activeSessions.set(sessionId, {
sessionId,
startTime: Date.now(),
messageCount: 1,
lastActivity: Date.now(),
resumed: false
});
currentSessionId = sessionId;
logger.info('Session captured', {
sessionId,
model: message.model,
tools: message.tools?.length
});
return sessionId;
}
// Update message count for existing session
if (message.session_id && activeSessions.has(message.session_id)) {
const session = activeSessions.get(message.session_id);
session.messageCount++;
session.lastActivity = Date.now();
}
return null;
}
/**
* Get the current active session ID
*/
export function getCurrentSessionId() {
return currentSessionId;
}
/**
* Get session info by ID
*/
export function getSessionInfo(sessionId) {
return activeSessions.get(sessionId);
}
/**
* Get all active sessions
*/
export function getActiveSessions() {
return Array.from(activeSessions.values());
}
/**
* Get resume options for continuing a session
* @param sessionId - Session ID to resume, or uses current session if not provided
*/
export function getResumeOptions(sessionId) {
const id = sessionId || currentSessionId;
if (!id) {
return {};
}
// Mark session as resumed
const session = activeSessions.get(id);
if (session) {
session.resumed = true;
}
logger.info('Preparing session resume', { sessionId: id });
return {
resume: id
};
}
/**
* Get fork options for creating a new session branch from an existing one
* @param sessionId - Session ID to fork from
*/
export function getForkOptions(sessionId) {
logger.info('Forking session', { sourceSessionId: sessionId });
return {
resume: sessionId,
forkSession: true
};
}
/**
* Mark a session as ended
*/
export function endSession(sessionId) {
if (activeSessions.has(sessionId)) {
const session = activeSessions.get(sessionId);
logger.info('Session ended', {
sessionId,
duration: Date.now() - session.startTime,
messageCount: session.messageCount
});
activeSessions.delete(sessionId);
if (currentSessionId === sessionId) {
currentSessionId = null;
}
}
}
/**
* Clear all sessions (for testing/reset)
*/
export function clearAllSessions() {
activeSessions.clear();
currentSessionId = null;
logger.info('All sessions cleared');
}
/**
* Get session statistics
*/
export function getSessionStats() {
const sessions = Array.from(activeSessions.values());
return {
totalSessions: sessions.length,
activeSessions: sessions.filter(s => !s.resumed).length,
currentSessionId,
totalMessages: sessions.reduce((sum, s) => sum + s.messageCount, 0)
};
}
/**
* Process result message and extract session info
*/
export function processResultMessage(message) {
if (message.type !== 'result')
return null;
const resultMsg = message;
return {
success: resultMsg.subtype === 'success',
sessionId: resultMsg.session_id,
duration: resultMsg.duration_ms,
cost: resultMsg.total_cost_usd,
result: resultMsg.result,
errors: resultMsg.errors
};
}
/**
* Build query options with session support
*/
export function buildQueryOptionsWithSession(baseOptions, options = {}) {
const { resumeSession, sessionId, forkSession } = options;
if (forkSession && sessionId) {
return {
...baseOptions,
...getForkOptions(sessionId)
};
}
if (resumeSession) {
return {
...baseOptions,
...getResumeOptions(sessionId)
};
}
return baseOptions;
}
//# sourceMappingURL=session-manager.js.map