From bea162c7574f7d7a809b79fc49db45c15c1f6c06 Mon Sep 17 00:00:00 2001 From: Andrei Bratu Date: Wed, 19 Feb 2025 11:15:01 +0000 Subject: [PATCH] pMap docstring + error catching --- package.json | 2 +- src/eval_utils/run.ts | 58 ++++++++++++++++++++++++++++++++++++------- src/version.ts | 2 +- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 5a5820f6..79a3cb19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "humanloop", - "version": "0.8.14-beta5", + "version": "0.8.15", "private": false, "repository": "https://github.com/humanloop/humanloop-node", "main": "./index.js", diff --git a/src/eval_utils/run.ts b/src/eval_utils/run.ts index 03b59a35..ddd2635d 100644 --- a/src/eval_utils/run.ts +++ b/src/eval_utils/run.ts @@ -46,17 +46,57 @@ const GREEN = "\x1b[92m"; const RED = "\x1b[91m"; const RESET = "\x1b[0m"; +/** + * Maps over an array of items with a concurrency limit, applying an asynchronous mapper function to each item. + * + * @template T - The type of the items in the input array. + * @template O - The type of the items in the output array. + * + * @param {T[]} iterable - The array of items to be mapped. + * @param {(item: T) => Promise} mapper - The asynchronous function to apply to each item. + * @param {{ concurrency: number }} options - Options for the mapping operation. + * @param {number} options.concurrency - The maximum number of promises to resolve concurrently. + * + * @returns {Promise} A promise that resolves to an array of mapped items. + * + * @throws {TypeError} If the first argument is not an array. + * @throws {TypeError} If the second argument is not a function. + * @throws {TypeError} If the concurrency option is not a positive number. + * + * @description + * The `pMap` function processes the input array in chunks, where the size of each chunk is determined by the `concurrency` option. + * This controls how many promises are resolved at a time, which can help avoid issues such as rate limit errors when making server requests. + */ async function pMap( - iterable: Array, - mapper: (obj: T) => Promise, - { concurrency }: { concurrency: number }, -): Promise> { - const result: Array = []; - result: for (let i = 0; i < iterable.length; i += concurrency) { + iterable: T[], + mapper: (item: T) => Promise, + options: { concurrency: number }, +): Promise { + const { concurrency } = options; + + if (!Array.isArray(iterable)) { + throw new TypeError("Expected the first argument to be an array"); + } + + if (typeof mapper !== "function") { + throw new TypeError("Expected the second argument to be a function"); + } + + if (typeof concurrency !== "number" || concurrency <= 0) { + throw new TypeError("Expected the concurrency option to be a positive number"); + } + + const result: O[] = []; + for (let i = 0; i < iterable.length; i += concurrency) { const chunk = iterable.slice(i, i + concurrency); - const promises = chunk.map(mapper); - const awaitedChunk = await Promise.all(promises); - result.push(...awaitedChunk); + try { + const chunkResults = await Promise.all(chunk.map(mapper)); + result.push(...chunkResults); + } catch (error) { + // Handle individual chunk errors if necessary + // For now, rethrow to reject the entire pMap promise + throw error; + } } return result; } diff --git a/src/version.ts b/src/version.ts index 53b7bbbc..6448fe94 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const SDK_VERSION = "0.8.14-beta5"; +export const SDK_VERSION = "0.8.15";