/**
 * pi-memory-mem0 — Passive semantic memory extension powered by Mem0.
 *
 * Two modes:
 * - **platform**: Uses Mem0 Cloud API (needs MEM0_API_KEY)
 * - **open-source**: Runs locally with SQLite vector store (needs OPENAI_API_KEY or Ollama)
 *
 * Configuration via settings.json key "pi-memory-mem0".
 * Supports ${ENV_VAR:-fallback} in all string values.
 */
import { loadPiSettings } from '@amaster.ai/pi-shared/settings';
import { Prefetch } from './prefetch.js';
import { createMem0Provider } from './provider.js';
import { TurnSync } from './sync.js';
import { createMem0Tools } from './tools.js';
const SETTINGS_KEY = 'pi-memory-mem0';
const STATUS_KEY = 'mem0';
function loadConfig(cwd) {
    try {
        return loadPiSettings(SETTINGS_KEY, {
            cwd,
        });
    }
    catch {
        return {};
    }
}
function resolveUserId(configUserId) {
    if (configUserId?.trim())
        return configUserId.trim();
    if (process.env.USER)
        return process.env.USER;
    if (process.env.USERNAME)
        return process.env.USERNAME;
    return 'default-user';
}
export default function mem0Extension(pi) {
    let provider;
    let sync;
    let prefetch;
    pi.on('session_start', async (_event, ctx) => {
        const config = loadConfig(ctx.cwd);
        const mode = config.mode ?? 'platform';
        // Platform mode requires apiKey; OSS mode requires an LLM provider (env key)
        if (mode === 'platform' && !config.apiKey?.trim()) {
            ctx.ui.setStatus(STATUS_KEY, 'mem0: disabled (no API key)');
            return;
        }
        try {
            provider = await createMem0Provider({
                config,
                resolveKey: async (providerName) => {
                    const registry = ctx.modelRegistry;
                    if (registry.getApiKeyForProvider) {
                        return registry.getApiKeyForProvider(providerName);
                    }
                    return undefined;
                },
            });
        }
        catch (err) {
            ctx.ui.setStatus(STATUS_KEY, 'mem0: init failed');
            ctx.ui.notify(`Mem0 init failed: ${err instanceof Error ? err.message : String(err)}`, 'error');
            return;
        }
        const userId = resolveUserId(config.userId);
        sync = new TurnSync(provider, userId);
        prefetch = new Prefetch(provider, userId, {
            topK: config.topK ?? 5,
        });
        ctx.ui.setStatus(STATUS_KEY, `mem0: ${mode}`);
        for (const tool of createMem0Tools(provider, userId)) {
            pi.registerTool(tool);
        }
    });
    pi.on('turn_end', async (event) => {
        if (!sync || !prefetch)
            return;
        const msg = event.message;
        const text = extractText(msg);
        if (!text)
            return;
        if (msg.role === 'user') {
            prefetch.queue(text);
        }
        // Buffer messages for paired sync
        sync.onMessage(msg.role ?? '', text);
    });
    pi.on('before_agent_start', async (event) => {
        if (!prefetch)
            return;
        const recalled = await prefetch.consume();
        if (!recalled)
            return;
        return {
            systemPrompt: event.systemPrompt ? `${event.systemPrompt}\n\n${recalled}` : recalled,
        };
    });
    pi.on('session_shutdown', async () => {
        provider = undefined;
        sync = undefined;
        prefetch = undefined;
    });
    pi.registerCommand('mem0', {
        description: 'Mem0 memory commands. Subcommands: status, search <query>, profile.',
        handler: async (args, ctx) => {
            if (!provider) {
                ctx.ui.notify('Mem0 is not active.', 'warning');
                return;
            }
            const config = loadConfig(ctx.cwd);
            const userId = resolveUserId(config.userId);
            const parts = args.trim().split(/\s+/).filter(Boolean);
            const subcommand = parts[0]?.toLowerCase() ?? 'status';
            const rest = parts.slice(1).join(' ').trim();
            switch (subcommand) {
                case 'status': {
                    ctx.ui.notify(`Mem0: active (mode: ${config.mode ?? 'platform'})`, 'info');
                    break;
                }
                case 'search': {
                    if (!rest) {
                        ctx.ui.notify('Usage: /mem0 search <query>', 'warning');
                        break;
                    }
                    const results = await provider.search(rest, { userId, topK: 10 });
                    if (results.length === 0) {
                        ctx.ui.notify('No relevant memories found.', 'info');
                    }
                    else {
                        const lines = results.map((r, i) => `${i + 1}. ${r.memory}`);
                        ctx.ui.notify(`Mem0 search results:\n${lines.join('\n')}`, 'info');
                    }
                    break;
                }
                case 'profile': {
                    const all = await provider.getAll({ userId });
                    if (all.length === 0) {
                        ctx.ui.notify('No memories stored yet.', 'info');
                    }
                    else {
                        const lines = all.map((m, i) => `${i + 1}. ${m.memory}`);
                        ctx.ui.notify(`Mem0 memories (${all.length}):\n${lines.join('\n')}`, 'info');
                    }
                    break;
                }
                default:
                    ctx.ui.notify('Unknown subcommand. Available: status, search, profile.', 'warning');
            }
        },
    });
}
function extractText(msg) {
    if (typeof msg.content === 'string')
        return msg.content;
    if (Array.isArray(msg.content)) {
        return msg.content
            .filter((c) => c.type === 'text' && c.text)
            .map((c) => c.text)
            .join('\n');
    }
    return '';
}
//# sourceMappingURL=index.js.map