langsmith 0.9.0 → 0.10.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.
Files changed (49) hide show
  1. package/dist/_openapi_client/client.cjs +1 -1
  2. package/dist/_openapi_client/client.d.ts +2 -2
  3. package/dist/_openapi_client/client.js +1 -1
  4. package/dist/_openapi_client/internal/detect-platform.cjs +1 -1
  5. package/dist/_openapi_client/internal/detect-platform.js +1 -1
  6. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.d.ts +1 -0
  7. package/dist/_openapi_client/resources/index.d.ts +1 -1
  8. package/dist/_openapi_client/resources/issues.cjs +1 -1
  9. package/dist/_openapi_client/resources/issues.d.ts +18 -1
  10. package/dist/_openapi_client/resources/issues.js +1 -1
  11. package/dist/_openapi_client/resources/online-evaluators.d.ts +2 -2
  12. package/dist/_openapi_client/resources/sandboxes/boxes.cjs +20 -3
  13. package/dist/_openapi_client/resources/sandboxes/boxes.d.ts +40 -9
  14. package/dist/_openapi_client/resources/sandboxes/boxes.js +20 -3
  15. package/dist/_openapi_client/resources/sandboxes/sandboxes.d.ts +46 -3
  16. package/dist/_openapi_client/resources/sandboxes/snapshots.cjs +6 -2
  17. package/dist/_openapi_client/resources/sandboxes/snapshots.d.ts +16 -6
  18. package/dist/_openapi_client/resources/sandboxes/snapshots.js +6 -2
  19. package/dist/client.cjs +56 -83
  20. package/dist/client.d.ts +16 -14
  21. package/dist/client.js +56 -83
  22. package/dist/env.cjs +14 -1
  23. package/dist/env.d.ts +9 -0
  24. package/dist/env.js +12 -0
  25. package/dist/evaluation/evaluate_comparative.cjs +2 -0
  26. package/dist/evaluation/evaluate_comparative.js +2 -0
  27. package/dist/experimental/vercel/telemetry.cjs +19 -6
  28. package/dist/experimental/vercel/telemetry.js +17 -4
  29. package/dist/index.cjs +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.js +1 -1
  32. package/dist/schemas.d.ts +2 -0
  33. package/dist/singletons/constants.cjs +7 -1
  34. package/dist/singletons/constants.d.ts +3 -0
  35. package/dist/singletons/constants.js +5 -0
  36. package/dist/traceable.cjs +46 -15
  37. package/dist/traceable.js +48 -17
  38. package/dist/utils/_uuid.cjs +11 -19
  39. package/dist/utils/_uuid.d.ts +7 -7
  40. package/dist/utils/_uuid.js +11 -19
  41. package/dist/utils/redaction.cjs +38 -0
  42. package/dist/utils/redaction.d.ts +10 -0
  43. package/dist/utils/redaction.js +33 -0
  44. package/dist/utils/sampling.cjs +34 -0
  45. package/dist/utils/sampling.d.ts +10 -0
  46. package/dist/utils/sampling.js +30 -0
  47. package/dist/wrappers/anthropic.cjs +21 -24
  48. package/dist/wrappers/anthropic.js +21 -24
  49. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -7,6 +7,7 @@ import { getEnvironmentVariable, getLangSmithEnvVarsMetadata, getLangSmithEnviro
7
7
  import { __version__ } from "./index.js";
8
8
  import { Langsmith as OpenAPILangsmith } from "./_openapi_client/index.js";
9
9
  import { assertUuid } from "./utils/_uuid.js";
10
+ import { isSampledById } from "./utils/sampling.js";
10
11
  import { warnOnce } from "./utils/warn.js";
11
12
  import { getQueryBackend, QueryBackend } from "./utils/v2_migration.js";
12
13
  import { parseHubIdentifier } from "./utils/prompts.js";
@@ -597,12 +598,6 @@ export class Client {
597
598
  writable: true,
598
599
  value: void 0
599
600
  });
