/**
 * src/sessions/manager.ts
 * Session Manager — Create, manage, and isolate agent sessions
 */
import { v4 as uuidv4 } from 'uuid';
import { createChildLogger } from '../utils/logger.js';
import { supabase } from '../utils/supabase.js';
import { processMessage } from '../agent/brain.js';
import { getTenantById } from '../tenants/manager.js';
const log = createChildLogger('sessions:manager');
/**
 * Create a new isolated session
 */
export async function createSession(options) {
    const sessionId = uuidv4();
    const now = new Date().toISOString();
    // Create isolated workspace path
    const workspacePath = `/Users/taseesai/.muassis/sessions/${sessionId}`;
    const session = {
        id: sessionId,
        tenant_id: options.tenantId,
        label: options.label || `Session ${sessionId.slice(0, 8)}`,
        kind: options.kind || 'isolated',
        status: 'active',
        model: options.model,
        thinking: options.thinking || false,
        timeoutSeconds: options.timeoutSeconds,
        parent_session_id: options.parentSessionId || null,
        root_workspace_path: workspacePath,
        message_count: 0,
    };
    const { data, error } = await supabase
        .from('sessions')
        .insert({
        ...session,
        created_at: now,
        updated_at: now,
        last_message_at: null,
    })
        .select()
        .single();
    if (error) {
        throw new Error(`Failed to create session: ${error.message}`);
    }
    log.info({ sessionId, tenantId: options.tenantId, kind: session.kind }, 'Session created');
    return data;
}
/**
 * Get session by ID
 */
export async function getSession(sessionId) {
    const { data, error } = await supabase
        .from('sessions')
        .select('*')
        .eq('id', sessionId)
        .single();
    if (error) {
        if (error.code === 'PGRST116')
            return null;
        throw new Error(`Database error: ${error.message}`);
    }
    return data;
}
/**
 * Get all sessions for a tenant
 */
export async function getTenantSessions(tenantId, limit = 20) {
    const { data, error } = await supabase
        .from('sessions')
        .select('*')
        .eq('tenant_id', tenantId)
        .eq('status', 'active')
        .order('created_at', { ascending: false })
        .limit(limit);
    if (error) {
        throw new Error(`Database error: ${error.message}`);
    }
    return data;
}
/**
 * Add a message to a session
 */
export async function addMessage(sessionId, message) {
    const messageId = uuidv4();
    const now = new Date().toISOString();
    const msg = {
        ...message,
        id: messageId,
        created_at: now,
    };
    await supabase.from('session_messages').insert({
        id: messageId,
        session_id: sessionId,
        role: message.role,
        content: message.content,
        tool_call_id: message.tool_call_id || null,
        tool_name: message.tool_name || null,
        created_at: now,
    });
    // Update session message count and last message time
    await supabase
        .from('sessions')
        .update({
        message_count: supabase.rpc('increment_counter'),
        last_message_at: now,
        updated_at: now,
    })
        .eq('id', sessionId);
    return msg;
}
/**
 * Get session message history
 */
export async function getSessionHistory(sessionId, limit = 50) {
    const { data, error } = await supabase
        .from('session_messages')
        .select('*')
        .eq('session_id', sessionId)
        .order('created_at', { ascending: true })
        .limit(limit);
    if (error) {
        throw new Error(`Database error: ${error.message}`);
    }
    return data;
}
/**
 * Process a message in a session (with full context)
 */
export async function processSessionMessage(sessionId, userMessage) {
    const session = await getSession(sessionId);
    if (!session) {
        throw new Error(`Session not found: ${sessionId}`);
    }
    if (session.status !== 'active') {
        throw new Error(`Session is not active: ${session.status}`);
    }
    const tenant = await getTenantById(session.tenant_id);
    if (!tenant) {
        throw new Error(`Tenant not found: ${session.tenant_id}`);
    }
    // Get message history
    const history = await getSessionHistory(sessionId);
    // Format as ChatMessage[]
    const recentMessages = history.slice(-20).map(m => ({
        role: m.role,
        content: m.content,
    }));
    // Add the new user message
    await addMessage(sessionId, {
        session_id: sessionId,
        role: 'user',
        content: userMessage,
        tool_call_id: undefined,
        tool_name: undefined,
    });
    // Process through brain
    const customerId = `session-${sessionId}`;
    const result = await processMessage(session.tenant_id, customerId, userMessage, {
        recentMessages,
        additionalInstructions: `This is an isolated session: ${session.label || session.id}.`,
    }, {
        budgetAware: true,
        enableTools: true,
        maxToolLoops: session.thinking ? 5 : 3,
    });
    // Add assistant response to history
    await addMessage(sessionId, {
        session_id: sessionId,
        role: 'assistant',
        content: result.response,
        tool_call_id: undefined,
        tool_name: undefined,
    });
    // Check if session should be closed (timeout or max messages)
    if (session.timeoutSeconds) {
        const age = (Date.now() - new Date(session.created_at).getTime()) / 1000;
        if (age > session.timeoutSeconds) {
            await closeSession(sessionId, 'timeout');
        }
    }
    return {
        session: session,
        messages: [
            { id: uuidv4(), session_id: sessionId, role: 'user', content: userMessage, created_at: new Date().toISOString(), tool_call_id: undefined, tool_name: undefined },
            { id: uuidv4(), session_id: sessionId, role: 'assistant', content: result.response, created_at: new Date().toISOString(), tool_call_id: undefined, tool_name: undefined },
        ],
        output: result.response,
    };
}
/**
 * Close a session
 */
export async function closeSession(sessionId, reason) {
    await supabase
        .from('sessions')
        .update({
        status: 'completed',
        updated_at: new Date().toISOString(),
    })
        .eq('id', sessionId);
    log.info({ sessionId, reason }, 'Session closed');
}
/**
 * Kill a session (force stop)
 */
export async function killSession(sessionId) {
    await supabase
        .from('sessions')
        .update({
        status: 'error',
        updated_at: new Date().toISOString(),
    })
        .eq('id', sessionId);
    log.info({ sessionId }, 'Session killed');
}
/**
 * Spawn a sub-agent (creates isolated session and processes message)
 */
export async function spawnSubAgent(options) {
    const session = await createSession(options);
    return processSessionMessage(session.id, options.message);
}
/**
 * List active sub-agents for a tenant
 */
export async function listSubAgents(tenantId) {
    return getTenantSessions(tenantId);
}
/**
 * Steer a sub-agent (send message to existing session)
 */
export async function steerSubAgent(sessionId, message) {
    return processSessionMessage(sessionId, message);
}
//# sourceMappingURL=manager.js.map