langsmith 0.3.57 → 0.3.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -225,6 +225,19 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
225
225
  ...lsConfig?.metadata,
226
226
  },
227
227
  processInputs: (inputs) => _formatTracedInputs(inputs),
228
+ processOutputs: async (outputs) => {
229
+ if (outputs.outputs == null || typeof outputs.outputs !== "object") {
230
+ return outputs;
231
+ }
232
+ const content = await outputs.outputs.content;
233
+ if (content == null || typeof content !== "object") {
234
+ return outputs;
235
+ }
236
+ return (0, middleware_js_1.populateToolCallsForTracing)({
237
+ content,
238
+ role: "assistant",
239
+ });
240
+ },
228
241
  });
229
242
  return traceableFunc(params);
230
243
  };
@@ -268,6 +281,16 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
268
281
  ...lsConfig?.metadata,
269
282
  },
270
283
  processInputs: (inputs) => _formatTracedInputs(inputs),
284
+ processOutputs: async (outputs) => {
285
+ if (outputs.outputs == null || typeof outputs.outputs !== "object") {
286
+ return outputs;
287
+ }
288
+ const object = await outputs.outputs.object;
289
+ if (object == null || typeof object !== "object") {
290
+ return outputs;
291
+ }
292
+ return object;
293
+ },
271
294
  });
272
295
  return traceableFunc(params);
273
296
  };
@@ -21,7 +21,7 @@ declare const wrapAISDK: <WrapLanguageModelType extends (...args: any[]) => any,
21
21
  streamText: StreamTextType;
22
22
  streamObject: StreamObjectType;
23
23
  generateObject: GenerateObjectType;
24
- }, lsConfig?: Partial<Omit<RunTreeConfig, "inputs" | "outputs">>) => {
24
+ }, lsConfig?: Partial<Omit<RunTreeConfig, "inputs" | "outputs" | "run_type">>) => {
25
25
  generateText: (params: Parameters<GenerateTextType>[0]) => Promise<ReturnType<GenerateTextType>>;
26
26
  generateObject: (params: Parameters<GenerateObjectType>[0]) => Promise<ReturnType<GenerateObjectType>>;
27
27
  streamText: (params: Parameters<StreamTextType>[0]) => Promise<ReturnType<StreamTextType>>;
@@ -222,6 +222,19 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
222
222
  ...lsConfig?.metadata,
223
223
  },
224
224
  processInputs: (inputs) => _formatTracedInputs(inputs),
225
+ processOutputs: async (outputs) => {
226
+ if (outputs.outputs == null || typeof outputs.outputs !== "object") {
227
+ return outputs;
228
+ }
229
+ const content = await outputs.outputs.content;
230
+ if (content == null || typeof content !== "object") {
231
+ return outputs;
232
+ }
233
+ return populateToolCallsForTracing({
234
+ content,
235
+ role: "assistant",
236
+ });
237
+ },
225
238
  });
226
239
  return traceableFunc(params);
227
240
  };
@@ -265,6 +278,16 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
265
278
  ...lsConfig?.metadata,
266
279
  },
267
280
  processInputs: (inputs) => _formatTracedInputs(inputs),
281
+ processOutputs: async (outputs) => {
282
+ if (outputs.outputs == null || typeof outputs.outputs !== "object") {
283
+ return outputs;
284
+ }
285
+ const object = await outputs.outputs.object;
286
+ if (object == null || typeof object !== "object") {
287
+ return outputs;
288
+ }
289
+ return object;
290
+ },
268
291
  });
269
292
  return traceableFunc(params);
270
293
  };
