langsmith 0.3.1 → 0.3.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/README.md CHANGED
@@ -3,7 +3,6 @@
3
3
  ![NPM Version](https://img.shields.io/npm/v/langsmith?logo=npm)
4
4
  [![JS Downloads](https://img.shields.io/npm/dm/langsmith)](https://www.npmjs.com/package/langsmith)
5
5
 
6
-
7
6
  This package contains the TypeScript client for interacting with the [LangSmith platform](https://smith.langchain.com/).
8
7
 
9
8
  To install:
@@ -51,11 +50,11 @@ yarn add langchain
51
50
  Tracing can be activated by setting the following environment variables or by manually specifying the LangChainTracer.
52
51
 
53
52
  ```typescript
54
- process.env["LANGSMITH_TRACING"] = "true";
55
- process.env["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com";
56
- // process.env["LANGCHAIN_ENDPOINT"] = "https://eu.api.smith.langchain.com"; // If signed up in the EU region
57
- process.env["LANGCHAIN_API_KEY"] = "<YOUR-LANGSMITH-API-KEY>";
58
- // process.env["LANGCHAIN_PROJECT"] = "My Project Name"; // Optional: "default" is used if not set
53
+ process.env.LANGSMITH_TRACING_V2 = "true";
54
+ process.env.LANGSMITH_ENDPOINT = "https://api.smith.langchain.com";
55
+ // process.env.LANGSMITH_ENDPOINT = "https://eu.api.smith.langchain.com"; // If signed up in the EU region
56
+ process.env.LANGSMITH_API_KEY = "<YOUR-LANGSMITH-API-KEY>";
57
+ // process.env.LANGSMITH_PROJECT = "My Project Name"; // Optional: "default" is used if not set
59
58
  ```
60
59
 
61
60
  > **Tip:** Projects are groups of traces. All runs are logged to a project. If not specified, the project is set to `default`.
@@ -83,9 +82,10 @@ or by directly specifying the connection information in the RunTree.
83
82
  1. **Copy the environment variables from the Settings Page and add them to your application.**
84
83
 
85
84
  ```shell
86
- export LANGCHAIN_API_KEY=<YOUR-LANGSMITH-API-KEY>
87
- # export LANGCHAIN_PROJECT="My Project Name" # Optional: "default" is used if not set
88
- # export LANGCHAIN_ENDPOINT=https://api.smith.langchain.com # or your own server
85
+ export LANGSMITH_TRACING_V2="true";
86
+ export LANGSMITH_API_KEY=<YOUR-LANGSMITH-API-KEY>
87
+ # export LANGSMITH_PROJECT="My Project Name" # Optional: "default" is used if not set
88
+ # export LANGSMITH_ENDPOINT=https://api.smith.langchain.com # or your own server
89
89
  ```
90
90
 
91
91
  ## Integrations
@@ -102,7 +102,8 @@ is using the `wrapOpenAI` wrapper function available in LangSmith 0.1.3 and up.
102
102
  In order to use, you first need to set your LangSmith API key:
103
103
 
104
104
  ```shell
105
- export LANGCHAIN_API_KEY=<your-api-key>
105
+ export LANGSMITH_TRACING_V2="true";
106
+ export LANGSMITH_API_KEY=<your-api-key>
106
107
  ```
107
108
 
108
109
  Next, you will need to install the LangSmith SDK and the OpenAI SDK:
@@ -345,9 +346,9 @@ const parentRunConfig: RunTreeConfig = {
345
346
  text: "Summarize this morning's meetings.",
346
347
  },
347
348
  serialized: {}, // Serialized representation of this chain
348
- // project_name: "Defaults to the LANGCHAIN_PROJECT env var"
349
- // apiUrl: "Defaults to the LANGCHAIN_ENDPOINT env var"
350
- // apiKey: "Defaults to the LANGCHAIN_API_KEY env var"
349
+ // project_name: "Defaults to the LANGSMITH_PROJECT env var"
350
+ // apiUrl: "Defaults to the LANGSMITH_ENDPOINT env var"
351
+ // apiKey: "Defaults to the LANGSMITH_API_KEY env var"
351
352
  };
352
353
 
353
354
  const parentRun = new RunTree(parentRunConfig);
@@ -440,8 +441,8 @@ the web interface, as explained in the [LangSmith docs](https://docs.smith.langc
440
441
  ```typescript
441
442
  import { Client } from "langsmith/client";
442
443
  const client = new Client({
443
- // apiUrl: "https://api.langchain.com", // Defaults to the LANGCHAIN_ENDPOINT env var
444
- // apiKey: "my_api_key", // Defaults to the LANGCHAIN_API_KEY env var
444
+ // apiUrl: "https://api.langchain.com", // Defaults to the LANGSMITH_ENDPOINT env var
445
+ // apiKey: "my_api_key", // Defaults to the LANGSMITH_API_KEY env var
445
446
  /* callerOptions: {
446
447
  maxConcurrency?: Infinity; // Maximum number of concurrent requests to make
447
448
  maxRetries?: 6; // Maximum number of retries to make
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.1";
11
+ exports.__version__ = "0.3.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.3.1";
5
+ export declare const __version__ = "0.3.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.3.1";
5
+ export const __version__ = "0.3.3";
@@ -5,8 +5,19 @@ 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
+ const groupedTestResults = testResult.testResults.reduce((groups, testResult) => {
9
+ const ancestorTitle = testResult.ancestorTitles.join(" > ");
10
+ if (groups[ancestorTitle] === undefined) {
11
+ groups[ancestorTitle] = [];
12
+ }
13
+ groups[ancestorTitle].push(testResult);
14
+ return groups;
15
+ }, {});
8
16
  try {
9
- await (0, reporter_js_1.printReporterTable)(testResult.testResults, testResult.failureMessage);
17
+ for (const testGroupName of Object.keys(groupedTestResults)) {
18
+ const resultGroup = groupedTestResults[testGroupName];
19
+ await (0, reporter_js_1.printReporterTable)(resultGroup, testResult.failureMessage);
20
+ }
10
21
  }
11
22
  catch (e) {
12
23
  console.log("Failed to display LangSmith eval results:", e.message);
@@ -3,8 +3,19 @@ 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
+ const groupedTestResults = testResult.testResults.reduce((groups, testResult) => {
7
+ const ancestorTitle = testResult.ancestorTitles.join(" > ");
8
+ if (groups[ancestorTitle] === undefined) {
9
+ groups[ancestorTitle] = [];
10
+ }
11
+ groups[ancestorTitle].push(testResult);
12
+ return groups;
13
+ }, {});
6
14
  try {
7
- await printReporterTable(testResult.testResults, testResult.failureMessage);
15
+ for (const testGroupName of Object.keys(groupedTestResults)) {
16
+ const resultGroup = groupedTestResults[testGroupName];
17
+ await printReporterTable(resultGroup, testResult.failureMessage);
18
+ }
8
19
  }
9
20
  catch (e) {
10
21
  console.log("Failed to display LangSmith eval results:", e.message);
@@ -28,7 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  return (mod && mod.__esModule) ? mod : { "default": mod };
29
29
  };
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.generateWrapperFromJestlikeMethods = exports.logOutputs = exports.logFeedback = exports.TEST_ID_DELIMITER = exports.STRIP_ANSI_REGEX = void 0;
31
+ exports.generateWrapperFromJestlikeMethods = exports.objectHash = exports.logOutputs = exports.logFeedback = exports.TEST_ID_DELIMITER = exports.STRIP_ANSI_REGEX = void 0;
32
32
  const crypto_1 = __importDefault(require("crypto"));
33
33
  const uuid_1 = require("uuid");
34
34
  const os = __importStar(require("node:os"));
@@ -86,31 +86,31 @@ function logOutputs(output) {
86
86
  context.setLoggedOutput(output);
87
87
  }
88
88
  exports.logOutputs = logOutputs;
89
+ function objectHash(obj, depth = 0) {
90
+ // Prevent infinite recursion
91
+ if (depth > 50) {
92
+ throw new Error("Object is too deep to check equality for serialization. Please use a simpler example.");
93
+ }
94
+ if (Array.isArray(obj)) {
95
+ const arrayHash = obj.map((item) => objectHash(item, depth + 1)).join(",");
96
+ return crypto_1.default.createHash("sha256").update(arrayHash).digest("hex");
97
+ }
98
+ if (obj && typeof obj === "object") {
99
+ const sortedHash = Object.keys(obj)
100
+ .sort()
101
+ .map((key) => `${key}:${objectHash(obj[key], depth + 1)}`)
102
+ .join(",");
103
+ return crypto_1.default.createHash("sha256").update(sortedHash).digest("hex");
104
+ }
105
+ return (crypto_1.default
106
+ .createHash("sha256")
107
+ // Treat null and undefined as equal for serialization purposes
108
+ .update(JSON.stringify(obj ?? null))
109
+ .digest("hex"));
110
+ }
111
+ exports.objectHash = objectHash;
89
112
  function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
90
113
  const { expect, test, describe, beforeAll, afterAll } = methods;
91
- const objectHash = (obj, depth = 0) => {
92
- // Prevent infinite recursion
93
- if (depth > 50) {
94
- throw new Error("Object is too deep to check equality for serialization. Please use a simpler example.");
95
- }
96
- if (Array.isArray(obj)) {
97
- const arrayHash = obj
98
- .map((item) => objectHash(item, depth + 1))
99
- .join(",");
100
- return crypto_1.default.createHash("sha256").update(arrayHash).digest("hex");
101
- }
102
- if (obj && typeof obj === "object") {
103
- const sortedHash = Object.keys(obj)
104
- .sort()
105
- .map((key) => `${key}:${objectHash(obj[key], depth + 1)}`)
106
- .join(",");
107
- return crypto_1.default.createHash("sha256").update(sortedHash).digest("hex");
108
- }
109
- return crypto_1.default
110
- .createHash("sha256")
111
- .update(JSON.stringify(obj))
112
- .digest("hex");
113
- };
114
114
  async function _createProject(client, datasetId, projectConfig) {
115
115
  // Create the project, updating the experimentName until we find a unique one.
116
116
  let project;
@@ -9,6 +9,7 @@ export declare function logFeedback(feedback: SimpleEvaluationResult, config?: {
9
9
  sourceRunId?: string;
10
10
  }): void;
11
11
  export declare function logOutputs(output: Record<string, unknown>): void;
12
+ export declare function objectHash(obj: KVMap, depth?: number): string;
12
13
  export declare function generateWrapperFromJestlikeMethods(methods: Record<string, any>, testRunnerName: string): {
13
14
  test: (<I extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Record<string, any>>(name: string, lsParams: LangSmithJestlikeWrapperParams<I, O>, testFn: (data: {
14
15
  inputs: I;
@@ -55,31 +55,30 @@ export function logOutputs(output) {
55
55
  }
56
56
  context.setLoggedOutput(output);
57
57
  }
58
+ export function objectHash(obj, depth = 0) {
59
+ // Prevent infinite recursion
60
+ if (depth > 50) {
61
+ throw new Error("Object is too deep to check equality for serialization. Please use a simpler example.");
62
+ }
63
+ if (Array.isArray(obj)) {
64
+ const arrayHash = obj.map((item) => objectHash(item, depth + 1)).join(",");
65
+ return crypto.createHash("sha256").update(arrayHash).digest("hex");
66
+ }
67
+ if (obj && typeof obj === "object") {
68
+ const sortedHash = Object.keys(obj)
69
+ .sort()
70
+ .map((key) => `${key}:${objectHash(obj[key], depth + 1)}`)
71
+ .join(",");
72
+ return crypto.createHash("sha256").update(sortedHash).digest("hex");
73
+ }
74
+ return (crypto
75
+ .createHash("sha256")
76
+ // Treat null and undefined as equal for serialization purposes
77
+ .update(JSON.stringify(obj ?? null))
78
+ .digest("hex"));
79
+ }
58
80
  export function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
59
81
  const { expect, test, describe, beforeAll, afterAll } = methods;
60
- const objectHash = (obj, depth = 0) => {
61
- // Prevent infinite recursion
62
- if (depth > 50) {
63
- throw new Error("Object is too deep to check equality for serialization. Please use a simpler example.");
64
- }
65
- if (Array.isArray(obj)) {
66
- const arrayHash = obj
67
- .map((item) => objectHash(item, depth + 1))
68
- .join(",");
69
- return crypto.createHash("sha256").update(arrayHash).digest("hex");
70
- }
71
- if (obj && typeof obj === "object") {
72
- const sortedHash = Object.keys(obj)
73
- .sort()
74
- .map((key) => `${key}:${objectHash(obj[key], depth + 1)}`)
75
- .join(",");
76
- return crypto.createHash("sha256").update(sortedHash).digest("hex");
77
- }
78
- return crypto
79
- .createHash("sha256")
80
- .update(JSON.stringify(obj))
81
- .digest("hex");
82
- };
83
82
  async function _createProject(client, datasetId, projectConfig) {
84
83
  // Create the project, updating the experimentName until we find a unique one.
85
84
  let project;
@@ -34,6 +34,7 @@ const path = __importStar(require("node:path"));
34
34
  const fs = __importStar(require("node:fs/promises"));
35
35
  const index_js_1 = require("./index.cjs");
36
36
  const FEEDBACK_COLLAPSE_THRESHOLD = 48;
37
+ const MAX_TEST_PARAMS_LENGTH = 18;
37
38
  const RESERVED_KEYS = [
38
39
  "Name",
39
40
  "Result",
@@ -86,7 +87,9 @@ function formatValue(value) {
86
87
  .map(([k, v]) => {
87
88
  const rawValue = typeof v === "string" ? v : JSON.stringify(v);
88
89
  const rawEntry = `${k}: ${rawValue}`;
89
- const entry = rawEntry.length > 24 ? rawEntry.slice(0, 21) + "..." : rawEntry;
90
+ const entry = rawEntry.length > MAX_TEST_PARAMS_LENGTH
91
+ ? rawEntry.slice(0, MAX_TEST_PARAMS_LENGTH - 3) + "..."
92
+ : rawEntry;
90
93
  return entry;
91
94
  })
92
95
  .join("\n");
@@ -230,9 +233,13 @@ async function printReporterTable(results, failureMessage) {
230
233
  }
231
234
  const defaultColumns = [
232
235
  { name: "Test", alignment: "left", maxLen: 36 },
233
- { name: "Inputs", alignment: "left", minLen: 24 },
234
- { name: "Reference Outputs", alignment: "left", minLen: 24 },
235
- { name: "Outputs", alignment: "left", minLen: 24 },
236
+ { name: "Inputs", alignment: "left", minLen: MAX_TEST_PARAMS_LENGTH },
237
+ {
238
+ name: "Reference Outputs",
239
+ alignment: "left",
240
+ minLen: MAX_TEST_PARAMS_LENGTH,
241
+ },
242
+ { name: "Outputs", alignment: "left", minLen: MAX_TEST_PARAMS_LENGTH },
236
243
  { name: "Status", alignment: "left" },
237
244
  ];
238
245
  if (collapseFeedbackColumn) {
@@ -245,7 +252,7 @@ async function printReporterTable(results, failureMessage) {
245
252
  defaultColumns.push({
246
253
  name: "Feedback",
247
254
  alignment: "left",
248
- minLen: feedbackColumnLength + 10,
255
+ minLen: feedbackColumnLength + 8,
249
256
  });
250
257
  }
251
258
  console.log();
@@ -5,6 +5,7 @@ import * as path from "node:path";
5
5
  import * as fs from "node:fs/promises";
6
6
  import { STRIP_ANSI_REGEX, TEST_ID_DELIMITER } from "./index.js";
7
7
  const FEEDBACK_COLLAPSE_THRESHOLD = 48;
8
+ const MAX_TEST_PARAMS_LENGTH = 18;
8
9
  const RESERVED_KEYS = [
9
10
  "Name",
10
11
  "Result",
@@ -57,7 +58,9 @@ function formatValue(value) {
57
58
  .map(([k, v]) => {
58
59
  const rawValue = typeof v === "string" ? v : JSON.stringify(v);
59
60
  const rawEntry = `${k}: ${rawValue}`;
60
- const entry = rawEntry.length > 24 ? rawEntry.slice(0, 21) + "..." : rawEntry;
61
+ const entry = rawEntry.length > MAX_TEST_PARAMS_LENGTH
62
+ ? rawEntry.slice(0, MAX_TEST_PARAMS_LENGTH - 3) + "..."
63
+ : rawEntry;
61
64
  return entry;
62
65
  })
63
66
  .join("\n");
@@ -201,9 +204,13 @@ export async function printReporterTable(results, failureMessage) {
201
204
  }
202
205
  const defaultColumns = [
203
206
  { name: "Test", alignment: "left", maxLen: 36 },
204
- { name: "Inputs", alignment: "left", minLen: 24 },
205
- { name: "Reference Outputs", alignment: "left", minLen: 24 },
206
- { name: "Outputs", alignment: "left", minLen: 24 },
207
+ { name: "Inputs", alignment: "left", minLen: MAX_TEST_PARAMS_LENGTH },
208
+ {
209
+ name: "Reference Outputs",
210
+ alignment: "left",
211
+ minLen: MAX_TEST_PARAMS_LENGTH,
212
+ },
213
+ { name: "Outputs", alignment: "left", minLen: MAX_TEST_PARAMS_LENGTH },
207
214
  { name: "Status", alignment: "left" },
208
215
  ];
209
216
  if (collapseFeedbackColumn) {
@@ -216,7 +223,7 @@ export async function printReporterTable(results, failureMessage) {
216
223
  defaultColumns.push({
217
224
  name: "Feedback",
218
225
  alignment: "left",
219
- minLen: feedbackColumnLength + 10,
226
+ minLen: feedbackColumnLength + 8,
220
227
  });
221
228
  }
222
229
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.1",
3
+ "version": "0.3.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": [