/**
 * ChatTracesService — retrieves the full execution trace of a chat session.
 *
 * A "chat id" is a session id. Its trace is everything that happened in that
 * chat: the persisted messages (with their executed tool calls, outbound LLM
 * context flow, and chain-of-thought) plus any agent threads spun off from the
 * session and their activity logs. This lets an agent inspect how a past chat
 * actually ran — useful for evaluating provider behaviour, diagnosing loops,
 * or auditing tool usage.
 */
const DEFAULT_MESSAGE_LIMIT = 200;
const MAX_MESSAGE_LIMIT = 1000;
const DEFAULT_ACTIVITY_LIMIT = 200;
const MAX_ACTIVITY_LIMIT = 2000;
function normalizeLimit(limit, def, max) {
    if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0)
        return def;
    return Math.min(Math.floor(limit), max);
}
function safeParse(value) {
    if (!value)
        return undefined;
    try {
        return JSON.parse(value);
    }
    catch {
        return undefined;
    }
}
export class ChatTracesService {
    sqlite;
    constructor(sqlite) {
        this.sqlite = sqlite;
    }
    traces(options) {
        const includeMessages = options.includeMessages !== false;
        const includeThreads = options.includeThreads !== false;
        const includeToolCalls = options.includeToolCalls !== false;
        const includeContextFlow = options.includeContextFlow === true;
        const includeThinking = options.includeThinking === true;
        const messageLimit = normalizeLimit(options.messageLimit, DEFAULT_MESSAGE_LIMIT, MAX_MESSAGE_LIMIT);
        const activityLimit = normalizeLimit(options.activityLimit, DEFAULT_ACTIVITY_LIMIT, MAX_ACTIVITY_LIMIT);
        const session = this.loadSession(options.chatId, options.userId);
        const messages = includeMessages && session
            ? this.loadMessages(options.chatId, messageLimit, includeToolCalls, includeContextFlow, includeThinking)
            : [];
        const threads = includeThreads && session
            ? this.loadThreads(options.chatId, activityLimit, options.userId)
            : [];
        const threadActivities = threads.reduce((sum, t) => sum + t.activities.length, 0);
        return {
            chatId: options.chatId,
            found: Boolean(session),
            session,
            messages,
            threads,
            counts: { messages: messages.length, threads: threads.length, threadActivities },
        };
    }
    loadSession(chatId, userId) {
        const rows = this.sqlite.prepare(`
      SELECT id, user_id AS userId, project_id AS projectId, name,
        project_path AS projectPath, status, created_at AS createdAt,
        last_active_at AS lastActiveAt
      FROM sessions
      WHERE id = ? AND (? IS NULL OR user_id = ?)
      LIMIT 1
    `).get(chatId, userId ?? null, userId ?? null);
        return rows ?? null;
    }
    loadMessages(chatId, limit, includeToolCalls, includeContextFlow, includeThinking) {
        // Take the most recent `limit` messages, returned oldest-first for readability.
        const rows = this.sqlite.prepare(`
      SELECT id, role, content, tool_calls AS toolCalls, segments,
        context_flow AS contextFlow, thinking, created_at AS createdAt
      FROM messages
      WHERE session_id = ?
      ORDER BY created_at DESC
      LIMIT ?
    `).all(chatId, limit);
        return rows
            .reverse()
            .map((r) => ({
            id: r.id,
            role: r.role,
            content: r.content,
            ...(includeToolCalls ? { toolCalls: safeParse(r.toolCalls) } : {}),
            ...(includeToolCalls ? { segments: safeParse(r.segments) } : {}),
            ...(includeContextFlow ? { contextFlow: safeParse(r.contextFlow) } : {}),
            ...(includeThinking ? { thinking: r.thinking } : {}),
            createdAt: r.createdAt,
        }));
    }
    loadThreads(chatId, activityLimit, userId) {
        const threads = this.sqlite.prepare(`
      SELECT id, user_id AS userId, title, provider_id AS providerId, model,
        runtime_mode AS runtimeMode, kind, status, error,
        working_directory AS workingDirectory, branch,
        pr_url AS prUrl, pr_state AS prState,
        execution_node_name AS executionNodeName,
        created_at AS createdAt, updated_at AS updatedAt, completed_at AS completedAt
      FROM agent_threads
      WHERE session_id = ? AND (? IS NULL OR user_id = ?)
      ORDER BY created_at ASC
    `).all(chatId, userId ?? null, userId ?? null);
        return threads.map((t) => ({
            id: t.id,
            title: t.title,
            providerId: t.providerId,
            model: t.model,
            runtimeMode: t.runtimeMode,
            kind: t.kind,
            status: t.status,
            error: t.error,
            workingDirectory: t.workingDirectory,
            branch: t.branch,
            prUrl: t.prUrl,
            prState: t.prState,
            executionNodeName: t.executionNodeName,
            createdAt: t.createdAt,
            updatedAt: t.updatedAt,
            completedAt: t.completedAt,
            activities: this.loadActivities(t.id, activityLimit),
        }));
    }
    loadActivities(threadId, limit) {
        const rows = this.sqlite.prepare(`
      SELECT id, kind, summary, payload, created_at AS createdAt
      FROM agent_thread_activities
      WHERE thread_id = ?
      ORDER BY created_at DESC
      LIMIT ?
    `).all(threadId, limit);
        return rows
            .reverse()
            .map((r) => ({
            id: r.id,
            kind: r.kind,
            summary: r.summary,
            payload: safeParse(r.payload),
            createdAt: r.createdAt,
        }));
    }
}
//# sourceMappingURL=chat-traces.js.map