UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

228 lines 8.57 kB
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