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