UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

319 lines (318 loc) 8.29 kB
class InterceptorManager { interceptors; contexts = []; constructor(interceptors = []) { this.interceptors = interceptors; } /** * Execute all "before" hooks in order * Each interceptor can modify the options */ 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; } /** * Execute all "after" hooks in order * Each interceptor can inspect/modify the result */ 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; } /** * Execute all "onError" hooks * Error hooks don't modify anything, just notify */ 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 ); } } } } /** * Get execution contexts for debugging */ getContexts() { return [...this.contexts]; } /** * Reset contexts */ reset() { this.contexts = []; } } 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 }); } }; } function metadataInterceptor(metadata) { return { name: "metadata", before: async (options) => { return { ...options, monitoring: { ...options.monitoring, enabled: options.monitoring?.enabled ?? true, metadata: { ...options.monitoring?.metadata, ...metadata } } }; } }; } function authInterceptor(getAuth) { return { name: "auth", before: async (options) => { const auth = await getAuth(); return { ...options, monitoring: { ...options.monitoring, metadata: { ...options.monitoring?.metadata, auth } } }; } }; } function timingInterceptor() { const startTimes = /* @__PURE__ */ 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; } }; } 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; } }; } 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; } }; } 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 { constructor(result) { super("Cached result available"); this.result = result; this.name = "CachedResultError"; } } function transformInterceptor(transform) { return { name: "transform", after: async (result) => { const transformed = await transform(result.state.content); return { ...result, state: { ...result.state, content: transformed } }; } }; } 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 }); } }; } function createInterceptorManager(interceptors = []) { return new InterceptorManager(interceptors); } export { InterceptorManager, analyticsInterceptor, authInterceptor, cachingInterceptor, createInterceptorManager, loggingInterceptor, metadataInterceptor, rateLimitInterceptor, timingInterceptor, transformInterceptor, validationInterceptor }; //# sourceMappingURL=interceptors.js.map