From bd717d340c2b1f3bd3a7409244c65b91de0dd0fe Mon Sep 17 00:00:00 2001 From: bracesproul Date: Tue, 7 May 2024 15:13:57 -0700 Subject: [PATCH 1/3] js[patch]: Fix listRuns limit arg --- js/package.json | 1 + js/src/client.ts | 17 +++++++++++- js/src/tests/client.int.test.ts | 49 ++++++++++++++++++++++++++++++++- js/src/tests/utils.ts | 27 ++++++++++++++++++ js/yarn.lock | 5 ++++ 5 files changed, 97 insertions(+), 2 deletions(-) diff --git a/js/package.json b/js/package.json index 484d8c4b3..71391ee54 100644 --- a/js/package.json +++ b/js/package.json @@ -84,6 +84,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.22.4", + "@faker-js/faker": "^8.4.1", "@jest/globals": "^29.5.0", "@langchain/core": "^0.1.32", "@langchain/langgraph": "^0.0.8", diff --git a/js/src/client.ts b/js/src/client.ts index 4736740f9..6ebaebe2f 100644 --- a/js/src/client.ts +++ b/js/src/client.ts @@ -1194,11 +1194,26 @@ export class Client { is_root: isRoot, }; + let runsYielded = 0; + console.log("going to list!"); for await (const runs of this._getCursorPaginatedList( "/runs/query", body )) { - yield* runs; + if (limit) { + if (runsYielded >= limit) { + break; + } + if (runs.length + runsYielded > limit) { + const newRuns = runs.splice(limit - runsYielded); + yield* newRuns; + break; + } + runsYielded += runs.length; + yield* runs; + } else { + yield* runs; + } } } diff --git a/js/src/tests/client.int.test.ts b/js/src/tests/client.int.test.ts index eaf49b975..64b7f72d1 100644 --- a/js/src/tests/client.int.test.ts +++ b/js/src/tests/client.int.test.ts @@ -3,7 +3,13 @@ import { FunctionMessage, HumanMessage } from "@langchain/core/messages"; import { Client } from "../client.js"; import { v4 as uuidv4 } from "uuid"; -import { deleteDataset, deleteProject, toArray, waitUntil } from "./utils.js"; +import { + createRunsFactory, + deleteDataset, + deleteProject, + toArray, + waitUntil, +} from "./utils.js"; type CheckOutputsType = boolean | ((run: Run) => boolean); async function waitUntilRunFound( @@ -558,3 +564,44 @@ test.concurrent( }, 180_000 ); + +test.concurrent.only("list runs limit arg works", async () => { + const client = new Client(); + + const projectName = "test-limit-runs-listRuns-endpoint"; + try { + // create a fresh project with 10 runs --default amount created by createRunsFactory + await client.createProject({ + projectName, + }); + await Promise.all(createRunsFactory(projectName).map(client.createRun)); + + const limit = 6; + let iters = 0; + const runsArr: Array = []; + for await (const run of client.listRuns({ limit, projectName })) { + expect(run).toBeDefined(); + runsArr.push(run); + iters += 1; + if (iters > limit) { + throw new Error( + `More runs returned than expected.\nExpected: ${limit}\nReceived: ${iters}` + ); + } + } + expect(runsArr.length).toBe(limit); + } catch (e: any) { + // cleanup by deleting the project + const projectExists = await client.hasProject({ projectName }); + if (projectExists) { + await client.deleteProject({ projectName }); + } + + // Error thrown by test, rethrow + if (e.message.startsWith("More runs returned than expected.")) { + throw e; + } else { + console.error(e); + } + } +}); diff --git a/js/src/tests/utils.ts b/js/src/tests/utils.ts index a7e4d3197..1165c7373 100644 --- a/js/src/tests/utils.ts +++ b/js/src/tests/utils.ts @@ -1,4 +1,8 @@ import { Client } from "../client.js"; +import { v4 as uuidv4 } from "uuid"; +// eslint-disable-next-line import/no-extraneous-dependencies +import { faker } from "@faker-js/faker"; +import { RunCreate } from "../schemas.js"; export async function toArray(iterable: AsyncIterable): Promise { const result: T[] = []; @@ -112,3 +116,26 @@ export function sanitizePresignedUrls(payload: unknown) { return value; }); } + +/** + * Factory which returns a list of `RunCreate` objects. + * @param {number} count Number of runs to create (default: 10) + * @returns {Array} List of `RunCreate` objects + */ +export function createRunsFactory( + projectName: string, + count = 10 +): Array { + return Array.from({ length: count }).map((_, idx) => ({ + id: uuidv4(), + name: `${idx}-${faker.lorem.words()}`, + run_type: faker.helpers.arrayElement(["tool", "chain", "llm", "runnable"]), + inputs: { + question: faker.lorem.sentence(), + }, + outputs: { + answer: faker.lorem.sentence(), + }, + project_name: projectName, + })); +} diff --git a/js/yarn.lock b/js/yarn.lock index 94e03d6a3..4968faf24 100644 --- a/js/yarn.lock +++ b/js/yarn.lock @@ -1109,6 +1109,11 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz" integrity sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA== +"@faker-js/faker@^8.4.1": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.4.1.tgz#5d5e8aee8fce48f5e189bf730ebd1f758f491451" + integrity sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg== + "@humanwhocodes/config-array@^0.11.8": version "0.11.8" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz" From 8887b06675492bba97a95f02314667556c4e62ff Mon Sep 17 00:00:00 2001 From: bracesproul Date: Tue, 7 May 2024 15:14:50 -0700 Subject: [PATCH 2/3] cr --- js/src/client.ts | 1 - js/src/tests/client.int.test.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/js/src/client.ts b/js/src/client.ts index 6ebaebe2f..961061300 100644 --- a/js/src/client.ts +++ b/js/src/client.ts @@ -1195,7 +1195,6 @@ export class Client { }; let runsYielded = 0; - console.log("going to list!"); for await (const runs of this._getCursorPaginatedList( "/runs/query", body diff --git a/js/src/tests/client.int.test.ts b/js/src/tests/client.int.test.ts index 64b7f72d1..9e047b5da 100644 --- a/js/src/tests/client.int.test.ts +++ b/js/src/tests/client.int.test.ts @@ -565,7 +565,7 @@ test.concurrent( 180_000 ); -test.concurrent.only("list runs limit arg works", async () => { +test.concurrent("list runs limit arg works", async () => { const client = new Client(); const projectName = "test-limit-runs-listRuns-endpoint"; From 78d688c319dd9ab725908a090f157d8d27f7e22d Mon Sep 17 00:00:00 2001 From: bracesproul Date: Tue, 7 May 2024 20:13:24 -0700 Subject: [PATCH 3/3] cr --- js/src/client.ts | 2 +- js/src/tests/client.int.test.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/js/src/client.ts b/js/src/client.ts index 961061300..8c4ad763c 100644 --- a/js/src/client.ts +++ b/js/src/client.ts @@ -1204,7 +1204,7 @@ export class Client { break; } if (runs.length + runsYielded > limit) { - const newRuns = runs.splice(limit - runsYielded); + const newRuns = runs.slice(0, limit - runsYielded); yield* newRuns; break; } diff --git a/js/src/tests/client.int.test.ts b/js/src/tests/client.int.test.ts index 9e047b5da..a69218736 100644 --- a/js/src/tests/client.int.test.ts +++ b/js/src/tests/client.int.test.ts @@ -569,6 +569,9 @@ test.concurrent("list runs limit arg works", async () => { const client = new Client(); const projectName = "test-limit-runs-listRuns-endpoint"; + const runsArr: Array = []; + const limit = 6; + try { // create a fresh project with 10 runs --default amount created by createRunsFactory await client.createProject({ @@ -576,9 +579,7 @@ test.concurrent("list runs limit arg works", async () => { }); await Promise.all(createRunsFactory(projectName).map(client.createRun)); - const limit = 6; let iters = 0; - const runsArr: Array = []; for await (const run of client.listRuns({ limit, projectName })) { expect(run).toBeDefined(); runsArr.push(run); @@ -589,7 +590,6 @@ test.concurrent("list runs limit arg works", async () => { ); } } - expect(runsArr.length).toBe(limit); } catch (e: any) { // cleanup by deleting the project const projectExists = await client.hasProject({ projectName }); @@ -604,4 +604,6 @@ test.concurrent("list runs limit arg works", async () => { console.error(e); } } + + expect(runsArr.length).toBe(limit); });