UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

263 lines 10.1 kB
import { l0 } from "./runtime/l0"; import { structured } from "./structured"; import { calculateSimilarityMatrix, findAgreements, findDisagreements, calculateFieldConsensus, resolveMajority, resolveBest, resolveMerge, meetsMinimumAgreement, } from "./utils/consensusUtils"; export async function consensus(options) { const { streams, schema, strategy = "majority", threshold = 0.8, resolveConflicts = "vote", weights, minimumAgreement = 0.6, timeout, signal, detectZeroTokens = true, monitoring, onComplete, onConsensus, metadata, } = options; if (streams.length < 2) { throw new Error("Consensus requires at least 2 streams"); } const startTime = Date.now(); const outputs = []; const defaultWeights = weights || streams.map(() => 1.0); const promises = streams.map(async (streamFactory, index) => { const outputStartTime = Date.now(); try { if (schema) { const result = await structured({ schema, stream: streamFactory, monitoring, detectZeroTokens, }); const text = result.raw || JSON.stringify(result.data); return { index, text, data: result.data, l0Result: undefined, structuredResult: result, status: "success", duration: Date.now() - outputStartTime, weight: defaultWeights[index] ?? 1.0, }; } else { const result = await l0({ stream: streamFactory, monitoring, signal, detectZeroTokens, }); let text = ""; for await (const event of result.stream) { if (event.type === "token" && event.value) { text += event.value; } } return { index, text: text || result.state.content, data: undefined, l0Result: result, status: "success", duration: Date.now() - outputStartTime, weight: defaultWeights[index] ?? 1.0, }; } } catch (error) { return { index, text: "", data: undefined, l0Result: undefined, status: "error", error: error instanceof Error ? error : new Error(String(error)), duration: Date.now() - outputStartTime, weight: defaultWeights[index] ?? 1.0, }; } }); const timeoutPromise = timeout ? new Promise((_, reject) => setTimeout(() => reject(new Error("Consensus timeout")), timeout)) : null; const results = timeoutPromise ? await Promise.race([Promise.all(promises), timeoutPromise]) : await Promise.all(promises); outputs.push(...results); if (onComplete) { await onComplete(outputs); } const successfulOutputs = outputs.filter((o) => o.status === "success"); if (successfulOutputs.length === 0) { throw new Error("All consensus streams failed"); } const similarityMatrix = calculateSimilarityMatrix(successfulOutputs); let totalSimilarity = 0; let comparisons = 0; let minSimilarity = 1.0; let maxSimilarity = 0.0; for (let i = 0; i < similarityMatrix.length; i++) { for (let j = i + 1; j < similarityMatrix.length; j++) { const sim = similarityMatrix[i]?.[j] ?? 0; totalSimilarity += sim; comparisons++; minSimilarity = Math.min(minSimilarity, sim); maxSimilarity = Math.max(maxSimilarity, sim); } } const averageSimilarity = comparisons > 0 ? totalSimilarity / comparisons : 1.0; const agreements = findAgreements(successfulOutputs, threshold); const disagreements = findDisagreements(successfulOutputs, threshold); if (!meetsMinimumAgreement(agreements, successfulOutputs.length, minimumAgreement)) { if (resolveConflicts === "fail") { throw new Error(`Consensus failed: agreement ratio ${agreements[0]?.ratio || 0} below minimum ${minimumAgreement}`); } } let consensusOutput; switch (strategy) { case "majority": consensusOutput = resolveMajority(successfulOutputs, defaultWeights); break; case "unanimous": if (averageSimilarity < 0.95) { if (resolveConflicts === "fail") { throw new Error("Unanimous consensus failed: outputs differ"); } consensusOutput = resolveMajority(successfulOutputs, defaultWeights); } else { consensusOutput = successfulOutputs[0]; } break; case "weighted": if (!weights) { throw new Error("Weighted strategy requires weights to be provided"); } consensusOutput = resolveMajority(successfulOutputs, weights); break; case "best": consensusOutput = resolveBest(successfulOutputs, defaultWeights); break; default: consensusOutput = resolveMajority(successfulOutputs, defaultWeights); } if (disagreements.length > 0 && resolveConflicts !== "vote") { switch (resolveConflicts) { case "merge": consensusOutput = resolveMerge(successfulOutputs); break; case "best": consensusOutput = resolveBest(successfulOutputs, defaultWeights); break; case "fail": throw new Error(`Consensus failed: ${disagreements.length} disagreements found`); } } disagreements.forEach((d) => { d.resolution = resolveConflicts; d.resolutionConfidence = averageSimilarity; }); const fieldConsensus = schema ? calculateFieldConsensus(successfulOutputs) : undefined; const confidence = calculateConfidence(successfulOutputs, agreements, disagreements, averageSimilarity, strategy); const identicalOutputs = countIdenticalOutputs(successfulOutputs); const analysis = { totalOutputs: outputs.length, successfulOutputs: successfulOutputs.length, failedOutputs: outputs.length - successfulOutputs.length, identicalOutputs, similarityMatrix, averageSimilarity, minSimilarity, maxSimilarity, totalAgreements: agreements.length, totalDisagreements: disagreements.length, strategy, conflictResolution: resolveConflicts, duration: Date.now() - startTime, }; const status = successfulOutputs.length === outputs.length ? "success" : successfulOutputs.length > 0 ? "partial" : "failed"; const result = { consensus: schema ? consensusOutput.data : consensusOutput.text, confidence, outputs, agreements, disagreements, analysis, type: schema ? "structured" : "text", fieldConsensus, status, metadata, }; if (onConsensus) { await onConsensus(result); } return result; } function calculateConfidence(outputs, agreements, disagreements, averageSimilarity, strategy) { if (outputs.length === 1) return 1.0; let confidence = averageSimilarity; if (agreements.length > 0) { const maxAgreementRatio = Math.max(...agreements.map((a) => a.ratio)); confidence = (confidence + maxAgreementRatio) / 2; } if (disagreements.length > 0) { const majorDisagreements = disagreements.filter((d) => d.severity === "major" || d.severity === "critical").length; const penalty = majorDisagreements * 0.1; confidence = Math.max(0, confidence - penalty); } if (strategy === "unanimous" && averageSimilarity > 0.95) { confidence = Math.min(1.0, confidence + 0.1); } return Math.max(0, Math.min(1.0, confidence)); } function countIdenticalOutputs(outputs) { if (outputs.length === 0) return 0; const first = outputs[0].text; return outputs.filter((o) => o.text === first).length; } export function quickConsensus(outputs, threshold = 0.8) { if (outputs.length < 2) return true; const counts = new Map(); outputs.forEach((output) => { counts.set(output, (counts.get(output) || 0) + 1); }); const maxCount = Math.max(...Array.from(counts.values())); const ratio = maxCount / outputs.length; return ratio >= threshold; } export function getConsensusValue(outputs) { if (outputs.length === 0) { throw new Error("No outputs to get consensus from"); } const counts = new Map(); outputs.forEach((output) => { const key = JSON.stringify(output); const existing = counts.get(key); if (existing) { existing.count++; } else { counts.set(key, { value: output, count: 1 }); } }); let maxCount = 0; let consensusValue = outputs[0]; for (const { value, count } of counts.values()) { if (count > maxCount) { maxCount = count; consensusValue = value; } } return consensusValue; } export function validateConsensus(result, minConfidence = 0.8, maxDisagreements = 0) { if (result.confidence < minConfidence) { return false; } const criticalDisagreements = result.disagreements.filter((d) => d.severity === "major" || d.severity === "critical").length; if (criticalDisagreements > maxDisagreements) { return false; } return true; } //# sourceMappingURL=consensus.js.map