UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

242 lines 9.17 kB
/** * @file Batch Strategy * Batch processing for evaluation pipelines */ function hasPipelineResult(result) { return !result.error && result.result !== undefined; } /** * Default batch configuration */ const DEFAULT_BATCH_CONFIG = { concurrency: 5, batchDelay: 0, continueOnError: true, onProgress: () => { }, onResult: () => { }, }; /** * Batch evaluation strategy */ export class BatchStrategy { _pipeline; _config; constructor(pipeline, config) { this._pipeline = pipeline; this._config = { ...DEFAULT_BATCH_CONFIG, ...config }; } /** * Evaluate a batch of inputs */ async evaluate(inputs, options) { const startTime = Date.now(); const results = []; const durations = []; // Process in batches based on concurrency for (let i = 0; i < inputs.length; i += this._config.concurrency) { const batch = inputs.slice(i, i + this._config.concurrency); // Execute batch in parallel const batchPromises = batch.map((input, batchIndex) => { const globalIndex = i + batchIndex; return this._evaluateItem(input, globalIndex, options); }); const batchResults = await Promise.all(batchPromises); // Record results for (const result of batchResults) { results.push(result); durations.push(result.duration); // Notify of individual result this._config.onResult(result); // Check for fatal error if (result.error && !this._config.continueOnError) { throw new Error(`Batch evaluation failed at index ${result.index}: ${result.error}`); } } // Report progress this._config.onProgress({ total: inputs.length, completed: results.length, failed: results.filter((r) => r.error).length, pending: inputs.length - results.length, percentComplete: (results.length / inputs.length) * 100, estimatedTimeRemaining: this._estimateRemainingTime(durations, inputs.length - results.length), }); // Apply batch delay if configured if (this._config.batchDelay > 0 && i + this._config.concurrency < inputs.length) { await this._delay(this._config.batchDelay); } } // Calculate summary const totalDuration = Date.now() - startTime; const successfulResults = results.filter(hasPipelineResult); const scores = successfulResults.map((r) => r.result.overallScore); const passed = successfulResults.filter((r) => r.result.passed); return { results, summary: { total: inputs.length, succeeded: successfulResults.length, failed: results.length - successfulResults.length, averageScore: scores.length > 0 ? scores.reduce((a, b) => a + b, 0) / scores.length : 0, passingRate: successfulResults.length > 0 ? passed.length / successfulResults.length : 0, totalDuration, averageDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0, }, }; } /** * Evaluate a single item */ async _evaluateItem(input, index, options) { const startTime = Date.now(); try { const result = await this._pipeline.execute(input, { ...options, correlationId: options?.correlationId ? `${options.correlationId}-${index}` : `batch-${index}`, }); return { index, input, result, duration: Date.now() - startTime, }; } catch (error) { return { index, input, error: error instanceof Error ? error.message : String(error), duration: Date.now() - startTime, }; } } /** * Estimate remaining time based on average duration */ _estimateRemainingTime(durations, remaining) { if (durations.length === 0 || remaining === 0) { return 0; } const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length; const batches = Math.ceil(remaining / this._config.concurrency); return avgDuration * batches + this._config.batchDelay * (batches - 1); } /** * Delay helper */ _delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * Update configuration */ configure(config) { this._config = { ...this._config, ...config }; } } /** * Create a batch strategy for a pipeline */ export function createBatchStrategy(pipeline, config) { return new BatchStrategy(pipeline, config); } /** * Evaluate a batch of inputs using a pipeline */ export async function evaluateBatch(pipeline, inputs, config) { const strategy = new BatchStrategy(pipeline, config); return strategy.evaluate(inputs); } /** * Stream batch evaluation results */ export async function* streamBatchEvaluation(pipeline, inputs, config) { const results = []; const durations = []; const startTime = Date.now(); const batchConfig = { ...DEFAULT_BATCH_CONFIG, ...config }; for (let i = 0; i < inputs.length; i += batchConfig.concurrency) { const batch = inputs.slice(i, i + batchConfig.concurrency); const batchPromises = batch.map(async (input, batchIndex) => { const globalIndex = i + batchIndex; const itemStart = Date.now(); try { const result = await pipeline.execute(input, { correlationId: `stream-batch-${globalIndex}`, }); return { index: globalIndex, input, result, duration: Date.now() - itemStart, }; } catch (error) { return { index: globalIndex, input, error: error instanceof Error ? error.message : String(error), duration: Date.now() - itemStart, }; } }); const batchResults = await Promise.all(batchPromises); for (const result of batchResults) { results.push(result); durations.push(result.duration); // If continueOnError is false and this result has an error, abort and return summary if (result.error && batchConfig.continueOnError === false) { const successfulResults = results.filter(hasPipelineResult); const earlyScores = successfulResults.map((r) => r.result.overallScore); const earlyPassed = successfulResults.filter((r) => r.result.passed); return { total: inputs.length, succeeded: successfulResults.length, failed: results.length - successfulResults.length, averageScore: earlyScores.length > 0 ? earlyScores.reduce((a, b) => a + b, 0) / earlyScores.length : 0, passingRate: successfulResults.length > 0 ? earlyPassed.length / successfulResults.length : 0, totalDuration: Date.now() - startTime, averageDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0, }; } yield result; } if (batchConfig.batchDelay > 0 && i + batchConfig.concurrency < inputs.length) { await new Promise((resolve) => setTimeout(resolve, batchConfig.batchDelay)); } } // Return summary const successfulResults = results.filter(hasPipelineResult); const scores = successfulResults.map((r) => r.result.overallScore); const passed = successfulResults.filter((r) => r.result.passed); return { total: inputs.length, succeeded: successfulResults.length, failed: results.length - successfulResults.length, averageScore: scores.length > 0 ? scores.reduce((a, b) => a + b, 0) / scores.length : 0, passingRate: successfulResults.length > 0 ? passed.length / successfulResults.length : 0, totalDuration: Date.now() - startTime, averageDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0, }; } //# sourceMappingURL=batchStrategy.js.map