langsmith 0.2.14-rc.2 → 0.2.14-rc.4

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.4";
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.4";
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.4";
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  return (mod && mod.__esModule) ? mod : { "default": mod };
6
6
  };
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.expect = exports.describe = exports.it = exports.test = void 0;
8
9
  const globals_1 = require("@jest/globals");
9
10
  const crypto_1 = __importDefault(require("crypto"));
10
11
  const uuid_1 = require("uuid");
@@ -14,11 +15,30 @@ const _random_name_js_1 = require("../evaluation/_random_name.cjs");
14
15
  const matchers_js_1 = require("./matchers.cjs");
15
16
  const globals_js_1 = require("./globals.cjs");
16
17
  const chain_js_1 = __importDefault(require("./vendor/chain.cjs"));
18
+ exports.expect = chain_js_1.default;
17
19
  globals_1.expect.extend({
18
20
  toBeRelativeCloseTo: matchers_js_1.toBeRelativeCloseTo,
19
21
  toBeAbsoluteCloseTo: matchers_js_1.toBeAbsoluteCloseTo,
20
22
  toBeSemanticCloseTo: matchers_js_1.toBeSemanticCloseTo,
21
23
  });
24
+ const objectHash = (obj, depth = 0) => {
25
+ // Prevent infinite recursion
26
+ if (depth > 50) {
27
+ return "[Max Depth Exceeded]";
28
+ }
29
+ if (Array.isArray(obj)) {
30
+ return obj.map((item) => objectHash(item, depth + 1));
31
+ }
32
+ if (obj && typeof obj === "object") {
33
+ return Object.keys(obj)
34
+ .sort()
35
+ .reduce((result, key) => {
36
+ result[key] = objectHash(obj[key], depth + 1);
37
+ return result;
38
+ }, {});
39
+ }
40
+ return crypto_1.default.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
41
+ };
22
42
  async function _createProject(client, datasetId) {
23
43
  // Create the project, updating the experimentName until we find a unique one.
24
44
  let project;
@@ -76,14 +96,8 @@ async function runDatasetSetup(testClient, datasetName) {
76
96
  });
77
97
  const examples = [];
78
98
  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");
99
+ const inputHash = objectHash(example.inputs);
100
+ const outputHash = objectHash(example.outputs ?? {});
87
101
  examples.push({ ...example, inputHash, outputHash });
88
102
  }
89
103
  const project = await _createProject(testClient, dataset.id);
@@ -122,8 +136,12 @@ const lsDescribe = Object.assign(wrapDescribeMethod(globals_1.describe), {
122
136
  only: wrapDescribeMethod(globals_1.describe.only),
123
137
  skip: wrapDescribeMethod(globals_1.describe.skip),
124
138
  });
