langsmith 0.3.11 → 0.3.12

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
@@ -1053,6 +1053,7 @@ class Client {
1053
1053
  * @param query - The query string to filter by.
1054
1054
  * @param filter - The filter string to apply to the run spans.
1055
1055
  * @param traceFilter - The filter string to apply on the root run of the trace.
1056
+ * @param treeFilter - The filter string to apply on other runs in the trace.
1056
1057
  * @param limit - The maximum number of runs to retrieve.
1057
1058
  * @returns {AsyncIterable<Run>} - The runs.
1058
1059
  *
@@ -1736,7 +1737,7 @@ class Client {
1736
1737
  datasetId = (await this.readDataset({ datasetName })).id;
1737
1738
  }
1738
1739
  else {
1739
- throw new Error("Must provide datasetName or datasetId");
1740
+ throw new Error("Must provide either datasetName or datasetId");
1740
1741
  }
1741
1742
  const response = await this._getResponse(`${path}/${datasetId}/openai_ft`);
1742
1743
  const datasetText = await response.text();
@@ -1928,74 +1929,104 @@ class Client {
1928
1929
  const result = await response.json();
1929
1930
  return result["examples"];
1930
1931
  }
1931
- async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId, metadata, split, sourceRunId, }) {
1932
- let datasetId_ = datasetId;
1933
- if (datasetId_ === undefined && datasetName === undefined) {
1932
+ async createExample(inputsOrUpdate, outputs, options) {
1933
+ if (isExampleCreate(inputsOrUpdate)) {
1934
+ if (outputs !== undefined || options !== undefined) {
1935
+ throw new Error("Cannot provide outputs or options when using ExampleCreate object");
1936
+ }
1937
+ }
1938
+ let datasetId_ = outputs ? options?.datasetId : inputsOrUpdate.dataset_id;
1939
+ const datasetName_ = outputs
1940
+ ? options?.datasetName
1941
+ : inputsOrUpdate.dataset_name;
1942
+ if (datasetId_ === undefined && datasetName_ === undefined) {
1934
1943
  throw new Error("Must provide either datasetName or datasetId");
1935
1944
  }
1936
- else if (datasetId_ !== undefined && datasetName !== undefined) {
1945
+ else if (datasetId_ !== undefined && datasetName_ !== undefined) {
1937
1946
  throw new Error("Must provide either datasetName or datasetId, not both");
1938
1947
  }
1939
1948
  else if (datasetId_ === undefined) {
1940
- const dataset = await this.readDataset({ datasetName });
1949
+ const dataset = await this.readDataset({ datasetName: datasetName_ });
1941
1950
  datasetId_ = dataset.id;
1942
1951
  }
1943
- const createdAt_ = createdAt || new Date();
1944
- const data = {
1945
- dataset_id: datasetId_,
1946
- inputs,
1947
- outputs,
1948
- created_at: createdAt_?.toISOString(),
1949
- id: exampleId,
1950
- metadata,
1951
- split,
1952
- source_run_id: sourceRunId,
1953
- };
1954
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/examples`, {
1955
- method: "POST",
1956
- headers: { ...this.headers, "Content-Type": "application/json" },
1957
- body: JSON.stringify(data),
1958
- signal: AbortSignal.timeout(this.timeout_ms),
1959
- ...this.fetchOptions,
1960
- });
1961
- await (0, error_js_1.raiseForStatus)(response, "create example");
1962
- const result = await response.json();
1963
- return result;
1952
+ const createdAt_ = (outputs ? options?.createdAt : inputsOrUpdate.created_at) || new Date();
1953
+ let data;
1954
+ if (!isExampleCreate(inputsOrUpdate)) {
1955
+ data = {
1956
+ inputs: inputsOrUpdate,
1957
+ outputs,
1958
+ created_at: createdAt_?.toISOString(),
1959
+ id: options?.exampleId,
1960
+ metadata: options?.metadata,
1961
+ split: options?.split,
1962
+ source_run_id: options?.sourceRunId,
1963
+ use_source_run_io: options?.useSourceRunIO,
1964
+ use_source_run_attachments: options?.useSourceRunAttachments,
1965
+ attachments: options?.attachments,
1966
+ };
1967
+ }
1968
+ else {
1969
+ data = inputsOrUpdate;
1970
+ }
1971
+ const response = await this._uploadExamplesMultipart(datasetId_, [data]);
1972
+ const example = await this.readExample(response.example_ids?.[0] ?? uuid.v4());
1973
+ return example;
1964
1974
  }
1965
- async createExamples(props) {
1966
- const { inputs, outputs, metadata, sourceRunIds, exampleIds, datasetId, datasetName, } = props;
1975
+ async createExamples(propsOrUploads) {
1976
+ if (Array.isArray(propsOrUploads)) {
1977
+ if (propsOrUploads.length === 0) {
1978
+ return [];
1979
+ }
1980
+ const uploads = propsOrUploads;
1981
+ let datasetId_ = uploads[0].dataset_id;
1982
+ const datasetName_ = uploads[0].dataset_name;
1983
+ if (datasetId_ === undefined && datasetName_ === undefined) {
1984
+ throw new Error("Must provide either datasetName or datasetId");
1985
+ }
1986
+ else if (datasetId_ !== undefined && datasetName_ !== undefined) {
1987
+ throw new Error("Must provide either datasetName or datasetId, not both");
1988
+ }
1989
+ else if (datasetId_ === undefined) {
1990
+ const dataset = await this.readDataset({ datasetName: datasetName_ });
1991
+ datasetId_ = dataset.id;
1992
+ }
1993
+ const response = await this._uploadExamplesMultipart(datasetId_, uploads);
1994
+ const examples = await Promise.all(response.example_ids.map((id) => this.readExample(id)));
1995
+ return examples;
1996
+ }
1997
+ const { inputs, outputs, metadata, splits, sourceRunIds, useSourceRunIOs, useSourceRunAttachments, attachments, exampleIds, datasetId, datasetName, } = propsOrUploads;
1998
+ if (inputs === undefined) {
1999
+ throw new Error("Must provide inputs when using legacy parameters");
2000
+ }
1967
2001
  let datasetId_ = datasetId;
1968
- if (datasetId_ === undefined && datasetName === undefined) {
2002
+ const datasetName_ = datasetName;
2003
+ if (datasetId_ === undefined && datasetName_ === undefined) {
1969
2004
  throw new Error("Must provide either datasetName or datasetId");
1970
2005
  }
1971
- else if (datasetId_ !== undefined && datasetName !== undefined) {
2006
+ else if (datasetId_ !== undefined && datasetName_ !== undefined) {
1972
2007
  throw new Error("Must provide either datasetName or datasetId, not both");
1973
2008
  }
1974
2009
  else if (datasetId_ === undefined) {
1975
- const dataset = await this.readDataset({ datasetName });
2010
+ const dataset = await this.readDataset({ datasetName: datasetName_ });
1976
2011
  datasetId_ = dataset.id;
1977
2012
  }
1978
2013
  const formattedExamples = inputs.map((input, idx) => {
1979
2014
  return {
1980
2015
  dataset_id: datasetId_,
1981
2016
  inputs: input,
1982
- outputs: outputs ? outputs[idx] : undefined,
1983
- metadata: metadata ? metadata[idx] : undefined,
1984
- split: props.splits ? props.splits[idx] : undefined,
1985
- id: exampleIds ? exampleIds[idx] : undefined,
1986
- source_run_id: sourceRunIds ? sourceRunIds[idx] : undefined,
2017
+ outputs: outputs?.[idx],
2018
+ metadata: metadata?.[idx],
2019
+ split: splits?.[idx],
2020
+ id: exampleIds?.[idx],
2021
+ attachments: attachments?.[idx],
2022
+ source_run_id: sourceRunIds?.[idx],
2023
+ use_source_run_io: useSourceRunIOs?.[idx],
2024
+ use_source_run_attachments: useSourceRunAttachments?.[idx],
1987
2025
  };
1988
2026
  });
1989
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/examples/bulk`, {
1990
- method: "POST",
1991
- headers: { ...this.headers, "Content-Type": "application/json" },
1992
- body: JSON.stringify(formattedExamples),
1993
- signal: AbortSignal.timeout(this.timeout_ms),
1994
- ...this.fetchOptions,
1995
- });
1996
- await (0, error_js_1.raiseForStatus)(response, "create examples");
1997
- const result = await response.json();
1998
- return result;
2027
+ const response = await this._uploadExamplesMultipart(datasetId_, formattedExamples);
2028
+ const examples = await Promise.all(response.example_ids.map((id) => this.readExample(id)));
2029
+ return examples;
1999
2030
  }
2000
2031
  async createLLMExample(input, generation, options) {
2001
2032
  return this.createExample({ input }, { output: generation }, options);
@@ -2019,7 +2050,6 @@ class Client {
2019
2050
  const { attachment_urls, ...rest } = rawExample;
2020
2051
  const example = rest;
2021
2052
  if (attachment_urls) {
2022
- // add attachments back to the example
2023
2053
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
2024
2054
  acc[key.slice("attachment.".length)] = {
2025
2055
  presigned_url: value.presigned_url,
@@ -2116,30 +2146,43 @@ class Client {
2116
2146
  await (0, error_js_1.raiseForStatus)(response, `delete ${path}`);
2117
2147
  await response.json();
2118
2148
  }
2119
- async updateExample(exampleId, update) {
2149
+ async updateExample(exampleIdOrUpdate, update) {
2150
+ let exampleId;
2151
+ if (update) {
2152
+ exampleId = exampleIdOrUpdate;
2153
+ }
2154
+ else {
2155
+ exampleId = exampleIdOrUpdate.id;
2156
+ }
2120
2157
  (0, _uuid_js_1.assertUuid)(exampleId);
2121
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/examples/${exampleId}`, {
2122
- method: "PATCH",
2123
- headers: { ...this.headers, "Content-Type": "application/json" },
2124
- body: JSON.stringify(update),
2125
- signal: AbortSignal.timeout(this.timeout_ms),
2126
- ...this.fetchOptions,
2127
- });
2128
- await (0, error_js_1.raiseForStatus)(response, "update example");
2129
- const result = await response.json();
2130
- return result;
2158
+ let updateToUse;
2159
+ if (update) {
2160
+ updateToUse = { id: exampleId, ...update };
2161
+ }
2162
+ else {
2163
+ updateToUse = exampleIdOrUpdate;
2164
+ }
2165
+ let datasetId;
2166
+ if (updateToUse.dataset_id !== undefined) {
2167
+ datasetId = updateToUse.dataset_id;
2168
+ }
2169
+ else {
2170
+ const example = await this.readExample(exampleId);
2171
+ datasetId = example.dataset_id;
2172
+ }
2173
+ return this._updateExamplesMultipart(datasetId, [updateToUse]);
2131
2174
  }
2132
2175
  async updateExamples(update) {
2133
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/examples/bulk`, {
2134
- method: "PATCH",
2135
- headers: { ...this.headers, "Content-Type": "application/json" },
2136
- body: JSON.stringify(update),
2137
- signal: AbortSignal.timeout(this.timeout_ms),
2138
- ...this.fetchOptions,
2139
- });
2140
- await (0, error_js_1.raiseForStatus)(response, "update examples");
2141
- const result = await response.json();
2142
- return result;
2176
+ // We will naively get dataset id from first example and assume it works for all
2177
+ let datasetId;
2178
+ if (update[0].dataset_id === undefined) {
2179
+ const example = await this.readExample(update[0].id);
2180
+ datasetId = example.dataset_id;
2181
+ }
2182
+ else {
2183
+ datasetId = update[0].dataset_id;
2184
+ }
2185
+ return this._updateExamplesMultipart(datasetId, update);
2143
2186
  }
2144
2187
  /**
2145
2188
  * Get dataset version by closest date or exact tag.
@@ -2379,10 +2422,10 @@ class Client {
2379
2422
  * applications the ability to submit feedback without needing
2380
2423
  * to expose an API key.
2381
2424
  *
2382
- * @param runId - The ID of the run.
2383
- * @param feedbackKey - The feedback key.
2384
- * @param options - Additional options for the token.
2385
- * @param options.expiration - The expiration time for the token.
2425
+ * @param runId The ID of the run.
2426
+ * @param feedbackKey The feedback key.
2427
+ * @param options Additional options for the token.
2428
+ * @param options.expiration The expiration time for the token.
2386
2429
  *
2387
2430
  * @returns A promise that resolves to a FeedbackIngestToken.
2388
2431
  */
@@ -2844,6 +2887,9 @@ class Client {
2844
2887
  * @returns Promise with the update response
2845
2888
  */
2846
2889
  async updateExamplesMultipart(datasetId, updates = []) {
2890
+ return this._updateExamplesMultipart(datasetId, updates);
2891
+ }
2892
+ async _updateExamplesMultipart(datasetId, updates = []) {
2847
2893
  if (!(await this._getMultiPartSupport())) {
2848
2894
  throw new Error("Your LangSmith version does not allow using the multipart examples endpoint, please update to the latest version.");
2849
2895
  }
@@ -2861,7 +2907,7 @@ class Client {
2861
2907
  type: "application/json",
2862
2908
  });
2863
2909
  formData.append(exampleId, exampleBlob);
2864
- // Add inputs
2910
+ // Add inputs if present
2865
2911
  if (example.inputs) {
2866
2912
  const stringifiedInputs = (0, index_js_2.serialize)(example.inputs);
2867
2913
  const inputsBlob = new Blob([stringifiedInputs], {
@@ -2903,7 +2949,8 @@ class Client {
2903
2949
  formData.append(`${exampleId}.attachments_operations`, attachmentsOperationsBlob);
2904
2950
  }
2905
2951
  }
2906
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/v1/platform/datasets/${datasetId}/examples`, {
2952
+ const datasetIdToUse = datasetId ?? updates[0]?.dataset_id;
2953
+ const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(), `${this.apiUrl}/v1/platform/datasets/${datasetIdToUse}/examples`, {
2907
2954
  method: "PATCH",
2908
2955
  headers: this.headers,
2909
2956
  body: formData,
@@ -2915,8 +2962,12 @@ class Client {
2915
2962
  * Upload examples with attachments using multipart form data.
2916
2963
  * @param uploads List of ExampleUploadWithAttachments objects to upload
2917
2964
  * @returns Promise with the upload response
2965
+ * @deprecated This method is deprecated and will be removed in future LangSmith versions, please use `createExamples` instead
2918
2966
  */
2919
2967
  async uploadExamplesMultipart(datasetId, uploads = []) {
2968
+ return this._uploadExamplesMultipart(datasetId, uploads);
2969
+ }
2970
+ async _uploadExamplesMultipart(datasetId, uploads = []) {
2920
2971
  if (!(await this._getMultiPartSupport())) {
2921
2972
  throw new Error("Your LangSmith version does not allow using the multipart examples endpoint, please update to the latest version.");
2922
2973
  }
@@ -2928,6 +2979,13 @@ class Client {
2928
2979
  created_at: example.created_at,
2929
2980
  ...(example.metadata && { metadata: example.metadata }),
2930
2981
  ...(example.split && { split: example.split }),
2982
+ ...(example.source_run_id && { source_run_id: example.source_run_id }),
2983
+ ...(example.use_source_run_io && {
2984
+ use_source_run_io: example.use_source_run_io,
2985
+ }),
2986
+ ...(example.use_source_run_attachments && {
2987
+ use_source_run_attachments: example.use_source_run_attachments,
2988
+ }),
2931
2989
  };
2932
2990
  // Add main example data
2933
2991
  const stringifiedExample = (0, index_js_2.serialize)(exampleBody);
@@ -2935,12 +2993,14 @@ class Client {
2935
2993
  type: "application/json",
2936
2994
  });
2937
2995
  formData.append(exampleId, exampleBlob);
2938
- // Add inputs
2939
- const stringifiedInputs = (0, index_js_2.serialize)(example.inputs);
2940
- const inputsBlob = new Blob([stringifiedInputs], {
2941
- type: "application/json",
2942
- });
2943
- formData.append(`${exampleId}.inputs`, inputsBlob);
2996
+ // Add inputs if present
2997
+ if (example.inputs) {
2998
+ const stringifiedInputs = (0, index_js_2.serialize)(example.inputs);
2999
+ const inputsBlob = new Blob([stringifiedInputs], {
3000
+ type: "application/json",
3001
+ });
3002
+ formData.append(`${exampleId}.inputs`, inputsBlob);
3003
+ }
2944
3004
  // Add outputs if present
2945
3005
  if (example.outputs) {
2946
3006
  const stringifiedOutputs = (0, index_js_2.serialize)(example.outputs);
@@ -3201,3 +3261,6 @@ class Client {
3201
3261
  }
3202
3262
  }
3203
3263
  exports.Client = Client;
3264
+ function isExampleCreate(input) {
3265
+ return "dataset_id" in input || "dataset_name" in input;
3266
+ }
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AsyncCallerParams } from "./utils/async_caller.js";
2
- import { ComparativeExperiment, DataType, Dataset, DatasetDiffInfo, DatasetShareSchema, Example, ExampleUpdate, ExampleUpdateWithId, Feedback, FeedbackConfig, FeedbackIngestToken, KVMap, LangChainBaseMessage, LangSmithSettings, LikePromptResponse, Prompt, PromptCommit, PromptSortField, Run, RunCreate, RunUpdate, ScoreType, ExampleSearch, TimeDelta, TracerSession, TracerSessionResult, ValueType, AnnotationQueue, RunWithAnnotationQueueInfo, Attachments, ExampleUploadWithAttachments, UploadExamplesResponse, ExampleUpdateWithAttachments, UpdateExamplesResponse, DatasetVersion } from "./schemas.js";
2
+ import { ComparativeExperiment, DataType, Dataset, DatasetDiffInfo, DatasetShareSchema, Example, ExampleCreate, ExampleUpdate, ExampleUpdateWithoutId, Feedback, FeedbackConfig, FeedbackIngestToken, KVMap, LangChainBaseMessage, LangSmithSettings, LikePromptResponse, Prompt, PromptCommit, PromptSortField, Run, RunCreate, RunUpdate, ScoreType, ExampleSearch, TimeDelta, TracerSession, TracerSessionResult, ValueType, AnnotationQueue, RunWithAnnotationQueueInfo, Attachments, UploadExamplesResponse, UpdateExamplesResponse, DatasetVersion } from "./schemas.js";
3
3
  import { EvaluationResult, EvaluationResults, RunEvaluator } from "./evaluation/evaluator.js";
4
4
  export interface ClientConfig {
5
5
  apiUrl?: string;
@@ -163,6 +163,12 @@ export type CreateExampleOptions = {
163
163
  split?: string | string[];
164
164
  /** The ID of the source run associated with this example. */
165
165
  sourceRunId?: string;
166
+ /** Whether to use the inputs and outputs from the source run. */
167
+ useSourceRunIO?: boolean;
168
+ /** Which attachments from the source run to use. */
169
+ useSourceRunAttachments?: string[];
170
+ /** Attachments for the example */
171
+ attachments?: Attachments;
166
172
  };
167
173
  export type CreateProjectParams = {
168
174
  projectName: string;
@@ -295,6 +301,7 @@ export declare class Client implements LangSmithTracingClientInterface {
295
301
  * @param query - The query string to filter by.
296
302
  * @param filter - The filter string to apply to the run spans.
297
303
  * @param traceFilter - The filter string to apply on the root run of the trace.
304
+ * @param treeFilter - The filter string to apply on other runs in the trace.
298
305
  * @param limit - The maximum number of runs to retrieve.
299
306
  * @returns {AsyncIterable<Run>} - The runs.
300
307
  *
@@ -550,13 +557,22 @@ export declare class Client implements LangSmithTracingClientInterface {
550
557
  similarExamples(inputs: KVMap, datasetId: string, limit: number, { filter, }?: {
551
558
  filter?: string;
552
559
  }): Promise<ExampleSearch[]>;
553
- createExample(inputs: KVMap, outputs: KVMap, { datasetId, datasetName, createdAt, exampleId, metadata, split, sourceRunId, }: CreateExampleOptions): Promise<Example>;
560
+ createExample(update: ExampleCreate): Promise<Example>;
561
+ /**
562
+ * @deprecated This signature is deprecated, use createExample(update: ExampleCreate) instead
563
+ */
564
+ createExample(inputs: KVMap, outputs: KVMap, options: CreateExampleOptions): Promise<Example>;
565
+ createExamples(uploads: ExampleCreate[]): Promise<Example[]>;
566
+ /** @deprecated Use the uploads-only overload instead */
554
567
  createExamples(props: {
555
- inputs: Array<KVMap>;
568
+ inputs?: Array<KVMap>;
556
569
  outputs?: Array<KVMap>;
557
570
  metadata?: Array<KVMap>;
558
571
  splits?: Array<string | Array<string>>;
559
572
  sourceRunIds?: Array<string>;
573
+ useSourceRunIOs?: Array<boolean>;
574
+ useSourceRunAttachments?: Array<string[]>;
575
+ attachments?: Array<Attachments>;
560
576
  exampleIds?: Array<string>;
561
577
  datasetId?: string;
562
578
  datasetName?: string;
@@ -578,8 +594,12 @@ export declare class Client implements LangSmithTracingClientInterface {
578
594
  includeAttachments?: boolean;
579
595
  }): AsyncIterable<Example>;
580
596
  deleteExample(exampleId: string): Promise<void>;
581
- updateExample(exampleId: string, update: ExampleUpdate): Promise<object>;
582
- updateExamples(update: ExampleUpdateWithId[]): Promise<object>;
597
+ /**
598
+ * @deprecated This signature is deprecated, use updateExample(update: ExampleUpdate) instead
599
+ */
600
+ updateExample(exampleId: string, update: ExampleUpdateWithoutId): Promise<object>;
601
+ updateExample(update: ExampleUpdate): Promise<object>;
602
+ updateExamples(update: ExampleUpdate[]): Promise<object>;
583
603
  /**
584
604
  * Get dataset version by closest date or exact tag.
585
605
  *
@@ -653,10 +673,10 @@ export declare class Client implements LangSmithTracingClientInterface {
653
673
  * applications the ability to submit feedback without needing
654
674
  * to expose an API key.
655
675
  *
656
- * @param runId - The ID of the run.
657
- * @param feedbackKey - The feedback key.
658
- * @param options - Additional options for the token.
659
- * @param options.expiration - The expiration time for the token.
676
+ * @param runId The ID of the run.
677
+ * @param feedbackKey The feedback key.
678
+ * @param options Additional options for the token.
679
+ * @param options.expiration The expiration time for the token.
660
680
  *
661
681
  * @returns A promise that resolves to a FeedbackIngestToken.
662
682
  */
@@ -796,13 +816,16 @@ export declare class Client implements LangSmithTracingClientInterface {
796
816
  * @param updates List of ExampleUpdateWithAttachments objects to upsert
797
817
  * @returns Promise with the update response
798
818
  */
799
- updateExamplesMultipart(datasetId: string, updates?: ExampleUpdateWithAttachments[]): Promise<UpdateExamplesResponse>;
819
+ updateExamplesMultipart(datasetId: string, updates?: ExampleUpdate[]): Promise<UpdateExamplesResponse>;
820
+ private _updateExamplesMultipart;
800
821
  /**
801
822
  * Upload examples with attachments using multipart form data.
802
823
  * @param uploads List of ExampleUploadWithAttachments objects to upload
803
824
  * @returns Promise with the upload response
825
+ * @deprecated This method is deprecated and will be removed in future LangSmith versions, please use `createExamples` instead
804
826
  */
805
- uploadExamplesMultipart(datasetId: string, uploads?: ExampleUploadWithAttachments[]): Promise<UploadExamplesResponse>;
827
+ uploadExamplesMultipart(datasetId: string, uploads?: ExampleCreate[]): Promise<UploadExamplesResponse>;
828
+ private _uploadExamplesMultipart;
806
829
  updatePrompt(promptIdentifier: string, options?: {
807
830
  description?: string;
808
831
  readme?: string;
package/dist/client.js CHANGED
@@ -1025,6 +1025,7 @@ export class Client {
1025
1025
  * @param query - The query string to filter by.
1026
1026
  * @param filter - The filter string to apply to the run spans.
1027
1027
  * @param traceFilter - The filter string to apply on the root run of the trace.
1028
+ * @param treeFilter - The filter string to apply on other runs in the trace.
1028
1029
  * @param limit - The maximum number of runs to retrieve.
1029
1030
  * @returns {AsyncIterable<Run>} - The runs.
1030
1031
  *
@@ -1708,7 +1709,7 @@ export class Client {
1708
1709
  datasetId = (await this.readDataset({ datasetName })).id;
1709
1710
  }
1710
1711
  else {
1711
- throw new Error("Must provide datasetName or datasetId");
1712
+ throw new Error("Must provide either datasetName or datasetId");
1712
1713
  }
1713
1714
  const response = await this._getResponse(`${path}/${datasetId}/openai_ft`);
1714
1715
  const datasetText = await response.text();
@@ -1900,74 +1901,104 @@ export class Client {
1900
1901
  const result = await response.json();
1901
1902
  return result["examples"];
1902
1903
  }
1903
- async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId, metadata, split, sourceRunId, }) {
1904
- let datasetId_ = datasetId;
1905
- if (datasetId_ === undefined && datasetName === undefined) {
1904
+ async createExample(inputsOrUpdate, outputs, options) {
1905
+ if (isExampleCreate(inputsOrUpdate)) {
1906
+ if (outputs !== undefined || options !== undefined) {
1907
+ throw new Error("Cannot provide outputs or options when using ExampleCreate object");
1908
+ }
1909
+ }
1910
+ let datasetId_ = outputs ? options?.datasetId : inputsOrUpdate.dataset_id;
1911
+ const datasetName_ = outputs
1912
+ ? options?.datasetName
1913
+ : inputsOrUpdate.dataset_name;
1914
+ if (datasetId_ === undefined && datasetName_ === undefined) {
1906
1915
  throw new Error("Must provide either datasetName or datasetId");
1907
1916
  }
1908
- else if (datasetId_ !== undefined && datasetName !== undefined) {
1917
+ else if (datasetId_ !== undefined && datasetName_ !== undefined) {
1909
1918
  throw new Error("Must provide either datasetName or datasetId, not both");
1910
1919
  }
1911
1920
  else if (datasetId_ === undefined) {
1912
- const dataset = await this.readDataset({ datasetName });
1921
+ const dataset = await this.readDataset({ datasetName: datasetName_ });
1913
1922
  datasetId_ = dataset.id;
1914
1923
  }
1915
- const createdAt_ = createdAt || new Date();
1916
- const data = {
1917
- dataset_id: datasetId_,
1918
- inputs,
1919
- outputs,
1920
- created_at: createdAt_?.toISOString(),
1921
- id: exampleId,
1922
- metadata,
1923
- split,
1924
- source_run_id: sourceRunId,
1925
- };
1926
- const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples`, {
1927
- method: "POST",
1928
- headers: { ...this.headers, "Content-Type": "application/json" },
1929
- body: JSON.stringify(data),
1930
- signal: AbortSignal.timeout(this.timeout_ms),
1931
- ...this.fetchOptions,
1932
- });
1933
- await raiseForStatus(response, "create example");
1934
- const result = await response.json();
1935
- return result;
1924
+ const createdAt_ = (outputs ? options?.createdAt : inputsOrUpdate.created_at) || new Date();
1925
+ let data;
1926
+ if (!isExampleCreate(inputsOrUpdate)) {
1927
+ data = {
1928
+ inputs: inputsOrUpdate,
1929
+ outputs,
1930
+ created_at: createdAt_?.toISOString(),
1931
+ id: options?.exampleId,
1932
+ metadata: options?.metadata,
1933
+ split: options?.split,
1934
+ source_run_id: options?.sourceRunId,
1935
+ use_source_run_io: options?.useSourceRunIO,
1936
+ use_source_run_attachments: options?.useSourceRunAttachments,
1937
+ attachments: options?.attachments,
1938
+ };
1939
+ }
1940
+ else {
1941
+ data = inputsOrUpdate;
1942
+ }
1943
+ const response = await this._uploadExamplesMultipart(datasetId_, [data]);
1944
+ const example = await this.readExample(response.example_ids?.[0] ?? uuid.v4());
1945
+ return example;
1936
1946
  }
1937
- async createExamples(props) {
1938
- const { inputs, outputs, metadata, sourceRunIds, exampleIds, datasetId, datasetName, } = props;
1947
+ async createExamples(propsOrUploads) {
1948
+ if (Array.isArray(propsOrUploads)) {
1949
+ if (propsOrUploads.length === 0) {
1950
+ return [];
1951
+ }
1952
+ const uploads = propsOrUploads;
1953
+ let datasetId_ = uploads[0].dataset_id;
1954
+ const datasetName_ = uploads[0].dataset_name;
1955
+ if (datasetId_ === undefined && datasetName_ === undefined) {
1956
+ throw new Error("Must provide either datasetName or datasetId");
1957
+ }
1958
+ else if (datasetId_ !== undefined && datasetName_ !== undefined) {
1959
+ throw new Error("Must provide either datasetName or datasetId, not both");
1960
+ }
1961
+ else if (datasetId_ === undefined) {
1962
+ const dataset = await this.readDataset({ datasetName: datasetName_ });
1963
+ datasetId_ = dataset.id;
1964
+ }
1965
+ const response = await this._uploadExamplesMultipart(datasetId_, uploads);
1966
+ const examples = await Promise.all(response.example_ids.map((id) => this.readExample(id)));
1967
+ return examples;
1968
+ }
1969
+ const { inputs, outputs, metadata, splits, sourceRunIds, useSourceRunIOs, useSourceRunAttachments, attachments, exampleIds, datasetId, datasetName, } = propsOrUploads;
1970
+ if (inputs === undefined) {
1971
+ throw new Error("Must provide inputs when using legacy parameters");
1972
+ }
1939
1973
  let datasetId_ = datasetId;
1940
- if (datasetId_ === undefined && datasetName === undefined) {
1974
+ const datasetName_ = datasetName;
1975
+ if (datasetId_ === undefined && datasetName_ === undefined) {
1941
1976
  throw new Error("Must provide either datasetName or datasetId");
1942
1977
  }
1943
- else if (datasetId_ !== undefined && datasetName !== undefined) {
1978
+ else if (datasetId_ !== undefined && datasetName_ !== undefined) {
1944
1979
  throw new Error("Must provide either datasetName or datasetId, not both");
1945
1980
  }
1946
1981
  else if (datasetId_ === undefined) {
1947
- const dataset = await this.readDataset({ datasetName });
1982
+ const dataset = await this.readDataset({ datasetName: datasetName_ });
1948
1983
  datasetId_ = dataset.id;
1949
1984
  }
1950
1985
  const formattedExamples = inputs.map((input, idx) => {
1951
1986
  return {
1952
1987
  dataset_id: datasetId_,
1953
1988
  inputs: input,
1954
- outputs: outputs ? outputs[idx] : undefined,
1955
- metadata: metadata ? metadata[idx] : undefined,
1956
- split: props.splits ? props.splits[idx] : undefined,
1957
- id: exampleIds ? exampleIds[idx] : undefined,
1958
- source_run_id: sourceRunIds ? sourceRunIds[idx] : undefined,
1989
+ outputs: outputs?.[idx],
1990
+ metadata: metadata?.[idx],
1991
+ split: splits?.[idx],
1992
+ id: exampleIds?.[idx],
1993
+ attachments: attachments?.[idx],
1994
+ source_run_id: sourceRunIds?.[idx],
1995
+ use_source_run_io: useSourceRunIOs?.[idx],
1996
+ use_source_run_attachments: useSourceRunAttachments?.[idx],
1959
1997
  };
1960
1998
  });
1961
- const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples/bulk`, {
1962
- method: "POST",
1963
- headers: { ...this.headers, "Content-Type": "application/json" },
1964
- body: JSON.stringify(formattedExamples),
1965
- signal: AbortSignal.timeout(this.timeout_ms),
1966
- ...this.fetchOptions,
1967
- });
1968
- await raiseForStatus(response, "create examples");
1969
- const result = await response.json();
1970
- return result;
1999
+ const response = await this._uploadExamplesMultipart(datasetId_, formattedExamples);
2000
+ const examples = await Promise.all(response.example_ids.map((id) => this.readExample(id)));
2001
+ return examples;
1971
2002
  }
1972
2003
  async createLLMExample(input, generation, options) {
1973
2004
  return this.createExample({ input }, { output: generation }, options);
@@ -1991,7 +2022,6 @@ export class Client {
1991
2022
  const { attachment_urls, ...rest } = rawExample;
1992
2023
  const example = rest;
1993
2024
  if (attachment_urls) {
1994
- // add attachments back to the example
1995
2025
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
1996
2026
  acc[key.slice("attachment.".length)] = {
1997
2027
  presigned_url: value.presigned_url,
@@ -2088,30 +2118,43 @@ export class Client {
2088
2118
  await raiseForStatus(response, `delete ${path}`);
2089
2119
  await response.json();
2090
2120
  }
2091
- async updateExample(exampleId, update) {
2121
+ async updateExample(exampleIdOrUpdate, update) {
2122
+ let exampleId;
2123
+ if (update) {
2124
+ exampleId = exampleIdOrUpdate;
2125
+ }
2126
+ else {
2127
+ exampleId = exampleIdOrUpdate.id;
2128
+ }
2092
2129
  assertUuid(exampleId);
2093
- const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples/${exampleId}`, {
2094
- method: "PATCH",
2095
- headers: { ...this.headers, "Content-Type": "application/json" },
2096
- body: JSON.stringify(update),
2097
- signal: AbortSignal.timeout(this.timeout_ms),
2098
- ...this.fetchOptions,
2099
- });
2100
- await raiseForStatus(response, "update example");
2101
- const result = await response.json();
2102
- return result;
2130
+ let updateToUse;
2131
+ if (update) {
2132
+ updateToUse = { id: exampleId, ...update };
2133
+ }
2134
+ else {
2135
+ updateToUse = exampleIdOrUpdate;
2136
+ }
2137
+ let datasetId;
2138
+ if (updateToUse.dataset_id !== undefined) {
2139
+ datasetId = updateToUse.dataset_id;
2140
+ }
2141
+ else {
2142
+ const example = await this.readExample(exampleId);
2143
+ datasetId = example.dataset_id;
2144
+ }
2145
+ return this._updateExamplesMultipart(datasetId, [updateToUse]);
2103
2146
  }
2104
2147
  async updateExamples(update) {
2105
- const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples/bulk`, {
2106
- method: "PATCH",
2107
- headers: { ...this.headers, "Content-Type": "application/json" },
2108
- body: JSON.stringify(update),
2109
- signal: AbortSignal.timeout(this.timeout_ms),
2110
- ...this.fetchOptions,
2111
- });
2112
- await raiseForStatus(response, "update examples");
2113
- const result = await response.json();
2114
- return result;
2148
+ // We will naively get dataset id from first example and assume it works for all
2149
+ let datasetId;
2150
+ if (update[0].dataset_id === undefined) {
2151
+ const example = await this.readExample(update[0].id);
2152
+ datasetId = example.dataset_id;
2153
+ }
2154
+ else {
2155
+ datasetId = update[0].dataset_id;
2156
+ }
2157
+ return this._updateExamplesMultipart(datasetId, update);
2115
2158
  }
2116
2159
  /**
2117
2160
  * Get dataset version by closest date or exact tag.
@@ -2351,10 +2394,10 @@ export class Client {
2351
2394
  * applications the ability to submit feedback without needing
2352
2395
  * to expose an API key.
2353
2396
  *
2354
- * @param runId - The ID of the run.
2355
- * @param feedbackKey - The feedback key.
2356
- * @param options - Additional options for the token.
2357
- * @param options.expiration - The expiration time for the token.
2397
+ * @param runId The ID of the run.
2398
+ * @param feedbackKey The feedback key.
2399
+ * @param options Additional options for the token.
2400
+ * @param options.expiration The expiration time for the token.
2358
2401
  *
2359
2402
  * @returns A promise that resolves to a FeedbackIngestToken.
2360
2403
  */
@@ -2816,6 +2859,9 @@ export class Client {
2816
2859
  * @returns Promise with the update response
2817
2860
  */
2818
2861
  async updateExamplesMultipart(datasetId, updates = []) {
2862
+ return this._updateExamplesMultipart(datasetId, updates);
2863
+ }
2864
+ async _updateExamplesMultipart(datasetId, updates = []) {
2819
2865
  if (!(await this._getMultiPartSupport())) {
2820
2866
  throw new Error("Your LangSmith version does not allow using the multipart examples endpoint, please update to the latest version.");
2821
2867
  }
@@ -2833,7 +2879,7 @@ export class Client {
2833
2879
  type: "application/json",
2834
2880
  });
2835
2881
  formData.append(exampleId, exampleBlob);
2836
- // Add inputs
2882
+ // Add inputs if present
2837
2883
  if (example.inputs) {
2838
2884
  const stringifiedInputs = serializePayloadForTracing(example.inputs);
2839
2885
  const inputsBlob = new Blob([stringifiedInputs], {
@@ -2875,7 +2921,8 @@ export class Client {
2875
2921
  formData.append(`${exampleId}.attachments_operations`, attachmentsOperationsBlob);
2876
2922
  }
2877
2923
  }
2878
- const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/v1/platform/datasets/${datasetId}/examples`, {
2924
+ const datasetIdToUse = datasetId ?? updates[0]?.dataset_id;
2925
+ const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/v1/platform/datasets/${datasetIdToUse}/examples`, {
2879
2926
  method: "PATCH",
2880
2927
  headers: this.headers,
2881
2928
  body: formData,
@@ -2887,8 +2934,12 @@ export class Client {
2887
2934
  * Upload examples with attachments using multipart form data.
2888
2935
  * @param uploads List of ExampleUploadWithAttachments objects to upload
2889
2936
  * @returns Promise with the upload response
2937
+ * @deprecated This method is deprecated and will be removed in future LangSmith versions, please use `createExamples` instead
2890
2938
  */
2891
2939
  async uploadExamplesMultipart(datasetId, uploads = []) {
2940
+ return this._uploadExamplesMultipart(datasetId, uploads);
2941
+ }
2942
+ async _uploadExamplesMultipart(datasetId, uploads = []) {
2892
2943
  if (!(await this._getMultiPartSupport())) {
2893
2944
  throw new Error("Your LangSmith version does not allow using the multipart examples endpoint, please update to the latest version.");
2894
2945
  }
@@ -2900,6 +2951,13 @@ export class Client {
2900
2951
  created_at: example.created_at,
2901
2952
  ...(example.metadata && { metadata: example.metadata }),
2902
2953
  ...(example.split && { split: example.split }),
2954
+ ...(example.source_run_id && { source_run_id: example.source_run_id }),
2955
+ ...(example.use_source_run_io && {
2956
+ use_source_run_io: example.use_source_run_io,
2957
+ }),
2958
+ ...(example.use_source_run_attachments && {
2959
+ use_source_run_attachments: example.use_source_run_attachments,
2960
+ }),
2903
2961
  };
2904
2962
  // Add main example data
2905
2963
  const stringifiedExample = serializePayloadForTracing(exampleBody);
@@ -2907,12 +2965,14 @@ export class Client {
2907
2965
  type: "application/json",
2908
2966
  });
2909
2967
  formData.append(exampleId, exampleBlob);
2910
- // Add inputs
2911
- const stringifiedInputs = serializePayloadForTracing(example.inputs);
2912
- const inputsBlob = new Blob([stringifiedInputs], {
2913
- type: "application/json",
2914
- });
2915
- formData.append(`${exampleId}.inputs`, inputsBlob);
2968
+ // Add inputs if present
2969
+ if (example.inputs) {
2970
+ const stringifiedInputs = serializePayloadForTracing(example.inputs);
2971
+ const inputsBlob = new Blob([stringifiedInputs], {
2972
+ type: "application/json",
2973
+ });
2974
+ formData.append(`${exampleId}.inputs`, inputsBlob);
2975
+ }
2916
2976
  // Add outputs if present
2917
2977
  if (example.outputs) {
2918
2978
  const stringifiedOutputs = serializePayloadForTracing(example.outputs);
@@ -3172,3 +3232,6 @@ export class Client {
3172
3232
  ]);
3173
3233
  }
3174
3234
  }
3235
+ function isExampleCreate(input) {
3236
+ return "dataset_id" in input || "dataset_name" in input;
3237
+ }
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.11";
11
+ exports.__version__ = "0.3.12";
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.11";
5
+ export declare const __version__ = "0.3.12";
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.11";
5
+ export const __version__ = "0.3.12";
package/dist/schemas.d.ts CHANGED
@@ -183,12 +183,7 @@ export interface RunUpdate {
183
183
  */
184
184
  attachments?: Attachments;
185
185
  }
186
- export interface ExampleCreate extends BaseExample {
187
- id?: string;
188
- created_at?: string;
189
- split?: string | string[];
190
- }
191
- export interface ExampleUploadWithAttachments {
186
+ export interface ExampleCreate {
192
187
  id?: string;
193
188
  inputs: KVMap;
194
189
  outputs?: KVMap;
@@ -196,8 +191,15 @@ export interface ExampleUploadWithAttachments {
196
191
  split?: string | string[];
197
192
  attachments?: Attachments;
198
193
  created_at?: string;
194
+ dataset_id?: string;
195
+ dataset_name?: string;
196
+ source_run_id?: string;
197
+ use_source_run_io?: boolean;
198
+ use_source_run_attachments?: string[];
199
+ }
200
+ export interface ExampleUploadWithAttachments extends ExampleCreate {
199
201
  }
200
- export interface ExampleUpdateWithAttachments {
202
+ export interface ExampleUpdate {
201
203
  id: string;
202
204
  inputs?: KVMap;
203
205
  outputs?: KVMap;
@@ -205,6 +207,11 @@ export interface ExampleUpdateWithAttachments {
205
207
  split?: string | string[];
206
208
  attachments?: Attachments;
207
209
  attachments_operations?: KVMap;
210
+ dataset_id?: string;
211
+ }
212
+ export interface ExampleUpdateWithoutId extends Omit<ExampleUpdate, "id"> {
213
+ }
214
+ export interface ExampleUpdateWithAttachments extends ExampleUpdate {
208
215
  }
209
216
  export interface UploadExamplesResponse {
210
217
  count: number;
@@ -234,15 +241,7 @@ export interface RawExample extends BaseExample {
234
241
  runs: Run[];
235
242
  attachment_urls?: Record<string, RawAttachmentInfo>;
236
243
  }
237
- export interface ExampleUpdate {
238
- dataset_id?: string;
239
- inputs?: KVMap;
240
- outputs?: KVMap;
241
- metadata?: KVMap;
242
- split?: string | string[];
243
- }
244
244
  export interface ExampleUpdateWithId extends ExampleUpdate {
245
- id: string;
246
245
  }
247
246
  export interface ExampleSearch extends BaseExample {
248
247
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.11",
3
+ "version": "0.3.12",
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": [