/**
 * Mem0 provider abstraction — supports both Platform (cloud) and OSS (local SQLite) modes.
 *
 * Uses the `mem0ai` npm SDK which handles:
 * - Platform mode: REST API calls to api.mem0.ai
 * - OSS mode: local SQLite vector store + LLM extraction via configured provider
 */
import { join } from 'node:path';
import { resolveHome } from '@amaster.ai/pi-shared/settings';
// ---------------------------------------------------------------------------
// Normalizers
// ---------------------------------------------------------------------------
function normalizeMemoryItem(raw) {
    return {
        id: String(raw.id ?? raw.memory_id ?? ''),
        memory: String(raw.memory ?? raw.text ?? raw.content ?? ''),
        score: typeof raw.score === 'number' ? raw.score : undefined,
        user_id: raw.user_id,
        created_at: (raw.created_at ?? raw.createdAt),
        updated_at: (raw.updated_at ?? raw.updatedAt),
    };
}
function normalizeResults(raw) {
    if (Array.isArray(raw))
        return raw.map((item) => normalizeMemoryItem(item));
    if (raw &&
        typeof raw === 'object' &&
        'results' in raw &&
        Array.isArray(raw.results)) {
        return raw.results.map((item) => normalizeMemoryItem(item));
    }
    return [];
}
// ---------------------------------------------------------------------------
// Platform Provider
// ---------------------------------------------------------------------------
class PlatformProvider {
    apiKey;
    baseUrl;
    client;
    initPromise = null;
    constructor(apiKey, baseUrl) {
        this.apiKey = apiKey;
        this.baseUrl = baseUrl;
    }
    async ensureClient() {
        if (this.client)
            return;
        if (this.initPromise)
            return this.initPromise;
        this.initPromise = this._init();
        return this.initPromise;
    }
    async _init() {
        const { MemoryClient } = await import('mem0ai');
        const opts = { apiKey: this.apiKey };
        if (this.baseUrl)
            opts.host = this.baseUrl;
        this.client = new MemoryClient(opts);
    }
    async add(messages, opts) {
        await this.ensureClient();
        const addOpts = { userId: opts.userId };
        if (opts.infer === false)
            addOpts.infer = false;
        const result = await this.client.add(messages, addOpts);
        return result;
    }
    async search(query, opts) {
        await this.ensureClient();
        const searchOpts = {
            filters: { user_id: opts.userId },
        };
        if (opts.topK)
            searchOpts.topK = opts.topK;
        const results = await this.client.search(query, searchOpts);
        return normalizeResults(results);
    }
    async getAll(opts) {
        await this.ensureClient();
        const results = await this.client.getAll({
            filters: { user_id: opts.userId },
        });
        return normalizeResults(results);
    }
}
class OSSProvider {
    ossConfig;
    resolveKey;
    memory;
    initPromise = null;
    constructor(ossConfig, resolveKey) {
        this.ossConfig = ossConfig;
        this.resolveKey = resolveKey;
    }
    async ensureMemory() {
        if (this.memory)
            return;
        if (this.initPromise)
            return this.initPromise;
        this.initPromise = this._init();
        return this.initPromise;
    }
    async _buildConfig() {
        const config = {};
        const defaultEmbedder = { provider: 'openai', config: { model: 'text-embedding-3-small' } };
        const defaultLlm = { provider: 'openai', config: { model: 'gpt-4.1-nano' } };
        const embedderProvider = this.ossConfig?.embedder?.provider || defaultEmbedder.provider;
        const embedderCfg = {
            ...defaultEmbedder.config,
            ...(this.ossConfig?.embedder?.config ?? {}),
        };
        const llmProvider = this.ossConfig?.llm?.provider || defaultLlm.provider;
        const llmCfg = {
            ...defaultLlm.config,
            ...(this.ossConfig?.llm?.config ?? {}),
        };
        // Resolve API keys from pi model registry if not explicitly set
        if (this.resolveKey) {
            if (!embedderCfg.apiKey && !embedderCfg.api_key) {
                const key = await this.resolveKey(embedderProvider);
                if (key)
                    embedderCfg.apiKey = key;
            }
            if (!llmCfg.apiKey && !llmCfg.api_key) {
                const key = await this.resolveKey(llmProvider);
                if (key)
                    llmCfg.apiKey = key;
            }
        }
        config.embedder = { provider: embedderProvider, config: embedderCfg };
        config.llm = { provider: llmProvider, config: llmCfg };
        if (this.ossConfig?.vectorStore) {
            config.vectorStore = this.ossConfig.vectorStore;
        }
        else {
            // Default: SQLite in <PI_AGENT_HOME>/memories/mem0.db (alongside pi-memory's files)
            config.vectorStore = {
                provider: 'sqlite',
                config: { dbPath: join(resolveHome(), 'memories', 'mem0.db') },
            };
        }
        if (this.ossConfig?.disableHistory) {
            config.disableHistory = true;
        }
        return config;
    }
    async _init() {
        const mod = await import('mem0ai/oss');
        const Memory = mod.Memory ?? mod.default;
        const builtConfig = await this._buildConfig();
        this.memory = new Memory(builtConfig);
        await this.memory.getAll({ filters: { user_id: '__warmup__' } });
    }
    async add(messages, opts) {
        await this.ensureMemory();
        const addOpts = { userId: opts.userId };
        if (opts.infer === false)
            addOpts.infer = false;
        const result = await this.memory.add(messages, addOpts);
        return result;
    }
    async search(query, opts) {
        await this.ensureMemory();
        const searchOpts = {
            filters: { user_id: opts.userId },
        };
        if (opts.topK)
            searchOpts.topK = opts.topK;
        const results = await this.memory.search(query, searchOpts);
        return normalizeResults(results);
    }
    async getAll(opts) {
        await this.ensureMemory();
        const results = await this.memory.getAll({
            filters: { user_id: opts.userId },
        });
        return normalizeResults(results);
    }
}
export async function createMem0Provider(opts) {
    const { config, resolveKey } = opts;
    const mode = config.mode ?? 'platform';
    if (mode === 'open-source') {
        const useRegistry = config.useRegistryKeys !== false;
        const provider = new OSSProvider(config.oss, useRegistry ? resolveKey : undefined);
        await provider.ensureMemory();
        return provider;
    }
    if (!config.apiKey?.trim()) {
        throw new Error('Platform mode requires apiKey.');
    }
    return new PlatformProvider(config.apiKey.trim(), config.baseUrl?.trim());
}
//# sourceMappingURL=provider.js.map