langsmith 0.1.61 → 0.1.63

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
@@ -116,11 +116,15 @@ class Queue {
116
116
  return this.items.length;
117
117
  }
118
118
  push(item) {
119
- // this.items.push is synchronous with promise creation:
120
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
121
- return new Promise((resolve) => {
122
- this.items.push([item, resolve]);
123
- });
119
+ let itemPromiseResolve;
120
+ const itemPromise = new Promise((resolve) => {
121
+ // Setting itemPromiseResolve is synchronous with promise creation:
122
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
123
+ itemPromiseResolve = resolve;
124
+ });
125
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
126
+ this.items.push([item, itemPromiseResolve, itemPromise]);
127
+ return itemPromise;
124
128
  }
125
129
  pop(upToN) {
126
130
  if (upToN < 1) {
@@ -270,6 +274,12 @@ class Client {
270
274
  writable: true,
271
275
  value: void 0
272
276
  });
277
+ Object.defineProperty(this, "blockOnRootRunFinalization", {
278
+ enumerable: true,
279
+ configurable: true,
280
+ writable: true,
281
+ value: true
282
+ });
273
283
  const defaultConfig = Client.getDefaultClientConfig();
274
284
  this.tracingSampleRate = getTracingSamplingRate();
275
285
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
@@ -292,6 +302,8 @@ class Client {
292
302
  this.hideOutputs =
293
303
  config.hideOutputs ?? config.anonymizer ?? defaultConfig.hideOutputs;
294
304
  this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
305
+ this.blockOnRootRunFinalization =
306
+ config.blockOnRootRunFinalization ?? this.blockOnRootRunFinalization;
295
307
  this.pendingAutoBatchedRunLimit =
296
308
  config.pendingAutoBatchedRunLimit ?? this.pendingAutoBatchedRunLimit;
297
309
  this.fetchOptions = config.fetchOptions || {};
@@ -698,7 +710,9 @@ class Client {
698
710
  if (this.autoBatchTracing &&
699
711
  data.trace_id !== undefined &&
700
712
  data.dotted_order !== undefined) {
701
- if (run.end_time !== undefined && data.parent_run_id === undefined) {
713
+ if (run.end_time !== undefined &&
714
+ data.parent_run_id === undefined &&
715
+ this.blockOnRootRunFinalization) {
702
716
  // Trigger a batch as soon as a root trace ends and block to ensure trace finishes
703
717
  // in serverless environments.
704
718
  await this.processRunOperation({ action: "update", item: data }, true);
@@ -2656,5 +2670,29 @@ class Client {
2656
2670
  throw new Error(`Invalid public ${kind} URL or token: ${urlOrToken}`);
2657
2671
  }
2658
2672
  }
2673
+ /**
2674
+ * Awaits all pending trace batches. Useful for environments where
2675
+ * you need to be sure that all tracing requests finish before execution ends,
2676
+ * such as serverless environments.
2677
+ *
2678
+ * @example
2679
+ * ```
2680
+ * import { Client } from "langsmith";
2681
+ *
2682
+ * const client = new Client();
2683
+ *
2684
+ * try {
2685
+ * // Tracing happens here
2686
+ * ...
2687
+ * } finally {
2688
+ * await client.awaitPendingTraceBatches();
2689
+ * }
2690
+ * ```
2691
+ *
2692
+ * @returns A promise that resolves once all currently pending traces have sent.
2693
+ */
2694
+ awaitPendingTraceBatches() {
2695
+ return Promise.all(this.autoBatchQueue.items.map(([, , promise]) => promise));
2696
+ }
2659
2697
  }
2660
2698
  exports.Client = Client;
package/dist/client.d.ts CHANGED
@@ -12,6 +12,7 @@ export interface ClientConfig {
12
12
  hideOutputs?: boolean | ((outputs: KVMap) => KVMap);
13
13
  autoBatchTracing?: boolean;
14
14
  pendingAutoBatchedRunLimit?: number;
15
+ blockOnRootRunFinalization?: boolean;
15
16
  fetchOptions?: RequestInit;
16
17
  }
17
18
  /**
@@ -157,7 +158,7 @@ export type CreateExampleOptions = {
157
158
  sourceRunId?: string;
158
159
  };
159
160
  export declare class Queue<T> {
160
- items: [T, () => void][];
161
+ items: [T, () => void, Promise<void>][];
161
162
  get size(): number;
162
163
  push(item: T): Promise<void>;
163
164
  pop(upToN: number): [T[], () => void];
@@ -185,6 +186,7 @@ export declare class Client {
185
186
  private serverInfo;
186
187
  private fetchOptions;
187
188
  private settings;
189
+ private blockOnRootRunFinalization;
188
190
  constructor(config?: ClientConfig);
189
191
  static getDefaultClientConfig(): {
190
192
  apiUrl: string;
@@ -736,5 +738,27 @@ export declare class Client {
736
738
  datasetName?: string;
737
739
  }): Promise<void>;
738
740
  private parseTokenOrUrl;
741
+ /**
742
+ * Awaits all pending trace batches. Useful for environments where
743
+ * you need to be sure that all tracing requests finish before execution ends,
744
+ * such as serverless environments.
745
+ *
746
+ * @example
747
+ * ```
748
+ * import { Client } from "langsmith";
749
+ *
750
+ * const client = new Client();
751
+ *
752
+ * try {
753
+ * // Tracing happens here
754
+ * ...
755
+ * } finally {
756
+ * await client.awaitPendingTraceBatches();
757
+ * }
758
+ * ```
759
+ *
760
+ * @returns A promise that resolves once all currently pending traces have sent.
761
+ */
762
+ awaitPendingTraceBatches(): Promise<void[]>;
739
763
  }
740
764
  export {};
package/dist/client.js CHANGED
@@ -90,11 +90,15 @@ export class Queue {
90
90
  return this.items.length;
91
91
  }
92
92
  push(item) {
93
- // this.items.push is synchronous with promise creation:
94
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
95
- return new Promise((resolve) => {
96
- this.items.push([item, resolve]);
97
- });
93
+ let itemPromiseResolve;
94
+ const itemPromise = new Promise((resolve) => {
95
+ // Setting itemPromiseResolve is synchronous with promise creation:
96
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
97
+ itemPromiseResolve = resolve;
98
+ });
99
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
100
+ this.items.push([item, itemPromiseResolve, itemPromise]);
101
+ return itemPromise;
98
102
  }
99
103
  pop(upToN) {
100
104
  if (upToN < 1) {
@@ -243,6 +247,12 @@ export class Client {
243
247
  writable: true,
244
248
  value: void 0
245
249
  });
250
+ Object.defineProperty(this, "blockOnRootRunFinalization", {
251
+ enumerable: true,
252
+ configurable: true,
253
+ writable: true,
254
+ value: true
255
+ });
246
256
  const defaultConfig = Client.getDefaultClientConfig();
247
257
  this.tracingSampleRate = getTracingSamplingRate();
248
258
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
@@ -265,6 +275,8 @@ export class Client {
265
275
  this.hideOutputs =
266
276
  config.hideOutputs ?? config.anonymizer ?? defaultConfig.hideOutputs;
267
277
  this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
278
+ this.blockOnRootRunFinalization =
279
+ config.blockOnRootRunFinalization ?? this.blockOnRootRunFinalization;
268
280
  this.pendingAutoBatchedRunLimit =
269
281
  config.pendingAutoBatchedRunLimit ?? this.pendingAutoBatchedRunLimit;
270
282
  this.fetchOptions = config.fetchOptions || {};
@@ -671,7 +683,9 @@ export class Client {
671
683
  if (this.autoBatchTracing &&
672
684
  data.trace_id !== undefined &&
673
685
  data.dotted_order !== undefined) {
674
- if (run.end_time !== undefined && data.parent_run_id === undefined) {
686
+ if (run.end_time !== undefined &&
687
+ data.parent_run_id === undefined &&
688
+ this.blockOnRootRunFinalization) {
675
689
  // Trigger a batch as soon as a root trace ends and block to ensure trace finishes
676
690
  // in serverless environments.
677
691
  await this.processRunOperation({ action: "update", item: data }, true);
@@ -2629,4 +2643,28 @@ export class Client {
2629
2643
  throw new Error(`Invalid public ${kind} URL or token: ${urlOrToken}`);
2630
2644
  }
2631
2645
  }
2646
+ /**
2647
+ * Awaits all pending trace batches. Useful for environments where
2648
+ * you need to be sure that all tracing requests finish before execution ends,
2649
+ * such as serverless environments.
2650
+ *
2651
+ * @example
2652
+ * ```
2653
+ * import { Client } from "langsmith";
2654
+ *
2655
+ * const client = new Client();
2656
+ *
2657
+ * try {
2658
+ * // Tracing happens here
2659
+ * ...
2660
+ * } finally {
2661
+ * await client.awaitPendingTraceBatches();
2662
+ * }
2663
+ * ```
2664
+ *
2665
+ * @returns A promise that resolves once all currently pending traces have sent.
2666
+ */
2667
+ awaitPendingTraceBatches() {
2668
+ return Promise.all(this.autoBatchQueue.items.map(([, , promise]) => promise));
2669
+ }
2632
2670
  }
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.1.61";
11
+ exports.__version__ = "0.1.63";
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { Client, type ClientConfig } from "./client.js";
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.1.61";
5
+ export declare const __version__ = "0.1.63";
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.1.61";
5
+ export const __version__ = "0.1.63";
@@ -142,52 +142,102 @@ const wrapOpenAI = (openai, options) => {
142
142
  (0, traceable_js_1.isTraceableFunction)(openai.completions.create)) {
143
143
  throw new Error("This instance of OpenAI client has been already wrapped once.");
144
144
  }
145
- openai.chat.completions.create = (0, traceable_js_1.traceable)(openai.chat.completions.create.bind(openai.chat.completions), {
146
- name: "ChatOpenAI",
147
- run_type: "llm",
148
- aggregator: chatAggregator,
149
- argsConfigPath: [1, "langsmithExtra"],
150
- getInvocationParams: (payload) => {
151
- if (typeof payload !== "object" || payload == null)
152
- return undefined;
153
- // we can safely do so, as the types are not exported in TSC
154
- const params = payload;
155
- const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
156
- undefined;
157
- return {
158
- ls_provider: "openai",
159
- ls_model_type: "chat",
160
- ls_model_name: params.model,
161
- ls_max_tokens: params.max_tokens ?? undefined,
162
- ls_temperature: params.temperature ?? undefined,
163
- ls_stop,
164
- };
165
- },
166
- ...options,
167
- });
168
- openai.completions.create = (0, traceable_js_1.traceable)(openai.completions.create.bind(openai.completions), {
169
- name: "OpenAI",
170
- run_type: "llm",
171
- aggregator: textAggregator,
172
- argsConfigPath: [1, "langsmithExtra"],
173
- getInvocationParams: (payload) => {
174
- if (typeof payload !== "object" || payload == null)
175
- return undefined;
176
- // we can safely do so, as the types are not exported in TSC
177
- const params = payload;
178
- const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
179
- undefined;
180
- return {
181
- ls_provider: "openai",
182
- ls_model_type: "llm",
183
- ls_model_name: params.model,
184
- ls_max_tokens: params.max_tokens ?? undefined,
185
- ls_temperature: params.temperature ?? undefined,
186
- ls_stop,
187
- };
145
+ // Some internal OpenAI methods call each other, so we need to preserve original
146
+ // OpenAI methods.
147
+ const tracedOpenAIClient = { ...openai };
148
+ if (openai.beta &&
149
+ openai.beta.chat &&
150
+ openai.beta.chat.completions &&
151
+ typeof openai.beta.chat.completions.parse === "function") {
152
+ tracedOpenAIClient.beta = {
153
+ ...openai.beta,
154
+ chat: {
155
+ ...openai.beta.chat,
156
+ completions: {
157
+ ...openai.beta.chat.completions,
158
+ parse: (0, traceable_js_1.traceable)(openai.beta.chat.completions.parse.bind(openai.beta.chat.completions), {
159
+ name: "ChatOpenAI",
160
+ run_type: "llm",
161
+ aggregator: chatAggregator,
162
+ argsConfigPath: [1, "langsmithExtra"],
163
+ getInvocationParams: (payload) => {
164
+ if (typeof payload !== "object" || payload == null)
165
+ return undefined;
166
+ // we can safely do so, as the types are not exported in TSC
167
+ const params = payload;
168
+ const ls_stop = (typeof params.stop === "string"
169
+ ? [params.stop]
170
+ : params.stop) ?? undefined;
171
+ return {
172
+ ls_provider: "openai",
173
+ ls_model_type: "chat",
174
+ ls_model_name: params.model,
175
+ ls_max_tokens: params.max_tokens ?? undefined,
176
+ ls_temperature: params.temperature ?? undefined,
177
+ ls_stop,
178
+ };
179
+ },
180
+ ...options,
181
+ }),
182
+ },
183
+ },
184
+ };
185
+ }
186
+ tracedOpenAIClient.chat = {
187
+ ...openai.chat,
188
+ completions: {
189
+ ...openai.chat.completions,
190
+ create: (0, traceable_js_1.traceable)(openai.chat.completions.create.bind(openai.chat.completions), {
191
+ name: "ChatOpenAI",
192
+ run_type: "llm",
193
+ aggregator: chatAggregator,
194
+ argsConfigPath: [1, "langsmithExtra"],
195
+ getInvocationParams: (payload) => {
196
+ if (typeof payload !== "object" || payload == null)
197
+ return undefined;
198
+ // we can safely do so, as the types are not exported in TSC
199
+ const params = payload;
200
+ const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
201
+ undefined;
202
+ return {
203
+ ls_provider: "openai",
204
+ ls_model_type: "chat",
205
+ ls_model_name: params.model,
206
+ ls_max_tokens: params.max_tokens ?? undefined,
207
+ ls_temperature: params.temperature ?? undefined,
208
+ ls_stop,
209
+ };
210
+ },
211
+ ...options,
212
+ }),
188
213
  },
189
- ...options,
190
- });
191
- return openai;
214
+ };
215
+ tracedOpenAIClient.completions = {
216
+ ...openai.completions,
217
+ create: (0, traceable_js_1.traceable)(openai.completions.create.bind(openai.completions), {
218
+ name: "OpenAI",
219
+ run_type: "llm",
220
+ aggregator: textAggregator,
221
+ argsConfigPath: [1, "langsmithExtra"],
222
+ getInvocationParams: (payload) => {
223
+ if (typeof payload !== "object" || payload == null)
224
+ return undefined;
225
+ // we can safely do so, as the types are not exported in TSC
226
+ const params = payload;
227
+ const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
228
+ undefined;
229
+ return {
230
+ ls_provider: "openai",
231
+ ls_model_type: "llm",
232
+ ls_model_name: params.model,
233
+ ls_max_tokens: params.max_tokens ?? undefined,
234
+ ls_temperature: params.temperature ?? undefined,
235
+ ls_stop,
236
+ };
237
+ },
238
+ ...options,
239
+ }),
240
+ };
241
+ return tracedOpenAIClient;
192
242
  };
193
243
  exports.wrapOpenAI = wrapOpenAI;
@@ -2,6 +2,13 @@ import { OpenAI } from "openai";
2
2
  import type { APIPromise } from "openai/core";
3
3
  import type { RunTreeConfig } from "../index.js";
4
4
  type OpenAIType = {
5
+ beta?: {
6
+ chat?: {
7
+ completions?: {
8
+ parse?: (...args: any[]) => any;
9
+ };
10
+ };
11
+ };
5
12
  chat: {
6
13
  completions: {
7
14
  create: (...args: any[]) => any;
@@ -139,51 +139,101 @@ export const wrapOpenAI = (openai, options) => {
139
139
  isTraceableFunction(openai.completions.create)) {
140
140
  throw new Error("This instance of OpenAI client has been already wrapped once.");
141
141
  }
142
- openai.chat.completions.create = traceable(openai.chat.completions.create.bind(openai.chat.completions), {
143
- name: "ChatOpenAI",
144
- run_type: "llm",
145
- aggregator: chatAggregator,
146
- argsConfigPath: [1, "langsmithExtra"],
147
- getInvocationParams: (payload) => {
148
- if (typeof payload !== "object" || payload == null)
149
- return undefined;
150
- // we can safely do so, as the types are not exported in TSC
151
- const params = payload;
152
- const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
153
- undefined;
154
- return {
155
- ls_provider: "openai",
156
- ls_model_type: "chat",
157
- ls_model_name: params.model,
158
- ls_max_tokens: params.max_tokens ?? undefined,
159
- ls_temperature: params.temperature ?? undefined,
160
- ls_stop,
161
- };
162
- },
163
- ...options,
164
- });
165
- openai.completions.create = traceable(openai.completions.create.bind(openai.completions), {
166
- name: "OpenAI",
167
- run_type: "llm",
168
- aggregator: textAggregator,
169
- argsConfigPath: [1, "langsmithExtra"],
170
- getInvocationParams: (payload) => {
171
- if (typeof payload !== "object" || payload == null)
172
- return undefined;
173
- // we can safely do so, as the types are not exported in TSC
174
- const params = payload;
175
- const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
176
- undefined;
177
- return {
178
- ls_provider: "openai",
179
- ls_model_type: "llm",
180
- ls_model_name: params.model,
181
- ls_max_tokens: params.max_tokens ?? undefined,
182
- ls_temperature: params.temperature ?? undefined,
183
- ls_stop,
184
- };
142
+ // Some internal OpenAI methods call each other, so we need to preserve original
143
+ // OpenAI methods.
144
+ const tracedOpenAIClient = { ...openai };
145
+ if (openai.beta &&
146
+ openai.beta.chat &&
147
+ openai.beta.chat.completions &&
148
+ typeof openai.beta.chat.completions.parse === "function") {
149
+ tracedOpenAIClient.beta = {
150
+ ...openai.beta,
151
+ chat: {
152
+ ...openai.beta.chat,
153
+ completions: {
154
+ ...openai.beta.chat.completions,
155
+ parse: traceable(openai.beta.chat.completions.parse.bind(openai.beta.chat.completions), {
156
+ name: "ChatOpenAI",
157
+ run_type: "llm",
158
+ aggregator: chatAggregator,
159
+ argsConfigPath: [1, "langsmithExtra"],
160
+ getInvocationParams: (payload) => {
161
+ if (typeof payload !== "object" || payload == null)
162
+ return undefined;
163
+ // we can safely do so, as the types are not exported in TSC
164
+ const params = payload;
165
+ const ls_stop = (typeof params.stop === "string"
166
+ ? [params.stop]
167
+ : params.stop) ?? undefined;
168
+ return {
169
+ ls_provider: "openai",
170
+ ls_model_type: "chat",
171
+ ls_model_name: params.model,
172
+ ls_max_tokens: params.max_tokens ?? undefined,
173
+ ls_temperature: params.temperature ?? undefined,
174
+ ls_stop,
175
+ };
176
+ },
177
+ ...options,
178
+ }),
179
+ },
180
+ },
181
+ };
182
+ }
183
+ tracedOpenAIClient.chat = {
184
+ ...openai.chat,
185
+ completions: {
186
+ ...openai.chat.completions,
187
+ create: traceable(openai.chat.completions.create.bind(openai.chat.completions), {
188
+ name: "ChatOpenAI",
189
+ run_type: "llm",
190
+ aggregator: chatAggregator,
191
+ argsConfigPath: [1, "langsmithExtra"],
192
+ getInvocationParams: (payload) => {
193
+ if (typeof payload !== "object" || payload == null)
194
+ return undefined;
195
+ // we can safely do so, as the types are not exported in TSC
196
+ const params = payload;
197
+ const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
198
+ undefined;
199
+ return {
200
+ ls_provider: "openai",
201
+ ls_model_type: "chat",
202
+ ls_model_name: params.model,
203
+ ls_max_tokens: params.max_tokens ?? undefined,
204
+ ls_temperature: params.temperature ?? undefined,
205
+ ls_stop,
206
+ };
207
+ },
208
+ ...options,
209
+ }),
185
210
  },
186
- ...options,
187
- });
188
- return openai;
211
+ };
212
+ tracedOpenAIClient.completions = {
213
+ ...openai.completions,
214
+ create: traceable(openai.completions.create.bind(openai.completions), {
215
+ name: "OpenAI",
216
+ run_type: "llm",
217
+ aggregator: textAggregator,
218
+ argsConfigPath: [1, "langsmithExtra"],
219
+ getInvocationParams: (payload) => {
220
+ if (typeof payload !== "object" || payload == null)
221
+ return undefined;
222
+ // we can safely do so, as the types are not exported in TSC
223
+ const params = payload;
224
+ const ls_stop = (typeof params.stop === "string" ? [params.stop] : params.stop) ??
225
+ undefined;
226
+ return {
227
+ ls_provider: "openai",
228
+ ls_model_type: "llm",
229
+ ls_model_name: params.model,
230
+ ls_max_tokens: params.max_tokens ?? undefined,
231
+ ls_temperature: params.temperature ?? undefined,
232
+ ls_stop,
233
+ };
234
+ },
235
+ ...options,
236
+ }),
237
+ };
238
+ return tracedOpenAIClient;
189
239
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.1.61",
3
+ "version": "0.1.63",
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": [
@@ -127,7 +127,7 @@
127
127
  "eslint-plugin-prettier": "^4.2.1",
128
128
  "jest": "^29.5.0",
129
129
  "langchain": "^0.3.2",
130
- "openai": "^4.38.5",
130
+ "openai": "^4.67.3",
131
131
  "prettier": "^2.8.8",
132
132
  "ts-jest": "^29.1.0",
133
133
  "ts-node": "^10.9.1",