600
- Object.defineProperty(this, "filteredPostUuids", {
601
- enumerable: true,
602
- configurable: true,
603
- writable: true,
604
- value: new Set()
605
- });
606
601
  Object.defineProperty(this, "autoBatchTracing", {
607
602
  enumerable: true,
608
603
  configurable: true,
@@ -1035,14 +1030,23 @@ export class Client {
1035
1030
  return headers;
1036
1031
  }
1037
1032
  /**
1038
- * The auth options and caller headers to build the generated client with.
1033
+ * The options to build the generated client with: its auth, and the headers
1034
+ * it should send on every request.
1039
1035
  *
1040
1036
  * The generated client applies `defaultHeaders` *after* its own auth headers,
1041
1037
  * so the ones this SDK sets are already dropped from `_callerHeaders` to keep
1042
1038
  * the precedence of `_mergedHeaders`, where required headers win.
1043
1039
  */
1044
- get _openAPIAuth() {
1040
+ get _openAPIClientOptions() {
1045
1041
  const headers = { ...this._callerHeaders };
1042
+ // Without this the generated client falls back to its own
1043
+ // `Langsmith/JS <generated version>`, so the same client would identify
1044
+ // itself two different ways depending on which path a call takes. A
1045
+ // caller-supplied one still wins, matched case-insensitively so the header
1046
+ // is not sent twice.
1047
+ if (!Object.keys(headers).some((name) => name.toLowerCase() === "user-agent")) {
1048
+ headers["User-Agent"] = `langsmith-js/${__version__}`;
1049
+ }
1046
1050
  // A caller may authenticate by supplying `x-api-key` themselves. The
1047
1051
  // generated client rejects that as a header (its `validateHeaders` requires
1048
1052
  // its own `apiKey` to be set), so hand it over as the `apiKey` option and
@@ -1094,25 +1098,25 @@ export class Client {
1094
1098
  * its token is refreshed.
1095
1099
  */
1096
1100
  get openAPIClient() {
1097
- const auth = this._openAPIAuth;
1098
- const signature = JSON.stringify([auth.apiKey, auth.defaultHeaders]);
1101
+ const options = this._openAPIClientOptions;
1102
+ const signature = JSON.stringify([options.apiKey, options.defaultHeaders]);
1099
1103
  if (this._openAPIClient === undefined ||
1100
1104
  this._openAPIClientSignature !== signature) {
1101
1105
  this._openAPIClientSignature = signature;
1102
- this._openAPIClient = this._newOpenAPIClient(auth);
1106
+ this._openAPIClient = this._newOpenAPIClient(options);
1103
1107
  }
1104
1108
  return this._openAPIClient;
1105
1109
  }
1106
- _newOpenAPIClient(auth = this._openAPIAuth) {
1110
+ _newOpenAPIClient(options = this._openAPIClientOptions) {
1107
1111
  const { method: _method, body: _body, signal: _signal, ...openAPIFetchOptions } = this.fetchOptions;
1108
1112
  return new OpenAPILangsmith({
1109
- apiKey: auth.apiKey,
1113
+ apiKey: options.apiKey,
1110
1114
  tenantID: this.workspaceId,
1111
1115
  baseURL: this._getOpenAPIBaseUrl(),
1112
1116
  timeout: this.timeout_ms,
1113
1117
  fetch: this._fetch,
1114
1118
  fetchOptions: openAPIFetchOptions,
1115
- defaultHeaders: auth.defaultHeaders,
1119
+ defaultHeaders: options.defaultHeaders,
1116
1120
  });
1117
1121
  }
1118
1122
  _getPlatformEndpointPath(path) {
@@ -1340,53 +1344,14 @@ export class Client {
1340
1344
  }
1341
1345
  }
1342
1346
  // Allows mocking for tests
1343
- _shouldSample() {
1344
- if (this.tracingSampleRate === undefined) {
1345
- return true;
1346
- }
1347
- return Math.random() < this.tracingSampleRate;
1347
+ _shouldSample(identifier) {
1348
+ return isSampledById(identifier, this.tracingSampleRate);
1348
1349
  }
1349
- _filterForSampling(runs, patch = false) {
1350
- if (this.tracingSampleRate === undefined) {
1351
- return runs;
1352
- }
1353
- if (patch) {
1354
- const sampled = [];
1355
- for (const run of runs) {
1356
- if (!this.filteredPostUuids.has(run.trace_id)) {
1357
- sampled.push(run);
1358
- }
1359
- else if (run.id === run.trace_id) {
1360
- this.filteredPostUuids.delete(run.trace_id);
1361
- }
1362
- }
1363
- return sampled;
1364
- }
1365
- else {
1366
- // For new runs, sample at trace level to maintain consistency
1367
- const sampled = [];
1368
- for (const run of runs) {
1369
- const traceId = run.trace_id ?? run.id;
1370
- // If we've already made a decision about this trace, follow it
1371
- if (this.filteredPostUuids.has(traceId)) {
1372
- continue;
1373
- }
1374
- // For new traces, apply sampling
1375
- if (run.id === traceId) {
1376
- if (this._shouldSample()) {
1377
- sampled.push(run);
1378
- }
1379
- else {
1380
- this.filteredPostUuids.add(traceId);
1381
- }
1382
- }
1383
- else {
1384
- // Child runs follow their trace's sampling decision
1385
- sampled.push(run);
1386
- }
1387
- }
1388
- return sampled;
1389
- }
1350
+ _filterForSampling(runs) {
1351
+ // updateRun() may omit trace_id; dotted order's first segment is the root.
1352
+ return runs.filter((run) => this._shouldSample(run.trace_id ??
1353
+ run.dotted_order?.split(".", 1)[0].split("Z")[1] ??
1354
+ run.id));
1390
1355
  }
1391
1356
  async _getBatchSizeLimitBytes() {
1392
1357
  const serverInfo = await this._ensureServerInfo();
@@ -1709,7 +1674,7 @@ export class Client {
1709
1674
  * feedback has no sessionId.
1710
1675
  */
1711
1676
  async _checkFeedbackSessionId() {
1712
- const docs = "https://docs.langchain.com/langsmith/smithdb-sdk-migration#feedback-create";
1677
+ const docs = "https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#feedback-create";
1713
1678
  const serverInfo = await this._ensureServerInfo();
1714
1679
  if (getQueryBackend(serverInfo.instance_flags) === QueryBackend.SMITHDB_ONLY) {
1715
1680
  throw new Error(`sessionId must be provided when creating feedback for a run: this ` +
@@ -2178,7 +2143,7 @@ export class Client {
2178
2143
  }
2179
2144
  // TODO: Untangle types
2180
2145
  const data = { ...run, id: runId };
2181
- if (!this._filterForSampling([data], true).length) {
2146
+ if (!this._filterForSampling([data]).length) {
2182
2147
  return;
2183
2148
  }
2184
2149
  if (this.autoBatchTracing &&
@@ -2236,11 +2201,11 @@ export class Client {
2236
2201
  return res;
2237
2202
  });
2238
2203
  }
2239
- /** @deprecated Use `client.runs.retrieve()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#runs-retrieve for the migration guide. Will be removed after Jan 31, 2027. */
2204
+ /** @deprecated Use `client.runs.retrieve()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-runs#runs-retrieve for the migration guide. Will be removed after Jan 31, 2027. */
2240
2205
  async readRun(runId, { loadChildRuns } = { loadChildRuns: false }) {
2241
2206
  warnOnce("readRun() is deprecated and will be removed after Jan 31, 2027. " +
2242
2207
  "Use client.runs.retrieve() instead. " +
2243
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#runs-retrieve for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_READ_RUN" });
2208
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-runs#runs-retrieve for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_READ_RUN" });
2244
2209
  return this._readRun(runId, { loadChildRuns });
2245
2210
  }
2246
2211
  /**
@@ -2259,11 +2224,11 @@ export class Client {
2259
2224
  }
2260
2225
  return run;
2261
2226
  }
2262
- /** @deprecated Use `client.runs.getURL()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#runs-get-url for the migration guide. Will be removed after Jan 31, 2027. */
2227
+ /** @deprecated Use `client.runs.getURL()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-runs#runs-get-url for the migration guide. Will be removed after Jan 31, 2027. */
2263
2228
  async getRunUrl({ runId, run, projectOpts, }) {
2264
2229
  warnOnce("getRunUrl() is deprecated and will be removed after Jan 31, 2027. " +
2265
2230
  "Use client.runs.getURL() instead. " +
2266
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#runs-get-url for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_GET_RUN_URL" });
2231
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-runs#runs-get-url for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_GET_RUN_URL" });
2267
2232
  if (run !== undefined) {
2268
2233
  let sessionId;
2269
2234
  if (run.session_id) {
@@ -2332,7 +2297,7 @@ export class Client {
2332
2297
  }
2333
2298
  /**
2334
2299
  * List runs from the LangSmith server.
2335
- * @deprecated Use `client.runs.query()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#runs-query for the migration guide. Will be removed after Jan 31, 2027.
2300
+ * @deprecated Use `client.runs.query()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-query-runs#runs-query for the migration guide. Will be removed after Jan 31, 2027.
2336
2301
  * @param projectId - The ID of the project to filter by.
2337
2302
  * @param projectName - The name of the project to filter by.
2338
2303
  * @param parentRunId - The ID of the parent run to filter by.
@@ -2416,7 +2381,7 @@ export class Client {
2416
2381
  async *listRuns(props) {
2417
2382
  warnOnce("listRuns() is deprecated and will be removed after Jan 31, 2027. " +
2418
2383
  "Use client.runs.query() instead. " +
2419
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#runs-query for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_LIST_RUNS" });
2384
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-query-runs#runs-query for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_LIST_RUNS" });
2420
2385
  yield* this._listRuns(props);
2421
2386
  }
2422
2387
  /**
@@ -2561,11 +2526,11 @@ export class Client {
2561
2526
  }
2562
2527
  }
2563
2528
  }
2564
- /** @deprecated Use `client.threads.listTraces()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#threads-list-traces for the migration guide. Will be removed after Jan 31, 2027. */
2529
+ /** @deprecated Use `client.threads.listTraces()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-threads#threads-list-traces for the migration guide. Will be removed after Jan 31, 2027. */
2565
2530
  async *readThread(props) {
2566
2531
  warnOnce("readThread() is deprecated and will be removed after Jan 31, 2027. " +
2567
2532
  "Use client.threads.listTraces() instead. " +
2568
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#threads-list-traces for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_READ_THREAD" });
2533
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-threads#threads-list-traces for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_READ_THREAD" });
2569
2534
  const { threadId, projectId, projectName, isRoot = true, limit, filter: userFilter, order = "asc", } = props;
2570
2535
  if (!projectId && !projectName) {
2571
2536
  throw new Error("threadId requires projectId or projectName");
@@ -2585,11 +2550,11 @@ export class Client {
2585
2550
  order,
2586
2551
  });
2587
2552
  }
2588
- /** @deprecated Use `client.threads.query()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#threads-query for the migration guide. Will be removed after Jan 31, 2027. */
2553
+ /** @deprecated Use `client.threads.query()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-threads#threads-query for the migration guide. Will be removed after Jan 31, 2027. */
2589
2554
  async listThreads(props) {
2590
2555
  warnOnce("listThreads() is deprecated and will be removed after Jan 31, 2027. " +
2591
2556
  "Use client.threads.query() instead. " +
2592
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#threads-query for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_LIST_THREADS" });
2557
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-threads#threads-query for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_LIST_THREADS" });
2593
2558
  const { projectId, projectName, limit, offset = 0, filter, startTime, isRoot = true, } = props;
2594
2559
  if (!projectId && !projectName) {
2595
2560
  throw new Error("Either projectId or projectName must be provided");
@@ -2739,11 +2704,11 @@ export class Client {
2739
2704
  const result = await response.json();
2740
2705
  return result;
2741
2706
  }
2742
- /** @deprecated Use `client.runs.share.create()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2707
+ /** @deprecated Use `client.runs.share.create()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2743
2708
  async shareRun(runId, { shareId } = {}) {
2744
2709
  warnOnce("shareRun() is deprecated and will be removed after Jan 31, 2027. " +
2745
2710
  "Use client.runs.share.create() instead. " +
2746
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_SHARE_RUN" });
2711
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_SHARE_RUN" });
2747
2712
  const data = {
2748
2713
  run_id: runId,
2749
2714
  share_token: shareId || uuid.v4(),
@@ -2767,11 +2732,11 @@ export class Client {
2767
2732
  }
2768
2733
  return `${this.getHostUrl()}/public/${result["share_token"]}/r`;
2769
2734
  }
2770
- /** @deprecated Use `client.runs.share.delete()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2735
+ /** @deprecated Use `client.runs.share.delete()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2771
2736
  async unshareRun(runId) {
2772
2737
  warnOnce("unshareRun() is deprecated and will be removed after Jan 31, 2027. " +
2773
2738
  "Use client.runs.share.delete() instead. " +
2774
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_UNSHARE_RUN" });
2739
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide.", { type: "DeprecationWarning", code: "LANGSMITH_DEPRECATED_UNSHARE_RUN" });
2775
2740
  assertUuid(runId);
2776
2741
  await this.caller.call(async () => {
2777
2742
  const res = await this._fetch(`${this.apiUrl}/runs/${runId}/share`, {
@@ -2784,11 +2749,11 @@ export class Client {
2784
2749
  return res;
2785
2750
  });
2786
2751
  }
2787
- /** @deprecated Use `client.runs.retrieve({ selects: ["SHARE_URL"] })` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2752
+ /** @deprecated Use `client.runs.retrieve({ selects: ["SHARE_URL"] })` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2788
2753
  async readRunSharedLink(runId) {
2789
2754
  warnOnce("readRunSharedLink() is deprecated and will be removed after Jan 31, 2027. " +
2790
2755
  'Use client.runs.retrieve({ selects: ["SHARE_URL"] }) instead. ' +
2791
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide.", {
2756
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide.", {
2792
2757
  type: "DeprecationWarning",
2793
2758
  code: "LANGSMITH_DEPRECATED_READ_RUN_SHARED_LINK",
2794
2759
  });
@@ -2809,11 +2774,11 @@ export class Client {
2809
2774
  }
2810
2775
  return `${this.getHostUrl()}/public/${result["share_token"]}/r`;
2811
2776
  }
2812
- /** @deprecated Use `client.public.runs.query()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2777
+ /** @deprecated Use `client.public.runs.query()` instead. See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide. Will be removed after Jan 31, 2027. */
2813
2778
  async listSharedRuns(shareToken, { runIds, } = {}) {
2814
2779
  warnOnce("listSharedRuns() is deprecated and will be removed after Jan 31, 2027. " +
2815
2780
  "Use client.public.runs.query() instead. " +
2816
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#share-and-read-public-runs for the migration guide.", {
2781
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#share-and-read-public-runs for the migration guide.", {
2817
2782
  type: "DeprecationWarning",
2818
2783
  code: "LANGSMITH_DEPRECATED_LIST_SHARED_RUNS",
2819
2784
  });
@@ -3887,7 +3852,7 @@ export class Client {
3887
3852
  });
3888
3853
  }
3889
3854
  async createFeedback(runIdOrParams, keyArg, optionsArg) {
3890
- const { runId = null, key, score, value, correction, comment, sourceInfo, feedbackSourceType = "api", sourceRunId, feedbackId, feedbackConfig, projectId, comparativeExperimentId, sessionId, startTime, extendTraceRetention, } = typeof runIdOrParams === "object" && runIdOrParams !== null
3855
+ const { runId = null, key, score, value, correction, comment, sourceInfo, feedbackSourceType = "api", sourceRunId, feedbackId, feedbackConfig, projectId, traceId, comparativeExperimentId, sessionId, startTime, extendTraceRetention, } = typeof runIdOrParams === "object" && runIdOrParams !== null
3891
3856
  ? runIdOrParams
3892
3857
  : { runId: runIdOrParams, key: keyArg, ...optionsArg };
3893
3858
  if (!runId && !projectId) {
@@ -3915,6 +3880,7 @@ export class Client {
3915
3880
  const feedback = {
3916
3881
  id: feedbackId ?? uuid.v7(),
3917
3882
  run_id: runId,
3883
+ trace_id: traceId,
3918
3884
  key,
3919
3885
  score: _formatFeedbackScore(score),
3920
3886
  value,
@@ -3927,6 +3893,10 @@ export class Client {
3927
3893
  start_time: startTime,
3928
3894
  extend_trace_retention: extendTraceRetention,
3929
3895
  };
3896
+ const samplingId = traceId ?? runId;
3897
+ if (samplingId != null && !this._shouldSample(samplingId)) {
3898
+ return feedback;
3899
+ }
3930
3900
  const body = JSON.stringify(feedback);
3931
3901
  const url = `${this.apiUrl}/feedback`;
3932
3902
  await this.caller.call(async () => {
@@ -4148,6 +4118,9 @@ export class Client {
4148
4118
  feedbackSourceType: "model",
4149
4119
  sessionId: run?.session_id ?? sessionId,
4150
4120
  startTime: run?.start_time,
4121
+ // If an evaluator result targets a different run, we can't
4122
+ // guarantee to know its trace ID.
4123
+ traceId: runId_ === run?.id ? run?.trace_id : undefined,
4151
4124
  }));
4152
4125
  }
4153
4126
  return [evalResults, feedbacks];
@@ -4413,7 +4386,7 @@ export class Client {
4413
4386
  * by SmithDB; routes to `POST /runs/by-key`.
4414
4387
  * - `string[]`: a plain list of run IDs. **Deprecated**: this path will be
4415
4388
  * removed after Jan 31, 2027; prefer the key form. Routes to `POST /runs`.
4416
- * See https://docs.langchain.com/langsmith/smithdb-sdk-migration#annotation-queues-add-runs.
4389
+ * See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#annotation-queues-add-runs.
4417
4390
  *
4418
4391
  * If every element is a string (or the list is empty) it is treated as run
4419
4392
  * IDs; otherwise the list is treated as `RunKey` objects.
@@ -4446,7 +4419,7 @@ export class Client {
4446
4419
  else {
4447
4420
  warnOnce("Passing run IDs as strings to addRunsToAnnotationQueue() is deprecated and will be removed after Jan 31, 2027. " +
4448
4421
  "Use RunKey[] instead. " +
4449
- "See https://docs.langchain.com/langsmith/smithdb-sdk-migration#annotation-queues-add-runs for the migration guide.", {
4422
+ "See https://docs.langchain.com/langsmith/smithdb-sdk-migration-feedback#annotation-queues-add-runs for the migration guide.", {
4450
4423
  type: "DeprecationWarning",
4451
4424
  code: "LANGSMITH_DEPRECATED_ADD_RUNS_STRING_IDS",
4452
4425
  });
package/dist/env.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isEnvTracingEnabled = void 0;
3
+ exports.allowUnprocessedPayloads = exports.isEnvTracingEnabled = void 0;
4
4
  const env_js_1 = require("./utils/env.cjs");
5
5
  const isEnvTracingEnabled = (tracingEnabled) => {
6
6
  if (tracingEnabled !== undefined) {
@@ -10,3 +10,16 @@ const isEnvTracingEnabled = (tracingEnabled) => {
10
10
  return !!envVars.find((envVar) => (0, env_js_1.getLangSmithEnvironmentVariable)(envVar) === "true");
11
11
  };
12
12
  exports.isEnvTracingEnabled = isEnvTracingEnabled;
13
+ /**
14
+ * Whether a failed redactor should fall back to tracing the raw payload.
15
+ *
16
+ * Set `LANGSMITH_ALLOW_UNPROCESSED_PAYLOADS` to restore the pre-fail-closed
17
+ * behavior in an emergency. It uploads data no redactor processed, so it is off
18
+ * by default and the caller logs a warning naming it whenever it takes effect.
19
+ * Read only on failure, so it stays off the hot path.
20
+ */
21
+ const allowUnprocessedPayloads = () => {
22
+ const value = (0, env_js_1.getLangSmithEnvironmentVariable)("ALLOW_UNPROCESSED_PAYLOADS");
23
+ return value?.toLowerCase() === "true" || value === "1";
24
+ };
25
+ exports.allowUnprocessedPayloads = allowUnprocessedPayloads;
package/dist/env.d.ts CHANGED
@@ -1 +1,10 @@
1
1
  export declare const isEnvTracingEnabled: (tracingEnabled?: boolean) => boolean;
2
+ /**
3
+ * Whether a failed redactor should fall back to tracing the raw payload.
4
+ *
5
+ * Set `LANGSMITH_ALLOW_UNPROCESSED_PAYLOADS` to restore the pre-fail-closed
6
+ * behavior in an emergency. It uploads data no redactor processed, so it is off
7
+ * by default and the caller logs a warning naming it whenever it takes effect.
8
+ * Read only on failure, so it stays off the hot path.
9
+ */
10
+ export declare const allowUnprocessedPayloads: () => boolean;
package/dist/env.js CHANGED
@@ -6,3 +6,15 @@ export const isEnvTracingEnabled = (tracingEnabled) => {
6
6
  const envVars = ["TRACING_V2", "TRACING"];
7
7
  return !!envVars.find((envVar) => getLangSmithEnvironmentVariable(envVar) === "true");
8
8
  };
9
+ /**
10
+ * Whether a failed redactor should fall back to tracing the raw payload.
11
+ *
12
+ * Set `LANGSMITH_ALLOW_UNPROCESSED_PAYLOADS` to restore the pre-fail-closed
13
+ * behavior in an emergency. It uploads data no redactor processed, so it is off
14
+ * by default and the caller logs a warning naming it whenever it takes effect.
15
+ * Read only on failure, so it stays off the hot path.
16
+ */
17
+ export const allowUnprocessedPayloads = () => {
18
+ const value = getLangSmithEnvironmentVariable("ALLOW_UNPROCESSED_PAYLOADS");
19
+ return value?.toLowerCase() === "true" || value === "1";
20
+ };
@@ -201,6 +201,8 @@ async function evaluateComparative(experiments, options) {
201
201
  comparativeExperimentId: comparativeExperiment.id,
202
202
  sessionId: run?.session_id,
203
203
  startTime: run?.start_time,
204
+ // `run` is the run being scored, so its trace is the right key.
205
+ traceId: run?.trace_id,
204
206
  });
205
207
  }
206
208
  return result;
@@ -194,6 +194,8 @@ export async function evaluateComparative(experiments, options) {
194
194
  comparativeExperimentId: comparativeExperiment.id,
195
195
  sessionId: run?.session_id,
196
196
  startTime: run?.start_time,
197
+ // `run` is the run being scored, so its trace is the right key.
198
+ traceId: run?.trace_id,
197
199
  });
198
200
  }
199
201
  return result;
@@ -2,8 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LangSmithTelemetry = LangSmithTelemetry;
4
4
  const run_trees_js_1 = require("../../run_trees.cjs");
5
- const traceable_js_1 = require("../../traceable.cjs");
6
5
  const env_js_1 = require("../../env.cjs");
6
+ const constants_js_1 = require("../../singletons/constants.cjs");
7
+ const traceable_js_1 = require("../../traceable.cjs");
8
+ const env_js_2 = require("../../env.cjs");
7
9
  const utils_js_1 = require("./utils.cjs");
8
10
  const utils_js_2 = require("./utils.cjs");
9
11
  const types_js_1 = require("../../utils/types.cjs");
@@ -53,6 +55,17 @@ event, traceRawHttp) {
53
55
  }
54
56
  return (0, utils_js_1.convertMessageToTracedFormat)(output);
55
57
  }
58
+ // Fail closed: a redactor that threw has redacted nothing, so the payload it
59
+ // was handed must not be traced. LANGSMITH_ALLOW_UNPROCESSED_PAYLOADS opts out.
60
+ function droppedPayload(payload, hook, raw, e) {
61
+ if ((0, env_js_1.allowUnprocessedPayloads)()) {
62
+ console.error(`Error in ${hook}. Tracing unprocessed ${payload} because ` +
63
+ "LANGSMITH_ALLOW_UNPROCESSED_PAYLOADS is set:", e);
64
+ return raw;
65
+ }
66
+ console.error(`Error in ${hook}. Dropping ${payload}:`, e);
67
+ return { [constants_js_1._PROCESSING_FAILED_KEY]: (0, constants_js_1._processingFailed)(payload, hook) };
68
+ }
56
69
  function _hasNonzeroUsageMetadata(runTree) {
57
70
  const usageMetadata = runTree.extra?.metadata?.usage_metadata;
58
71
  if (!(0, types_js_1.isRecord)(usageMetadata))
@@ -146,7 +159,7 @@ function LangSmithTelemetry(config) {
146
159
  /** Per-generation state keyed by AI SDK `callId` (stable across nested calls). */
147
160
  const invocationsByCallId = new Map();
148
161
  const onStart = async (event) => {
149
- if (!(0, env_js_1.isEnvTracingEnabled)(tracingEnabled))
162
+ if (!(0, env_js_2.isEnvTracingEnabled)(tracingEnabled))
150
163
  return;
151
164
  if (!("callId" in event) || typeof event.callId !== "string")
152
165
  return;
@@ -181,7 +194,7 @@ function LangSmithTelemetry(config) {
181
194
  inputs = processInputs(inputs);
182
195
  }
183
196
  catch (e) {
184
- console.error("Error in processInputs, using raw inputs:", e);
197
+ inputs = droppedPayload("inputs", "processInputs", inputs, e);
185
198
  }
186
199
  }
187
200
  }
@@ -251,7 +264,7 @@ function LangSmithTelemetry(config) {
251
264
  inputs = processChildLLMRunInputs(inputs);
252
265
  }
253
266
  catch (e) {
254
- console.error("Error in processChildLLMRunInputs, using raw inputs:", e);
267
+ inputs = droppedPayload("inputs", "processChildLLMRunInputs", inputs, e);
255
268
  }
256
269
  }
257
270
  }
@@ -395,7 +408,7 @@ function LangSmithTelemetry(config) {
395
408
  outputs = processChildLLMRunOutputs(outputs);
396
409
  }
397
410
  catch (e) {
398
- console.error("Error in processChildLLMRunOutputs, using raw outputs:", e);
411
+ outputs = droppedPayload("outputs", "processChildLLMRunOutputs", outputs, e);
399
412
  }
400
413
  }
401
414
  }
@@ -503,7 +516,7 @@ function LangSmithTelemetry(config) {
503
516
  outputs = processOutputs(outputs);
504
517
  }
505
518
  catch (e) {
506
- console.error("Error in processOutputs, using raw outputs:", e);
519
+ outputs = droppedPayload("outputs", "processOutputs", outputs, e);
507
520
  }
508
521
  }
509
522
  }
@@ -1,4 +1,6 @@
1
1
  import { isRunTree, RunTree } from "../../run_trees.js";
2
+ import { allowUnprocessedPayloads } from "../../env.js";
3
+ import { _PROCESSING_FAILED_KEY, _processingFailed, } from "../../singletons/constants.js";
2
4
  import { getCurrentRunTree, withRunTree } from "../../traceable.js";
3
5
  import { isEnvTracingEnabled } from "../../env.js";
4
6
  import { convertMessageToTracedFormat } from "./utils.js";
@@ -50,6 +52,17 @@ event, traceRawHttp) {
50
52
  }
51
53
  return convertMessageToTracedFormat(output);
52
54
  }
55
+ // Fail closed: a redactor that threw has redacted nothing, so the payload it
56
+ // was handed must not be traced. LANGSMITH_ALLOW_UNPROCESSED_PAYLOADS opts out.
57
+ function droppedPayload(payload, hook, raw, e) {
58
+ if (allowUnprocessedPayloads()) {
59
+ console.error(`Error in ${hook}. Tracing unprocessed ${payload} because ` +
60
+ "LANGSMITH_ALLOW_UNPROCESSED_PAYLOADS is set:", e);
61
+ return raw;
62
+ }
63
+ console.error(`Error in ${hook}. Dropping ${payload}:`, e);
64
+ return { [_PROCESSING_FAILED_KEY]: _processingFailed(payload, hook) };
65
+ }
53
66
  function _hasNonzeroUsageMetadata(runTree) {
54
67
  const usageMetadata = runTree.extra?.metadata?.usage_metadata;
55
68
  if (!isRecord(usageMetadata))
@@ -178,7 +191,7 @@ export function LangSmithTelemetry(config) {
178
191
  inputs = processInputs(inputs);
179
192
  }
180
193
  catch (e) {
181
- console.error("Error in processInputs, using raw inputs:", e);
194
+ inputs = droppedPayload("inputs", "processInputs", inputs, e);
182
195
  }
183
196
  }
184
197
  }
@@ -248,7 +261,7 @@ export function LangSmithTelemetry(config) {
248
261
  inputs = processChildLLMRunInputs(inputs);
249
262
  }
250
263
  catch (e) {
251
- console.error("Error in processChildLLMRunInputs, using raw inputs:", e);
264
+ inputs = droppedPayload("inputs", "processChildLLMRunInputs", inputs, e);
252
265
  }
253
266
  }
254
267
  }
@@ -392,7 +405,7 @@ export function LangSmithTelemetry(config) {
392
405
  outputs = processChildLLMRunOutputs(outputs);
393
406
  }
394
407
  catch (e) {
395
- console.error("Error in processChildLLMRunOutputs, using raw outputs:", e);
408
+ outputs = droppedPayload("outputs", "processChildLLMRunOutputs", outputs, e);
396
409
  }
397
410
  }
398
411
  }
@@ -500,7 +513,7 @@ export function LangSmithTelemetry(config) {
500
513
  outputs = processOutputs(outputs);
501
514
  }
502
515
  catch (e) {
503
- console.error("Error in processOutputs, using raw outputs:", e);
516
+ outputs = droppedPayload("outputs", "processOutputs", outputs, e);
504
517
  }
505
518
  }
506
519
  }
package/dist/index.cjs CHANGED
@@ -35,6 +35,6 @@ Object.defineProperty(exports, "UnprocessableEntityError", { enumerable: true, g
35
35
  Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return error_js_1.RateLimitError; } });
36
36
  Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return error_js_1.InternalServerError; } });
37
37
  // Update using pnpm bump-version
38
- exports.__version__ = "0.9.0";
38
+ exports.__version__ = "0.10.0";
39
39
  // Metadata key to hide a traced run from LangSmith's Messages View.
40
40
  exports.LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
package/dist/index.d.ts CHANGED
@@ -7,5 +7,5 @@ export { computeRunIdForSecondaryReplica, uuid7, uuid7FromTime, } from "./uuid.j
7
7
  export { isTracingEnabled } from "./utils/guard.js";
8
8
  export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
9
9
  export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
10
- export declare const __version__ = "0.9.0";
10
+ export declare const __version__ = "0.10.0";
11
11
  export declare const LS_MESSAGE_VIEW_EXCLUDE: "ls_message_view_exclude";
package/dist/index.js CHANGED
@@ -7,6 +7,6 @@ export { isTracingEnabled } from "./utils/guard.js";
7
7
  export { Cache, PromptCache, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
8
8
  export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
9
9
  // Update using pnpm bump-version
10
- export const __version__ = "0.9.0";
10
+ export const __version__ = "0.10.0";
11
11
  // Metadata key to hide a traced run from LangSmith's Messages View.
12
12
  export const LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
package/dist/schemas.d.ts CHANGED
@@ -288,6 +288,8 @@ export interface FeedbackBase {
288
288
  created_at: string;
289
289
  modified_at: string;
290
290
  run_id: string;
291
+ /** The trace the run belongs to. Equals run_id for a root run. */
292
+ trace_id?: string;
291
293
  key: string;
292
294
  score: ScoreType;
293
295
  value: ValueType;
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._REPLICA_TRACE_ROOTS_KEY = exports._LC_CHILD_RUN_END_PROMISES_KEY = exports._LC_CONTEXT_VARIABLES_KEY = void 0;
3
+ exports._processingFailed = exports._PROCESSING_FAILED_PREFIX = exports._PROCESSING_FAILED_KEY = exports._REPLICA_TRACE_ROOTS_KEY = exports._LC_CHILD_RUN_END_PROMISES_KEY = exports._LC_CONTEXT_VARIABLES_KEY = void 0;
4
4
  exports._LC_CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables");
5
5
  exports._LC_CHILD_RUN_END_PROMISES_KEY = Symbol.for("lc:child_run_end_promises");
6
6
  exports._REPLICA_TRACE_ROOTS_KEY = Symbol.for("langsmith:replica_trace_roots");
7
+ // Marker for a payload whose redactor threw.
8
+ // Takes the hook name, never the error: reading e.constructor runs user code.
9
+ exports._PROCESSING_FAILED_KEY = "ls_error";
10
+ exports._PROCESSING_FAILED_PREFIX = "Processing failed; ";
11
+ const _processingFailed = (payload, hook) => `${exports._PROCESSING_FAILED_PREFIX}${payload} dropped (${hook})`;
12
+ exports._processingFailed = _processingFailed;
@@ -1,3 +1,6 @@
1
1
  export declare const _LC_CONTEXT_VARIABLES_KEY: unique symbol;
2
2
  export declare const _LC_CHILD_RUN_END_PROMISES_KEY: unique symbol;
3
3
  export declare const _REPLICA_TRACE_ROOTS_KEY: unique symbol;
4
+ export declare const _PROCESSING_FAILED_KEY = "ls_error";
5
+ export declare const _PROCESSING_FAILED_PREFIX = "Processing failed; ";
6
+ export declare const _processingFailed: (payload: "inputs" | "outputs", hook: string) => string;
@@ -1,3 +1,8 @@
1
1
  export const _LC_CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables");
2
2
  export const _LC_CHILD_RUN_END_PROMISES_KEY = Symbol.for("lc:child_run_end_promises");
3
3
  export const _REPLICA_TRACE_ROOTS_KEY = Symbol.for("langsmith:replica_trace_roots");
4
+ // Marker for a payload whose redactor threw.
5
+ // Takes the hook name, never the error: reading e.constructor runs user code.
6
+ export const _PROCESSING_FAILED_KEY = "ls_error";
7
+ export const _PROCESSING_FAILED_PREFIX = "Processing failed; ";
8
+ export const _processingFailed = (payload, hook) => `${_PROCESSING_FAILED_PREFIX}${payload} dropped (${hook})`;