"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashProviderRuntimeSnapshot = hashProviderRuntimeSnapshot;
exports.resolveProviderRuntimeSnapshot = resolveProviderRuntimeSnapshot;
const crypto_1 = __importDefault(require("crypto"));
const SENSITIVE_CONNECTION_FIELDS = [
    'apiKey',
    'claudeApiKey',
    'claudeAuthToken',
    'openaiApiKey',
    'awsBearerToken',
    'awsAccessKeyId',
    'awsSecretAccessKey',
    'awsSessionToken',
];
const SECRET_ENV_KEYS = [
    'ANTHROPIC_API_KEY',
    'ANTHROPIC_AUTH_TOKEN',
    'OPENAI_API_KEY',
    'AWS_BEARER_TOKEN_BEDROCK',
    'AWS_ACCESS_KEY_ID',
    'AWS_SECRET_ACCESS_KEY',
    'AWS_SESSION_TOKEN',
];
const PROVIDER_RUNTIME_ENV_KEYS = [
    'SMARTPERFETTO_AGENT_RUNTIME',
    'CLAUDE_MODEL',
    'CLAUDE_LIGHT_MODEL',
    'CLAUDE_SUB_AGENT_MODEL',
    'OPENAI_MODEL',
    'OPENAI_LIGHT_MODEL',
    'ANTHROPIC_BASE_URL',
    'ANTHROPIC_BEDROCK_BASE_URL',
    'OPENAI_BASE_URL',
    'OPENAI_AGENTS_PROTOCOL',
    'CLAUDE_CODE_USE_BEDROCK',
    'AWS_REGION',
    'AWS_PROFILE',
    'CLAUDE_CODE_USE_VERTEX',
    'ANTHROPIC_VERTEX_PROJECT_ID',
    'CLOUD_ML_REGION',
    'CLAUDE_MAX_TURNS',
    'CLAUDE_EFFORT',
    'CLAUDE_MAX_BUDGET_USD',
    'CLAUDE_FULL_PER_TURN_MS',
    'CLAUDE_QUICK_PER_TURN_MS',
    'CLAUDE_VERIFIER_TIMEOUT_MS',
    'CLAUDE_CLASSIFIER_TIMEOUT_MS',
    'CLAUDE_ENABLE_SUB_AGENTS',
    'CLAUDE_ENABLE_VERIFICATION',
    'OPENAI_MAX_TURNS',
    'OPENAI_FULL_PER_TURN_MS',
    'OPENAI_QUICK_PER_TURN_MS',
    'OPENAI_CLASSIFIER_TIMEOUT_MS',
];
const TIMEOUT_KEYS = [
    'fullPerTurnMs',
    'quickPerTurnMs',
    'verifierTimeoutMs',
    'classifierTimeoutMs',
];
function sha256Hex(value) {
    return crypto_1.default.createHash('sha256').update(value, 'utf8').digest('hex');
}
function normalizeForJson(value) {
    if (value === undefined)
        return undefined;
    if (value === null)
        return null;
    if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
        return value;
    }
    if (Array.isArray(value)) {
        return value
            .map((item) => normalizeForJson(item))
            .filter((item) => item !== undefined);
    }
    if (typeof value === 'object') {
        const out = {};
        for (const key of Object.keys(value).sort()) {
            const normalized = normalizeForJson(value[key]);
            if (normalized !== undefined)
                out[key] = normalized;
        }
        return out;
    }
    return undefined;
}
function canonicalJson(value) {
    return JSON.stringify(normalizeForJson(value));
}
function hashSecretEntries(entries) {
    const present = entries.filter((entry) => Boolean(entry[1]));
    if (present.length === 0)
        return 'none';
    return `sha256:${sha256Hex(canonicalJson(present))}`;
}
function pickEnv(env, keys) {
    const picked = {};
    for (const key of keys) {
        const value = env[key];
        if (value !== undefined && value !== '')
            picked[key] = value;
    }
    return picked;
}
function parseRuntimeEnv(value) {
    switch (value) {
        case 'claude-agent-sdk':
        case 'openai-agents-sdk':
            return value;
        default:
            return undefined;
    }
}
function pickResolvedTimeouts(tuning, runtimeKind) {
    const resolved = {};
    const keys = runtimeKind === 'openai-agents-sdk'
        ? TIMEOUT_KEYS.filter((key) => key !== 'verifierTimeoutMs')
        : TIMEOUT_KEYS;
    for (const key of keys) {
        const value = tuning?.[key];
        if (typeof value === 'number')
            resolved[key] = value;
    }
    return resolved;
}
function inferBaseUrl(runtimeKind, env) {
    if (runtimeKind === 'openai-agents-sdk') {
        return env.OPENAI_BASE_URL;
    }
    return env.ANTHROPIC_BASE_URL || env.ANTHROPIC_BEDROCK_BASE_URL;
}
function envRuntimeSnapshot(runtimeOverride) {
    const runtimeKind = runtimeOverride
        ?? parseRuntimeEnv(process.env.SMARTPERFETTO_AGENT_RUNTIME)
        ?? 'claude-agent-sdk';
    const env = pickEnv(process.env, [...PROVIDER_RUNTIME_ENV_KEYS, ...SECRET_ENV_KEYS]);
    const timeoutPrefix = runtimeKind === 'openai-agents-sdk' ? 'OPENAI' : 'CLAUDE';
    const resolvedTimeouts = {};
    const timeoutMap = [
        ['fullPerTurnMs', `${timeoutPrefix}_FULL_PER_TURN_MS`],
        ['quickPerTurnMs', `${timeoutPrefix}_QUICK_PER_TURN_MS`],
        ['classifierTimeoutMs', `${timeoutPrefix}_CLASSIFIER_TIMEOUT_MS`],
    ];
    if (runtimeKind === 'claude-agent-sdk') {
        timeoutMap.push(['verifierTimeoutMs', 'CLAUDE_VERIFIER_TIMEOUT_MS']);
    }
    for (const [key, envKey] of timeoutMap) {
        const value = env[envKey];
        const parsed = value ? Number.parseInt(value, 10) : NaN;
        if (Number.isFinite(parsed))
            resolvedTimeouts[key] = parsed;
    }
    const modelPrefix = runtimeKind === 'openai-agents-sdk' ? 'OPENAI' : 'CLAUDE';
    const nonSecretEnv = pickEnv(process.env, PROVIDER_RUNTIME_ENV_KEYS);
    return {
        version: 1,
        providerId: null,
        providerType: 'env',
        runtimeKind,
        resolvedModels: {
            primary: env[`${modelPrefix}_MODEL`],
            light: env[`${modelPrefix}_LIGHT_MODEL`],
            subAgent: runtimeKind === 'claude-agent-sdk'
                ? env.CLAUDE_SUB_AGENT_MODEL
                : undefined,
        },
        resolvedTimeouts,
        baseUrl: inferBaseUrl(runtimeKind, nonSecretEnv),
        openaiProtocol: runtimeKind === 'openai-agents-sdk' ? env.OPENAI_AGENTS_PROTOCOL : undefined,
        environment: nonSecretEnv,
        secretVersion: hashSecretEntries(SECRET_ENV_KEYS.map((key) => [key, process.env[key]])),
    };
}
function providerSecretVersion(provider) {
    return hashSecretEntries(SENSITIVE_CONNECTION_FIELDS.map((field) => [field, provider.connection[field]]));
}
function providerRuntimeSnapshot(providerService, provider, providerScope) {
    const runtimeKind = providerService.resolveAgentRuntime(provider);
    const env = providerService.getEnvForProvider(provider.id, providerScope) ?? {};
    const nonSecretEnv = pickEnv(env, PROVIDER_RUNTIME_ENV_KEYS);
    return {
        version: 1,
        providerId: provider.id,
        providerType: provider.type,
        runtimeKind,
        resolvedModels: {
            primary: provider.models.primary,
            light: provider.models.light,
            subAgent: runtimeKind === 'claude-agent-sdk' ? provider.models.subAgent : undefined,
        },
        resolvedTimeouts: pickResolvedTimeouts(provider.tuning, runtimeKind),
        baseUrl: inferBaseUrl(runtimeKind, nonSecretEnv),
        openaiProtocol: runtimeKind === 'openai-agents-sdk'
            ? providerService.resolveOpenAIProtocol(provider)
            : undefined,
        environment: nonSecretEnv,
        secretVersion: providerSecretVersion(provider),
    };
}
function hashProviderRuntimeSnapshot(snapshot) {
    return sha256Hex(canonicalJson(snapshot));
}
function resolveProviderRuntimeSnapshot(providerService, providerId, runtimeOverride, providerScope) {
    const snapshot = typeof providerId === 'string'
        ? (() => {
            const provider = providerService.getRawProvider(providerId, providerScope);
            if (!provider)
                throw new Error(`Provider not found: ${providerId}`);
            return providerRuntimeSnapshot(providerService, provider, providerScope);
        })()
        : envRuntimeSnapshot(runtimeOverride);
    return {
        snapshot,
        snapshotHash: hashProviderRuntimeSnapshot(snapshot),
    };
}
//# sourceMappingURL=providerSnapshot.js.map