UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

282 lines 9.27 kB
export class InterceptorManager { interceptors; contexts = []; constructor(interceptors = []) { this.interceptors = interceptors; } async executeBefore(options) { let currentOptions = options; for (const interceptor of this.interceptors) { if (interceptor.before) { const startTime = Date.now(); const context = { name: interceptor.name || "anonymous", phase: "before", timestamp: startTime, }; try { currentOptions = await interceptor.before(currentOptions); context.duration = Date.now() - startTime; this.contexts.push(context); } catch (error) { context.duration = Date.now() - startTime; this.contexts.push(context); throw new Error(`Interceptor "${context.name}" before hook failed: ${error instanceof Error ? error.message : String(error)}`); } } } return currentOptions; } async executeAfter(result) { let currentResult = result; for (const interceptor of this.interceptors) { if (interceptor.after) { const startTime = Date.now(); const context = { name: interceptor.name || "anonymous", phase: "after", timestamp: startTime, }; try { currentResult = await interceptor.after(currentResult); context.duration = Date.now() - startTime; this.contexts.push(context); } catch (error) { context.duration = Date.now() - startTime; this.contexts.push(context); throw new Error(`Interceptor "${context.name}" after hook failed: ${error instanceof Error ? error.message : String(error)}`); } } } return currentResult; } async executeError(error, options) { for (const interceptor of this.interceptors) { if (interceptor.onError) { const startTime = Date.now(); const context = { name: interceptor.name || "anonymous", phase: "error", timestamp: startTime, }; try { await interceptor.onError(error, options); context.duration = Date.now() - startTime; this.contexts.push(context); } catch (err) { context.duration = Date.now() - startTime; this.contexts.push(context); console.error(`Interceptor "${context.name}" error hook failed:`, err); } } } } getContexts() { return [...this.contexts]; } reset() { this.contexts = []; } } export function loggingInterceptor(logger = console) { return { name: "logging", before: async (options) => { logger.info("L0 execution starting", { hasGuardrails: !!options.guardrails?.length, hasRetry: !!options.retry, hasMonitoring: options.monitoring?.enabled, }); return options; }, after: async (result) => { logger.info("L0 execution completed", { completed: result.state.completed, tokens: result.state.tokenCount, retries: result.state.modelRetryCount, networkRetryCount: result.state.networkRetryCount, violations: result.state.violations.length, }); return result; }, onError: async (error) => { logger.error("L0 execution failed", { error: error.message, }); }, }; } export function metadataInterceptor(metadata) { return { name: "metadata", before: async (options) => { return { ...options, monitoring: { ...options.monitoring, enabled: options.monitoring?.enabled ?? true, metadata: { ...options.monitoring?.metadata, ...metadata, }, }, }; }, }; } export function authInterceptor(getAuth) { return { name: "auth", before: async (options) => { const auth = await getAuth(); return { ...options, monitoring: { ...options.monitoring, metadata: { ...options.monitoring?.metadata, auth: auth, }, }, }; }, }; } export function timingInterceptor() { const startTimes = new Map(); return { name: "timing", before: async (options) => { const sessionId = `session_${Date.now()}`; startTimes.set(sessionId, Date.now()); return { ...options, monitoring: { ...options.monitoring, enabled: true, includeTimings: true, metadata: { ...options.monitoring?.metadata, sessionId, }, }, }; }, after: async (result) => { const sessionId = result.telemetry?.sessionId; if (sessionId && startTimes.has(sessionId)) { startTimes.delete(sessionId); } return result; }, }; } export function validationInterceptor(validate, onInvalid) { return { name: "validation", after: async (result) => { const isValid = await validate(result.state.content); if (!isValid) { if (onInvalid) { onInvalid(result.state.content); } throw new Error("Output validation failed"); } return result; }, }; } export function rateLimitInterceptor(maxRequests, windowMs) { const requests = []; return { name: "rate-limit", before: async (options) => { const now = Date.now(); while (requests.length > 0 && requests[0] < now - windowMs) { requests.shift(); } if (requests.length >= maxRequests) { const oldestRequest = requests[0] ?? now; const waitTime = windowMs - (now - oldestRequest); throw new Error(`Rate limit exceeded. Wait ${waitTime}ms before retrying.`); } requests.push(now); return options; }, }; } export function cachingInterceptor(cache, getCacheKey) { return { name: "caching", before: async (options) => { const key = getCacheKey(options); if (cache.has(key)) { const cached = cache.get(key); throw new CachedResultError(cached); } return options; }, after: async (result) => { return result; }, }; } class CachedResultError extends Error { result; constructor(result) { super("Cached result available"); this.result = result; this.name = "CachedResultError"; } } export function transformInterceptor(transform) { return { name: "transform", after: async (result) => { const transformed = await transform(result.state.content); return { ...result, state: { ...result.state, content: transformed, }, }; }, }; } export function analyticsInterceptor(track) { let startTime; return { name: "analytics", before: async (options) => { startTime = Date.now(); await track("l0_started", { timestamp: startTime, hasGuardrails: !!options.guardrails?.length, }); return options; }, after: async (result) => { await track("l0_completed", { duration: Date.now() - startTime, tokens: result.state.tokenCount, retries: result.state.modelRetryCount, completed: result.state.completed, }); return result; }, onError: async (error) => { await track("l0_failed", { duration: Date.now() - startTime, error: error.message, }); }, }; } export function createInterceptorManager(interceptors = []) { return new InterceptorManager(interceptors); } //# sourceMappingURL=interceptors.js.map