// Resolve .env from one of several stable locations BEFORE zod parses
// process.env. See utils/load-env.ts for the search order. Falls back
// silently if no .env is found (cloud deployments use real env vars).
import { loadMuassisEnv } from './utils/load-env.js';
loadMuassisEnv();
import { z } from 'zod';
import { getBundledNimKey, getBundledOllamaKey } from './models/bundled-key.js';
const envSchema = z.object({
    // Server. HOST defaults to 127.0.0.1 — the gateway holds business PII,
    // ZATCA tax data, WhatsApp creds, and email passwords. Binding 0.0.0.0
    // exposes all of that to anyone on the same Wi-Fi network. Customers who
    // need LAN access (multi-device team) opt-in via MUASSIS_HOST=0.0.0.0
    // and add their own reverse-proxy + auth.
    PORT: z.coerce.number().default(3000),
    HOST: z.string().default('127.0.0.1'),
    // Default to production so CORS is locked down on first install. Customers
    // who deliberately want dev-mode CORS set MUASSIS_NODE_ENV=development.
    NODE_ENV: z.enum(['development', 'production', 'test']).default('production'),
    LOG_LEVEL: z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']).default('info'),
    // Storage backend selector — Phase 1 customer devices run 'device' (SQLite, single-tenant).
    // 'control-plane' is for TaseesAI's own infra (Supabase, multi-tenant license/billing/telemetry).
    MUASSIS_MODE: z.enum(['device', 'control-plane']).default('device'),
    // Override platform-default data dir (e.g. ~/Library/Application Support/Muassis on macOS).
    MUASSIS_DATA_DIR: z.string().optional(),
    // Supabase — required only when MUASSIS_MODE=control-plane. Optional in device mode.
    SUPABASE_URL: z.string().url().optional(),
    SUPABASE_ANON_KEY: z.string().min(40).optional(),
    SUPABASE_SERVICE_ROLE_KEY: z.string().min(40).optional(),
    // NVIDIA NIM — by default المؤسس routes through TaseesAI's hosted proxy at
    // NVIDIA_NIM_BASE_URL, which injects a server-side key. That keeps the
    // zero-config UX without shipping a secret in the npm tarball. Power users
    // can set NVIDIA_NIM_API_KEY to call NVIDIA directly (override base URL too).
    NVIDIA_NIM_BASE_URL: z.string().url().default('https://aimoasis-license-server.vercel.app/free'),
    NVIDIA_NIM_API_KEY: z.string().optional(),
    // Frontier provider keys — paste any to auto-extend the failover chain.
    // NIM/qwen stays as the zero-setup default. Customer's choice for upgrades.
    TOGETHER_API_KEY: z.string().optional().default('mock_together_key'),
    GOOGLE_AI_API_KEY: z.string().optional().default('mock_google_key'),
    DEEPSEEK_API_KEY: z.string().optional(),
    OPENAI_API_KEY: z.string().optional(),
    ANTHROPIC_API_KEY: z.string().optional(),
    MOONSHOT_API_KEY: z.string().optional(),
    // Optional: pin a default model per tier. Format: "<provider>:<model>"
    //   MUASSIS_BRAIN_MODEL=anthropic:claude-sonnet-4-6
    //   MUASSIS_BRAIN_MODEL=openai:gpt-4o
    //   MUASSIS_BRAIN_MODEL=kimi:kimi-k2-0711-preview
    // Per-tenant overrides live in identity_facts.preference.model.brain.
    MUASSIS_BRAIN_MODEL: z.string().optional(),
    MUASSIS_FLASH_MODEL: z.string().optional(),
    MUASSIS_REASONING_MODEL: z.string().optional(),
    // WhatsApp Business API (Optional for demo)
    WHATSAPP_VERIFY_TOKEN: z.string().optional().default('demo_verify_token'),
    WHATSAPP_ACCESS_TOKEN: z.string().optional().default('demo_access_token'),
    WHATSAPP_PHONE_NUMBER_ID: z.string().optional().default('demo_phone_id'),
    WHATSAPP_BUSINESS_ACCOUNT_ID: z.string().optional(),
    // Voice / TTS (Optional)
    AZURE_TTS_KEY: z.string().optional(),
    AZURE_TTS_REGION: z.string().default('westeurope'),
    ELEVENLABS_API_KEY: z.string().optional(),
    // Knowledge Graph (Optional)
    NEO4J_URI: z.string().default('bolt://localhost:7687'),
    NEO4J_USER: z.string().default('neo4j'),
    NEO4J_PASSWORD: z.string().optional(),
    // Encryption (Optional)
    TENANT_ENCRYPTION_KEY: z.string().optional(),
});
function loadConfig() {
    // Backward-compat: many existing user .env files use NVIDIA_API_KEY (the
    // name on build.nvidia.com). Accept either spelling — if NVIDIA_NIM_API_KEY
    // is missing but NVIDIA_API_KEY is set, treat them as equivalent.
    if (!process.env.NVIDIA_NIM_API_KEY && process.env.NVIDIA_API_KEY) {
        process.env.NVIDIA_NIM_API_KEY = process.env.NVIDIA_API_KEY;
    }
    // Last-resort fallback: a TaseesAI-bundled NIM key, XOR-obfuscated in
    // src/models/bundled-key.ts. Lets brand-new customers get working agents
    // without any setup. Trade-off is documented in that file. This is
    // testing-phase only — replace with the server-side proxy before scale.
    if (!process.env.NVIDIA_NIM_API_KEY) {
        const fallback = getBundledNimKey();
        if (fallback) {
            process.env.NVIDIA_NIM_API_KEY = fallback;
            process.env.MUASSIS_USING_BUNDLED_KEY = '1';
        }
    }
    // Zero-config demo default: if STILL no key, use the bundled Ollama Cloud
    // key pointed at ollama.com/v1. The shipped default brain model is
    // `kimi-k2.5` which only exists on Ollama Cloud — without this a fresh
    // friend install would send kimi-k2.5 to the (dead) Vercel proxy and 400
    // on every chat. Setting NVIDIA_NIM_BASE_URL here makes the integrate.api
    // override below a no-op, so the key talks to the right backend.
    if (!process.env.NVIDIA_NIM_API_KEY) {
        const ollamaFallback = getBundledOllamaKey();
        if (ollamaFallback) {
            process.env.NVIDIA_NIM_API_KEY = ollamaFallback;
            // The bundled Ollama key is ONLY valid against ollama.com/v1, so it
            // must be paired with that base URL. FORCE it even if one is already
            // set: a prior install can persist a stale/foreign base URL (e.g. the
            // dead Vercel proxy `taseesai-nim-proxy`) into the data-dir .env, and
            // without this override the bundled key gets POSTed there → 404 on
            // every chat (the "friend error 404" even on a fixed build). This is
            // always correct here because this branch only runs when the user
            // supplied NO key of their own — a real user key short-circuits above.
            process.env.NVIDIA_NIM_BASE_URL = 'https://ollama.com/v1';
            process.env.MUASSIS_USING_BUNDLED_OLLAMA = '1';
        }
    }
    // If we have a NIM key (whether the user's or the bundled fallback),
    // route directly to NVIDIA — the hosted TaseesAI proxy on Vercel exists
    // only for keyless mode, and its 25s function-invocation cap will time
    // out on big tool turns. Direct calls have no such ceiling.
    if (process.env.NVIDIA_NIM_API_KEY && !process.env.NVIDIA_NIM_BASE_URL) {
        process.env.NVIDIA_NIM_BASE_URL = 'https://integrate.api.nvidia.com/v1';
    }
    const result = envSchema.safeParse(process.env);
    if (!result.success) {
        console.error('❌ Invalid environment configuration:');
        for (const issue of result.error.issues) {
            console.error(` → ${issue.path.join('.')}: ${issue.message}`);
        }
        process.exit(1);
    }
    // Conditional requirement: control-plane mode needs full Supabase credentials.
    // Device mode runs entirely on local SQLite — no cloud creds needed.
    if (result.data.MUASSIS_MODE === 'control-plane') {
        const missing = [];
        if (!result.data.SUPABASE_URL)
            missing.push('SUPABASE_URL');
        if (!result.data.SUPABASE_ANON_KEY)
            missing.push('SUPABASE_ANON_KEY');
        if (!result.data.SUPABASE_SERVICE_ROLE_KEY)
            missing.push('SUPABASE_SERVICE_ROLE_KEY');
        if (missing.length > 0) {
            console.error('❌ control-plane mode requires:', missing.join(', '));
            process.exit(1);
        }
    }
    return result.data;
}
export const config = loadConfig();
// Model configuration — NVIDIA NIM (all tiers, free hosted catalog).
//
// 1.0.44: reverted from Llama 3.3 70B back to qwen3-next-80b. Llama 3.3 on
// NIM's free tier rate-limited aggressively under our normal usage pattern
// (tool-loops with maxToolLoops=12 × eager tool-calling = 12 NIM calls per
// turn → E429 on second message). Qwen has been working reliably with the
// bundled key since 1.0.38 and tolerates our payload format more leniently
// (the multimodal-preprocessor bug from 1.0.42 didn't trip on it).
//
// The prompt-builder fix from 1.0.42 (no literal `<img src="data:image/png
// ;base64,...">` in the system prompt) stays — it makes the prompt safe
// against any future text-only NIM model that might trigger that path.
//
// Other model IDs verified working with the bundled key (rotation candidates
// if qwen ever stalls): meta/llama-3.3-70b-instruct (rate-limit-prone),
// meta/llama-3.1-70b-instruct, meta/llama-3.1-405b-instruct,
// mistralai/mixtral-8x22b-instruct-v0.1.
// Demo override: Kimi K2.5 via Ollama Cloud (NVIDIA_NIM_BASE_URL=https://ollama.com/v1).
// K2.5 chosen over K2.6 because K2.6 is a thinking-mode model that adds
// 60-90s of reasoning latency per turn — E503'd contract drafts in live demo.
// K2.5 is the Jan 2026 Kimi release: same 1T MoE, same tool-calling quality,
// no chain-of-thought overhead (~25s vs ~86s for a contract draft). Reasoning
// tier still uses kimi-k2-thinking when explicit deep reasoning is needed.
// To revert: restore 'qwen/qwen3-next-80b-a3b-instruct' and .env from .env.bak.pre-kimi-demo.
// Zero-config default brain (Ollama Cloud, served via the bundled key).
// CHANGED from 'kimi-k2.5': live testing showed kimi-k2.5 on Ollama Cloud is a
// THINKING model — it emits 250+ tokens into a `reasoning` field before any
// `content`, and our OpenAI-compat client only reads `content`. Under normal
// agent token budgets a tool-heavy turn truncates mid-reasoning → EMPTY reply
// (this is why a fresh friend install "doesn't really answer"). deepseek-v3.1
// returns Arabic content immediately + calls tools with ZERO reasoning
// overhead (~32 tokens for a greeting+tool turn) — fast, reliable, no CoT
// latency. The owner overrides this via MUASSIS_BRAIN_MODEL in their .env, so
// this default only affects zero-config / friend installs.
// Deep-reasoning work still uses kimi-k2-thinking via the `reasoning` tier.
const BRAIN_MODEL = 'meta/llama-3.3-70b-instruct';
export const MODELS = {
    router: {
        provider: 'nvidia-nim',
        model: BRAIN_MODEL,
        costPer1MInput: 0.00,
        costPer1MOutput: 0.00,
    },
    brain: {
        provider: 'nvidia-nim',
        model: BRAIN_MODEL,
        costPer1MInput: 0.00,
        costPer1MOutput: 0.00,
    },
    vision: {
        provider: 'nvidia-nim',
        model: BRAIN_MODEL,
        costPer1MInput: 0.00,
        costPer1MOutput: 0.00,
    },
    reasoning: {
        provider: 'nvidia-nim',
        // NVIDIA NIM flagship — strong Arabic + reasoning, returns content directly.
        model: 'qwen/qwen3.5-397b-a17b',
        costPer1MInput: 0.00,
        costPer1MOutput: 0.00,
    },
    primary: {
        provider: 'nvidia-nim',
        model: BRAIN_MODEL,
        costPer1MInput: 0.00,
        costPer1MOutput: 0.00,
    },
};
//# sourceMappingURL=config.js.map