139
+ exports.describe = lsDescribe;
125
140
  function wrapTestMethod(method) {
126
141
  return function (params, config) {
142
+ // Due to https://github.com/jestjs/jest/issues/13653,
143
+ // we must access the local store value here before
144
+ // entering an async context
127
145
  const context = globals_js_1.jestAsyncLocalStorageInstance.getStore();
128
146
  // This typing is wrong, but necessary to avoid lint errors
129
147
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -140,14 +158,8 @@ function wrapTestMethod(method) {
140
158
  const { examples, dataset, createdAt, project, client } = await setupPromises.get(context.suiteUuid);
141
159
  const testInput = typeof params === "string" ? {} : params.inputs;
142
160
  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");
161
+ const inputHash = objectHash(testInput);
162
+ const outputHash = objectHash(testOutput ?? {});
151
163
  if ((0, globals_js_1.trackingEnabled)()) {
152
164
  const missingFields = [];
153
165
  if (examples === undefined) {
@@ -224,13 +236,18 @@ function wrapTestMethod(method) {
224
236
  };
225
237
  };
226
238
  }
239
+ function eachMethod(table) {
240
+ return function (name, fn, timeout) {
241
+ for (let i = 0; i < table.length; i += 1) {
242
+ const example = table[i];
243
+ wrapTestMethod(globals_1.test)(example)(`${name} ${i}`, fn, timeout);
244
+ }
245
+ };
246
+ }
227
247
  const lsTest = Object.assign(wrapTestMethod(globals_1.test), {
228
248
  only: wrapTestMethod(globals_1.test.only),
229
249
  skip: wrapTestMethod(globals_1.test.skip),
250
+ each: eachMethod,
230
251
  });
231
- exports.default = {
232
- test: lsTest,
233
- it: lsTest,
234
- describe: lsDescribe,
235
- expect: chain_js_1.default,
236
- };
252
+ exports.test = lsTest;
253
+ exports.it = 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 {
@@ -21,42 +22,34 @@ declare global {
21
22
  }
22
23
  }
23
24
  export type LangSmithJestDescribeWrapper = (name: string, fn: () => void | Promise<void>, config?: Partial<RunTreeConfig>) => void;
25
+ declare const lsDescribe: LangSmithJestDescribeWrapper & {
26
+ only: LangSmithJestDescribeWrapper;
27
+ skip: LangSmithJestDescribeWrapper;
28
+ };
24
29
  export type LangSmithJestTestWrapper<I, O> = (name: string, fn: (params: {
25
30
  inputs: I;
26
31
  outputs: O;
27
32
  }) => unknown | Promise<unknown>, timeout?: number) => void;
28
- declare const _default: {
29
- test: (<I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
33
+ declare function eachMethod<I extends KVMap, O extends KVMap>(table: {
34
+ inputs: I;
35
+ outputs: O;
36
+ }[]): (name: string, fn: (params: {
37
+ inputs: I;
38
+ outputs: O;
39
+ }) => unknown | Promise<unknown>, timeout?: number) => void;
40
+ declare const lsTest: (<I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: {
41
+ inputs: I;
42
+ outputs: O;
43
+ } | string, config?: Partial<RunTreeConfig>) => LangSmithJestTestWrapper<I, O>) & {
44
+ only: <I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: {
30
45
  inputs: I;
31
46
  outputs: O;
32
- }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>) & {
33
- only: <I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
34
- inputs: I;
35
- outputs: O;
36
- }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>;
37
- skip: <I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
38
- inputs: I;
39
- outputs: O;
40
- }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>;
41
- };
42
- it: (<I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
47
+ } | string, config?: Partial<RunTreeConfig>) => LangSmithJestTestWrapper<I, O>;
48
+ skip: <I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: {
43
49
  inputs: I;
44
50
  outputs: O;
45
- }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>) & {
46
- only: <I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
47
- inputs: I;
48
- outputs: O;
49
- }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>;
50
- skip: <I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(params: string | {
51
- inputs: I;
52
- outputs: O;
53
- }, config?: Partial<RunTreeConfig> | undefined) => LangSmithJestTestWrapper<I, O>;
54
- };
55
- describe: LangSmithJestDescribeWrapper & {
56
- only: LangSmithJestDescribeWrapper;
57
- skip: LangSmithJestDescribeWrapper;
58
- };
59
- expect: typeof expectWithGradedBy;
51
+ } | string, config?: Partial<RunTreeConfig>) => LangSmithJestTestWrapper<I, O>;
52
+ each: typeof eachMethod;
60
53
  };
61
- export default _default;
54
+ export { lsTest as test, lsTest as it, lsDescribe as describe, expectWithGradedBy as expect, };
62
55
  export { type SimpleEvaluator };
@@ -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,13 +228,17 @@ 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
- export default {
227
- test: lsTest,
228
- it: lsTest,
229
- describe: lsDescribe,
230
- expect: expectWithGradedBy,
231
- };
244
+ export { lsTest as test, lsTest as it, lsDescribe as describe, expectWithGradedBy as expect, };
@@ -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.4",
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": [