const FACTUAL_ASSERTION_TYPES = new Set([
    'contains',
    'not_contains',
    'regex',
    'json_valid',
    'json_schema',
    'equals',
    'not_equals',
    'contains_all',
    'contains_any',
    'semantic_similarity',
    'tool_output_contains',
    'tool_input_contains',
    'tool_input_not_contains',
]);
const BEHAVIORAL_ASSERTION_TYPES = new Set([
    'starts_with',
    'ends_with',
    'min_length',
    'max_length',
    'word_count_min',
    'word_count_max',
    'cost_max',
    'latency_max',
    'turns_min',
    'turns_max',
    'tools_called',
    'tools_not_called',
    'tools_count_min',
    'tools_count_max',
    'custom',
]);
function ratioToScore(ratio) {
    return Number((1 + ratio * 4).toFixed(2));
}
function scoreFromDetails(details) {
    if (details.length === 0)
        return null;
    const totalWeight = details.reduce((s, d) => s + d.weight, 0);
    if (totalWeight === 0)
        return null;
    const passedWeight = details.filter((d) => d.passed).reduce((s, d) => s + d.weight, 0);
    return ratioToScore(passedWeight / totalWeight);
}
export function computeLayeredScores(results) {
    const layered = {};
    if (results.assertions?.details) {
        const factDetails = results.assertions.details.filter((d) => FACTUAL_ASSERTION_TYPES.has(d.type));
        const behaviorDetails = results.assertions.details.filter((d) => BEHAVIORAL_ASSERTION_TYPES.has(d.type));
        layered.factScore = scoreFromDetails(factDetails) ?? undefined;
        layered.behaviorScore = scoreFromDetails(behaviorDetails) ?? undefined;
    }
    // 评委打 0 分是"完全不合格"的合法低分,不是缺失——保留进 composite 计算,不做 > 0 gate。
    // 只排除 undefined(真正缺数据:没配 judge 或打分失败)。fact/behavior 通过 ratioToScore
    // 产出的分数理论上 ≥ 1,null 判断即可。
    if (typeof results.llmScore === 'number') {
        layered.judgeScore = results.llmScore;
    }
    const scores = [layered.factScore, layered.behaviorScore, layered.judgeScore].filter((s) => s != null);
    const compositeScore = scores.length > 0 ? Number((scores.reduce((a, b) => a + b, 0) / scores.length).toFixed(2)) : 0;
    return { compositeScore, layeredScores: layered };
}
//# sourceMappingURL=layered-scores.js.map