langsmith 0.3.4-rc.0 → 0.3.5

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.
package/dist/client.cjs CHANGED
@@ -127,7 +127,7 @@ class AutoBatchQueue {
127
127
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
128
128
  itemPromiseResolve = resolve;
129
129
  });
130
- const size = (0, index_js_2.stringify)(item.item).length;
130
+ const size = (0, index_js_2.serialize)(item.item).length;
131
131
  this.items.push({
132
132
  action: item.action,
133
133
  payload: item.item,
@@ -371,6 +371,10 @@ class Client {
371
371
  this.webUrl = "http://localhost:3000";
372
372
  return this.webUrl;
373
373
  }
374
+ else if (this.apiUrl.endsWith("/api/v1")) {
375
+ this.webUrl = this.apiUrl.replace("/api/v1", "");
376
+ return this.webUrl;
377
+ }
374
378
  else if (this.apiUrl.includes("/api") &&
375
379
  !this.apiUrl.split(".", 1)[0].endsWith("api")) {
376
380
  this.webUrl = this.apiUrl.replace("/api", "");
@@ -384,6 +388,10 @@ class Client {
384
388
  this.webUrl = "https://eu.smith.langchain.com";
385
389
  return this.webUrl;
386
390
  }
391
+ else if (this.apiUrl.split(".", 1)[0].includes("beta")) {
392
+ this.webUrl = "https://beta.smith.langchain.com";
393
+ return this.webUrl;
394
+ }
387
395
  else {
388
396
  this.webUrl = "https://smith.langchain.com";
389
397
  return this.webUrl;
@@ -675,7 +683,7 @@ class Client {
675
683
  const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/runs`, {
676
684
  method: "POST",
677
685
  headers,
678
- body: (0, index_js_2.stringify)(mergedRunCreateParam),
686
+ body: (0, index_js_2.serialize)(mergedRunCreateParam),
679
687
  signal: AbortSignal.timeout(this.timeout_ms),
680
688
  ...this.fetchOptions,
681
689
  });
@@ -735,7 +743,7 @@ class Client {
735
743
  }
736
744
  }
737
745
  if (batchChunks.post.length > 0 || batchChunks.patch.length > 0) {
738
- await this._postBatchIngestRuns((0, index_js_2.stringify)(batchChunks));
746
+ await this._postBatchIngestRuns((0, index_js_2.serialize)(batchChunks));
739
747
  }
740
748
  }
741
749
  async _postBatchIngestRuns(body) {
@@ -830,7 +838,7 @@ class Client {
830
838
  const { inputs, outputs, events, attachments, ...payload } = originalPayload;
831
839
  const fields = { inputs, outputs, events };
832
840
  // encode the main run payload
833
- const stringifiedPayload = (0, index_js_2.stringify)(payload);
841
+ const stringifiedPayload = (0, index_js_2.serialize)(payload);
834
842
  accumulatedParts.push({
835
843
  name: `${method}.${payload.id}`,
836
844
  payload: new Blob([stringifiedPayload], {
@@ -842,7 +850,7 @@ class Client {
842
850
  if (value === undefined) {
843
851
  continue;
844
852
  }
845
- const stringifiedValue = (0, index_js_2.stringify)(value);
853
+ const stringifiedValue = (0, index_js_2.serialize)(value);
846
854
  accumulatedParts.push({
847
855
  name: `${method}.${payload.id}.${key}`,
848
856
  payload: new Blob([stringifiedValue], {
@@ -907,7 +915,7 @@ class Client {
907
915
  const body = new Blob(chunks);
908
916
  // Convert Blob to ArrayBuffer for compatibility
909
917
  const arrayBuffer = await body.arrayBuffer();
910
- const res = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/v1/runs/multipart`, {
918
+ const res = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/runs/multipart`, {
911
919
  method: "POST",
912
920
  headers: {
913
921
  ...this.headers,
@@ -958,7 +966,7 @@ class Client {
958
966
  const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/runs/${runId}`, {
959
967
  method: "PATCH",
960
968
  headers,
961
- body: (0, index_js_2.stringify)(run),
969
+ body: (0, index_js_2.serialize)(run),
962
970
  signal: AbortSignal.timeout(this.timeout_ms),
963
971
  ...this.fetchOptions,
964
972
  });
@@ -2845,14 +2853,14 @@ class Client {
2845
2853
  ...(example.split && { split: example.split }),
2846
2854
  };
2847
2855
  // Add main example data
2848
- const stringifiedExample = (0, index_js_2.stringify)(exampleBody);
2856
+ const stringifiedExample = (0, index_js_2.serialize)(exampleBody);
2849
2857
  const exampleBlob = new Blob([stringifiedExample], {
2850
2858
  type: "application/json",
2851
2859
  });
2852
2860
  formData.append(exampleId, exampleBlob);
2853
2861
  // Add inputs
2854
2862
  if (example.inputs) {
2855
- const stringifiedInputs = (0, index_js_2.stringify)(example.inputs);
2863
+ const stringifiedInputs = (0, index_js_2.serialize)(example.inputs);
2856
2864
  const inputsBlob = new Blob([stringifiedInputs], {
2857
2865
  type: "application/json",
2858
2866
  });
@@ -2860,7 +2868,7 @@ class Client {
2860
2868
  }
2861
2869
  // Add outputs if present
2862
2870
  if (example.outputs) {
2863
- const stringifiedOutputs = (0, index_js_2.stringify)(example.outputs);
2871
+ const stringifiedOutputs = (0, index_js_2.serialize)(example.outputs);
2864
2872
  const outputsBlob = new Blob([stringifiedOutputs], {
2865
2873
  type: "application/json",
2866
2874
  });
@@ -2885,7 +2893,7 @@ class Client {
2885
2893
  }
2886
2894
  }
2887
2895
  if (example.attachments_operations) {
2888
- const stringifiedAttachmentsOperations = (0, index_js_2.stringify)(example.attachments_operations);
2896
+ const stringifiedAttachmentsOperations = (0, index_js_2.serialize)(example.attachments_operations);
2889
2897
  const attachmentsOperationsBlob = new Blob([stringifiedAttachmentsOperations], {
2890
2898
  type: "application/json",
2891
2899
  });
@@ -2919,20 +2927,20 @@ class Client {
2919
2927
  ...(example.split && { split: example.split }),
2920
2928
  };
2921
2929
  // Add main example data
2922
- const stringifiedExample = (0, index_js_2.stringify)(exampleBody);
2930
+ const stringifiedExample = (0, index_js_2.serialize)(exampleBody);
2923
2931
  const exampleBlob = new Blob([stringifiedExample], {
2924
2932
  type: "application/json",
2925
2933
  });
2926
2934
  formData.append(exampleId, exampleBlob);
2927
2935
  // Add inputs
2928
- const stringifiedInputs = (0, index_js_2.stringify)(example.inputs);
2936
+ const stringifiedInputs = (0, index_js_2.serialize)(example.inputs);
2929
2937
  const inputsBlob = new Blob([stringifiedInputs], {
2930
2938
  type: "application/json",
2931
2939
  });
2932
2940
  formData.append(`${exampleId}.inputs`, inputsBlob);
2933
2941
  // Add outputs if present
2934
2942
  if (example.outputs) {
2935
- const stringifiedOutputs = (0, index_js_2.stringify)(example.outputs);
2943
+ const stringifiedOutputs = (0, index_js_2.serialize)(example.outputs);
2936
2944
  const outputsBlob = new Blob([stringifiedOutputs], {
2937
2945
  type: "application/json",
2938
2946
  });
package/dist/client.js CHANGED
@@ -8,7 +8,7 @@ import { warnOnce } from "./utils/warn.js";
8
8
  import { parsePromptIdentifier } from "./utils/prompts.js";
9
9
  import { raiseForStatus } from "./utils/error.js";
10
10
  import { _getFetchImplementation } from "./singletons/fetch.js";
11
- import { stringify as stringifyForTracing } from "./utils/fast-safe-stringify/index.js";
11
+ import { serialize as serializePayloadForTracing } from "./utils/fast-safe-stringify/index.js";
12
12
  export function mergeRuntimeEnvIntoRunCreate(run) {
13
13
  const runtimeEnv = getRuntimeEnvironment();
14
14
  const envVars = getLangChainEnvVarsMetadata();
@@ -100,7 +100,7 @@ export class AutoBatchQueue {
100
100
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
101
101
  itemPromiseResolve = resolve;
102
102
  });
103
- const size = stringifyForTracing(item.item).length;
103
+ const size = serializePayloadForTracing(item.item).length;
104
104
  this.items.push({
105
105
  action: item.action,
106
106
  payload: item.item,
@@ -343,6 +343,10 @@ export class Client {
343
343
  this.webUrl = "http://localhost:3000";
344
344
  return this.webUrl;
345
345
  }
346
+ else if (this.apiUrl.endsWith("/api/v1")) {
347
+ this.webUrl = this.apiUrl.replace("/api/v1", "");
348
+ return this.webUrl;
349
+ }
346
350
  else if (this.apiUrl.includes("/api") &&
347
351
  !this.apiUrl.split(".", 1)[0].endsWith("api")) {
348
352
  this.webUrl = this.apiUrl.replace("/api", "");
@@ -356,6 +360,10 @@ export class Client {
356
360
  this.webUrl = "https://eu.smith.langchain.com";
357
361
  return this.webUrl;
358
362
  }
363
+ else if (this.apiUrl.split(".", 1)[0].includes("beta")) {
364
+ this.webUrl = "https://beta.smith.langchain.com";
365
+ return this.webUrl;
366
+ }
359
367
  else {
360
368
  this.webUrl = "https://smith.langchain.com";
361
369
  return this.webUrl;
@@ -647,7 +655,7 @@ export class Client {
647
655
  const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs`, {
648
656
  method: "POST",
649
657
  headers,
650
- body: stringifyForTracing(mergedRunCreateParam),
658
+ body: serializePayloadForTracing(mergedRunCreateParam),
651
659
  signal: AbortSignal.timeout(this.timeout_ms),
652
660
  ...this.fetchOptions,
653
661
  });
@@ -707,7 +715,7 @@ export class Client {
707
715
  }
708
716
  }
709
717
  if (batchChunks.post.length > 0 || batchChunks.patch.length > 0) {
710
- await this._postBatchIngestRuns(stringifyForTracing(batchChunks));
718
+ await this._postBatchIngestRuns(serializePayloadForTracing(batchChunks));
711
719
  }
712
720
  }
713
721
  async _postBatchIngestRuns(body) {
@@ -802,7 +810,7 @@ export class Client {
802
810
  const { inputs, outputs, events, attachments, ...payload } = originalPayload;
803
811
  const fields = { inputs, outputs, events };
804
812
  // encode the main run payload
805
- const stringifiedPayload = stringifyForTracing(payload);
813
+ const stringifiedPayload = serializePayloadForTracing(payload);
806
814
  accumulatedParts.push({
807
815
  name: `${method}.${payload.id}`,
808
816
  payload: new Blob([stringifiedPayload], {
@@ -814,7 +822,7 @@ export class Client {
814
822
  if (value === undefined) {
815
823
  continue;
816
824
  }
817
- const stringifiedValue = stringifyForTracing(value);
825
+ const stringifiedValue = serializePayloadForTracing(value);
818
826
  accumulatedParts.push({
819
827
  name: `${method}.${payload.id}.${key}`,
820
828
  payload: new Blob([stringifiedValue], {
@@ -879,7 +887,7 @@ export class Client {
879
887
  const body = new Blob(chunks);
880
888
  // Convert Blob to ArrayBuffer for compatibility
881
889
  const arrayBuffer = await body.arrayBuffer();
882
- const res = await this.batchIngestCaller.call(_getFetchImplementation(), `${this.apiUrl}/v1/runs/multipart`, {
890
+ const res = await this.batchIngestCaller.call(_getFetchImplementation(), `${this.apiUrl}/runs/multipart`, {
883
891
  method: "POST",
884
892
  headers: {
885
893
  ...this.headers,
@@ -930,7 +938,7 @@ export class Client {
930
938
  const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs/${runId}`, {
931
939
  method: "PATCH",
932
940
  headers,
933
- body: stringifyForTracing(run),
941
+ body: serializePayloadForTracing(run),
934
942
  signal: AbortSignal.timeout(this.timeout_ms),
935
943
  ...this.fetchOptions,
936
944
  });
@@ -2817,14 +2825,14 @@ export class Client {
2817
2825
  ...(example.split && { split: example.split }),
2818
2826
  };
2819
2827
  // Add main example data
2820
- const stringifiedExample = stringifyForTracing(exampleBody);
2828
+ const stringifiedExample = serializePayloadForTracing(exampleBody);
2821
2829
  const exampleBlob = new Blob([stringifiedExample], {
2822
2830
  type: "application/json",
2823
2831
  });
2824
2832
  formData.append(exampleId, exampleBlob);
2825
2833
  // Add inputs
2826
2834
  if (example.inputs) {
2827
- const stringifiedInputs = stringifyForTracing(example.inputs);
2835
+ const stringifiedInputs = serializePayloadForTracing(example.inputs);
2828
2836
  const inputsBlob = new Blob([stringifiedInputs], {
2829
2837
  type: "application/json",
2830
2838
  });
@@ -2832,7 +2840,7 @@ export class Client {
2832
2840
  }
2833
2841
  // Add outputs if present
2834
2842
  if (example.outputs) {
2835
- const stringifiedOutputs = stringifyForTracing(example.outputs);
2843
+ const stringifiedOutputs = serializePayloadForTracing(example.outputs);
2836
2844
  const outputsBlob = new Blob([stringifiedOutputs], {
2837
2845
  type: "application/json",
2838
2846
  });
@@ -2857,7 +2865,7 @@ export class Client {
2857
2865
  }
2858
2866
  }
2859
2867
  if (example.attachments_operations) {
2860
- const stringifiedAttachmentsOperations = stringifyForTracing(example.attachments_operations);
2868
+ const stringifiedAttachmentsOperations = serializePayloadForTracing(example.attachments_operations);
2861
2869
  const attachmentsOperationsBlob = new Blob([stringifiedAttachmentsOperations], {
2862
2870
  type: "application/json",
2863
2871
  });
@@ -2891,20 +2899,20 @@ export class Client {
2891
2899
  ...(example.split && { split: example.split }),
2892
2900
  };
2893
2901
  // Add main example data
2894
- const stringifiedExample = stringifyForTracing(exampleBody);
2902
+ const stringifiedExample = serializePayloadForTracing(exampleBody);
2895
2903
  const exampleBlob = new Blob([stringifiedExample], {
2896
2904
  type: "application/json",
2897
2905
  });
2898
2906
  formData.append(exampleId, exampleBlob);
2899
2907
  // Add inputs
2900
- const stringifiedInputs = stringifyForTracing(example.inputs);
2908
+ const stringifiedInputs = serializePayloadForTracing(example.inputs);
2901
2909
  const inputsBlob = new Blob([stringifiedInputs], {
2902
2910
  type: "application/json",
2903
2911
  });
2904
2912
  formData.append(`${exampleId}.inputs`, inputsBlob);
2905
2913
  // Add outputs if present
2906
2914
  if (example.outputs) {
2907
- const stringifiedOutputs = stringifyForTracing(example.outputs);
2915
+ const stringifiedOutputs = serializePayloadForTracing(example.outputs);
2908
2916
  const outputsBlob = new Blob([stringifiedOutputs], {
2909
2917
  type: "application/json",
2910
2918
  });
@@ -574,7 +574,6 @@ class _ExperimentManager {
574
574
  projectMetadata["revision_id"] = await (0, _git_js_1.getDefaultRevisionId)();
575
575
  }
576
576
  await this.client.updateProject(experiment.id, {
577
- endTime: new Date().toISOString(),
578
577
  metadata: projectMetadata,
579
578
  });
580
579
  }
@@ -570,7 +570,6 @@ export class _ExperimentManager {
570
570
  projectMetadata["revision_id"] = await getDefaultRevisionId();
571
571
  }
572
572
  await this.client.updateProject(experiment.id, {
573
- endTime: new Date().toISOString(),
574
573
  metadata: projectMetadata,
575
574
  });
576
575
  }
package/dist/index.cjs CHANGED
@@ -8,4 +8,4 @@ Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () {
8
8
  var fetch_js_1 = require("./singletons/fetch.cjs");
9
9
  Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true, get: function () { return fetch_js_1.overrideFetchImplementation; } });
10
10
  // Update using yarn bump-version
11
- exports.__version__ = "0.3.4-rc.0";
11
+ exports.__version__ = "0.3.5";
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { Client, type ClientConfig, type LangSmithTracingClientInterface, } from
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, RetrieverOutput, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
4
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
- export declare const __version__ = "0.3.4-rc.0";
5
+ export declare const __version__ = "0.3.5";
package/dist/index.js CHANGED
@@ -2,4 +2,4 @@ export { Client, } from "./client.js";
2
2
  export { RunTree } from "./run_trees.js";
3
3
  export { overrideFetchImplementation } from "./singletons/fetch.js";
4
4
  // Update using yarn bump-version
5
- export const __version__ = "0.3.4-rc.0";
5
+ export const __version__ = "0.3.5";
@@ -5,6 +5,9 @@ const reporters_1 = require("@jest/reporters");
5
5
  const reporter_js_1 = require("../utils/jestlike/reporter.cjs");
6
6
  class LangSmithEvalReporter extends reporters_1.DefaultReporter {
7
7
  async onTestResult(test, testResult, aggregatedResults) {
8
+ if (testResult.failureMessage) {
9
+ console.log(testResult.failureMessage);
10
+ }
8
11
  const groupedTestResults = testResult.testResults.reduce((groups, testResult) => {
9
12
  const ancestorTitle = testResult.ancestorTitles.join(" > ");
10
13
  if (groups[ancestorTitle] === undefined) {
@@ -16,7 +19,13 @@ class LangSmithEvalReporter extends reporters_1.DefaultReporter {
16
19
  try {
17
20
  for (const testGroupName of Object.keys(groupedTestResults)) {
18
21
  const resultGroup = groupedTestResults[testGroupName];
19
- await (0, reporter_js_1.printReporterTable)(resultGroup, testResult.failureMessage);
22
+ const unskippedTests = resultGroup.filter((result) => result.status !== "pending");
23
+ const overallResult = unskippedTests.length === 0
24
+ ? "skip"
25
+ : unskippedTests.every((result) => result.status === "passed")
26
+ ? "pass"
27
+ : "fail";
28
+ await (0, reporter_js_1.printReporterTable)(testGroupName, resultGroup, overallResult);
20
29
  }
21
30
  }
22
31
  catch (e) {
@@ -3,6 +3,9 @@ import { DefaultReporter } from "@jest/reporters";
3
3
  import { printReporterTable } from "../utils/jestlike/reporter.js";
4
4
  class LangSmithEvalReporter extends DefaultReporter {
5
5
  async onTestResult(test, testResult, aggregatedResults) {
6
+ if (testResult.failureMessage) {
7
+ console.log(testResult.failureMessage);
8
+ }
6
9
  const groupedTestResults = testResult.testResults.reduce((groups, testResult) => {
7
10
  const ancestorTitle = testResult.ancestorTitles.join(" > ");
8
11
  if (groups[ancestorTitle] === undefined) {
@@ -14,7 +17,13 @@ class LangSmithEvalReporter extends DefaultReporter {
14
17
  try {
15
18
  for (const testGroupName of Object.keys(groupedTestResults)) {
16
19
  const resultGroup = groupedTestResults[testGroupName];
17
- await printReporterTable(resultGroup, testResult.failureMessage);
20
+ const unskippedTests = resultGroup.filter((result) => result.status !== "pending");
21
+ const overallResult = unskippedTests.length === 0
22
+ ? "skip"
23
+ : unskippedTests.every((result) => result.status === "passed")
24
+ ? "pass"
25
+ : "fail";
26
+ await printReporterTable(testGroupName, resultGroup, overallResult);
18
27
  }
19
28
  }
20
29
  catch (e) {
@@ -1,35 +1,40 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stringify = void 0;
3
+ exports.serialize = void 0;
4
4
  /* eslint-disable */
5
5
  // @ts-nocheck
6
6
  var LIMIT_REPLACE_NODE = "[...]";
7
7
  var CIRCULAR_REPLACE_NODE = { result: "[Circular]" };
8
8
  var arr = [];
9
9
  var replacerStack = [];
10
+ const encoder = new TextEncoder();
10
11
  function defaultOptions() {
11
12
  return {
12
13
  depthLimit: Number.MAX_SAFE_INTEGER,
13
14
  edgesLimit: Number.MAX_SAFE_INTEGER,
14
15
  };
15
16
  }
17
+ function encodeString(str) {
18
+ return encoder.encode(str);
19
+ }
16
20
  // Regular stringify
17
- function stringify(obj, replacer, spacer, options) {
21
+ function serialize(obj, replacer, spacer, options) {
18
22
  try {
19
- return JSON.stringify(obj, replacer, spacer);
23
+ const str = JSON.stringify(obj, replacer, spacer);
24
+ return encodeString(str);
20
25
  }
21
26
  catch (e) {
22
27
  // Fall back to more complex stringify if circular reference
23
28
  if (!e.message?.includes("Converting circular structure to JSON")) {
24
29
  console.warn("[WARNING]: LangSmith received unserializable value.");
25
- return "[Unserializable]";
30
+ return encodeString("[Unserializable]");
26
31
  }
27
32
  console.warn("[WARNING]: LangSmith received circular JSON. This will decrease tracer performance.");
28
33
  if (typeof options === "undefined") {
29
34
  options = defaultOptions();
30
35
  }
31
36
  decirc(obj, "", 0, [], undefined, 0, options);
32
- var res;
37
+ let res;
33
38
  try {
34
39
  if (replacerStack.length === 0) {
35
40
  res = JSON.stringify(obj, replacer, spacer);
@@ -39,11 +44,11 @@ function stringify(obj, replacer, spacer, options) {
39
44
  }
40
45
  }
41
46
  catch (_) {
42
- return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]");
47
+ return encodeString("[unable to serialize, circular reference is too complex to analyze]");
43
48
  }
44
49
  finally {
45
50
  while (arr.length !== 0) {
46
- var part = arr.pop();
51
+ const part = arr.pop();
47
52
  if (part.length === 4) {
48
53
  Object.defineProperty(part[0], part[1], part[3]);
49
54
  }
@@ -52,10 +57,10 @@ function stringify(obj, replacer, spacer, options) {
52
57
  }
53
58
  }
54
59
  }
55
- return res;
60
+ return encodeString(res);
56
61
  }
57
62
  }
58
- exports.stringify = stringify;
63
+ exports.serialize = serialize;
59
64
  function setReplace(replace, val, k, parent) {
60
65
  var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k);
61
66
  if (propertyDescriptor.get !== undefined) {
@@ -1 +1 @@
1
- export declare function stringify(obj: any, replacer?: any, spacer?: any, options?: any): string;
1
+ export declare function serialize(obj: any, replacer?: any, spacer?: any, options?: any): Uint8Array;
@@ -4,29 +4,34 @@ var LIMIT_REPLACE_NODE = "[...]";
4
4
  var CIRCULAR_REPLACE_NODE = { result: "[Circular]" };
5
5
  var arr = [];
6
6
  var replacerStack = [];
7
+ const encoder = new TextEncoder();
7
8
  function defaultOptions() {
8
9
  return {
9
10
  depthLimit: Number.MAX_SAFE_INTEGER,
10
11
  edgesLimit: Number.MAX_SAFE_INTEGER,
11
12
  };
12
13
  }
14
+ function encodeString(str) {
15
+ return encoder.encode(str);
16
+ }
13
17
  // Regular stringify
14
- export function stringify(obj, replacer, spacer, options) {
18
+ export function serialize(obj, replacer, spacer, options) {
15
19
  try {
16
- return JSON.stringify(obj, replacer, spacer);
20
+ const str = JSON.stringify(obj, replacer, spacer);
21
+ return encodeString(str);
17
22
  }
18
23
  catch (e) {
19
24
  // Fall back to more complex stringify if circular reference
20
25
  if (!e.message?.includes("Converting circular structure to JSON")) {
21
26
  console.warn("[WARNING]: LangSmith received unserializable value.");
22
- return "[Unserializable]";
27
+ return encodeString("[Unserializable]");
23
28
  }
24
29
  console.warn("[WARNING]: LangSmith received circular JSON. This will decrease tracer performance.");
25
30
  if (typeof options === "undefined") {
26
31
  options = defaultOptions();
27
32
  }
28
33
  decirc(obj, "", 0, [], undefined, 0, options);
29
- var res;
34
+ let res;
30
35
  try {
31
36
  if (replacerStack.length === 0) {
32
37
  res = JSON.stringify(obj, replacer, spacer);
@@ -36,11 +41,11 @@ export function stringify(obj, replacer, spacer, options) {
36
41
  }
37
42
  }
38
43
  catch (_) {
39
- return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]");
44
+ return encodeString("[unable to serialize, circular reference is too complex to analyze]");
40
45
  }
41
46
  finally {
42
47
  while (arr.length !== 0) {
43
- var part = arr.pop();
48
+ const part = arr.pop();
44
49
  if (part.length === 4) {
45
50
  Object.defineProperty(part[0], part[1], part[3]);
46
51
  }
@@ -49,7 +54,7 @@ export function stringify(obj, replacer, spacer, options) {
49
54
  }
50
55
  }
51
56
  }
52
- return res;
57
+ return encodeString(res);
53
58
  }
54
59
  }
55
60
  function setReplace(replace, val, k, parent) {
@@ -53,13 +53,13 @@ function formatTestName(name, duration) {
53
53
  }
54
54
  function getFormattedStatus(status) {
55
55
  const s = status.toLowerCase();
56
- if (s === "pending") {
56
+ if (s === "pending" || s === "skipped") {
57
57
  return chalk_1.default.yellow("○ Skipped");
58
58
  }
59
- else if (s === "passed") {
59
+ else if (s.includes("pass")) {
60
60
  return chalk_1.default.green("✓ Passed");
61
61
  }
62
- else if (s === "failed") {
62
+ else if (s.includes("fail")) {
63
63
  return chalk_1.default.red("✕ Failed");
64
64
  }
65
65
  else {
@@ -68,13 +68,13 @@ function getFormattedStatus(status) {
68
68
  }
69
69
  function getColorParam(status) {
70
70
  const s = status.toLowerCase();
71
- if (s === "pending") {
71
+ if (s === "pending" || s === "skipped") {
72
72
  return { color: "yellow" };
73
73
  }
74
- else if (s === "passed") {
74
+ else if (s.includes("pass")) {
75
75
  return { color: "grey" };
76
76
  }
77
- else if (s === "failed") {
77
+ else if (s.includes("fail")) {
78
78
  return { color: "red" };
79
79
  }
80
80
  else {
@@ -99,7 +99,7 @@ function formatValue(value) {
99
99
  }
100
100
  return String(value);
101
101
  }
102
- async function printReporterTable(results, failureMessage) {
102
+ async function printReporterTable(testSuiteName, results, testStatus, failureMessage) {
103
103
  const rows = [];
104
104
  const feedbackKeys = new Set();
105
105
  let experimentUrl;
@@ -122,7 +122,7 @@ async function printReporterTable(results, failureMessage) {
122
122
  getColorParam(status),
123
123
  ]);
124
124
  }
125
- else if (status === "pending") {
125
+ else if (status === "pending" || status === "skipped") {
126
126
  // Skipped
127
127
  rows.push([
128
128
  {
@@ -265,6 +265,14 @@ async function printReporterTable(results, failureMessage) {
265
265
  for (const row of rows) {
266
266
  table.addRow(row[0], row[1]);
267
267
  }
268
+ const testStatusColor = testStatus.includes("pass")
269
+ ? chalk_1.default.green
270
+ : testStatus.includes("fail")
271
+ ? chalk_1.default.red
272
+ : chalk_1.default.yellow;
273
+ if (testSuiteName) {
274
+ console.log(testStatusColor(`› ${testSuiteName}`));
275
+ }
268
276
  if (failureMessage) {
269
277
  console.log(failureMessage);
270
278
  }
@@ -1,5 +1,5 @@
1
- export declare function printReporterTable(results: {
1
+ export declare function printReporterTable(testSuiteName: string, results: {
2
2
  title: string;
3
3
  duration: number;
4
- status: string;
5
- }[], failureMessage?: string): Promise<void>;
4
+ status: "pass" | "passed" | "fail" | "failed" | "pending" | "skipped";
5
+ }[], testStatus: "pass" | "skip" | "fail", failureMessage?: string): Promise<void>;
@@ -24,13 +24,13 @@ function formatTestName(name, duration) {
24
24
  }
25
25
  function getFormattedStatus(status) {
26
26
  const s = status.toLowerCase();
27
- if (s === "pending") {
27
+ if (s === "pending" || s === "skipped") {
28
28
  return chalk.yellow("○ Skipped");
29
29
  }
30
- else if (s === "passed") {
30
+ else if (s.includes("pass")) {
31
31
  return chalk.green("✓ Passed");
32
32
  }
33
- else if (s === "failed") {
33
+ else if (s.includes("fail")) {
34
34
  return chalk.red("✕ Failed");
35
35
  }
36
36
  else {
@@ -39,13 +39,13 @@ function getFormattedStatus(status) {
39
39
  }
40
40
  function getColorParam(status) {
41
41
  const s = status.toLowerCase();
42
- if (s === "pending") {
42
+ if (s === "pending" || s === "skipped") {
43
43
  return { color: "yellow" };
44
44
  }
45
- else if (s === "passed") {
45
+ else if (s.includes("pass")) {
46
46
  return { color: "grey" };
47
47
  }
48
- else if (s === "failed") {
48
+ else if (s.includes("fail")) {
49
49
  return { color: "red" };
50
50
  }
51
51
  else {
@@ -70,7 +70,7 @@ function formatValue(value) {
70
70
  }
71
71
  return String(value);
72
72
  }
73
- export async function printReporterTable(results, failureMessage) {
73
+ export async function printReporterTable(testSuiteName, results, testStatus, failureMessage) {
74
74
  const rows = [];
75
75
  const feedbackKeys = new Set();
76
76
  let experimentUrl;
@@ -93,7 +93,7 @@ export async function printReporterTable(results, failureMessage) {
93
93
  getColorParam(status),
94
94
  ]);
95
95
  }
96
- else if (status === "pending") {
96
+ else if (status === "pending" || status === "skipped") {
97
97
  // Skipped
98
98
  rows.push([
99
99
  {
@@ -236,6 +236,14 @@ export async function printReporterTable(results, failureMessage) {
236
236
  for (const row of rows) {
237
237
  table.addRow(row[0], row[1]);
238
238
  }
239
+ const testStatusColor = testStatus.includes("pass")
240
+ ? chalk.green
241
+ : testStatus.includes("fail")
242
+ ? chalk.red
243
+ : chalk.yellow;
244
+ if (testSuiteName) {
245
+ console.log(testStatusColor(`› ${testSuiteName}`));
246
+ }
239
247
  if (failureMessage) {
240
248
  console.log(failureMessage);
241
249
  }
@@ -9,15 +9,20 @@ class LangSmithEvalReporter extends reporters_1.DefaultReporter {
9
9
  async onFinished(files, errors) {
10
10
  super.onFinished(files, errors);
11
11
  for (const file of files) {
12
- const testModule = this.ctx.state.getReportedEntity(file);
13
- const tests = [...testModule.children.allTests()].map((test) => {
14
- return {
15
- title: test.name,
16
- status: test.result()?.state ?? "skipped",
17
- duration: Math.round(test.diagnostic()?.duration ?? 0),
18
- };
19
- });
20
- await (0, reporter_js_1.printReporterTable)(tests);
12
+ for (const task of file.tasks) {
13
+ const testModule = this.ctx.state.getReportedEntity(task);
14
+ const tests = [...testModule.children.allTests()].map((test) => {
15
+ return {
16
+ title: test.name,
17
+ status: test.result()?.state ?? "skipped",
18
+ duration: Math.round(test.diagnostic()?.duration ?? 0),
19
+ };
20
+ });
21
+ const result = ["pass", "fail", "skip"].includes(task.result?.state ?? "")
22
+ ? task.result?.state
23
+ : "skip";
24
+ await (0, reporter_js_1.printReporterTable)(task.name, tests, result);
25
+ }
21
26
  }
22
27
  }
23
28
  }
@@ -7,15 +7,20 @@ class LangSmithEvalReporter extends DefaultReporter {
7
7
  async onFinished(files, errors) {
8
8
  super.onFinished(files, errors);
9
9
  for (const file of files) {
10
- const testModule = this.ctx.state.getReportedEntity(file);
11
- const tests = [...testModule.children.allTests()].map((test) => {
12
- return {
13
- title: test.name,
14
- status: test.result()?.state ?? "skipped",
15
- duration: Math.round(test.diagnostic()?.duration ?? 0),
16
- };
17
- });
18
- await printReporterTable(tests);
10
+ for (const task of file.tasks) {
11
+ const testModule = this.ctx.state.getReportedEntity(task);
12
+ const tests = [...testModule.children.allTests()].map((test) => {
13
+ return {
14
+ title: test.name,
15
+ status: test.result()?.state ?? "skipped",
16
+ duration: Math.round(test.diagnostic()?.duration ?? 0),
17
+ };
18
+ });
19
+ const result = ["pass", "fail", "skip"].includes(task.result?.state ?? "")
20
+ ? task.result?.state
21
+ : "skip";
22
+ await printReporterTable(task.name, tests, result);
23
+ }
19
24
  }
20
25
  }
21
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.4-rc.0",
3
+ "version": "0.3.5",
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": [