@ai2070/l0
Version:
L0: The Missing Reliability Substrate for AI
319 lines (318 loc) • 8.29 kB
JavaScript
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