From 22903fe494a14efccbc2b8a694b9f962b796356a Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Thu, 26 Sep 2024 00:19:44 -0700 Subject: [PATCH] [JS] Catch any errors in create/update run (#1044) --- js/package.json | 2 +- js/src/index.ts | 2 +- js/src/run_trees.ts | 58 +++++++++++++++++++--------------- js/src/tests/traceable.test.ts | 22 +++++++++++++ js/src/traceable.ts | 30 ++++++++++-------- 5 files changed, 74 insertions(+), 40 deletions(-) diff --git a/js/package.json b/js/package.json index d54af9b47..45a05380e 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "langsmith", - "version": "0.1.60", + "version": "0.1.61", "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.", "packageManager": "yarn@1.22.19", "files": [ diff --git a/js/src/index.ts b/js/src/index.ts index d77c8b7d1..96d782360 100644 --- a/js/src/index.ts +++ b/js/src/index.ts @@ -14,4 +14,4 @@ export { RunTree, type RunTreeConfig } from "./run_trees.js"; export { overrideFetchImplementation } from "./singletons/fetch.js"; // Update using yarn bump-version -export const __version__ = "0.1.60"; +export const __version__ = "0.1.61"; diff --git a/js/src/run_trees.ts b/js/src/run_trees.ts index 64cc7fb2b..5cb2aea97 100644 --- a/js/src/run_trees.ts +++ b/js/src/run_trees.ts @@ -356,36 +356,44 @@ export class RunTree implements BaseRun { } async postRun(excludeChildRuns = true): Promise { - const runtimeEnv = await getRuntimeEnvironment(); - const runCreate = await this._convertToCreate(this, runtimeEnv, true); - await this.client.createRun(runCreate); - - if (!excludeChildRuns) { - warnOnce( - "Posting with excludeChildRuns=false is deprecated and will be removed in a future version." - ); - for (const childRun of this.child_runs) { - await childRun.postRun(false); + try { + const runtimeEnv = await getRuntimeEnvironment(); + const runCreate = await this._convertToCreate(this, runtimeEnv, true); + await this.client.createRun(runCreate); + + if (!excludeChildRuns) { + warnOnce( + "Posting with excludeChildRuns=false is deprecated and will be removed in a future version." + ); + for (const childRun of this.child_runs) { + await childRun.postRun(false); + } } + } catch (error) { + console.error(`Error in postRun for run ${this.id}:`, error); } } async patchRun(): Promise { - const runUpdate: RunUpdate = { - end_time: this.end_time, - error: this.error, - inputs: this.inputs, - outputs: this.outputs, - parent_run_id: this.parent_run?.id, - reference_example_id: this.reference_example_id, - extra: this.extra, - events: this.events, - dotted_order: this.dotted_order, - trace_id: this.trace_id, - tags: this.tags, - }; - - await this.client.updateRun(this.id, runUpdate); + try { + const runUpdate: RunUpdate = { + end_time: this.end_time, + error: this.error, + inputs: this.inputs, + outputs: this.outputs, + parent_run_id: this.parent_run?.id, + reference_example_id: this.reference_example_id, + extra: this.extra, + events: this.events, + dotted_order: this.dotted_order, + trace_id: this.trace_id, + tags: this.tags, + }; + + await this.client.updateRun(this.id, runUpdate); + } catch (error) { + console.error(`Error in patchRun for run ${this.id}`, error); + } } toJSON() { diff --git a/js/src/tests/traceable.test.ts b/js/src/tests/traceable.test.ts index 9720701d1..ea8c009e3 100644 --- a/js/src/tests/traceable.test.ts +++ b/js/src/tests/traceable.test.ts @@ -1031,3 +1031,25 @@ test("argsConfigPath", async () => { }, }); }); + +test("traceable continues execution when client throws error", async () => { + const errorClient = { + createRun: jest.fn().mockRejectedValue(new Error("Client error") as never), + updateRun: jest.fn().mockRejectedValue(new Error("Client error") as never), + }; + + const tracedFunction = traceable( + async (value: number): Promise => value * 2, + { + client: errorClient as unknown as Client, + name: "errorTest", + tracingEnabled: true, + } + ); + + const result = await tracedFunction(5); + + expect(result).toBe(10); + expect(errorClient.createRun).toHaveBeenCalled(); + expect(errorClient.updateRun).toHaveBeenCalled(); +}); diff --git a/js/src/traceable.ts b/js/src/traceable.ts index dc43af0d3..aa8137c1a 100644 --- a/js/src/traceable.ts +++ b/js/src/traceable.ts @@ -617,20 +617,24 @@ export function traceable any>( if (isGenerator(wrappedFunc) && isIteratorLike(rawOutput)) { const chunks = gatherAll(rawOutput); - await currentRunTree?.end( - handleRunOutputs( - await handleChunks( - chunks.reduce((memo, { value, done }) => { - if (!done || typeof value !== "undefined") { - memo.push(value); - } - - return memo; - }, []) + try { + await currentRunTree?.end( + handleRunOutputs( + await handleChunks( + chunks.reduce((memo, { value, done }) => { + if (!done || typeof value !== "undefined") { + memo.push(value); + } + + return memo; + }, []) + ) ) - ) - ); - await handleEnd(); + ); + await handleEnd(); + } catch (e) { + console.error("Error occurred during handleEnd:", e); + } return (function* () { for (const ret of chunks) {