@@ -142,6 +142,17 @@ function LangSmithMiddleware(config) {
142
142
  const chunks = [];
143
143
  const transformStream = new TransformStream({
144
144
  async transform(chunk, controller) {
145
+ if (chunk.type === "tool-input-start" ||
146
+ chunk.type === "text-start") {
147
+ // Only necessary to log the first token event
148
+ if (runTree?.events == null ||
149
+ (Array.isArray(runTree.events) && runTree.events.length === 0)) {
150
+ runTree?.addEvent({ name: "new_token" });
151
+ }
152
+ }
153
+ else if (chunk.type === "finish") {
154
+ runTree?.addEvent({ name: "end" });
155
+ }
145
156
  chunks.push(chunk);
146
157
  controller.enqueue(chunk);
147
158
  },
@@ -137,6 +137,17 @@ export function LangSmithMiddleware(config) {
137
137
  const chunks = [];
138
138
  const transformStream = new TransformStream({
139
139
  async transform(chunk, controller) {
140
+ if (chunk.type === "tool-input-start" ||
141
+ chunk.type === "text-start") {
142
+ // Only necessary to log the first token event
143
+ if (runTree?.events == null ||
144
+ (Array.isArray(runTree.events) && runTree.events.length === 0)) {
145
+ runTree?.addEvent({ name: "new_token" });
146
+ }
147
+ }
148
+ else if (chunk.type === "finish") {
149
+ runTree?.addEvent({ name: "end" });
150
+ }
140
151
  chunks.push(chunk);
141
152
  controller.enqueue(chunk);
142
153
  },
package/dist/index.cjs CHANGED
@@ -10,4 +10,4 @@ Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true
10
10
  var project_js_1 = require("./utils/project.cjs");
11
11
  Object.defineProperty(exports, "getDefaultProjectName", { enumerable: true, get: function () { return project_js_1.getDefaultProjectName; } });
12
12
  // Update using yarn bump-version
13
- exports.__version__ = "0.3.57";
13
+ exports.__version__ = "0.3.59";
package/dist/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export type { Dataset, Example, TracerSession, Run, Feedback, RetrieverOutput, }
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
4
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
- export declare const __version__ = "0.3.57";
6
+ export declare const __version__ = "0.3.59";
package/dist/index.js CHANGED
@@ -3,4 +3,4 @@ export { RunTree } from "./run_trees.js";
3
3
  export { overrideFetchImplementation } from "./singletons/fetch.js";
4
4
  export { getDefaultProjectName } from "./utils/project.js";
5
5
  // Update using yarn bump-version
6
- export const __version__ = "0.3.57";
6
+ export const __version__ = "0.3.59";
@@ -100,7 +100,7 @@ const handleRunInputs = (inputs, processInputs) => {
100
100
  const _extractUsage = (runData) => {
101
101
  const usageMetadataFromMetadata = (runData.runTree.extra.metadata ?? {})
102
102
  .usage_metadata;
103
- return runData.outputs.usage_metadata ?? usageMetadataFromMetadata;
103
+ return runData.outputs?.usage_metadata ?? usageMetadataFromMetadata;
104
104
  };
105
105
  function validateExtractedUsageMetadata(data) {
106
106
  const allowedKeys = new Set([
@@ -121,26 +121,25 @@ function validateExtractedUsageMetadata(data) {
121
121
  }
122
122
  return data;
123
123
  }
124
- // Note: This mutates the run tree
125
- function handleRunOutputs(params) {
126
- const { runTree, rawOutputs, processOutputsFn } = params;
127
- let outputs;
128
- if ((0, asserts_js_1.isKVMap)(rawOutputs)) {
129
- outputs = { ...rawOutputs };
130
- }
131
- else {
132
- outputs = { outputs: rawOutputs };
133
- }
134
- try {
135
- outputs = processOutputsFn(outputs);
136
- }
137
- catch (e) {
138
- console.error("Error occurred during processOutputs. Sending unprocessed outputs:", e);
124
+ async function handleEnd(params) {
125
+ const { runTree, on_end, postRunPromise } = params;
126
+ const onEnd = on_end;
127
+ if (onEnd) {
128
+ if (!runTree) {
129
+ console.warn("Can not call 'on_end' if currentRunTree is undefined");
130
+ }
131
+ else {
132
+ onEnd(runTree);
133
+ }
139
134
  }
135
+ await postRunPromise;
136
+ await runTree?.patchRun();
137
+ }
138
+ const _populateUsageMetadata = (processedOutputs, runTree) => {
140
139
  if (runTree !== undefined) {
141
140
  let usageMetadata;
142
141
  try {
143
- usageMetadata = _extractUsage({ runTree, outputs });
142
+ usageMetadata = _extractUsage({ runTree, outputs: processedOutputs });
144
143
  }
145
144
  catch (e) {
146
145
  console.error("Error occurred while extracting usage metadata:", e);
@@ -150,10 +149,52 @@ function handleRunOutputs(params) {
150
149
  ...runTree.extra.metadata,
151
150
  usage_metadata: validateExtractedUsageMetadata(usageMetadata),
152
151
  };
153
- outputs.usage_metadata = usageMetadata;
152
+ processedOutputs.usage_metadata = usageMetadata;
153
+ }
154
+ }
155
+ };
156
+ function isAsyncFn(fn) {
157
+ return (fn != null &&
158
+ typeof fn === "function" &&
159
+ fn.constructor.name === "AsyncFunction");
160
+ }
161
+ // Note: This mutates the run tree
162
+ async function handleRunOutputs(params) {
163
+ const { runTree, rawOutputs, processOutputsFn, on_end, postRunPromise } = params;
164
+ let outputs;
165
+ if ((0, asserts_js_1.isKVMap)(rawOutputs)) {
166
+ outputs = { ...rawOutputs };
167
+ }
168
+ else {
169
+ outputs = { outputs: rawOutputs };
170
+ }
171
+ try {
172
+ outputs = processOutputsFn(outputs);
173
+ // TODO: Investigate making this behavior for all returned promises
174
+ // on next minor bump.
175
+ if (isAsyncFn(processOutputsFn)) {
176
+ void outputs
177
+ .then(async (processedOutputs) => {
178
+ _populateUsageMetadata(processedOutputs, runTree);
179
+ await runTree?.end(processedOutputs);
180
+ })
181
+ .catch(async (e) => {
182
+ console.error("Error occurred during processOutputs. Sending unprocessed outputs:", e);
183
+ await runTree?.end(outputs);
184
+ })
185
+ .finally(async () => {
186
+ await handleEnd({ runTree, postRunPromise, on_end });
187
+ });
188
+ return;
154
189
  }
155
190
  }
156
- return outputs;
191
+ catch (e) {
192
+ console.error("Error occurred during processOutputs. Sending unprocessed outputs:", e);
193
+ }
194
+ _populateUsageMetadata(outputs, runTree);
195
+ await runTree?.end(outputs);
196
+ await handleEnd({ runTree, postRunPromise, on_end });
197
+ return;
157
198
  }
158
199
  const handleRunAttachments = (rawInputs, extractAttachments) => {
159
200
  if (!extractAttachments) {
@@ -473,13 +514,13 @@ function traceable(wrappedFunc, config) {
473
514
  : otel_context.with(capturedOtelContext, () => reader.read()));
474
515
  if (result.done) {
475
516
  finished = true;
476
- const processedOutputs = handleRunOutputs({
517
+ await handleRunOutputs({
477
518
  runTree: currentRunTree,
478
519
  rawOutputs: await handleChunks(chunks),
479
520
  processOutputsFn,
521
+ on_end: config?.on_end,
522
+ postRunPromise,
480
523
  });
481
- await currentRunTree?.end(processedOutputs);
482
- await handleEnd();
483
524
  controller.close();
484
525
  break;
485
526
  }
@@ -497,13 +538,13 @@ function traceable(wrappedFunc, config) {
497
538
  async cancel(reason) {
498
539
  if (!finished)
499
540
  await currentRunTree?.end(undefined, "Cancelled");
500
- const processedOutputs = handleRunOutputs({
541
+ await handleRunOutputs({
501
542
  runTree: currentRunTree,
502
543
  rawOutputs: await handleChunks(chunks),
503
544
  processOutputsFn,
545
+ on_end: config?.on_end,
546
+ postRunPromise,
504
547
  });
505
- await currentRunTree?.end(processedOutputs);
506
- await handleEnd();
507
548
  return reader.cancel(reason);
508
549
  },
509
550
  });
@@ -540,13 +581,13 @@ function traceable(wrappedFunc, config) {
540
581
  finally {
541
582
  if (!finished)
542
583
  await currentRunTree?.end(undefined, "Cancelled");
543
- const processedOutputs = handleRunOutputs({
584
+ await handleRunOutputs({
544
585
  runTree: currentRunTree,
545
586
  rawOutputs: await handleChunks(chunks),
546
587
  processOutputsFn,
588
+ on_end: config?.on_end,
589
+ postRunPromise,
547
590
  });
548
- await currentRunTree?.end(processedOutputs);
549
- await handleEnd();
550
591
  }
551
592
  }
552
593
  function wrapAsyncGeneratorForTracing(iterable, snapshot) {
@@ -558,19 +599,6 @@ function traceable(wrappedFunc, config) {
558
599
  iterable[Symbol.asyncIterator] = () => wrappedIterator;
559
600
  return iterable;
560
601
  }
561
- async function handleEnd() {
562
- const onEnd = config?.on_end;
563
- if (onEnd) {
564
- if (!currentRunTree) {
565
- console.warn("Can not call 'on_end' if currentRunTree is undefined");
566
- }
567
- else {
568
- onEnd(currentRunTree);
569
- }
570
- }
571
- await postRunPromise;
572
- await currentRunTree?.patchRun();
573
- }
574
602
  function gatherAll(iterator) {
575
603
  const chunks = [];
576
604
  // eslint-disable-next-line no-constant-condition
@@ -625,7 +653,7 @@ function traceable(wrappedFunc, config) {
625
653
  if ((0, asserts_js_1.isGenerator)(wrappedFunc) && (0, asserts_js_1.isIteratorLike)(rawOutput)) {
626
654
  const chunks = gatherAll(rawOutput);
627
655
  try {
628
- const processedOutputs = handleRunOutputs({
656
+ await handleRunOutputs({
629
657
  runTree: currentRunTree,
630
658
  rawOutputs: await handleChunks(chunks.reduce((memo, { value, done }) => {
631
659
  if (!done || typeof value !== "undefined") {
@@ -634,12 +662,12 @@ function traceable(wrappedFunc, config) {
634
662
  return memo;
635
663
  }, [])),
636
664
  processOutputsFn,
665
+ on_end: config?.on_end,
666
+ postRunPromise,
637
667
  });
638
- await currentRunTree?.end(processedOutputs);
639
- await handleEnd();
640
668
  }
641
669
  catch (e) {
642
- console.error("Error occurred during handleEnd:", e);
670
+ console.error("[LANGSMITH]: Error occurred while handling run outputs:", e);
643
671
  }
644
672
  return (function* () {
645
673
  for (const ret of chunks) {
@@ -650,13 +678,13 @@ function traceable(wrappedFunc, config) {
650
678
  })();
651
679
  }
652
680
  try {
653
- const processedOutputs = handleRunOutputs({
681
+ await handleRunOutputs({
654
682
  runTree: currentRunTree,
655
683
  rawOutputs: rawOutput,
656
684
  processOutputsFn,
685
+ on_end: config?.on_end,
686
+ postRunPromise,
657
687
  });
658
- await currentRunTree?.end(processedOutputs);
659
- await handleEnd();
660
688
  }
661
689
  finally {
662
690
  // eslint-disable-next-line no-unsafe-finally
@@ -664,7 +692,11 @@ function traceable(wrappedFunc, config) {
664
692
  }
665
693
  }, async (error) => {
666
694
  await currentRunTree?.end(undefined, String(error));
667
- await handleEnd();
695
+ await handleEnd({
696
+ runTree: currentRunTree,
697
+ postRunPromise,
698
+ on_end: config?.on_end,
699
+ });
668
700
  throw error;
669
701
  })
670
702
  .then(resolve, reject);
@@ -39,7 +39,7 @@ export type TraceableConfig<Func extends (...args: any[]) => any> = Partial<Omit
39
39
  * @param outputs Key-value map of the function outputs
40
40
  * @returns Transformed key-value map
41
41
  */
42
- processOutputs?: (outputs: Readonly<KVMap>) => KVMap;
42
+ processOutputs?: (outputs: Readonly<KVMap>) => KVMap | Promise<KVMap>;
43
43
  };
44
44
  /**
45
45
  * Higher-order function that takes function as input and returns a
package/dist/traceable.js CHANGED
@@ -96,7 +96,7 @@ const handleRunInputs = (inputs, processInputs) => {
96
96
  const _extractUsage = (runData) => {
97
97
  const usageMetadataFromMetadata = (runData.runTree.extra.metadata ?? {})
98
98
  .usage_metadata;
99
- return runData.outputs.usage_metadata ?? usageMetadataFromMetadata;
99
+ return runData.outputs?.usage_metadata ?? usageMetadataFromMetadata;
100
100
  };
101
101
  function validateExtractedUsageMetadata(data) {
102
102
  const allowedKeys = new Set([
@@ -117,26 +117,25 @@ function validateExtractedUsageMetadata(data) {
117
117
  }
118
118
  return data;
119
119
  }
120
- // Note: This mutates the run tree
121
- function handleRunOutputs(params) {
122
- const { runTree, rawOutputs, processOutputsFn } = params;
123
- let outputs;
124
- if (isKVMap(rawOutputs)) {
125
- outputs = { ...rawOutputs };
126
- }
127
- else {
128
- outputs = { outputs: rawOutputs };
129
- }
130
- try {
131
- outputs = processOutputsFn(outputs);
132
- }
133
- catch (e) {
134
- console.error("Error occurred during processOutputs. Sending unprocessed outputs:", e);
120
+ async function handleEnd(params) {
121
+ const { runTree, on_end, postRunPromise } = params;
122
+ const onEnd = on_end;
123
+ if (onEnd) {
124
+ if (!runTree) {
125
+ console.warn("Can not call 'on_end' if currentRunTree is undefined");
126
+ }
127
+ else {
128
+ onEnd(runTree);
129
+ }
135
130
  }
131
+ await postRunPromise;
132
+ await runTree?.patchRun();
133
+ }
134
+ const _populateUsageMetadata = (processedOutputs, runTree) => {
136
135
  if (runTree !== undefined) {
137
136
  let usageMetadata;
138
137
  try {
139
- usageMetadata = _extractUsage({ runTree, outputs });
138
+ usageMetadata = _extractUsage({ runTree, outputs: processedOutputs });
140
139
  }
141
140
  catch (e) {
142
141
  console.error("Error occurred while extracting usage metadata:", e);
@@ -146,10 +145,52 @@ function handleRunOutputs(params) {
146
145
  ...runTree.extra.metadata,
147
146
  usage_metadata: validateExtractedUsageMetadata(usageMetadata),
148
147
  };
149
- outputs.usage_metadata = usageMetadata;
148
+ processedOutputs.usage_metadata = usageMetadata;
149
+ }
150
+ }
151
+ };
152
+ function isAsyncFn(fn) {
153
+ return (fn != null &&
154
+ typeof fn === "function" &&
155
+ fn.constructor.name === "AsyncFunction");
156
+ }
157
+ // Note: This mutates the run tree
158
+ async function handleRunOutputs(params) {
159
+ const { runTree, rawOutputs, processOutputsFn, on_end, postRunPromise } = params;
160
+ let outputs;
161
+ if (isKVMap(rawOutputs)) {
162
+ outputs = { ...rawOutputs };
163
+ }
164
+ else {
165
+ outputs = { outputs: rawOutputs };
166
+ }
167
+ try {
168
+ outputs = processOutputsFn(outputs);
169
+ // TODO: Investigate making this behavior for all returned promises
170
+ // on next minor bump.
171
+ if (isAsyncFn(processOutputsFn)) {
172
+ void outputs
173
+ .then(async (processedOutputs) => {
174
+ _populateUsageMetadata(processedOutputs, runTree);
175
+ await runTree?.end(processedOutputs);
176
+ })
177
+ .catch(async (e) => {
178
+ console.error("Error occurred during processOutputs. Sending unprocessed outputs:", e);
179
+ await runTree?.end(outputs);
180
+ })
181
+ .finally(async () => {
182
+ await handleEnd({ runTree, postRunPromise, on_end });
183
+ });
184
+ return;
150
185
  }
151
186
  }
152
- return outputs;
187
+ catch (e) {
188
+ console.error("Error occurred during processOutputs. Sending unprocessed outputs:", e);
189
+ }
190
+ _populateUsageMetadata(outputs, runTree);
191
+ await runTree?.end(outputs);
192
+ await handleEnd({ runTree, postRunPromise, on_end });
193
+ return;
153
194
  }
154
195
  const handleRunAttachments = (rawInputs, extractAttachments) => {
155
196
  if (!extractAttachments) {
@@ -469,13 +510,13 @@ export function traceable(wrappedFunc, config) {
469
510
  : otel_context.with(capturedOtelContext, () => reader.read()));
470
511
  if (result.done) {
471
512
  finished = true;
472
- const processedOutputs = handleRunOutputs({
513
+ await handleRunOutputs({
473
514
  runTree: currentRunTree,
474
515
  rawOutputs: await handleChunks(chunks),
475
516
  processOutputsFn,
517
+ on_end: config?.on_end,
518
+ postRunPromise,
476
519
  });
477
- await currentRunTree?.end(processedOutputs);
478
- await handleEnd();
479
520
  controller.close();
480
521
  break;
481
522
  }
@@ -493,13 +534,13 @@ export function traceable(wrappedFunc, config) {
493
534
  async cancel(reason) {
494
535
  if (!finished)
495
536
  await currentRunTree?.end(undefined, "Cancelled");
496
- const processedOutputs = handleRunOutputs({
537
+ await handleRunOutputs({
497
538
  runTree: currentRunTree,
498
539
  rawOutputs: await handleChunks(chunks),
499
540
  processOutputsFn,
541
+ on_end: config?.on_end,
542
+ postRunPromise,
500
543
  });
501
- await currentRunTree?.end(processedOutputs);
502
- await handleEnd();
503
544
  return reader.cancel(reason);
504
545
  },
505
546
  });
@@ -536,13 +577,13 @@ export function traceable(wrappedFunc, config) {
536
577
  finally {
537
578
  if (!finished)
538
579
  await currentRunTree?.end(undefined, "Cancelled");
539
- const processedOutputs = handleRunOutputs({
580
+ await handleRunOutputs({
540
581
  runTree: currentRunTree,
541
582
  rawOutputs: await handleChunks(chunks),
542
583
  processOutputsFn,
584
+ on_end: config?.on_end,
585
+ postRunPromise,
543
586
  });
544
- await currentRunTree?.end(processedOutputs);
545
- await handleEnd();
546
587
  }
547
588
  }
548
589
  function wrapAsyncGeneratorForTracing(iterable, snapshot) {
@@ -554,19 +595,6 @@ export function traceable(wrappedFunc, config) {
554
595
  iterable[Symbol.asyncIterator] = () => wrappedIterator;
555
596
  return iterable;
556
597
  }
557
- async function handleEnd() {
558
- const onEnd = config?.on_end;
559
- if (onEnd) {
560
- if (!currentRunTree) {
561
- console.warn("Can not call 'on_end' if currentRunTree is undefined");
562
- }
563
- else {
564
- onEnd(currentRunTree);
565
- }
566
- }
567
- await postRunPromise;
568
- await currentRunTree?.patchRun();
569
- }
570
598
  function gatherAll(iterator) {
571
599
  const chunks = [];
572
600
  // eslint-disable-next-line no-constant-condition
@@ -621,7 +649,7 @@ export function traceable(wrappedFunc, config) {
621
649
  if (isGenerator(wrappedFunc) && isIteratorLike(rawOutput)) {
622
650
  const chunks = gatherAll(rawOutput);
623
651
  try {
624
- const processedOutputs = handleRunOutputs({
652
+ await handleRunOutputs({
625
653
  runTree: currentRunTree,
626
654
  rawOutputs: await handleChunks(chunks.reduce((memo, { value, done }) => {
627
655
  if (!done || typeof value !== "undefined") {
@@ -630,12 +658,12 @@ export function traceable(wrappedFunc, config) {
630
658
  return memo;
631
659
  }, [])),
632
660
  processOutputsFn,
661
+ on_end: config?.on_end,
662
+ postRunPromise,
633
663
  });
634
- await currentRunTree?.end(processedOutputs);
635
- await handleEnd();
636
664
  }
637
665
  catch (e) {
638
- console.error("Error occurred during handleEnd:", e);
666
+ console.error("[LANGSMITH]: Error occurred while handling run outputs:", e);
639
667
  }
640
668
  return (function* () {
641
669
  for (const ret of chunks) {
@@ -646,13 +674,13 @@ export function traceable(wrappedFunc, config) {
646
674
  })();
647
675
  }
648
676
  try {
649
- const processedOutputs = handleRunOutputs({
677
+ await handleRunOutputs({
650
678
  runTree: currentRunTree,
651
679
  rawOutputs: rawOutput,
652
680
  processOutputsFn,
681
+ on_end: config?.on_end,
682
+ postRunPromise,
653
683
  });
654
- await currentRunTree?.end(processedOutputs);
655
- await handleEnd();
656
684
  }
657
685
  finally {
658
686
  // eslint-disable-next-line no-unsafe-finally
@@ -660,7 +688,11 @@ export function traceable(wrappedFunc, config) {
660
688
  }
661
689
  }, async (error) => {
662
690
  await currentRunTree?.end(undefined, String(error));
663
- await handleEnd();
691
+ await handleEnd({
692
+ runTree: currentRunTree,
693
+ postRunPromise,
694
+ on_end: config?.on_end,
695
+ });
664
696
  throw error;
665
697
  })
666
698
  .then(resolve, reject);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.57",
3
+ "version": "0.3.59",
4
4
  "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
5
5
  "packageManager": "yarn@1.22.19",
6
6
  "files": [