@ai2070/l0
Version:
L0: The Missing Reliability Substrate for AI
263 lines • 10.1 kB
JavaScript
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