langsmith 0.2.14-rc.2 → 0.2.14-rc.3

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/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.2.14-rc.2";
11
+ exports.__version__ = "0.2.14-rc.3";
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.2.14-rc.2";
5
+ export declare const __version__ = "0.2.14-rc.3";
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.2.14-rc.2";
5
+ export const __version__ = "0.2.14-rc.3";
@@ -19,6 +19,24 @@ globals_1.expect.extend({
19
19
  toBeAbsoluteCloseTo: matchers_js_1.toBeAbsoluteCloseTo,
20
20
  toBeSemanticCloseTo: matchers_js_1.toBeSemanticCloseTo,
21
21
  });
22
+ const objectHash = (obj, depth = 0) => {
23
+ // Prevent infinite recursion
24
+ if (depth > 50) {
25
+ return "[Max Depth Exceeded]";
26
+ }
27
+ if (Array.isArray(obj)) {
28
+ return obj.map((item) => objectHash(item, depth + 1));
29
+ }
30
+ if (obj && typeof obj === "object") {
31
+ return Object.keys(obj)
32
+ .sort()
33
+ .reduce((result, key) => {
34
+ result[key] = objectHash(obj[key], depth + 1);
35
+ return result;
36
+ }, {});
37
+ }
38
+ return crypto_1.default.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
39
+ };
22
40
  async function _createProject(client, datasetId) {
23
41
  // Create the project, updating the experimentName until we find a unique one.
24
42
  let project;
@@ -76,14 +94,8 @@ async function runDatasetSetup(testClient, datasetName) {
76
94
  });
77
95
  const examples = [];
78
96
  for await (const example of examplesList) {
79
- const inputHash = crypto_1.default
80
- .createHash("sha256")
81
- .update(JSON.stringify(example.inputs))
82
- .digest("hex");
83
- const outputHash = crypto_1.default
84
- .createHash("sha256")
85
- .update(JSON.stringify(example.inputs))
86
- .digest("hex");
97
+ const inputHash = objectHash(example.inputs);
98
+ const outputHash = objectHash(example.outputs ?? {});
87
99
  examples.push({ ...example, inputHash, outputHash });
88
100
  }
89
101
  const project = await _createProject(testClient, dataset.id);
@@ -124,6 +136,9 @@ const lsDescribe = Object.assign(wrapDescribeMethod(globals_1.describe), {
124
136
  });
