langsmith 0.0.66 → 0.0.68

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
@@ -29,6 +29,40 @@ const async_caller_js_1 = require("./utils/async_caller.cjs");
29
29
  const messages_js_1 = require("./utils/messages.cjs");
30
30
  const env_js_1 = require("./utils/env.cjs");
31
31
  const index_js_1 = require("./index.cjs");
32
+ async function mergeRuntimeEnvIntoRunCreates(runs) {
33
+ const runtimeEnv = await (0, env_js_1.getRuntimeEnvironment)();
34
+ const envVars = (0, env_js_1.getLangChainEnvVarsMetadata)();
35
+ return runs.map((run) => {
36
+ const extra = run.extra ?? {};
37
+ const metadata = extra.metadata;
38
+ run.extra = {
39
+ ...extra,
40
+ runtime: {
41
+ ...runtimeEnv,
42
+ ...extra?.runtime,
43
+ },
44
+ metadata: {
45
+ ...envVars,
46
+ ...(envVars.revision_id || run.revision_id
47
+ ? { revision_id: run.revision_id ?? envVars.revision_id }
48
+ : {}),
49
+ ...metadata,
50
+ },
51
+ };
52
+ return run;
53
+ });
54
+ }
55
+ const getTracingSamplingRate = () => {
56
+ const samplingRateStr = (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_TRACING_SAMPLING_RATE");
57
+ if (samplingRateStr === undefined) {
58
+ return undefined;
59
+ }
60
+ const samplingRate = parseFloat(samplingRateStr);
61
+ if (samplingRate < 0 || samplingRate > 1) {
62
+ throw new Error(`LANGCHAIN_TRACING_SAMPLING_RATE must be between 0 and 1 if set. Got: ${samplingRate}`);
63
+ }
64
+ return samplingRate;
65
+ };
32
66
  // utility functions
33
67
  const isLocalhost = (url) => {
34
68
  const strippedUrl = url.replace("http://", "").replace("https://", "");
@@ -114,7 +148,56 @@ class Client {
114
148
  writable: true,
115
149
  value: void 0
116
150
  });
151
+ Object.defineProperty(this, "tracingSampleRate", {
152
+ enumerable: true,
153
+ configurable: true,
154
+ writable: true,
155
+ value: void 0
156
+ });
157
+ Object.defineProperty(this, "sampledPostUuids", {
158
+ enumerable: true,
159
+ configurable: true,
160
+ writable: true,
161
+ value: new Set()
162
+ });
163
+ Object.defineProperty(this, "autoBatchTracing", {
164
+ enumerable: true,
165
+ configurable: true,
166
+ writable: true,
167
+ value: false
168
+ });
169
+ Object.defineProperty(this, "pendingAutoBatchedRuns", {
170
+ enumerable: true,
171
+ configurable: true,
172
+ writable: true,
173
+ value: []
174
+ });
175
+ Object.defineProperty(this, "pendingAutoBatchedRunLimit", {
176
+ enumerable: true,
177
+ configurable: true,
178
+ writable: true,
179
+ value: 100
180
+ });
181
+ Object.defineProperty(this, "autoBatchTimeout", {
182
+ enumerable: true,
183
+ configurable: true,
184
+ writable: true,
185
+ value: void 0
186
+ });
187
+ Object.defineProperty(this, "autoBatchInitialDelayMs", {
188
+ enumerable: true,
189
+ configurable: true,
190
+ writable: true,
191
+ value: 250
192
+ });
193
+ Object.defineProperty(this, "autoBatchAggregationDelayMs", {
194
+ enumerable: true,
195
+ configurable: true,
196
+ writable: true,
197
+ value: 50
198
+ });
117
199
  const defaultConfig = Client.getDefaultClientConfig();
200
+ this.tracingSampleRate = getTracingSamplingRate();
118
201
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
119
202
  this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
120
203
  this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
@@ -123,6 +206,9 @@ class Client {
123
206
  this.caller = new async_caller_js_1.AsyncCaller(config.callerOptions ?? {});
124
207
  this.hideInputs = config.hideInputs ?? defaultConfig.hideInputs;
125
208
  this.hideOutputs = config.hideOutputs ?? defaultConfig.hideOutputs;
209
+ this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
210
+ this.pendingAutoBatchedRunLimit =
211
+ config.pendingAutoBatchedRunLimit ?? this.pendingAutoBatchedRunLimit;
126
212
  }
127
213
  static getDefaultClientConfig() {
128
214
  const apiKey = (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_API_KEY");
@@ -187,6 +273,16 @@ class Client {
187
273
  }
188
274
  return outputs;
189
275
  }
276
+ prepareRunCreateOrUpdateInputs(run) {
277
+ const runParams = { ...run };
278
+ if (runParams.inputs !== undefined) {
279
+ runParams.inputs = this.processInputs(runParams.inputs);
280
+ }
281
+ if (runParams.outputs !== undefined) {
282
+ runParams.outputs = this.processOutputs(runParams.outputs);
283
+ }
284
+ return runParams;
285
+ }
190
286
  async _getResponse(path, queryParams) {
191
287
  const paramsString = queryParams?.toString() ?? "";
192
288
  const url = `${this.apiUrl}${path}?${paramsString}`;
@@ -257,45 +353,157 @@ class Client {
257
353
  bodyParams.cursor = cursors.next;
258
354
  }
259
355
  }
356
+ _filterForSampling(runs, patch = false) {
357
+ if (this.tracingSampleRate === undefined) {
358
+ return runs;
359
+ }
360
+ if (patch) {
361
+ const sampled = [];
362
+ for (const run of runs) {
363
+ if (this.sampledPostUuids.has(run.id)) {
364
+ sampled.push(run);
365
+ this.sampledPostUuids.delete(run.id);
366
+ }
367
+ }
368
+ return sampled;
369
+ }
370
+ else {
371
+ const sampled = [];
372
+ for (const run of runs) {
373
+ if (Math.random() < this.tracingSampleRate) {
374
+ sampled.push(run);
375
+ this.sampledPostUuids.add(run.id);
376
+ }
377
+ }
378
+ return sampled;
379
+ }
380
+ }
381
+ async triggerAutoBatchSend(runs) {
382
+ let batch = runs;
383
+ if (batch === undefined) {
384
+ batch = this.pendingAutoBatchedRuns.slice(0, this.pendingAutoBatchedRunLimit);
385
+ this.pendingAutoBatchedRuns = this.pendingAutoBatchedRuns.slice(this.pendingAutoBatchedRunLimit);
386
+ }
387
+ await this.batchIngestRuns({
388
+ runCreates: batch
389
+ .filter((item) => item.action === "create")
390
+ .map((item) => item.item),
391
+ runUpdates: batch
392
+ .filter((item) => item.action === "update")
393
+ .map((item) => item.item),
394
+ });
395
+ }
396
+ appendRunCreateToAutoBatchQueue(item) {
397
+ const oldTimeout = this.autoBatchTimeout;
398
+ clearTimeout(this.autoBatchTimeout);
399
+ this.autoBatchTimeout = undefined;
400
+ this.pendingAutoBatchedRuns.push(item);
401
+ while (this.pendingAutoBatchedRuns.length >= this.pendingAutoBatchedRunLimit) {
402
+ const batch = this.pendingAutoBatchedRuns.slice(0, this.pendingAutoBatchedRunLimit);
403
+ this.pendingAutoBatchedRuns = this.pendingAutoBatchedRuns.slice(this.pendingAutoBatchedRunLimit);
404
+ void this.triggerAutoBatchSend(batch);
405
+ }
406
+ if (this.pendingAutoBatchedRuns.length > 0) {
407
+ if (!oldTimeout) {
408
+ this.autoBatchTimeout = setTimeout(() => {
409
+ this.autoBatchTimeout = undefined;
410
+ void this.triggerAutoBatchSend();
411
+ }, this.autoBatchInitialDelayMs);
412
+ }
413
+ else {
414
+ this.autoBatchTimeout = setTimeout(() => {
415
+ this.autoBatchTimeout = undefined;
416
+ void this.triggerAutoBatchSend();
417
+ }, this.autoBatchAggregationDelayMs);
418
+ }
419
+ }
420
+ }
260
421
  async createRun(run) {
422
+ if (!this._filterForSampling([run]).length) {
423
+ return;
424
+ }
261
425
  const headers = { ...this.headers, "Content-Type": "application/json" };
262
- const extra = run.extra ?? {};
263
- const metadata = extra.metadata;
264
- const runtimeEnv = await (0, env_js_1.getRuntimeEnvironment)();
265
- const envVars = (0, env_js_1.getLangChainEnvVarsMetadata)();
266
426
  const session_name = run.project_name;
267
427
  delete run.project_name;
268
- const runCreate = {
428
+ const runCreate = this.prepareRunCreateOrUpdateInputs({
269
429
  session_name,
270
430
  ...run,
271
- extra: {
272
- ...run.extra,
273
- runtime: {
274
- ...runtimeEnv,
275
- ...extra.runtime,
276
- },
277
- metadata: {
278
- ...envVars,
279
- ...(envVars.revision_id || run.revision_id
280
- ? { revision_id: run.revision_id ?? envVars.revision_id }
281
- : {}),
282
- ...metadata,
283
- },
284
- },
285
- };
286
- runCreate.inputs = this.processInputs(runCreate.inputs);
287
- if (runCreate.outputs) {
288
- runCreate.outputs = this.processOutputs(runCreate.outputs);
431
+ start_time: run.start_time ?? Date.now(),
432
+ });
433
+ if (this.autoBatchTracing &&
434
+ runCreate.trace_id !== undefined &&
435
+ runCreate.dotted_order !== undefined) {
436
+ this.appendRunCreateToAutoBatchQueue({
437
+ action: "create",
438
+ item: runCreate,
439
+ });
440
+ return;
289
441
  }
290
- runCreate.start_time = run.start_time ?? Date.now();
442
+ const mergedRunCreateParams = await mergeRuntimeEnvIntoRunCreates([
443
+ runCreate,
444
+ ]);
291
445
  const response = await this.caller.call(fetch, `${this.apiUrl}/runs`, {
292
446
  method: "POST",
293
447
  headers,
294
- body: JSON.stringify(runCreate),
448
+ body: JSON.stringify(mergedRunCreateParams[0]),
295
449
  signal: AbortSignal.timeout(this.timeout_ms),
296
450
  });
297
451
  await raiseForStatus(response, "create run");
298
452
  }
453
+ /**
454
+ * Batch ingest/upsert multiple runs in the Langsmith system.
455
+ * @param runs
456
+ */
457
+ async batchIngestRuns({ runCreates, runUpdates, }) {
458
+ if (runCreates === undefined && runUpdates === undefined) {
459
+ return;
460
+ }
461
+ let preparedCreateParams = runCreates?.map((create) => this.prepareRunCreateOrUpdateInputs(create)) ?? [];
462
+ let preparedUpdateParams = runUpdates?.map((update) => this.prepareRunCreateOrUpdateInputs(update)) ?? [];
463
+ if (preparedCreateParams.length > 0 && preparedUpdateParams.length > 0) {
464
+ const createById = preparedCreateParams.reduce((params, run) => {
465
+ if (!run.id) {
466
+ return params;
467
+ }
468
+ params[run.id] = run;
469
+ return params;
470
+ }, {});
471
+ const standaloneUpdates = [];
472
+ for (const updateParam of preparedUpdateParams) {
473
+ if (updateParam.id !== undefined && createById[updateParam.id]) {
474
+ createById[updateParam.id] = {
475
+ ...createById[updateParam.id],
476
+ ...updateParam,
477
+ };
478
+ }
479
+ else {
480
+ standaloneUpdates.push(updateParam);
481
+ }
482
+ }
483
+ preparedCreateParams = Object.values(createById);
484
+ preparedUpdateParams = standaloneUpdates;
485
+ }
486
+ const body = {
487
+ post: this._filterForSampling(preparedCreateParams),
488
+ patch: this._filterForSampling(preparedUpdateParams, true),
489
+ };
490
+ if (!body.post.length && !body.patch.length) {
491
+ return;
492
+ }
493
+ preparedCreateParams = await mergeRuntimeEnvIntoRunCreates(preparedCreateParams);
494
+ const headers = {
495
+ ...this.headers,
496
+ "Content-Type": "application/json",
497
+ Accept: "application/json",
498
+ };
499
+ const response = await this.caller.call(fetch, `${this.apiUrl}/runs/batch`, {
500
+ method: "POST",
501
+ headers,
502
+ body: JSON.stringify(body),
503
+ signal: AbortSignal.timeout(this.timeout_ms),
504
+ });
505
+ await raiseForStatus(response, "batch create run");
506
+ }
299
507
  async updateRun(runId, run) {
300
508
  assertUuid(runId);
301
509
  if (run.inputs) {
@@ -304,6 +512,17 @@ class Client {
304
512
  if (run.outputs) {
305
513
  run.outputs = this.processOutputs(run.outputs);
306
514
  }
515
+ // TODO: Untangle types
516
+ const data = { ...run, id: runId };
517
+ if (!this._filterForSampling([data], true).length) {
518
+ return;
519
+ }
520
+ if (this.autoBatchTracing &&
521
+ data.trace_id !== undefined &&
522
+ data.dotted_order !== undefined) {
523
+ this.appendRunCreateToAutoBatchQueue({ action: "update", item: data });
524
+ return;
525
+ }
307
526
  const headers = { ...this.headers, "Content-Type": "application/json" };
308
527
  const response = await this.caller.call(fetch, `${this.apiUrl}/runs/${runId}`, {
309
528
  method: "PATCH",
@@ -572,7 +791,7 @@ class Client {
572
791
  }
573
792
  return result;
574
793
  }
575
- async readProject({ projectId, projectName, }) {
794
+ async readProject({ projectId, projectName, includeStats, }) {
576
795
  let path = "/sessions";
577
796
  const params = new URLSearchParams();
578
797
  if (projectId !== undefined && projectName !== undefined) {
@@ -588,6 +807,9 @@ class Client {
588
807
  else {
589
808
  throw new Error("Must provide projectName or projectId");
590
809
  }
810
+ if (includeStats !== undefined) {
811
+ params.append("include_stats", includeStats.toString());
812
+ }
591
813
  const response = await this._get(path, params);
592
814
  let result;
593
815
  if (Array.isArray(response)) {
package/dist/client.d.ts CHANGED
@@ -9,6 +9,8 @@ interface ClientConfig {
9
9
  webUrl?: string;
10
10
  hideInputs?: boolean;
11
11
  hideOutputs?: boolean;
12
+ autoBatchTracing?: boolean;
13
+ pendingAutoBatchedRunLimit?: number;
12
14
  }
13
15
  interface ListRunsParams {
14
16
  projectId?: string;
@@ -49,8 +51,10 @@ interface CreateRunParams {
49
51
  parent_run_id?: string;
50
52
  project_name?: string;
51
53
  revision_id?: string;
54
+ trace_id?: string;
55
+ dotted_order?: string;
52
56
  }
53
- interface projectOptions {
57
+ interface ProjectOptions {
54
58
  projectName?: string;
55
59
  projectId?: string;
56
60
  }
@@ -70,6 +74,14 @@ export declare class Client {
70
74
  private _tenantId;
71
75
  private hideInputs?;
72
76
  private hideOutputs?;
77
+ private tracingSampleRate?;
78
+ private sampledPostUuids;
79
+ private autoBatchTracing;
80
+ private pendingAutoBatchedRuns;
81
+ private pendingAutoBatchedRunLimit;
82
+ private autoBatchTimeout;
83
+ private autoBatchInitialDelayMs;
84
+ private autoBatchAggregationDelayMs;
73
85
  constructor(config?: ClientConfig);
74
86
  static getDefaultClientConfig(): {
75
87
  apiUrl: string;
@@ -83,11 +95,23 @@ export declare class Client {
83
95
  private get headers();
84
96
  private processInputs;
85
97
  private processOutputs;
98
+ private prepareRunCreateOrUpdateInputs;
86
99
  private _getResponse;
87
100
  private _get;
88
101
  private _getPaginated;
89
102
  private _getCursorPaginatedList;
103
+ private _filterForSampling;
104
+ private triggerAutoBatchSend;
105
+ private appendRunCreateToAutoBatchQueue;
90
106
  createRun(run: CreateRunParams): Promise<void>;
107
+ /**
108
+ * Batch ingest/upsert multiple runs in the Langsmith system.
109
+ * @param runs
110
+ */
111
+ batchIngestRuns({ runCreates, runUpdates, }: {
112
+ runCreates?: RunCreate[];
113
+ runUpdates?: RunUpdate[];
114
+ }): Promise<void>;
91
115
  updateRun(runId: string, run: RunUpdate): Promise<void>;
92
116
  readRun(runId: string, { loadChildRuns }?: {
93
117
  loadChildRuns: boolean;
@@ -95,7 +119,7 @@ export declare class Client {
95
119
  getRunUrl({ runId, run, projectOpts, }: {
96
120
  runId?: string;
97
121
  run?: Run;
98
- projectOpts?: projectOptions;
122
+ projectOpts?: ProjectOptions;
99
123
  }): Promise<string>;
100
124
  private _loadChildRuns;
101
125
  listRuns({ projectId, projectName, parentRunId, referenceExampleId, startTime, executionOrder, runType, error, id, query, filter, limit, }: ListRunsParams): AsyncIterable<Run>;
@@ -126,9 +150,10 @@ export declare class Client {
126
150
  projectExtra?: Record<string, any> | null;
127
151
  endTime?: string | null;
128
152
  }): Promise<TracerSession>;
129
- readProject({ projectId, projectName, }: {
153
+ readProject({ projectId, projectName, includeStats, }: {
130
154
  projectId?: string;
131
155
  projectName?: string;
156
+ includeStats?: boolean;
132
157
  }): Promise<TracerSessionResult>;
133
158
  private _getTenantId;
134
159
  listProjects({ projectIds, name, nameContains, referenceDatasetId, referenceDatasetName, referenceFree, }?: {
package/dist/client.js CHANGED
@@ -3,6 +3,40 @@ import { AsyncCaller } from "./utils/async_caller.js";
3
3
  import { convertLangChainMessageToExample, isLangChainMessage, } from "./utils/messages.js";
4
4
  import { getEnvironmentVariable, getLangChainEnvVarsMetadata, getRuntimeEnvironment, } from "./utils/env.js";
5
5
  import { __version__ } from "./index.js";
6
+ async function mergeRuntimeEnvIntoRunCreates(runs) {
7
+ const runtimeEnv = await getRuntimeEnvironment();
8
+ const envVars = getLangChainEnvVarsMetadata();
9
+ return runs.map((run) => {
10
+ const extra = run.extra ?? {};
11
+ const metadata = extra.metadata;
12
+ run.extra = {
13
+ ...extra,
14
+ runtime: {
15
+ ...runtimeEnv,
16
+ ...extra?.runtime,
17
+ },
18
+ metadata: {
19
+ ...envVars,
20
+ ...(envVars.revision_id || run.revision_id
21
+ ? { revision_id: run.revision_id ?? envVars.revision_id }
22
+ : {}),
23
+ ...metadata,
24
+ },
25
+ };
26
+ return run;
27
+ });
28
+ }
29
+ const getTracingSamplingRate = () => {
30
+ const samplingRateStr = getEnvironmentVariable("LANGCHAIN_TRACING_SAMPLING_RATE");
31
+ if (samplingRateStr === undefined) {
32
+ return undefined;
33
+ }
34
+ const samplingRate = parseFloat(samplingRateStr);
35
+ if (samplingRate < 0 || samplingRate > 1) {
36
+ throw new Error(`LANGCHAIN_TRACING_SAMPLING_RATE must be between 0 and 1 if set. Got: ${samplingRate}`);
37
+ }
38
+ return samplingRate;
39
+ };
6
40
  // utility functions
7
41
  const isLocalhost = (url) => {
8
42
  const strippedUrl = url.replace("http://", "").replace("https://", "");
@@ -88,7 +122,56 @@ export class Client {
88
122
  writable: true,
89
123
  value: void 0
90
124
  });
125
+ Object.defineProperty(this, "tracingSampleRate", {
126
+ enumerable: true,
127
+ configurable: true,
128
+ writable: true,
129
+ value: void 0
130
+ });
131
+ Object.defineProperty(this, "sampledPostUuids", {
132
+ enumerable: true,
133
+ configurable: true,
134
+ writable: true,
135
+ value: new Set()
136
+ });
137
+ Object.defineProperty(this, "autoBatchTracing", {
138
+ enumerable: true,
139
+ configurable: true,
140
+ writable: true,
141
+ value: false
142
+ });
143
+ Object.defineProperty(this, "pendingAutoBatchedRuns", {
144
+ enumerable: true,
145
+ configurable: true,
146
+ writable: true,
147
+ value: []
148
+ });
149
+ Object.defineProperty(this, "pendingAutoBatchedRunLimit", {
150
+ enumerable: true,
151
+ configurable: true,
152
+ writable: true,
153
+ value: 100
154
+ });
155
+ Object.defineProperty(this, "autoBatchTimeout", {
156
+ enumerable: true,
157
+ configurable: true,
158
+ writable: true,
159
+ value: void 0
160
+ });
161
+ Object.defineProperty(this, "autoBatchInitialDelayMs", {
162
+ enumerable: true,
163
+ configurable: true,
164
+ writable: true,
165
+ value: 250
166
+ });
167
+ Object.defineProperty(this, "autoBatchAggregationDelayMs", {
168
+ enumerable: true,
169
+ configurable: true,
170
+ writable: true,
171
+ value: 50
172
+ });
91
173
  const defaultConfig = Client.getDefaultClientConfig();
174
+ this.tracingSampleRate = getTracingSamplingRate();
92
175
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
93
176
  this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
94
177
  this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
@@ -97,6 +180,9 @@ export class Client {
97
180
  this.caller = new AsyncCaller(config.callerOptions ?? {});
98
181
  this.hideInputs = config.hideInputs ?? defaultConfig.hideInputs;
99
182
  this.hideOutputs = config.hideOutputs ?? defaultConfig.hideOutputs;
183
+ this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
184
+ this.pendingAutoBatchedRunLimit =
185
+ config.pendingAutoBatchedRunLimit ?? this.pendingAutoBatchedRunLimit;
100
186
  }
101
187
  static getDefaultClientConfig() {
102
188
  const apiKey = getEnvironmentVariable("LANGCHAIN_API_KEY");
@@ -161,6 +247,16 @@ export class Client {
161
247
  }
162
248
  return outputs;
163
249
  }
250
+ prepareRunCreateOrUpdateInputs(run) {
251
+ const runParams = { ...run };
252
+ if (runParams.inputs !== undefined) {
253
+ runParams.inputs = this.processInputs(runParams.inputs);
254
+ }
255
+ if (runParams.outputs !== undefined) {
256
+ runParams.outputs = this.processOutputs(runParams.outputs);
257
+ }
258
+ return runParams;
259
+ }
164
260
  async _getResponse(path, queryParams) {
165
261
  const paramsString = queryParams?.toString() ?? "";
166
262
  const url = `${this.apiUrl}${path}?${paramsString}`;
@@ -231,45 +327,157 @@ export class Client {
231
327
  bodyParams.cursor = cursors.next;
232
328
  }
233
329
  }
330
+ _filterForSampling(runs, patch = false) {
331
+ if (this.tracingSampleRate === undefined) {
332
+ return runs;
333
+ }
334
+ if (patch) {
335
+ const sampled = [];
336
+ for (const run of runs) {
337
+ if (this.sampledPostUuids.has(run.id)) {
338
+ sampled.push(run);
339
+ this.sampledPostUuids.delete(run.id);
340
+ }
341
+ }
342
+ return sampled;
343
+ }
344
+ else {
345
+ const sampled = [];
346
+ for (const run of runs) {
347
+ if (Math.random() < this.tracingSampleRate) {
348
+ sampled.push(run);
349
+ this.sampledPostUuids.add(run.id);
350
+ }
351
+ }
352
+ return sampled;
353
+ }
354
+ }
355
+ async triggerAutoBatchSend(runs) {
356
+ let batch = runs;
357
+ if (batch === undefined) {
358
+ batch = this.pendingAutoBatchedRuns.slice(0, this.pendingAutoBatchedRunLimit);
359
+ this.pendingAutoBatchedRuns = this.pendingAutoBatchedRuns.slice(this.pendingAutoBatchedRunLimit);
360
+ }
361
+ await this.batchIngestRuns({
362
+ runCreates: batch
363
+ .filter((item) => item.action === "create")
364
+ .map((item) => item.item),
365
+ runUpdates: batch
366
+ .filter((item) => item.action === "update")
367
+ .map((item) => item.item),
368
+ });
369
+ }
370
+ appendRunCreateToAutoBatchQueue(item) {
371
+ const oldTimeout = this.autoBatchTimeout;
372
+ clearTimeout(this.autoBatchTimeout);
373
+ this.autoBatchTimeout = undefined;
374
+ this.pendingAutoBatchedRuns.push(item);
375
+ while (this.pendingAutoBatchedRuns.length >= this.pendingAutoBatchedRunLimit) {
376
+ const batch = this.pendingAutoBatchedRuns.slice(0, this.pendingAutoBatchedRunLimit);
377
+ this.pendingAutoBatchedRuns = this.pendingAutoBatchedRuns.slice(this.pendingAutoBatchedRunLimit);
378
+ void this.triggerAutoBatchSend(batch);
379
+ }
380
+ if (this.pendingAutoBatchedRuns.length > 0) {
381
+ if (!oldTimeout) {
382
+ this.autoBatchTimeout = setTimeout(() => {
383
+ this.autoBatchTimeout = undefined;
384
+ void this.triggerAutoBatchSend();
385
+ }, this.autoBatchInitialDelayMs);
386
+ }
387
+ else {
388
+ this.autoBatchTimeout = setTimeout(() => {
389
+ this.autoBatchTimeout = undefined;
390
+ void this.triggerAutoBatchSend();
391
+ }, this.autoBatchAggregationDelayMs);
392
+ }
393
+ }
394
+ }
234
395
  async createRun(run) {
396
+ if (!this._filterForSampling([run]).length) {
397
+ return;
398
+ }
235
399
  const headers = { ...this.headers, "Content-Type": "application/json" };
236
- const extra = run.extra ?? {};
237
- const metadata = extra.metadata;
238
- const runtimeEnv = await getRuntimeEnvironment();
239
- const envVars = getLangChainEnvVarsMetadata();
240
400
  const session_name = run.project_name;
241
401
  delete run.project_name;
242
- const runCreate = {
402
+ const runCreate = this.prepareRunCreateOrUpdateInputs({
243
403
  session_name,
244
404
  ...run,
245
- extra: {
246
- ...run.extra,
247
- runtime: {
248
- ...runtimeEnv,
249
- ...extra.runtime,
250
- },
251
- metadata: {
252
- ...envVars,
253
- ...(envVars.revision_id || run.revision_id
254
- ? { revision_id: run.revision_id ?? envVars.revision_id }
255
- : {}),
256
- ...metadata,
257
- },
258
- },
259
- };
260
- runCreate.inputs = this.processInputs(runCreate.inputs);
261
- if (runCreate.outputs) {
262
- runCreate.outputs = this.processOutputs(runCreate.outputs);
405
+ start_time: run.start_time ?? Date.now(),
406
+ });
407
+ if (this.autoBatchTracing &&
408
+ runCreate.trace_id !== undefined &&
409
+ runCreate.dotted_order !== undefined) {
410
+ this.appendRunCreateToAutoBatchQueue({
411
+ action: "create",
412
+ item: runCreate,
413
+ });
414
+ return;
263
415
  }
264
- runCreate.start_time = run.start_time ?? Date.now();
416
+ const mergedRunCreateParams = await mergeRuntimeEnvIntoRunCreates([
417
+ runCreate,
418
+ ]);
265
419
  const response = await this.caller.call(fetch, `${this.apiUrl}/runs`, {
266
420
  method: "POST",
267
421
  headers,
268
- body: JSON.stringify(runCreate),
422
+ body: JSON.stringify(mergedRunCreateParams[0]),
269
423
  signal: AbortSignal.timeout(this.timeout_ms),
270
424
  });
271
425
  await raiseForStatus(response, "create run");
272
426
  }
427
+ /**
428
+ * Batch ingest/upsert multiple runs in the Langsmith system.
429
+ * @param runs
430
+ */
431
+ async batchIngestRuns({ runCreates, runUpdates, }) {
432
+ if (runCreates === undefined && runUpdates === undefined) {
433
+ return;
434
+ }
435
+ let preparedCreateParams = runCreates?.map((create) => this.prepareRunCreateOrUpdateInputs(create)) ?? [];
436
+ let preparedUpdateParams = runUpdates?.map((update) => this.prepareRunCreateOrUpdateInputs(update)) ?? [];
437
+ if (preparedCreateParams.length > 0 && preparedUpdateParams.length > 0) {
438
+ const createById = preparedCreateParams.reduce((params, run) => {
439
+ if (!run.id) {
440
+ return params;
441
+ }
442
+ params[run.id] = run;
443
+ return params;
444
+ }, {});
445
+ const standaloneUpdates = [];
446
+ for (const updateParam of preparedUpdateParams) {
447
+ if (updateParam.id !== undefined && createById[updateParam.id]) {
448
+ createById[updateParam.id] = {
449
+ ...createById[updateParam.id],
450
+ ...updateParam,
451
+ };
452
+ }
453
+ else {
454
+ standaloneUpdates.push(updateParam);
455
+ }
456
+ }
457
+ preparedCreateParams = Object.values(createById);
458
+ preparedUpdateParams = standaloneUpdates;
459
+ }
460
+ const body = {
461
+ post: this._filterForSampling(preparedCreateParams),
462
+ patch: this._filterForSampling(preparedUpdateParams, true),
463
+ };
464
+ if (!body.post.length && !body.patch.length) {
465
+ return;
466
+ }
467
+ preparedCreateParams = await mergeRuntimeEnvIntoRunCreates(preparedCreateParams);
468
+ const headers = {
469
+ ...this.headers,
470
+ "Content-Type": "application/json",
471
+ Accept: "application/json",
472
+ };
473
+ const response = await this.caller.call(fetch, `${this.apiUrl}/runs/batch`, {
474
+ method: "POST",
475
+ headers,
476
+ body: JSON.stringify(body),
477
+ signal: AbortSignal.timeout(this.timeout_ms),
478
+ });
479
+ await raiseForStatus(response, "batch create run");
480
+ }
273
481
  async updateRun(runId, run) {
274
482
  assertUuid(runId);
275
483
  if (run.inputs) {
@@ -278,6 +486,17 @@ export class Client {
278
486
  if (run.outputs) {
279
487
  run.outputs = this.processOutputs(run.outputs);
280
488
  }
489
+ // TODO: Untangle types
490
+ const data = { ...run, id: runId };
491
+ if (!this._filterForSampling([data], true).length) {
492
+ return;
493
+ }
494
+ if (this.autoBatchTracing &&
495
+ data.trace_id !== undefined &&
496
+ data.dotted_order !== undefined) {
497
+ this.appendRunCreateToAutoBatchQueue({ action: "update", item: data });
498
+ return;
499
+ }
281
500
  const headers = { ...this.headers, "Content-Type": "application/json" };
282
501
  const response = await this.caller.call(fetch, `${this.apiUrl}/runs/${runId}`, {
283
502
  method: "PATCH",
@@ -546,7 +765,7 @@ export class Client {
546
765
  }
547
766
  return result;
548
767
  }
549
- async readProject({ projectId, projectName, }) {
768
+ async readProject({ projectId, projectName, includeStats, }) {
550
769
  let path = "/sessions";
551
770
  const params = new URLSearchParams();
552
771
  if (projectId !== undefined && projectName !== undefined) {
@@ -562,6 +781,9 @@ export class Client {
562
781
  else {
563
782
  throw new Error("Must provide projectName or projectId");
564
783
  }
784
+ if (includeStats !== undefined) {
785
+ params.append("include_stats", includeStats.toString());
786
+ }
565
787
  const response = await this._get(path, params);
566
788
  let result;
567
789
  if (Array.isArray(response)) {
package/dist/index.cjs CHANGED
@@ -6,4 +6,4 @@ Object.defineProperty(exports, "Client", { enumerable: true, get: function () {
6
6
  var run_trees_js_1 = require("./run_trees.cjs");
7
7
  Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () { return run_trees_js_1.RunTree; } });
8
8
  // Update using yarn bump-version
9
- exports.__version__ = "0.0.66";
9
+ exports.__version__ = "0.0.68";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Client } from "./client.js";
2
2
  export { Dataset, Example, TracerSession, Run, Feedback } from "./schemas.js";
3
3
  export { RunTree, RunTreeConfig } from "./run_trees.js";
4
- export declare const __version__ = "0.0.66";
4
+ export declare const __version__ = "0.0.68";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Client } from "./client.js";
2
2
  export { RunTree } from "./run_trees.js";
3
3
  // Update using yarn bump-version
4
- export const __version__ = "0.0.66";
4
+ export const __version__ = "0.0.68";
package/dist/schemas.d.ts CHANGED
@@ -61,6 +61,21 @@ export interface BaseRun {
61
61
  parent_run_id?: string;
62
62
  /** Tags for further categorizing or annotating the run. */
63
63
  tags?: string[];
64
+ /** Unique ID assigned to every run within this nested trace. **/
65
+ trace_id?: string;
66
+ /**
67
+ * The dotted order for the run.
68
+ *
69
+ * This is a string composed of {time}{run-uuid}.* so that a trace can be
70
+ * sorted in the order it was executed.
71
+ *
72
+ * Example:
73
+ * - Parent: 20230914T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8
74
+ * - Children:
75
+ * - 20230914T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8.20230914T223155649Z809ed3a2-0172-4f4d-8a02-a64e9b7a0f8a
76
+ * - 20230915T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8.20230914T223155650Zc8d9f4c5-6c5a-4b2d-9b1c-3d9d7a7c5c7c
77
+ */
78
+ dotted_order?: string;
64
79
  }
65
80
  /**
66
81
  * Describes properties of a run when loaded from the database.
@@ -93,27 +108,14 @@ export interface Run extends BaseRun {
93
108
  first_token_time?: number;
94
109
  /** IDs of parent runs, if multiple exist. */
95
110
  parent_run_ids?: string[];
96
- /**Unique ID assigned to every run within this nested trace.**/
97
- trace_id?: string;
98
- /**
99
- * The dotted order for the run.
100
- *
101
- * This is a string composed of {time}{run-uuid}.* so that a trace can be
102
- * sorted in the order it was executed.
103
- *
104
- * Example:
105
- * - Parent: 20230914T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8
106
- * - Children:
107
- * - 20230914T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8.20230914T223155649Z809ed3a2-0172-4f4d-8a02-a64e9b7a0f8a
108
- * - 20230915T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8.20230914T223155650Zc8d9f4c5-6c5a-4b2d-9b1c-3d9d7a7c5c7c
109
- */
110
- dotted_order?: string;
111
111
  }
112
112
  export interface RunCreate extends BaseRun {
113
+ revision_id?: string;
113
114
  child_runs?: this[];
114
115
  session_name?: string;
115
116
  }
116
117
  export interface RunUpdate {
118
+ id?: string;
117
119
  end_time?: number;
118
120
  extra?: KVMap;
119
121
  error?: string;
@@ -123,6 +125,21 @@ export interface RunUpdate {
123
125
  reference_example_id?: string;
124
126
  events?: KVMap[];
125
127
  session_id?: string;
128
+ /** Unique ID assigned to every run within this nested trace. **/
129
+ trace_id?: string;
130
+ /**
131
+ * The dotted order for the run.
132
+ *
133
+ * This is a string composed of {time}{run-uuid}.* so that a trace can be
134
+ * sorted in the order it was executed.
135
+ *
136
+ * Example:
137
+ * - Parent: 20230914T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8
138
+ * - Children:
139
+ * - 20230914T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8.20230914T223155649Z809ed3a2-0172-4f4d-8a02-a64e9b7a0f8a
140
+ * - 20230915T223155647Z1b64098b-4ab7-43f6-afee-992304f198d8.20230914T223155650Zc8d9f4c5-6c5a-4b2d-9b1c-3d9d7a7c5c7c
141
+ */
142
+ dotted_order?: string;
126
143
  }
127
144
  export interface ExampleCreate extends BaseExample {
128
145
  id?: string;
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.0.66",
3
+ "version": "0.0.68",
4
4
  "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
5
+ "packageManager": "yarn@1.22.19",
5
6
  "files": [
6
7
  "dist/",
7
8
  "client.cjs",