langsmith 0.2.12 → 0.2.14-beta.0

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
@@ -308,6 +308,12 @@ class Client {
308
308
  writable: true,
309
309
  value: void 0
310
310
  });
311
+ Object.defineProperty(this, "manualFlushMode", {
312
+ enumerable: true,
313
+ configurable: true,
314
+ writable: true,
315
+ value: false
316
+ });
311
317
  const defaultConfig = Client.getDefaultClientConfig();
312
318
  this.tracingSampleRate = getTracingSamplingRate();
313
319
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
@@ -341,6 +347,7 @@ class Client {
341
347
  config.blockOnRootRunFinalization ?? this.blockOnRootRunFinalization;
342
348
  this.batchSizeBytesLimit = config.batchSizeBytesLimit;
343
349
  this.fetchOptions = config.fetchOptions || {};
350
+ this.manualFlushMode = config.manualFlushMode ?? this.manualFlushMode;
344
351
  }
345
352
  static getDefaultClientConfig() {
346
353
  const apiKey = (0, env_js_1.getLangSmithEnvironmentVariable)("API_KEY");
@@ -538,14 +545,17 @@ class Client {
538
545
  return (serverInfo.instance_flags?.dataset_examples_multipart_enabled ?? false);
539
546
  }
540
547
  drainAutoBatchQueue(batchSizeLimit) {
548
+ const promises = [];
541
549
  while (this.autoBatchQueue.items.length > 0) {
542
550
  const [batch, done] = this.autoBatchQueue.pop(batchSizeLimit);
543
551
  if (!batch.length) {
544
552
  done();
545
553
  break;
546
554
  }
547
- void this._processBatch(batch, done).catch(console.error);
555
+ const batchPromise = this._processBatch(batch, done).catch(console.error);
556
+ promises.push(batchPromise);
548
557
  }
558
+ return Promise.all(promises);
549
559
  }
550
560
  async _processBatch(batch, done) {
551
561
  if (!batch.length) {
@@ -580,14 +590,18 @@ class Client {
580
590
  item.item = mergeRuntimeEnvIntoRunCreate(item.item);
581
591
  }
582
592
  const itemPromise = this.autoBatchQueue.push(item);
593
+ if (this.manualFlushMode) {
594
+ // Rely on manual flushing in serverless environments
595
+ return itemPromise;
596
+ }
583
597
  const sizeLimitBytes = await this._getBatchSizeLimitBytes();
584
598
  if (this.autoBatchQueue.sizeBytes > sizeLimitBytes) {
585
- this.drainAutoBatchQueue(sizeLimitBytes);
599
+ void this.drainAutoBatchQueue(sizeLimitBytes);
586
600
  }
587
601
  if (this.autoBatchQueue.items.length > 0) {
588
602
  this.autoBatchTimeout = setTimeout(() => {
589
603
  this.autoBatchTimeout = undefined;
590
- this.drainAutoBatchQueue(sizeLimitBytes);
604
+ void this.drainAutoBatchQueue(sizeLimitBytes);
591
605
  }, this.autoBatchAggregationDelayMs);
592
606
  }
593
607
  return itemPromise;
@@ -629,6 +643,13 @@ class Client {
629
643
  }
630
644
  return await this.settings;
631
645
  }
646
+ /**
647
+ * Flushes current queued traces.
648
+ */
649
+ async flush() {
650
+ const sizeLimitBytes = await this._getBatchSizeLimitBytes();
651
+ await this.drainAutoBatchQueue(sizeLimitBytes);
652
+ }
632
653
  async createRun(run) {
633
654
  if (!this._filterForSampling([run]).length) {
634
655
  return;
@@ -834,7 +855,16 @@ class Client {
834
855
  const attachments = allAttachments[payload.id];
835
856
  if (attachments) {
836
857
  delete allAttachments[payload.id];
837
- for (const [name, [contentType, content]] of Object.entries(attachments)) {
858
+ for (const [name, attachment] of Object.entries(attachments)) {
859
+ let contentType;
860
+ let content;
861
+ if (Array.isArray(attachment)) {
862
+ [contentType, content] = attachment;
863
+ }
864
+ else {
865
+ contentType = attachment.mimeType;
866
+ content = attachment.data;
867
+ }
838
868
  // Validate that the attachment name doesn't contain a '.'
839
869
  if (name.includes(".")) {
840
870
  console.warn(`Skipping attachment '${name}' for run ${payload.id}: Invalid attachment name. ` +
@@ -912,7 +942,8 @@ class Client {
912
942
  data.dotted_order !== undefined) {
913
943
  if (run.end_time !== undefined &&
914
944
  data.parent_run_id === undefined &&
915
- this.blockOnRootRunFinalization) {
945
+ this.blockOnRootRunFinalization &&
946
+ !this.manualFlushMode) {
916
947
  // Trigger batches as soon as a root trace ends and wait to ensure trace finishes
917
948
  // in serverless environments.
918
949
  await this.processRunOperation({ action: "update", item: data }).catch(console.error);
@@ -1948,7 +1979,7 @@ class Client {
1948
1979
  if (attachment_urls) {
1949
1980
  // add attachments back to the example
1950
1981
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
1951
- acc[key] = {
1982
+ acc[key.slice("attachment.".length)] = {
1952
1983
  presigned_url: value.presigned_url,
1953
1984
  };
1954
1985
  return acc;
@@ -2015,7 +2046,7 @@ class Client {
2015
2046
  const example = rest;
2016
2047
  if (attachment_urls) {
2017
2048
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
2018
- acc[key] = {
2049
+ acc[key.slice("attachment.".length)] = {
2019
2050
  presigned_url: value.presigned_url,
2020
2051
  };
2021
2052
  return acc;
@@ -2732,7 +2763,16 @@ class Client {
2732
2763
  }
2733
2764
  // Add attachments if present
2734
2765
  if (example.attachments) {
2735
- for (const [name, [mimeType, data]] of Object.entries(example.attachments)) {
2766
+ for (const [name, attachment] of Object.entries(example.attachments)) {
2767
+ let mimeType;
2768
+ let data;
2769
+ if (Array.isArray(attachment)) {
2770
+ [mimeType, data] = attachment;
2771
+ }
2772
+ else {
2773
+ mimeType = attachment.mimeType;
2774
+ data = attachment.data;
2775
+ }
2736
2776
  const attachmentBlob = new Blob([data], {
2737
2777
  type: `${mimeType}; length=${data.byteLength}`,
2738
2778
  });
@@ -2795,7 +2835,16 @@ class Client {
2795
2835
  }
2796
2836
  // Add attachments if present
2797
2837
  if (example.attachments) {
2798
- for (const [name, [mimeType, data]] of Object.entries(example.attachments)) {
2838
+ for (const [name, attachment] of Object.entries(example.attachments)) {
2839
+ let mimeType;
2840
+ let data;
2841
+ if (Array.isArray(attachment)) {
2842
+ [mimeType, data] = attachment;
2843
+ }
2844
+ else {
2845
+ mimeType = attachment.mimeType;
2846
+ data = attachment.data;
2847
+ }
2799
2848
  const attachmentBlob = new Blob([data], {
2800
2849
  type: `${mimeType}; length=${data.byteLength}`,
2801
2850
  });
@@ -3025,6 +3074,10 @@ class Client {
3025
3074
  * @returns A promise that resolves once all currently pending traces have sent.
3026
3075
  */
3027
3076
  awaitPendingTraceBatches() {
3077
+ if (this.manualFlushMode) {
3078
+ console.warn("[WARNING]: When tracing in manual flush mode, you must call `await client.flush()` manually to submit trace batches.");
3079
+ return Promise.resolve();
3080
+ }
3028
3081
  return Promise.all([
3029
3082
  ...this.autoBatchQueue.items.map(({ itemPromise }) => itemPromise),
3030
3083
  this.batchIngestCaller.queue.onIdle(),
package/dist/client.d.ts CHANGED
@@ -15,6 +15,11 @@ export interface ClientConfig {
15
15
  blockOnRootRunFinalization?: boolean;
16
16
  traceBatchConcurrency?: number;
17
17
  fetchOptions?: RequestInit;
18
+ /**
19
+ * Whether to require manual .flush() calls before sending traces.
20
+ * Useful if encountering network rate limits at trace high volumes.
21
+ */
22
+ manualFlushMode?: boolean;
18
23
  }
19
24
  /**
20
25
  * Represents the parameters for listing runs (spans) from the Langsmith server.
@@ -207,6 +212,7 @@ export declare class Client implements LangSmithTracingClientInterface {
207
212
  private traceBatchConcurrency;
208
213
  private _serverInfo;
209
214
  private _getServerInfoPromise?;
215
+ private manualFlushMode;
210
216
  constructor(config?: ClientConfig);
211
217
  static getDefaultClientConfig(): {
212
218
  apiUrl: string;
@@ -233,6 +239,10 @@ export declare class Client implements LangSmithTracingClientInterface {
233
239
  protected _getServerInfo(): Promise<any>;
234
240
  protected _ensureServerInfo(): Promise<Record<string, any>>;
235
241
  protected _getSettings(): Promise<LangSmithSettings>;
242
+ /**
243
+ * Flushes current queued traces.
244
+ */
245
+ flush(): Promise<void>;
236
246
  createRun(run: CreateRunParams): Promise<void>;
237
247
  /**
238
248
  * Batch ingest/upsert multiple runs in the Langsmith system.
@@ -804,7 +814,7 @@ export declare class Client implements LangSmithTracingClientInterface {
804
814
  *
805
815
  * @returns A promise that resolves once all currently pending traces have sent.
806
816
  */
807
- awaitPendingTraceBatches(): Promise<[...void[], void]>;
817
+ awaitPendingTraceBatches(): Promise<void> | Promise<[...void[], void]>;
808
818
  }
809
819
  export interface LangSmithTracingClientInterface {
810
820
  createRun: (run: CreateRunParams) => Promise<void>;
package/dist/client.js CHANGED
@@ -280,6 +280,12 @@ export class Client {
280
280
  writable: true,
281
281
  value: void 0
282
282
  });
283
+ Object.defineProperty(this, "manualFlushMode", {
284
+ enumerable: true,
285
+ configurable: true,
286
+ writable: true,
287
+ value: false
288
+ });
283
289
  const defaultConfig = Client.getDefaultClientConfig();
284
290
  this.tracingSampleRate = getTracingSamplingRate();
285
291
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
@@ -313,6 +319,7 @@ export class Client {
313
319
  config.blockOnRootRunFinalization ?? this.blockOnRootRunFinalization;
314
320
  this.batchSizeBytesLimit = config.batchSizeBytesLimit;
315
321
  this.fetchOptions = config.fetchOptions || {};
322
+ this.manualFlushMode = config.manualFlushMode ?? this.manualFlushMode;
316
323
  }
317
324
  static getDefaultClientConfig() {
318
325
  const apiKey = getLangSmithEnvironmentVariable("API_KEY");
@@ -510,14 +517,17 @@ export class Client {
510
517
  return (serverInfo.instance_flags?.dataset_examples_multipart_enabled ?? false);
511
518
  }
512
519
  drainAutoBatchQueue(batchSizeLimit) {
520
+ const promises = [];
513
521
  while (this.autoBatchQueue.items.length > 0) {
514
522
  const [batch, done] = this.autoBatchQueue.pop(batchSizeLimit);
515
523
  if (!batch.length) {
516
524
  done();
517
525
  break;
518
526
  }
519
- void this._processBatch(batch, done).catch(console.error);
527
+ const batchPromise = this._processBatch(batch, done).catch(console.error);
528
+ promises.push(batchPromise);
520
529
  }
530
+ return Promise.all(promises);
521
531
  }
522
532
  async _processBatch(batch, done) {
523
533
  if (!batch.length) {
@@ -552,14 +562,18 @@ export class Client {
552
562
  item.item = mergeRuntimeEnvIntoRunCreate(item.item);
553
563
  }
554
564
  const itemPromise = this.autoBatchQueue.push(item);
565
+ if (this.manualFlushMode) {
566
+ // Rely on manual flushing in serverless environments
567
+ return itemPromise;
568
+ }
555
569
  const sizeLimitBytes = await this._getBatchSizeLimitBytes();
556
570
  if (this.autoBatchQueue.sizeBytes > sizeLimitBytes) {
557
- this.drainAutoBatchQueue(sizeLimitBytes);
571
+ void this.drainAutoBatchQueue(sizeLimitBytes);
558
572
  }
559
573
  if (this.autoBatchQueue.items.length > 0) {
560
574
  this.autoBatchTimeout = setTimeout(() => {
561
575
  this.autoBatchTimeout = undefined;
562
- this.drainAutoBatchQueue(sizeLimitBytes);
576
+ void this.drainAutoBatchQueue(sizeLimitBytes);
563
577
  }, this.autoBatchAggregationDelayMs);
564
578
  }
565
579
  return itemPromise;
@@ -601,6 +615,13 @@ export class Client {
601
615
  }
602
616
  return await this.settings;
603
617
  }
618
+ /**
619
+ * Flushes current queued traces.
620
+ */
621
+ async flush() {
622
+ const sizeLimitBytes = await this._getBatchSizeLimitBytes();
623
+ await this.drainAutoBatchQueue(sizeLimitBytes);
624
+ }
604
625
  async createRun(run) {
605
626
  if (!this._filterForSampling([run]).length) {
606
627
  return;
@@ -806,7 +827,16 @@ export class Client {
806
827
  const attachments = allAttachments[payload.id];
807
828
  if (attachments) {
808
829
  delete allAttachments[payload.id];
809
- for (const [name, [contentType, content]] of Object.entries(attachments)) {
830
+ for (const [name, attachment] of Object.entries(attachments)) {
831
+ let contentType;
832
+ let content;
833
+ if (Array.isArray(attachment)) {
834
+ [contentType, content] = attachment;
835
+ }
836
+ else {
837
+ contentType = attachment.mimeType;
838
+ content = attachment.data;
839
+ }
810
840
  // Validate that the attachment name doesn't contain a '.'
811
841
  if (name.includes(".")) {
812
842
  console.warn(`Skipping attachment '${name}' for run ${payload.id}: Invalid attachment name. ` +
@@ -884,7 +914,8 @@ export class Client {
884
914
  data.dotted_order !== undefined) {
885
915
  if (run.end_time !== undefined &&
886
916
  data.parent_run_id === undefined &&
887
- this.blockOnRootRunFinalization) {
917
+ this.blockOnRootRunFinalization &&
918
+ !this.manualFlushMode) {
888
919
  // Trigger batches as soon as a root trace ends and wait to ensure trace finishes
889
920
  // in serverless environments.
890
921
  await this.processRunOperation({ action: "update", item: data }).catch(console.error);
@@ -1920,7 +1951,7 @@ export class Client {
1920
1951
  if (attachment_urls) {
1921
1952
  // add attachments back to the example
1922
1953
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
1923
- acc[key] = {
1954
+ acc[key.slice("attachment.".length)] = {
1924
1955
  presigned_url: value.presigned_url,
1925
1956
  };
1926
1957
  return acc;
@@ -1987,7 +2018,7 @@ export class Client {
1987
2018
  const example = rest;
1988
2019
  if (attachment_urls) {
1989
2020
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
1990
- acc[key] = {
2021
+ acc[key.slice("attachment.".length)] = {
1991
2022
  presigned_url: value.presigned_url,
1992
2023
  };
1993
2024
  return acc;
@@ -2704,7 +2735,16 @@ export class Client {
2704
2735
  }
2705
2736
  // Add attachments if present
2706
2737
  if (example.attachments) {
2707
- for (const [name, [mimeType, data]] of Object.entries(example.attachments)) {
2738
+ for (const [name, attachment] of Object.entries(example.attachments)) {
2739
+ let mimeType;
2740
+ let data;
2741
+ if (Array.isArray(attachment)) {
2742
+ [mimeType, data] = attachment;
2743
+ }
2744
+ else {
2745
+ mimeType = attachment.mimeType;
2746
+ data = attachment.data;
2747
+ }
2708
2748
  const attachmentBlob = new Blob([data], {
2709
2749
  type: `${mimeType}; length=${data.byteLength}`,
2710
2750
  });
@@ -2767,7 +2807,16 @@ export class Client {
2767
2807
  }
2768
2808
  // Add attachments if present
2769
2809
  if (example.attachments) {
2770
- for (const [name, [mimeType, data]] of Object.entries(example.attachments)) {
2810
+ for (const [name, attachment] of Object.entries(example.attachments)) {
2811
+ let mimeType;
2812
+ let data;
2813
+ if (Array.isArray(attachment)) {
2814
+ [mimeType, data] = attachment;
2815
+ }
2816
+ else {
2817
+ mimeType = attachment.mimeType;
2818
+ data = attachment.data;
2819
+ }
2771
2820
  const attachmentBlob = new Blob([data], {
2772
2821
  type: `${mimeType}; length=${data.byteLength}`,
2773
2822
  });
@@ -2997,6 +3046,10 @@ export class Client {
2997
3046
  * @returns A promise that resolves once all currently pending traces have sent.
2998
3047
  */
2999
3048
  awaitPendingTraceBatches() {
3049
+ if (this.manualFlushMode) {
3050
+ console.warn("[WARNING]: When tracing in manual flush mode, you must call `await client.flush()` manually to submit trace batches.");
3051
+ return Promise.resolve();
3052
+ }
3000
3053
  return Promise.all([
3001
3054
  ...this.autoBatchQueue.items.map(({ itemPromise }) => itemPromise),
3002
3055
  this.batchIngestCaller.queue.onIdle(),
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.12";
11
+ exports.__version__ = "0.2.14-beta.0";
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.12";
5
+ export declare const __version__ = "0.2.14-beta.0";
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.12";
5
+ export const __version__ = "0.2.14-beta.0";
package/dist/schemas.d.ts CHANGED
@@ -36,7 +36,14 @@ export interface AttachmentInfo {
36
36
  presigned_url: string;
37
37
  }
38
38
  export type AttachmentData = Uint8Array | ArrayBuffer;
39
- export type Attachments = Record<string, [string, AttachmentData]>;
39
+ export type AttachmentDescription = {
40
+ mimeType: string;
41
+ data: AttachmentData;
42
+ };
43
+ export type Attachments = Record<string, [
44
+ string,
45
+ AttachmentData
46
+ ] | AttachmentDescription>;
40
47
  /**
41
48
  * A run can represent either a trace (root run)
42
49
  * or a child run (~span).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.2.12",
3
+ "version": "0.2.14-beta.0",
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": [