langsmith 0.1.5 → 0.1.6

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
@@ -98,6 +98,18 @@ function assertUuid(str) {
98
98
  throw new Error(`Invalid UUID: ${str}`);
99
99
  }
100
100
  }
101
+ const handle429 = async (response) => {
102
+ if (response?.status === 429) {
103
+ const retryAfter = parseInt(response.headers.get("retry-after") ?? "30", 10) * 1000;
104
+ if (retryAfter > 0) {
105
+ await new Promise((resolve) => setTimeout(resolve, retryAfter));
106
+ // Return directly after calling this check
107
+ return true;
108
+ }
109
+ }
110
+ // Fall back to existing status checks
111
+ return false;
112
+ };
101
113
  class Queue {
102
114
  constructor() {
103
115
  Object.defineProperty(this, "items", {
@@ -161,6 +173,12 @@ class Client {
161
173
  writable: true,
162
174
  value: void 0
163
175
  });
176
+ Object.defineProperty(this, "batchIngestCaller", {
177
+ enumerable: true,
178
+ configurable: true,
179
+ writable: true,
180
+ value: void 0
181
+ });
164
182
  Object.defineProperty(this, "timeout_ms", {
165
183
  enumerable: true,
166
184
  configurable: true,
@@ -246,6 +264,10 @@ class Client {
246
264
  this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
247
265
  this.timeout_ms = config.timeout_ms ?? 12000;
248
266
  this.caller = new async_caller_js_1.AsyncCaller(config.callerOptions ?? {});
267
+ this.batchIngestCaller = new async_caller_js_1.AsyncCaller({
268
+ ...(config.callerOptions ?? {}),
269
+ onFailedResponseHook: handle429,
270
+ });
249
271
  this.hideInputs = config.hideInputs ?? defaultConfig.hideInputs;
250
272
  this.hideOutputs = config.hideOutputs ?? defaultConfig.hideOutputs;
251
273
  this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
@@ -448,7 +470,9 @@ class Client {
448
470
  if (this.autoBatchQueue.size > 0) {
449
471
  this.autoBatchTimeout = setTimeout(() => {
450
472
  this.autoBatchTimeout = undefined;
451
- void this.drainAutoBatchQueue();
473
+ // This error would happen in the background and is uncatchable
474
+ // from the outside. So just log instead.
475
+ void this.drainAutoBatchQueue().catch(console.error);
452
476
  }, oldTimeout
453
477
  ? this.autoBatchAggregationDelayMs
454
478
  : this.autoBatchInitialDelayMs);
@@ -487,7 +511,7 @@ class Client {
487
511
  void this.processRunOperation({
488
512
  action: "create",
489
513
  item: runCreate,
490
- });
514
+ }).catch(console.error);
491
515
  return;
492
516
  }
493
517
  const mergedRunCreateParams = await mergeRuntimeEnvIntoRunCreates([
@@ -562,18 +586,13 @@ class Client {
562
586
  "Content-Type": "application/json",
563
587
  Accept: "application/json",
564
588
  };
565
- try {
566
- const response = await this.caller.call(fetch, `${this.apiUrl}/runs/batch`, {
567
- method: "POST",
568
- headers,
569
- body: JSON.stringify(body),
570
- signal: AbortSignal.timeout(this.timeout_ms),
571
- });
572
- await raiseForStatus(response, "batch create run");
573
- }
574
- catch (e) {
575
- console.error(`Failed to batch create runs: ${e}`);
576
- }
589
+ const response = await this.batchIngestCaller.call(fetch, `${this.apiUrl}/runs/batch`, {
590
+ method: "POST",
591
+ headers,
592
+ body: JSON.stringify(body),
593
+ signal: AbortSignal.timeout(this.timeout_ms),
594
+ });
595
+ await raiseForStatus(response, "batch create run");
577
596
  }
578
597
  async updateRun(runId, run) {
579
598
  assertUuid(runId);
@@ -598,7 +617,7 @@ class Client {
598
617
  return;
599
618
  }
600
619
  else {
601
- void this.processRunOperation({ action: "update", item: data });
620
+ void this.processRunOperation({ action: "update", item: data }).catch(console.error);
602
621
  }
603
622
  return;
604
623
  }
package/dist/client.d.ts CHANGED
@@ -77,6 +77,7 @@ export declare class Client {
77
77
  private apiUrl;
78
78
  private webUrl?;
79
79
  private caller;
80
+ private batchIngestCaller;
80
81
  private timeout_ms;
81
82
  private _tenantId;
82
83
  private hideInputs?;
package/dist/client.js CHANGED
@@ -72,6 +72,18 @@ function assertUuid(str) {
72
72
  throw new Error(`Invalid UUID: ${str}`);
73
73
  }
74
74
  }
75
+ const handle429 = async (response) => {
76
+ if (response?.status === 429) {
77
+ const retryAfter = parseInt(response.headers.get("retry-after") ?? "30", 10) * 1000;
78
+ if (retryAfter > 0) {
79
+ await new Promise((resolve) => setTimeout(resolve, retryAfter));
80
+ // Return directly after calling this check
81
+ return true;
82
+ }
83
+ }
84
+ // Fall back to existing status checks
85
+ return false;
86
+ };
75
87
  export class Queue {
76
88
  constructor() {
77
89
  Object.defineProperty(this, "items", {
@@ -134,6 +146,12 @@ export class Client {
134
146
  writable: true,
135
147
  value: void 0
136
148
  });
149
+ Object.defineProperty(this, "batchIngestCaller", {
150
+ enumerable: true,
151
+ configurable: true,
152
+ writable: true,
153
+ value: void 0
154
+ });
137
155
  Object.defineProperty(this, "timeout_ms", {
138
156
  enumerable: true,
139
157
  configurable: true,
@@ -219,6 +237,10 @@ export class Client {
219
237
  this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
220
238
  this.timeout_ms = config.timeout_ms ?? 12000;
221
239
  this.caller = new AsyncCaller(config.callerOptions ?? {});
240
+ this.batchIngestCaller = new AsyncCaller({
241
+ ...(config.callerOptions ?? {}),
242
+ onFailedResponseHook: handle429,
243
+ });
222
244
  this.hideInputs = config.hideInputs ?? defaultConfig.hideInputs;
223
245
  this.hideOutputs = config.hideOutputs ?? defaultConfig.hideOutputs;
224
246
  this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
@@ -421,7 +443,9 @@ export class Client {
421
443
  if (this.autoBatchQueue.size > 0) {
422
444
  this.autoBatchTimeout = setTimeout(() => {
423
445
  this.autoBatchTimeout = undefined;
424
- void this.drainAutoBatchQueue();
446
+ // This error would happen in the background and is uncatchable
447
+ // from the outside. So just log instead.
448
+ void this.drainAutoBatchQueue().catch(console.error);
425
449
  }, oldTimeout
426
450
  ? this.autoBatchAggregationDelayMs
427
451
  : this.autoBatchInitialDelayMs);
@@ -460,7 +484,7 @@ export class Client {
460
484
  void this.processRunOperation({
461
485
  action: "create",
462
486
  item: runCreate,
463
- });
487
+ }).catch(console.error);
464
488
  return;
465
489
  }
466
490
  const mergedRunCreateParams = await mergeRuntimeEnvIntoRunCreates([
@@ -535,18 +559,13 @@ export class Client {
535
559
  "Content-Type": "application/json",
536
560
  Accept: "application/json",
537
561
  };
538
- try {
539
- const response = await this.caller.call(fetch, `${this.apiUrl}/runs/batch`, {
540
- method: "POST",
541
- headers,
542
- body: JSON.stringify(body),
543
- signal: AbortSignal.timeout(this.timeout_ms),
544
- });
545
- await raiseForStatus(response, "batch create run");
546
- }
547
- catch (e) {
548
- console.error(`Failed to batch create runs: ${e}`);
549
- }
562
+ const response = await this.batchIngestCaller.call(fetch, `${this.apiUrl}/runs/batch`, {
563
+ method: "POST",
564
+ headers,
565
+ body: JSON.stringify(body),
566
+ signal: AbortSignal.timeout(this.timeout_ms),
567
+ });
568
+ await raiseForStatus(response, "batch create run");
550
569
  }
551
570
  async updateRun(runId, run) {
552
571
  assertUuid(runId);
@@ -571,7 +590,7 @@ export class Client {
571
590
  return;
572
591
  }
573
592
  else {
574
- void this.processRunOperation({ action: "update", item: data });
593
+ void this.processRunOperation({ action: "update", item: data }).catch(console.error);
575
594
  }
576
595
  return;
577
596
  }
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.1.5";
9
+ exports.__version__ = "0.1.6";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Client } from "./client.js";
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
- export declare const __version__ = "0.1.5";
4
+ export declare const __version__ = "0.1.6";
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.1.5";
4
+ export const __version__ = "0.1.6";
@@ -52,13 +52,21 @@ class AsyncCaller {
52
52
  writable: true,
53
53
  value: void 0
54
54
  });
55
+ Object.defineProperty(this, "onFailedResponseHook", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: void 0
60
+ });
55
61
  this.maxConcurrency = params.maxConcurrency ?? Infinity;
56
62
  this.maxRetries = params.maxRetries ?? 6;
57
63
  const PQueue = "default" in p_queue_1.default ? p_queue_1.default.default : p_queue_1.default;
58
64
  this.queue = new PQueue({ concurrency: this.maxConcurrency });
65
+ this.onFailedResponseHook = params?.onFailedResponseHook;
59
66
  }
60
67
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
68
  call(callable, ...args) {
69
+ const onFailedResponseHook = this.onFailedResponseHook;
62
70
  return this.queue.add(() => (0, p_retry_1.default)(() => callable(...args).catch((error) => {
63
71
  // eslint-disable-next-line no-instanceof/no-instanceof
64
72
  if (error instanceof Error) {
@@ -68,7 +76,7 @@ class AsyncCaller {
68
76
  throw new Error(error);
69
77
  }
70
78
  }), {
71
- onFailedAttempt(error) {
79
+ async onFailedAttempt(error) {
72
80
  if (error.message.startsWith("Cancel") ||
73
81
  error.message.startsWith("TimeoutError") ||
74
82
  error.message.startsWith("AbortError")) {
@@ -79,7 +87,8 @@ class AsyncCaller {
79
87
  throw error;
80
88
  }
81
89
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
- const status = error?.response?.status;
90
+ const response = error?.response;
91
+ const status = response?.status;
83
92
  if (status) {
84
93
  if (STATUS_NO_RETRY.includes(+status)) {
85
94
  throw error;
@@ -87,6 +96,9 @@ class AsyncCaller {
87
96
  else if (STATUS_IGNORE.includes(+status)) {
88
97
  return;
89
98
  }
99
+ if (onFailedResponseHook) {
100
+ await onFailedResponseHook(response);
101
+ }
90
102
  }
91
103
  },
92
104
  // If needed we can change some of the defaults here,
@@ -1,3 +1,4 @@
1
+ type ResponseCallback = (response?: Response) => Promise<boolean>;
1
2
  export interface AsyncCallerParams {
2
3
  /**
3
4
  * The maximum number of concurrent calls that can be made.
@@ -9,6 +10,7 @@ export interface AsyncCallerParams {
9
10
  * with an exponential backoff between each attempt. Defaults to 6.
10
11
  */
11
12
  maxRetries?: number;
13
+ onFailedResponseHook?: ResponseCallback;
12
14
  }
13
15
  export interface AsyncCallerCallOptions {
14
16
  signal?: AbortSignal;
@@ -30,8 +32,10 @@ export declare class AsyncCaller {
30
32
  protected maxConcurrency: AsyncCallerParams["maxConcurrency"];
31
33
  protected maxRetries: AsyncCallerParams["maxRetries"];
32
34
  private queue;
35
+ private onFailedResponseHook?;
33
36
  constructor(params: AsyncCallerParams);
34
37
  call<A extends any[], T extends (...args: A) => Promise<any>>(callable: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
35
38
  callWithOptions<A extends any[], T extends (...args: A) => Promise<any>>(options: AsyncCallerCallOptions, callable: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
36
39
  fetch(...args: Parameters<typeof fetch>): ReturnType<typeof fetch>;
37
40
  }
41
+ export {};
@@ -46,13 +46,21 @@ export class AsyncCaller {
46
46
  writable: true,
47
47
  value: void 0
48
48
  });
49
+ Object.defineProperty(this, "onFailedResponseHook", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: void 0
54
+ });
49
55
  this.maxConcurrency = params.maxConcurrency ?? Infinity;
50
56
  this.maxRetries = params.maxRetries ?? 6;
51
57
  const PQueue = "default" in PQueueMod ? PQueueMod.default : PQueueMod;
52
58
  this.queue = new PQueue({ concurrency: this.maxConcurrency });
59
+ this.onFailedResponseHook = params?.onFailedResponseHook;
53
60
  }
54
61
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
62
  call(callable, ...args) {
63
+ const onFailedResponseHook = this.onFailedResponseHook;
56
64
  return this.queue.add(() => pRetry(() => callable(...args).catch((error) => {
57
65
  // eslint-disable-next-line no-instanceof/no-instanceof
58
66
  if (error instanceof Error) {
@@ -62,7 +70,7 @@ export class AsyncCaller {
62
70
  throw new Error(error);
63
71
  }
64
72
  }), {
65
- onFailedAttempt(error) {
73
+ async onFailedAttempt(error) {
66
74
  if (error.message.startsWith("Cancel") ||
67
75
  error.message.startsWith("TimeoutError") ||
68
76
  error.message.startsWith("AbortError")) {
@@ -73,7 +81,8 @@ export class AsyncCaller {
73
81
  throw error;
74
82
  }
75
83
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
- const status = error?.response?.status;
84
+ const response = error?.response;
85
+ const status = response?.status;
77
86
  if (status) {
78
87
  if (STATUS_NO_RETRY.includes(+status)) {
79
88
  throw error;
@@ -81,6 +90,9 @@ export class AsyncCaller {
81
90
  else if (STATUS_IGNORE.includes(+status)) {
82
91
  return;
83
92
  }
93
+ if (onFailedResponseHook) {
94
+ await onFailedResponseHook(response);
95
+ }
84
96
  }
85
97
  },
86
98
  // If needed we can change some of the defaults here,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
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": [