UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and

131 lines (130 loc) 5.52 kB
import { logger } from "../../utils/logger.js"; /** * Create analytics middleware for tracking AI model usage * Collects metrics on token usage, response times, and model performance */ export function createAnalyticsMiddleware() { const requestMetrics = new Map(); const metadata = { id: "analytics", name: "Analytics Tracking", description: "Tracks token usage, response times, and model performance metrics", priority: 100, // High priority to ensure analytics are captured defaultEnabled: true, }; const middleware = { wrapGenerate: async ({ doGenerate, params }) => { const requestId = `analytics-${Date.now()}`; const startTime = Date.now(); logger.debug(`[AnalyticsMiddleware] Starting request tracking`, { requestId, hasPrompt: !!params.prompt, }); try { // Execute the generation const result = await doGenerate(); // Calculate metrics const responseTime = Date.now() - startTime; const analytics = { requestId, responseTime, timestamp: new Date().toISOString(), usage: { inputTokens: result.usage?.promptTokens || 0, outputTokens: result.usage?.completionTokens || 0, totalTokens: (result.usage?.promptTokens || 0) + (result.usage?.completionTokens || 0), }, }; // Store metrics for potential retrieval requestMetrics.set(requestId, analytics); logger.debug(`[AnalyticsMiddleware] Request completed`, analytics); // Add analytics to the result // eslint-disable-next-line @typescript-eslint/no-explicit-any const updatedResult = { ...result }; if (!updatedResult.experimental_providerMetadata) { updatedResult.experimental_providerMetadata = {}; } if (!updatedResult.experimental_providerMetadata.neurolink) { updatedResult.experimental_providerMetadata.neurolink = {}; } updatedResult.experimental_providerMetadata.neurolink.analytics = analytics; return updatedResult; } catch (error) { const responseTime = Date.now() - startTime; logger.error(`[AnalyticsMiddleware] Request failed`, { requestId, responseTime, error: error instanceof Error ? error.message : String(error), }); throw error; } }, wrapStream: async ({ doStream, params }) => { const requestId = `analytics-stream-${Date.now()}`; const startTime = Date.now(); logger.debug(`[AnalyticsMiddleware] Starting stream tracking`, { requestId, hasPrompt: !!params.prompt, }); try { const result = await doStream(); const streamAnalytics = { requestId, startTime, timestamp: new Date().toISOString(), streamingMode: true, }; requestMetrics.set(requestId, streamAnalytics); // The 'result' is a stream, so we can't directly modify it. // Analytics for streams are typically handled after the stream is consumed. // For this middleware, we'll log the start and rely on other mechanisms // to capture the end-to-end stream metrics if needed. // We will pass a new property in the `rawResponse` // eslint-disable-next-line @typescript-eslint/no-explicit-any const updatedResult = { ...result }; if (!updatedResult.rawResponse) { updatedResult.rawResponse = {}; } if (!updatedResult.rawResponse.neurolink) { updatedResult.rawResponse.neurolink = {}; } updatedResult.rawResponse.neurolink.analytics = streamAnalytics; return updatedResult; } catch (error) { const responseTime = Date.now() - startTime; logger.error(`[AnalyticsMiddleware] Stream failed`, { requestId, responseTime, error: error instanceof Error ? error.message : String(error), }); throw error; } }, }; // Return the NeuroLinkMiddleware with metadata return { ...middleware, metadata, }; } /** * Get collected metrics from analytics middleware * Note: This is a utility function for accessing metrics */ export function getAnalyticsMetrics() { // This would need to be implemented with a global registry // For now, return empty map return new Map(); } /** * Clear collected metrics from analytics middleware * Note: This is a utility function for clearing metrics */ export function clearAnalyticsMetrics() { // This would need to be implemented with a global registry // For now, do nothing }