@ai2070/l0
Version:
L0: The Missing Reliability Substrate for AI
228 lines • 8.57 kB
JavaScript
import { deserializeError, L0RecordedEventTypes } from "../types/events";
import { L0Monitor } from "./monitoring";
export async function replay(options) {
const { streamId, eventStore, speed = 0, fireCallbacks = true, fromSeq = 0, toSeq = Infinity, } = options;
const exists = await eventStore.exists(streamId);
if (!exists) {
throw new Error(`Stream not found: ${streamId}`);
}
const envelopes = await eventStore.getEvents(streamId);
if (envelopes.length === 0) {
throw new Error(`Stream has no events: ${streamId}`);
}
const startEvent = envelopes.find((e) => e.event.type === L0RecordedEventTypes.START);
const originalOptions = startEvent
? startEvent.event
.options
: {};
const state = createInitialState();
const errors = [];
const abortController = new AbortController();
const monitor = new L0Monitor({
enabled: true,
includeTimings: true,
});
monitor.start();
let onToken;
let onViolation;
let onRetry;
let onEvent;
const streamGenerator = async function* () {
let lastTs = null;
for (const envelope of envelopes) {
if (envelope.seq < fromSeq)
continue;
if (envelope.seq > toSeq)
break;
if (abortController.signal.aborted) {
break;
}
const event = envelope.event;
if (speed > 0 && lastTs !== null) {
const delay = (event.ts - lastTs) / speed;
if (delay > 0) {
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
lastTs = event.ts;
switch (event.type) {
case L0RecordedEventTypes.START:
break;
case L0RecordedEventTypes.TOKEN: {
state.content += event.value;
state.tokenCount = event.index + 1;
monitor.recordToken(event.ts);
const tokenEvent = {
type: "token",
value: event.value,
timestamp: event.ts,
};
if (fireCallbacks) {
if (onToken)
onToken(event.value);
if (onEvent)
onEvent(tokenEvent);
}
yield tokenEvent;
break;
}
case L0RecordedEventTypes.CHECKPOINT:
state.checkpoint = event.content;
break;
case L0RecordedEventTypes.GUARDRAIL: {
state.violations.push(...event.result.violations);
monitor.recordGuardrailViolations(event.result.violations);
if (fireCallbacks && onViolation) {
for (const violation of event.result.violations) {
onViolation(violation);
}
}
break;
}
case L0RecordedEventTypes.DRIFT:
if (event.result.detected) {
state.driftDetected = true;
monitor.recordDrift(true, event.result.types);
}
break;
case L0RecordedEventTypes.RETRY: {
if (event.countsTowardLimit) {
state.modelRetryCount++;
}
else {
state.networkRetryCount++;
}
monitor.recordRetry(!event.countsTowardLimit);
if (fireCallbacks && onRetry) {
onRetry(event.attempt, event.reason);
}
break;
}
case L0RecordedEventTypes.FALLBACK:
state.fallbackIndex = event.to;
break;
case L0RecordedEventTypes.CONTINUATION:
state.resumed = true;
state.resumePoint = event.checkpoint;
monitor.recordContinuation(true, true, event.checkpoint);
break;
case L0RecordedEventTypes.COMPLETE: {
state.completed = true;
state.content = event.content;
state.tokenCount = event.tokenCount;
monitor.complete();
const completeEvent = {
type: "complete",
timestamp: event.ts,
};
if (fireCallbacks && onEvent) {
onEvent(completeEvent);
}
yield completeEvent;
break;
}
case L0RecordedEventTypes.ERROR: {
const error = deserializeError(event.error);
errors.push(error);
const errorEvent = {
type: "error",
error,
timestamp: event.ts,
};
if (fireCallbacks && onEvent) {
onEvent(errorEvent);
}
yield errorEvent;
break;
}
}
}
};
const result = {
stream: streamGenerator(),
state,
errors,
telemetry: monitor.export(),
abort: () => abortController.abort(),
streamId,
isReplay: true,
originalOptions,
setCallbacks(callbacks) {
onToken = callbacks.onToken;
onViolation = callbacks.onViolation;
onRetry = callbacks.onRetry;
onEvent = callbacks.onEvent;
},
};
return result;
}
function createInitialState() {
return {
content: "",
checkpoint: "",
tokenCount: 0,
modelRetryCount: 0,
networkRetryCount: 0,
fallbackIndex: 0,
violations: [],
driftDetected: false,
completed: false,
networkErrors: [],
resumed: false,
dataOutputs: [],
};
}
export function compareReplays(a, b) {
const differences = [];
if (a.content !== b.content) {
differences.push(`content: "${a.content.slice(0, 50)}..." vs "${b.content.slice(0, 50)}..."`);
}
if (a.tokenCount !== b.tokenCount) {
differences.push(`tokenCount: ${a.tokenCount} vs ${b.tokenCount}`);
}
if (a.completed !== b.completed) {
differences.push(`completed: ${a.completed} vs ${b.completed}`);
}
if (a.modelRetryCount !== b.modelRetryCount) {
differences.push(`modelRetryCount: ${a.modelRetryCount} vs ${b.modelRetryCount}`);
}
if (a.fallbackIndex !== b.fallbackIndex) {
differences.push(`fallbackIndex: ${a.fallbackIndex} vs ${b.fallbackIndex}`);
}
if (a.violations.length !== b.violations.length) {
differences.push(`violations: ${a.violations.length} vs ${b.violations.length}`);
}
if (a.driftDetected !== b.driftDetected) {
differences.push(`driftDetected: ${a.driftDetected} vs ${b.driftDetected}`);
}
return {
identical: differences.length === 0,
differences,
};
}
export async function getStreamMetadata(eventStore, streamId) {
const exists = await eventStore.exists(streamId);
if (!exists)
return null;
const events = await eventStore.getEvents(streamId);
if (events.length === 0)
return null;
const startEvent = events.find((e) => e.event.type === L0RecordedEventTypes.START);
const completeEvent = events.find((e) => e.event.type === L0RecordedEventTypes.COMPLETE);
const errorEvent = events.find((e) => e.event.type === L0RecordedEventTypes.ERROR);
const tokenEvents = events.filter((e) => e.event.type === L0RecordedEventTypes.TOKEN);
return {
streamId,
eventCount: events.length,
tokenCount: tokenEvents.length,
startTs: startEvent?.event.ts ?? events[0].event.ts,
endTs: (completeEvent ?? errorEvent ?? events[events.length - 1]).event.ts,
completed: !!completeEvent,
hasError: !!errorEvent,
options: startEvent
? startEvent.event
.options
: {},
};
}
//# sourceMappingURL=replay.js.map