125
137
  function wrapTestMethod(method) {
126
138
  return function (params, config) {
139
+ // Due to https://github.com/jestjs/jest/issues/13653,
140
+ // we must access the local store value here before
141
+ // entering an async context
127
142
  const context = globals_js_1.jestAsyncLocalStorageInstance.getStore();
128
143
  // This typing is wrong, but necessary to avoid lint errors
129
144
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -140,14 +155,8 @@ function wrapTestMethod(method) {
140
155
  const { examples, dataset, createdAt, project, client } = await setupPromises.get(context.suiteUuid);
141
156
  const testInput = typeof params === "string" ? {} : params.inputs;
142
157
  const testOutput = typeof params === "string" ? {} : params.outputs;
143
- const inputHash = crypto_1.default
144
- .createHash("sha256")
145
- .update(JSON.stringify(testInput))
146
- .digest("hex");
147
- const outputHash = crypto_1.default
148
- .createHash("sha256")
149
- .update(JSON.stringify(testOutput))
150
- .digest("hex");
158
+ const inputHash = objectHash(testInput);
159
+ const outputHash = objectHash(testOutput ?? {});
151
160
  if ((0, globals_js_1.trackingEnabled)()) {
152
161
  const missingFields = [];
153
162
  if (examples === undefined) {
@@ -224,9 +233,18 @@ function wrapTestMethod(method) {
224
233
  };
225
234
  };
226
235
  }
236
+ function eachMethod(table) {
237
+ return function (name, fn, timeout) {
238
+ for (let i = 0; i < table.length; i += 1) {
239
+ const example = table[i];
240
+ wrapTestMethod(globals_1.test)(example)(`${name} ${i}`, fn, timeout);
241
+ }
242
+ };
243
+ }
227
244
  const lsTest = Object.assign(wrapTestMethod(globals_1.test), {
228
245
  only: wrapTestMethod(globals_1.test.only),
229
246
  skip: wrapTestMethod(globals_1.test.skip),
247
+ each: eachMethod,
230
248
  });
231
249
  exports.default = {
232
250
  test: lsTest,
@@ -1,4 +1,5 @@
1
1
  import { RunTreeConfig } from "../run_trees.js";
2
+ import { KVMap } from "../schemas.js";
2
3
  import expectWithGradedBy from "./vendor/chain.js";
3
4
  import type { SimpleEvaluator } from "./vendor/gradedBy.js";
4
5
  declare global {
@@ -25,6 +26,13 @@ export type LangSmithJestTestWrapper<I, O> = (name: string, fn: (params: {
25
26
  inputs: I;
26
27
  outputs: O;
27
28
  }) => unknown | Promise<unknown>, timeout?: number) => void;
29
+ declare function eachMethod<I extends KVMap, O extends KVMap>(table: {
30
+ inputs: I;
31
+ outputs: O;
32
+ }[]): (name: string, fn: (params: {
33
+ inputs: I;
34
+ outputs: O;
35
+ }) => unknown | Promise<unknown>, timeout?: number) => void;
28
36
  declare const _default: {
29
37
  test: (<I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
30
38
  inputs: I;
@@ -38,6 +46,7 @@ declare const _default: {
38
46
  inputs: I;
39
47
  outputs: O;
40
48
  }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>;
49
+ each: typeof eachMethod;
41
50
  };
42
51
  it: (<I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
43
52
  inputs: I;
@@ -51,6 +60,7 @@ declare const _default: {
51
60
  inputs: I;
52
61
  outputs: O;
53
62
  }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>;
63
+ each: typeof eachMethod;
54
64
  };
55
65
  describe: LangSmithJestDescribeWrapper & {
56
66
  only: LangSmithJestDescribeWrapper;
@@ -14,6 +14,24 @@ expect.extend({
14
14
  toBeAbsoluteCloseTo,
15
15
  toBeSemanticCloseTo,
16
16
  });
17
+ const objectHash = (obj, depth = 0) => {
18
+ // Prevent infinite recursion
19
+ if (depth > 50) {
20
+ return "[Max Depth Exceeded]";
21
+ }
22
+ if (Array.isArray(obj)) {
23
+ return obj.map((item) => objectHash(item, depth + 1));
24
+ }
25
+ if (obj && typeof obj === "object") {
26
+ return Object.keys(obj)
27
+ .sort()
28
+ .reduce((result, key) => {
29
+ result[key] = objectHash(obj[key], depth + 1);
30
+ return result;
31
+ }, {});
32
+ }
33
+ return crypto.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
34
+ };
17
35
  async function _createProject(client, datasetId) {
18
36
  // Create the project, updating the experimentName until we find a unique one.
19
37
  let project;
@@ -71,14 +89,8 @@ async function runDatasetSetup(testClient, datasetName) {
71
89
  });
72
90
  const examples = [];
73
91
  for await (const example of examplesList) {
74
- const inputHash = crypto
75
- .createHash("sha256")
76
- .update(JSON.stringify(example.inputs))
77
- .digest("hex");
78
- const outputHash = crypto
79
- .createHash("sha256")
80
- .update(JSON.stringify(example.inputs))
81
- .digest("hex");
92
+ const inputHash = objectHash(example.inputs);
93
+ const outputHash = objectHash(example.outputs ?? {});
82
94
  examples.push({ ...example, inputHash, outputHash });
83
95
  }
84
96
  const project = await _createProject(testClient, dataset.id);
@@ -119,6 +131,9 @@ const lsDescribe = Object.assign(wrapDescribeMethod(describe), {
119
131
  });
120
132
  function wrapTestMethod(method) {
121
133
  return function (params, config) {
134
+ // Due to https://github.com/jestjs/jest/issues/13653,
135
+ // we must access the local store value here before
136
+ // entering an async context
122
137
  const context = jestAsyncLocalStorageInstance.getStore();
123
138
  // This typing is wrong, but necessary to avoid lint errors
124
139
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -135,14 +150,8 @@ function wrapTestMethod(method) {
135
150
  const { examples, dataset, createdAt, project, client } = await setupPromises.get(context.suiteUuid);
136
151
  const testInput = typeof params === "string" ? {} : params.inputs;
137
152
  const testOutput = typeof params === "string" ? {} : params.outputs;
138
- const inputHash = crypto
139
- .createHash("sha256")
140
- .update(JSON.stringify(testInput))
141
- .digest("hex");
142
- const outputHash = crypto
143
- .createHash("sha256")
144
- .update(JSON.stringify(testOutput))
145
- .digest("hex");
153
+ const inputHash = objectHash(testInput);
154
+ const outputHash = objectHash(testOutput ?? {});
146
155
  if (trackingEnabled()) {
147
156
  const missingFields = [];
148
157
  if (examples === undefined) {
@@ -219,9 +228,18 @@ function wrapTestMethod(method) {
219
228
  };
220
229
  };
221
230
  }
231
+ function eachMethod(table) {
232
+ return function (name, fn, timeout) {
233
+ for (let i = 0; i < table.length; i += 1) {
234
+ const example = table[i];
235
+ wrapTestMethod(test)(example)(`${name} ${i}`, fn, timeout);
236
+ }
237
+ };
238
+ }
222
239
  const lsTest = Object.assign(wrapTestMethod(test), {
223
240
  only: wrapTestMethod(test.only),
224
241
  skip: wrapTestMethod(test.skip),
242
+ each: eachMethod,
225
243
  });
226
244
  export default {
227
245
  test: lsTest,
@@ -99,51 +99,3 @@ async function toBeSemanticCloseTo(received, expected, options) {
99
99
  };
100
100
  }
101
101
  exports.toBeSemanticCloseTo = toBeSemanticCloseTo;
102
- // export async function toPassEvaluator(
103
- // this: MatcherContext,
104
- // actual: KVMap,
105
- // evaluator: SimpleEvaluator,
106
- // _expected?: KVMap
107
- // ) {
108
- // const runTree = getCurrentRunTree();
109
- // const context = localStorage.getStore();
110
- // if (context === undefined || context.currentExample === undefined) {
111
- // throw new Error(
112
- // `Could not identify example context from current context.\nPlease ensure you are calling this matcher within "ls.test()"`
113
- // );
114
- // }
115
- // const wrappedEvaluator = traceable(evaluator, {
116
- // reference_example_id: context.currentExample.id,
117
- // metadata: {
118
- // example_version: context.currentExample.modified_at
119
- // ? new Date(context.currentExample.modified_at).toISOString()
120
- // : new Date(context.currentExample.created_at).toISOString(),
121
- // },
122
- // client: context.client,
123
- // tracingEnabled: true,
124
- // });
125
- // const evalResult = await wrappedEvaluator({
126
- // input: runTree.inputs,
127
- // expected: context.currentExample.outputs ?? {},
128
- // actual,
129
- // });
130
- // await context.client.logEvaluationFeedback(evalResult, runTree);
131
- // if (!("results" in evalResult) && !evalResult.score) {
132
- // return {
133
- // pass: false,
134
- // message: () =>
135
- // `expected ${this.utils.printReceived(
136
- // actual
137
- // )} to pass evaluator. Failed with ${JSON.stringify(
138
- // evalResult,
139
- // null,
140
- // 2
141
- // )}`,
142
- // };
143
- // }
144
- // return {
145
- // pass: true,
146
- // message: () =>
147
- // `evaluator passed with score ${JSON.stringify(evalResult, null, 2)}`,
148
- // };
149
- // }
@@ -93,51 +93,3 @@ export async function toBeSemanticCloseTo(received, expected, options) {
93
93
  : `Expected "${received}" to be semantically close to "${expected}" (threshold: ${threshold}, similarity: ${similarity})`,
94
94
  };
95
95
  }
96
- // export async function toPassEvaluator(
97
- // this: MatcherContext,
98
- // actual: KVMap,
99
- // evaluator: SimpleEvaluator,
100
- // _expected?: KVMap
101
- // ) {
102
- // const runTree = getCurrentRunTree();
103
- // const context = localStorage.getStore();
104
- // if (context === undefined || context.currentExample === undefined) {
105
- // throw new Error(
106
- // `Could not identify example context from current context.\nPlease ensure you are calling this matcher within "ls.test()"`
107
- // );
108
- // }
109
- // const wrappedEvaluator = traceable(evaluator, {
110
- // reference_example_id: context.currentExample.id,
111
- // metadata: {
112
- // example_version: context.currentExample.modified_at
113
- // ? new Date(context.currentExample.modified_at).toISOString()
114
- // : new Date(context.currentExample.created_at).toISOString(),
115
- // },
116
- // client: context.client,
117
- // tracingEnabled: true,
118
- // });
119
- // const evalResult = await wrappedEvaluator({
120
- // input: runTree.inputs,
121
- // expected: context.currentExample.outputs ?? {},
122
- // actual,
123
- // });
124
- // await context.client.logEvaluationFeedback(evalResult, runTree);
125
- // if (!("results" in evalResult) && !evalResult.score) {
126
- // return {
127
- // pass: false,
128
- // message: () =>
129
- // `expected ${this.utils.printReceived(
130
- // actual
131
- // )} to pass evaluator. Failed with ${JSON.stringify(
132
- // evalResult,
133
- // null,
134
- // 2
135
- // )}`,
136
- // };
137
- // }
138
- // return {
139
- // pass: true,
140
- // message: () =>
141
- // `evaluator passed with score ${JSON.stringify(evalResult, null, 2)}`,
142
- // };
143
- // }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.2.14-rc.2",
3
+ "version": "0.2.14-rc.3",
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": [