"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.bootstrapModels = bootstrapModels;
/**
 * YAML→registry boot bridge (#629 / #630 of #510).
 *
 * Reads the top-level `models` block from the root config and dispatches each
 * `models.embedding.<name>` / `models.generative.<name>` entry to the matching
 * per-backend register function. Backends self-contain in `components/<name>/`
 * (matches the pattern in `components/mcp/index.ts` from PR #649).
 *
 * Boot site: `components/componentLoader.ts` calls this after `getConfigObj()`
 * returns the root config and before per-component iteration, so that
 * `scope.models.embed(...)` works from `handleApplication(scope)`.
 *
 * Env-var expansion: each entry's string leaves are run through
 * `expandEnvVarsDeep` before dispatch — `apiKey: ${OPENAI_API_KEY}` in YAML
 * becomes the resolved process.env value at the backend. Matches the
 * convention from `@harperfast/oauth`'s config loader.
 *
 * Errors per entry are logged and skipped, not thrown — one misconfigured
 * backend should not block Harper boot.
 */
const harper_logger_ts_1 = __importDefault(require("../../utility/logging/harper_logger.js"));
const expandEnvVar_ts_1 = require("../../utility/expandEnvVar.js");
const index_ts_1 = require("../../components/ollama/index.js");
const index_ts_2 = require("../../components/openai/index.js");
const index_ts_3 = require("../../components/anthropic/index.js");
const index_ts_4 = require("../../components/bedrock/index.js");
/**
 * Field names treated as credentials. When present in config as a literal
 * value (not a `${VAR}` placeholder), bootstrap warns the operator at boot
 * — `harperdb-config.yaml` on disk in plaintext is a real anti-pattern.
 * Extend this list as future backends add credential fields.
 */
const CREDENTIAL_FIELDS = new Set(['apiKey']);
const FACTORIES = {
    ollama: (args) => (0, index_ts_1.registerOllamaBackend)({ ...args, config: args.config }),
    openai: (args) => (0, index_ts_2.registerOpenAIBackend)({ ...args, config: args.config }),
    anthropic: (args) => (0, index_ts_3.registerAnthropicBackend)({ ...args, config: args.config }),
    bedrock: (args) => (0, index_ts_4.registerBedrockBackend)({ ...args, config: args.config }),
};
/**
 * Populate the model registry from `rootConfig.models`. No-op if the block
 * is absent or empty. Idempotent within a process: each entry overwrites any
 * prior registration under the same logical name (registry uses `.set()`).
 */
function bootstrapModels(rootConfig) {
    const block = rootConfig?.models;
    if (!block)
        return;
    registerKind('embedding', block.embedding);
    registerKind('generative', block.generative);
}
function warnOnLiteralCredentials(kind, logicalName, entry) {
    for (const field of CREDENTIAL_FIELDS) {
        const value = entry[field];
        if (typeof value !== 'string' || value.length === 0)
            continue;
        if ((0, expandEnvVar_ts_1.isUnresolvedEnvVarPlaceholder)(value))
            continue; // operator is using ${VAR} indirection
        harper_logger_ts_1.default.warn(`models.${kind}.${logicalName}: '${field}' is a literal value in harperdb-config.yaml; ` +
            `prefer \${ENV_VAR} indirection for credentials to keep them off disk`);
    }
}
function registerKind(kind, entries) {
    if (!entries)
        return;
    for (const [logicalName, entry] of Object.entries(entries)) {
        if (!entry || typeof entry !== 'object') {
            // Schema validation (configValidator.ts) catches this before bootstrap
            // runs, so reaching here means config was loaded by an unusual path
            // (test, programmatic). Log at error so it's visible.
            harper_logger_ts_1.default.error(`models.${kind}.${logicalName} is not an object; skipping`);
            continue;
        }
        const factory = entry.backend ? FACTORIES[entry.backend] : undefined;
        if (!factory) {
            // Loud because the operator opted into `models:` specifically to enable
            // a backend — silently registering nothing is a footgun. Schema-level
            // typo guards (`.unknown(false)` on modelEntrySchema) catch field-name
            // typos before this point; reaching here means `backend:` itself names
            // a type Harper doesn't ship a factory for in this version. List the
            // known backends so operators can spot value-name typos
            // (`backend: 'openi'` instead of `'openai'`).
            const known = Object.keys(FACTORIES).sort().join(', ');
            harper_logger_ts_1.default.error(`models.${kind}.${logicalName}: unknown backend '${entry.backend ?? '(missing)'}'; skipping. Known backends: ${known}.`);
            continue;
        }
        // Warn before expansion: literal credentials in `harperdb-config.yaml`
        // land on disk, in backups, and (depending on deployment) in replicated
        // config tables. The `${VAR}` indirection pattern from
        // `@harperfast/oauth` is documented but not enforced.
        warnOnLiteralCredentials(kind, logicalName, entry);
        try {
            // Resolve `${VAR}` placeholders on every string leaf before handing the
            // entry to the backend factory. Backends receive concrete values and
            // don't need to know about env-var syntax. Unresolved placeholders
            // (env var unset) pass through unchanged — backend's required-field
            // validation catches them with a meaningful error.
            const resolved = (0, expandEnvVar_ts_1.expandEnvVarsDeep)(entry);
            factory({ logicalName, kind, config: resolved });
        }
        catch (err) {
            harper_logger_ts_1.default.error(`models.${kind}.${logicalName}: registration failed (${err?.message ?? err})`);
        }
    }
}
//# sourceMappingURL=bootstrap.js.map