langsmith 0.10.4 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/address.cjs +119 -0
  2. package/dist/address.d.ts +13 -0
  3. package/dist/address.js +107 -0
  4. package/dist/client.cjs +68 -22
  5. package/dist/client.d.ts +13 -0
  6. package/dist/client.js +68 -22
  7. package/dist/evaluation/_runner.cjs +47 -5
  8. package/dist/evaluation/_runner.d.ts +12 -0
  9. package/dist/evaluation/_runner.js +47 -5
  10. package/dist/experimental/otel/constants.cjs +5 -1
  11. package/dist/experimental/otel/constants.d.ts +3 -0
  12. package/dist/experimental/otel/constants.js +3 -0
  13. package/dist/experimental/otel/translator.cjs +14 -0
  14. package/dist/experimental/otel/translator.js +14 -0
  15. package/dist/index.cjs +4 -2
  16. package/dist/index.d.ts +2 -1
  17. package/dist/index.js +2 -1
  18. package/dist/run_trees.cjs +154 -24
  19. package/dist/run_trees.d.ts +13 -1
  20. package/dist/run_trees.js +154 -24
  21. package/dist/sandbox/access_delegation.cjs +24 -0
  22. package/dist/sandbox/access_delegation.d.ts +15 -0
  23. package/dist/sandbox/access_delegation.js +21 -0
  24. package/dist/sandbox/client.cjs +70 -5
  25. package/dist/sandbox/client.d.ts +18 -0
  26. package/dist/sandbox/client.js +70 -5
  27. package/dist/sandbox/command_handle.cjs +34 -0
  28. package/dist/sandbox/command_handle.d.ts +10 -0
  29. package/dist/sandbox/command_handle.js +34 -0
  30. package/dist/sandbox/errors.cjs +12 -1
  31. package/dist/sandbox/errors.d.ts +7 -0
  32. package/dist/sandbox/errors.js +10 -0
  33. package/dist/sandbox/helpers.cjs +129 -0
  34. package/dist/sandbox/helpers.d.ts +29 -0
  35. package/dist/sandbox/helpers.js +123 -0
  36. package/dist/sandbox/index.cjs +12 -1
  37. package/dist/sandbox/index.d.ts +8 -2
  38. package/dist/sandbox/index.js +4 -1
  39. package/dist/sandbox/mounts.cjs +21 -3
  40. package/dist/sandbox/mounts.d.ts +7 -1
  41. package/dist/sandbox/mounts.js +21 -3
  42. package/dist/sandbox/proxy_config.cjs +41 -10
  43. package/dist/sandbox/proxy_config.d.ts +33 -6
  44. package/dist/sandbox/proxy_config.js +40 -10
  45. package/dist/sandbox/sandbox.cjs +160 -4
  46. package/dist/sandbox/sandbox.d.ts +71 -1
  47. package/dist/sandbox/sandbox.js +161 -5
  48. package/dist/sandbox/service_url.cjs +125 -0
  49. package/dist/sandbox/service_url.d.ts +50 -0
  50. package/dist/sandbox/service_url.js +120 -0
  51. package/dist/sandbox/types.d.ts +251 -8
  52. package/dist/sandbox/verify.cjs +300 -0
  53. package/dist/sandbox/verify.d.ts +122 -0
  54. package/dist/sandbox/verify.js +296 -0
  55. package/dist/sandbox/ws_execute.cjs +31 -1
  56. package/dist/sandbox/ws_execute.d.ts +9 -0
  57. package/dist/sandbox/ws_execute.js +31 -1
  58. package/dist/schemas.d.ts +5 -0
  59. package/dist/traceable.cjs +7 -1
  60. package/dist/traceable.js +7 -1
  61. package/dist/utils/agent_addressing.cjs +92 -0
  62. package/dist/utils/agent_addressing.d.ts +30 -0
  63. package/dist/utils/agent_addressing.js +83 -0
  64. package/dist/utils/env.cjs +2 -0
  65. package/dist/utils/env.js +2 -0
  66. package/dist/utils/error.cjs +17 -22
  67. package/dist/utils/error.js +17 -22
  68. package/package.json +5 -5
package/dist/client.js CHANGED
@@ -9,6 +9,8 @@ import { Langsmith as OpenAPILangsmith } from "./_openapi_client/index.js";
9
9
  import { assertUuid } from "./utils/_uuid.js";
10
10
  import { isSampledById } from "./utils/sampling.js";
11
11
  import { warnOnce } from "./utils/warn.js";
12
+ import { EnvAddressError, toWire } from "./address.js";
13
+ import { applyToPayload, checkAddress, logUntraced, rejectConflicting, resolveFromEnv, warnOnEnv, } from "./utils/agent_addressing.js";
12
14
  import { getQueryBackend, QueryBackend } from "./utils/v2_migration.js";
13
15
  import { parseHubIdentifier } from "./utils/prompts.js";
14
16
  import { raiseForStatus, isLangSmithNotFoundError, isLangSmithConflictError, } from "./utils/error.js";
@@ -44,6 +46,26 @@ function _normalizeRunTimestamps(run) {
44
46
  end_time: _ensureUTCTimestamp(run.end_time),
45
47
  };
46
48
  }
49
+ /** Index creates by id (last wins); warns when one id goes to two projects. */
50
+ function indexRunCreatesById(creates) {
51
+ const byId = {};
52
+ for (const run of creates) {
53
+ if (!run.id) {
54
+ continue;
55
+ }
56
+ const previous = byId[run.id];
57
+ if (previous !== undefined && previous.session_name !== run.session_name) {
58
+ console.warn(`LangSmith run ${run.id} was queued for two projects with the same id ` +
59
+ `(${JSON.stringify(previous.session_name)} and ` +
60
+ `${JSON.stringify(run.session_name)}); only one of the projects will ` +
61
+ "keep the run. This usually means two write replicas both keep the " +
62
+ "original run ids, for example a replica marked `primary` plus one " +
63
+ "for the run's own project.");
64
+ }
65
+ byId[run.id] = run;
66
+ }
67
+ return byId;
68
+ }
47
69
  export function mergeRuntimeEnvIntoRun(run, cachedEnvVars, omitTracedRuntimeInfo, tracingSampleRate) {
48
70
  if (omitTracedRuntimeInfo) {
49
71
  return run;
@@ -827,6 +849,10 @@ export class Client {
827
849
  throw new Error("Trace batch concurrency must be positive.");
828
850
  }
829
851
  this.debug = config.debug ?? this.debug;
852
+ if (this.debug) {
853
+ const source = config.apiUrl != null ? "apiUrl option" : defaultConfig.apiUrlSource;
854
+ console.log(`LangSmith API URL ${this.apiUrl} resolved from ${source}`);
855
+ }
830
856
  this.fetchImplementation = config.fetchImplementation;
831
857
  // Failed trace dump configuration
832
858
  this.failedTracesDir =
@@ -878,6 +904,7 @@ export class Client {
878
904
  }
879
905
  // Cache metadata env vars once during construction to avoid repeatedly scanning process.env
880
906
  this.cachedLSEnvVarsForMetadata = getLangSmithEnvVarsMetadata();
907
+ warnOnEnv();
881
908
  // Initialize prompt cache
882
909
  // Handle backwards compatibility for deprecated `cache` parameter
883
910
  if (config.cache !== undefined && config.disablePromptCache) {
@@ -913,12 +940,18 @@ export class Client {
913
940
  const envWorkspaceId = getLangSmithEnvironmentVariable("WORKSPACE_ID");
914
941
  const envAuthSet = hasValue(envApiKey);
915
942
  const apiUrl = envApiUrl ?? profileConfig.apiUrl ?? DEFAULT_API_URL;
943
+ const apiUrlSource = envApiUrl != null
944
+ ? "LANGSMITH_ENDPOINT / LANGCHAIN_ENDPOINT environment variable"
945
+ : profileConfig.apiUrl != null
946
+ ? "profile config"
947
+ : "built-in default";
916
948
  const workspaceId = envWorkspaceId ?? profileConfig.workspaceId;
917
949
  const hideInputs = getLangSmithEnvironmentVariable("HIDE_INPUTS") === "true";
918
950
  const hideOutputs = getLangSmithEnvironmentVariable("HIDE_OUTPUTS") === "true";
919
951
  const hideMetadata = getLangSmithEnvironmentVariable("HIDE_METADATA") === "true";
920
952
  return {
921
953
  apiUrl: apiUrl,
954
+ apiUrlSource,
922
955
  apiKey: envApiKey,
923
956
  webUrl: undefined,
924
957
  hideInputs: hideInputs,
@@ -1239,8 +1272,9 @@ export class Client {
1239
1272
  return event;
1240
1273
  });
1241
1274
  }
1242
- async prepareRunCreateOrUpdateInputs(run) {
1275
+ async prepareRunCreateOrUpdateInputs(run, options) {
1243
1276
  const runParams = { ...run };
1277
+ applyToPayload(runParams, { update: options?.update ?? false });
1244
1278
  if (runParams.inputs !== undefined) {
1245
1279
  runParams.inputs = await this.processInputs(runParams.inputs);
1246
1280
  }
@@ -1722,8 +1756,24 @@ export class Client {
1722
1756
  ...this._mergedHeaders,
1723
1757
  "Content-Type": "application/json",
1724
1758
  };
1759
+ const address = checkAddress(run.address);
1760
+ // `RunTree.postRun` passes a built run body, carrying the wire `session_name`.
1761
+ const bodySessionName = run.session_name;
1762
+ rejectConflicting(run.project_name ?? bodySessionName, address);
1725
1763
  const session_name = run.project_name;
1726
1764
  delete run.project_name;
1765
+ if (!session_name && bodySessionName == null && !address) {
1766
+ try {
1767
+ run.address = resolveFromEnv()[1];
1768
+ }
1769
+ catch (e) {
1770
+ if (!(e instanceof EnvAddressError)) {
1771
+ throw e;
1772
+ }
1773
+ logUntraced(e);
1774
+ return;
1775
+ }
1776
+ }
1727
1777
  const runCreate = await this.prepareRunCreateOrUpdateInputs({
1728
1778
  session_name,
1729
1779
  ...run,
@@ -1772,15 +1822,10 @@ export class Client {
1772
1822
  return;
1773
1823
  }
1774
1824
  let preparedCreateParams = await Promise.all(runCreates?.map((create) => this.prepareRunCreateOrUpdateInputs(create)) ?? []);
1775
- let preparedUpdateParams = await Promise.all(runUpdates?.map((update) => this.prepareRunCreateOrUpdateInputs(update)) ?? []);
1825
+ let preparedUpdateParams = await Promise.all(runUpdates?.map((update) => this.prepareRunCreateOrUpdateInputs(update, { update: true })) ?? []);
1826
+ // Index even without updates: the collision warning must see creates-only batches.
1827
+ const createById = indexRunCreatesById(preparedCreateParams);
1776
1828
  if (preparedCreateParams.length > 0 && preparedUpdateParams.length > 0) {
1777
- const createById = preparedCreateParams.reduce((params, run) => {
1778
- if (!run.id) {
1779
- return params;
1780
- }
1781
- params[run.id] = run;
1782
- return params;
1783
- }, {});
1784
1829
  const standaloneUpdates = [];
1785
1830
  for (const updateParam of preparedUpdateParams) {
1786
1831
  if (updateParam.id !== undefined && createById[updateParam.id]) {
@@ -1871,7 +1916,7 @@ export class Client {
1871
1916
  }
1872
1917
  let preparedUpdateParams = [];
1873
1918
  for (const update of runUpdates ?? []) {
1874
- preparedUpdateParams.push(await this.prepareRunCreateOrUpdateInputs(update));
1919
+ preparedUpdateParams.push(await this.prepareRunCreateOrUpdateInputs(update, { update: true }));
1875
1920
  }
1876
1921
  // require trace_id and dotted_order
1877
1922
  const invalidRunCreate = preparedCreateParams.find((runCreate) => {
@@ -1887,14 +1932,8 @@ export class Client {
1887
1932
  throw new Error(`Multipart ingest requires "trace_id" and "dotted_order" to be set when updating a run`);
1888
1933
  }
1889
1934
  // combine post and patch dicts where possible
1935
+ const createById = indexRunCreatesById(preparedCreateParams);
1890
1936
  if (preparedCreateParams.length > 0 && preparedUpdateParams.length > 0) {
1891
- const createById = preparedCreateParams.reduce((params, run) => {
1892
- if (!run.id) {
1893
- return params;
1894
- }
1895
- params[run.id] = run;
1896
- return params;
1897
- }, {});
1898
1937
  const standaloneUpdates = [];
1899
1938
  for (const updateParam of preparedUpdateParams) {
1900
1939
  if (updateParam.id !== undefined && createById[updateParam.id]) {
@@ -2144,6 +2183,8 @@ export class Client {
2144
2183
  if (run.events) {
2145
2184
  run.events = this._filterNewTokenEvents(run.events);
2146
2185
  }
2186
+ // On `run` too: the direct path below serializes it.
2187
+ applyToPayload(run, { update: true });
2147
2188
  // TODO: Untangle types
2148
2189
  const data = { ...run, id: runId };
2149
2190
  if (!this._filterForSampling([data]).length) {
@@ -2235,6 +2276,9 @@ export class Client {
2235
2276
  "Use client.runs.getURL() instead. " +
2236
2277
  "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" });
2237
2278
  if (run !== undefined) {
2279
+ if (!run.session_id && run.address) {
2280
+ throw new Error("Addressed runs have no URL until read back.");
2281
+ }
2238
2282
  let sessionId;
2239
2283
  if (run.session_id) {
2240
2284
  sessionId = run.session_id;
@@ -3564,7 +3608,7 @@ export class Client {
3564
3608
  if (attachment_urls) {
3565
3609
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
3566
3610
  acc[key.slice("attachment.".length)] = {
3567
- presigned_url: value.presigned_url,
3611
+ presigned_url: new URL(value.presigned_url, this.apiUrl).href,
3568
3612
  mime_type: value.mime_type,
3569
3613
  };
3570
3614
  return acc;
@@ -3632,7 +3676,7 @@ export class Client {
3632
3676
  if (attachment_urls) {
3633
3677
  example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value]) => {
3634
3678
  acc[key.slice("attachment.".length)] = {
3635
- presigned_url: value.presigned_url,
3679
+ presigned_url: new URL(value.presigned_url, this.apiUrl).href,
3636
3680
  mime_type: value.mime_type || undefined,
3637
3681
  };
3638
3682
  return acc;
@@ -3857,16 +3901,18 @@ export class Client {
3857
3901
  });
3858
3902
  }
3859
3903
  async createFeedback(runIdOrParams, keyArg, optionsArg) {
3860
- 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
3904
+ const { runId = null, key, score, value, correction, comment, sourceInfo, feedbackSourceType = "api", sourceRunId, feedbackId, feedbackConfig, projectId, traceId, comparativeExperimentId, sessionId, startTime, extendTraceRetention, address: rawAddress, } = typeof runIdOrParams === "object" && runIdOrParams !== null
3861
3905
  ? runIdOrParams
3862
3906
  : { runId: runIdOrParams, key: keyArg, ...optionsArg };
3907
+ const address = checkAddress(rawAddress);
3908
+ rejectConflicting(sessionId ?? projectId, address);
3863
3909
  if (!runId && !projectId) {
3864
3910
  throw new Error("One of runId or projectId must be provided");
3865
3911
  }
3866
3912
  if (runId && projectId) {
3867
3913
  throw new Error("Only one of runId or projectId can be provided");
3868
3914
  }
3869
- if (runId && sessionId === undefined) {
3915
+ if (runId && sessionId === undefined && !address) {
3870
3916
  await this._checkFeedbackSessionId();
3871
3917
  }
3872
3918
  const feedback_source = {
@@ -3902,7 +3948,7 @@ export class Client {
3902
3948
  if (samplingId != null && !this._shouldSample(samplingId)) {
3903
3949
  return feedback;
3904
3950
  }
3905
- const body = JSON.stringify(feedback);
3951
+ const body = JSON.stringify(address ? { ...feedback, ...toWire(address) } : feedback);
3906
3952
  const url = `${this.apiUrl}/feedback`;
3907
3953
  await this.caller.call(async () => {
3908
3954
  const res = await this._fetch(url, {
@@ -211,6 +211,12 @@ class _ExperimentManager {
211
211
  writable: true,
212
212
  value: void 0
213
213
  });
214
+ Object.defineProperty(this, "_disableEvaluatorTracing", {
215
+ enumerable: true,
216
+ configurable: true,
217
+ writable: true,
218
+ value: void 0
219
+ });
214
220
  this.client = args.client ?? new index_js_1.Client();
215
221
  if (!args.experiment) {
216
222
  this._experimentName = (0, _random_name_js_1.randomName)();
@@ -248,6 +254,7 @@ class _ExperimentManager {
248
254
  this._numExamples = args.numExamples;
249
255
  this._evaluatorKeys = args.evaluatorKeys;
250
256
  this._includeAttachments = args.includeAttachments;
257
+ this._disableEvaluatorTracing = args.disableEvaluatorTracing;
251
258
  }
252
259
  _getExperiment() {
253
260
  if (!this._experiment) {
@@ -350,6 +357,7 @@ class _ExperimentManager {
350
357
  numExamples: this._numExamples,
351
358
  evaluatorKeys: this._evaluatorKeys,
352
359
  includeAttachments: this._includeAttachments,
360
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
353
361
  });
354
362
  }
355
363
  async withPredictions(target, options) {
@@ -379,6 +387,7 @@ class _ExperimentManager {
379
387
  numExamples: this._numExamples,
380
388
  evaluatorKeys: this._evaluatorKeys,
381
389
  includeAttachments: this._includeAttachments,
390
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
382
391
  });
383
392
  }
384
393
  async withEvaluators(evaluators, options) {
@@ -406,6 +415,7 @@ class _ExperimentManager {
406
415
  numExamples: this._numExamples,
407
416
  evaluatorKeys: this._evaluatorKeys,
408
417
  includeAttachments: this._includeAttachments,
418
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
409
419
  });
410
420
  }
411
421
  async withSummaryEvaluators(summaryEvaluators) {
@@ -424,6 +434,7 @@ class _ExperimentManager {
424
434
  numExamples: this._numExamples,
425
435
  evaluatorKeys: this._evaluatorKeys,
426
436
  includeAttachments: this._includeAttachments,
437
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
427
438
  });
428
439
  }
429
440
  async *getResults() {
@@ -541,9 +552,14 @@ class _ExperimentManager {
541
552
  : new Date(example.created_at).toISOString(),
542
553
  },
543
554
  client: fields.client,
544
- tracingEnabled: true,
555
+ tracingEnabled: !this._disableEvaluatorTracing,
545
556
  };
546
- const evaluatorResponse = await evaluator.evaluateRun(run, example, options);
557
+ const rawEvaluatorResponse = await evaluator.evaluateRun(run, example, options);
558
+ // With tracing off there is no evaluator run for the feedback to point
559
+ // at, so drop the link rather than leaving it dangling.
560
+ const evaluatorResponse = this._disableEvaluatorTracing
561
+ ? _withoutSourceRunIds(rawEvaluatorResponse)
562
+ : rawEvaluatorResponse;
547
563
  evaluationResults.results.push(...(await fields.client.logEvaluationFeedback({
548
564
  evaluatorResponse,
549
565
  run,
@@ -590,7 +606,10 @@ class _ExperimentManager {
590
606
  experiment: this.experimentName,
591
607
  projectId: projectId,
592
608
  }));
593
- const wrappedEvaluators = await wrapSummaryEvaluators(summaryEvaluators, options);
609
+ const wrappedEvaluators = await wrapSummaryEvaluators(summaryEvaluators, options,
610
+ // Only override when disabling. Passing `true` here would force tracing
611
+ // on for callers who have it switched off via the environment.
612
+ this._disableEvaluatorTracing ? false : undefined);
594
613
  yield async function* (runsArray) {
595
614
  const aggregateFeedback = [];
596
615
  for (const evaluator of wrappedEvaluators) {
@@ -777,6 +796,7 @@ async function _evaluate(target, fields) {
777
796
  numRepetitions: fields.numRepetitions ?? 1,
778
797
  evaluatorKeys: _collectEvaluatorKeys(standardFields.evaluators),
779
798
  includeAttachments: standardFields.includeAttachments,
799
+ disableEvaluatorTracing: standardFields.disableEvaluatorTracing,
780
800
  }).start();
781
801
  const targetConcurrency = standardFields.targetConcurrency ?? standardFields.maxConcurrency ?? 0;
782
802
  const evaluationConcurrency = standardFields.evaluationConcurrency ?? standardFields.maxConcurrency ?? 0;
@@ -988,7 +1008,25 @@ function _resolveData(data, options) {
988
1008
  }
989
1009
  return data;
990
1010
  }
991
- async function wrapSummaryEvaluators(evaluators, optionsArray) {
1011
+ /**
1012
+ * Strip evaluator-run links from an evaluator response.
1013
+ *
1014
+ * Used when evaluator tracing is disabled: no evaluator run is created, so a
1015
+ * `sourceRunId` on the feedback would point at a run that does not exist.
1016
+ */
1017
+ function _withoutSourceRunIds(response) {
1018
+ if ("results" in response) {
1019
+ return {
1020
+ ...response,
1021
+ results: response.results.map((result) => ({
1022
+ ...result,
1023
+ sourceRunId: undefined,
1024
+ })),
1025
+ };
1026
+ }
1027
+ return { ...response, sourceRunId: undefined };
1028
+ }
1029
+ async function wrapSummaryEvaluators(evaluators, optionsArray, tracingEnabled) {
992
1030
  async function _wrap(evaluator) {
993
1031
  const evalName = evaluator.name || "BatchEvaluator";
994
1032
  const wrapperInner = (runs, examples) => {
@@ -1008,7 +1046,11 @@ async function wrapSummaryEvaluators(evaluators, optionsArray) {
1008
1046
  }
1009
1047
  // Otherwise use the traditional (runs, examples) signature
1010
1048
  return Promise.resolve(evaluator(runs, examples));
1011
- }, { ...optionsArray, name: evalName });
1049
+ }, {
1050
+ ...optionsArray,
1051
+ name: evalName,
1052
+ ...(tracingEnabled === undefined ? {} : { tracingEnabled }),
1053
+ });
1012
1054
  return Promise.resolve(wrapperSuperInner(`Runs[] (Length=${runs.length})`, `Examples[] (Length=${examples.length})`));
1013
1055
  };
1014
1056
  return wrapperInner;
@@ -73,6 +73,7 @@ interface _ExperimentManagerArgs {
73
73
  _runsArray?: Run[];
74
74
  resultRows?: AsyncGenerator<_ExperimentResultRowWithIndex>;
75
75
  includeAttachments?: boolean;
76
+ disableEvaluatorTracing?: boolean;
76
77
  }
77
78
  type BaseEvaluateOptions = {
78
79
  /**
@@ -140,6 +141,16 @@ export interface EvaluateOptions extends BaseEvaluateOptions {
140
141
  * @default false
141
142
  */
142
143
  includeAttachments?: boolean;
144
+ /**
145
+ * Whether to skip tracing evaluator invocations to the `evaluators` project.
146
+ *
147
+ * When `true`, evaluators run without creating evaluator traces. Feedback is
148
+ * still created and attached to the experiment runs, but it won't link back
149
+ * to an evaluator run, which also means it can't be corrected from the UI.
150
+ * Tracing of the target itself is unaffected.
151
+ * @default false
152
+ */
153
+ disableEvaluatorTracing?: boolean;
143
154
  }
144
155
  export interface ComparativeEvaluateOptions extends BaseEvaluateOptions {
145
156
  /**
@@ -194,6 +205,7 @@ export declare class _ExperimentManager {
194
205
  _metadata: KVMap;
195
206
  _description?: string;
196
207
  _includeAttachments?: boolean;
208
+ _disableEvaluatorTracing?: boolean;
197
209
  get experimentName(): string;
198
210
  getExamples(): Promise<Array<Example>>;
199
211
  setExamples(examples: Example[]): void;
@@ -203,6 +203,12 @@ export class _ExperimentManager {
203
203
  writable: true,
204
204
  value: void 0
205
205
  });
206
+ Object.defineProperty(this, "_disableEvaluatorTracing", {
207
+ enumerable: true,
208
+ configurable: true,
209
+ writable: true,
210
+ value: void 0
211
+ });
206
212
  this.client = args.client ?? new Client();
207
213
  if (!args.experiment) {
208
214
  this._experimentName = randomName();
@@ -240,6 +246,7 @@ export class _ExperimentManager {
240
246
  this._numExamples = args.numExamples;
241
247
  this._evaluatorKeys = args.evaluatorKeys;
242
248
  this._includeAttachments = args.includeAttachments;
249
+ this._disableEvaluatorTracing = args.disableEvaluatorTracing;
243
250
  }
244
251
  _getExperiment() {
245
252
  if (!this._experiment) {
@@ -342,6 +349,7 @@ export class _ExperimentManager {
342
349
  numExamples: this._numExamples,
343
350
  evaluatorKeys: this._evaluatorKeys,
344
351
  includeAttachments: this._includeAttachments,
352
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
345
353
  });
346
354
  }
347
355
  async withPredictions(target, options) {
@@ -371,6 +379,7 @@ export class _ExperimentManager {
371
379
  numExamples: this._numExamples,
372
380
  evaluatorKeys: this._evaluatorKeys,
373
381
  includeAttachments: this._includeAttachments,
382
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
374
383
  });
375
384
  }
376
385
  async withEvaluators(evaluators, options) {
@@ -398,6 +407,7 @@ export class _ExperimentManager {
398
407
  numExamples: this._numExamples,
399
408
  evaluatorKeys: this._evaluatorKeys,
400
409
  includeAttachments: this._includeAttachments,
410
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
401
411
  });
402
412
  }
403
413
  async withSummaryEvaluators(summaryEvaluators) {
@@ -416,6 +426,7 @@ export class _ExperimentManager {
416
426
  numExamples: this._numExamples,
417
427
  evaluatorKeys: this._evaluatorKeys,
418
428
  includeAttachments: this._includeAttachments,
429
+ disableEvaluatorTracing: this._disableEvaluatorTracing,
419
430
  });
420
431
  }
421
432
  async *getResults() {
@@ -533,9 +544,14 @@ export class _ExperimentManager {
533
544
  : new Date(example.created_at).toISOString(),
534
545
  },
535
546
  client: fields.client,
536
- tracingEnabled: true,
547
+ tracingEnabled: !this._disableEvaluatorTracing,
537
548
  };
538
- const evaluatorResponse = await evaluator.evaluateRun(run, example, options);
549
+ const rawEvaluatorResponse = await evaluator.evaluateRun(run, example, options);
550
+ // With tracing off there is no evaluator run for the feedback to point
551
+ // at, so drop the link rather than leaving it dangling.
552
+ const evaluatorResponse = this._disableEvaluatorTracing
553
+ ? _withoutSourceRunIds(rawEvaluatorResponse)
554
+ : rawEvaluatorResponse;
539
555
  evaluationResults.results.push(...(await fields.client.logEvaluationFeedback({
540
556
  evaluatorResponse,
541
557
  run,
@@ -582,7 +598,10 @@ export class _ExperimentManager {
582
598
  experiment: this.experimentName,
583
599
  projectId: projectId,
584
600
  }));
585
- const wrappedEvaluators = await wrapSummaryEvaluators(summaryEvaluators, options);
601
+ const wrappedEvaluators = await wrapSummaryEvaluators(summaryEvaluators, options,
602
+ // Only override when disabling. Passing `true` here would force tracing
603
+ // on for callers who have it switched off via the environment.
604
+ this._disableEvaluatorTracing ? false : undefined);
586
605
  yield async function* (runsArray) {
587
606
  const aggregateFeedback = [];
588
607
  for (const evaluator of wrappedEvaluators) {
@@ -768,6 +787,7 @@ async function _evaluate(target, fields) {
768
787
  numRepetitions: fields.numRepetitions ?? 1,
769
788
  evaluatorKeys: _collectEvaluatorKeys(standardFields.evaluators),
770
789
  includeAttachments: standardFields.includeAttachments,
790
+ disableEvaluatorTracing: standardFields.disableEvaluatorTracing,
771
791
  }).start();
772
792
  const targetConcurrency = standardFields.targetConcurrency ?? standardFields.maxConcurrency ?? 0;
773
793
  const evaluationConcurrency = standardFields.evaluationConcurrency ?? standardFields.maxConcurrency ?? 0;
@@ -979,7 +999,25 @@ function _resolveData(data, options) {
979
999
  }
980
1000
  return data;
981
1001
  }
982
- async function wrapSummaryEvaluators(evaluators, optionsArray) {
1002
+ /**
1003
+ * Strip evaluator-run links from an evaluator response.
1004
+ *
1005
+ * Used when evaluator tracing is disabled: no evaluator run is created, so a
1006
+ * `sourceRunId` on the feedback would point at a run that does not exist.
1007
+ */
1008
+ function _withoutSourceRunIds(response) {
1009
+ if ("results" in response) {
1010
+ return {
1011
+ ...response,
1012
+ results: response.results.map((result) => ({
1013
+ ...result,
1014
+ sourceRunId: undefined,
1015
+ })),
1016
+ };
1017
+ }
1018
+ return { ...response, sourceRunId: undefined };
1019
+ }
1020
+ async function wrapSummaryEvaluators(evaluators, optionsArray, tracingEnabled) {
983
1021
  async function _wrap(evaluator) {
984
1022
  const evalName = evaluator.name || "BatchEvaluator";
985
1023
  const wrapperInner = (runs, examples) => {
@@ -999,7 +1037,11 @@ async function wrapSummaryEvaluators(evaluators, optionsArray) {
999
1037
  }
1000
1038
  // Otherwise use the traditional (runs, examples) signature
1001
1039
  return Promise.resolve(evaluator(runs, examples));
1002
- }, { ...optionsArray, name: evalName });
1040
+ }, {
1041
+ ...optionsArray,
1042
+ name: evalName,
1043
+ ...(tracingEnabled === undefined ? {} : { tracingEnabled }),
1044
+ });
1003
1045
  return Promise.resolve(wrapperSuperInner(`Runs[] (Length=${runs.length})`, `Examples[] (Length=${examples.length})`));
1004
1046
  };
1005
1047
  return wrapperInner;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AI_SDK_TOOL_OPERATIONS = exports.AI_SDK_LLM_OPERATIONS = exports.GEN_AI_CHOICE = exports.GEN_AI_ASSISTANT_MESSAGE = exports.GEN_AI_USER_MESSAGE = exports.GEN_AI_SYSTEM_MESSAGE = exports.LANGSMITH_TRACEABLE_PARENT_OTEL_SPAN_ID = exports.LANGSMITH_IS_ROOT = exports.LANGSMITH_TRACEABLE = exports.LANGSMITH_REFERENCE_EXAMPLE_ID = exports.LANGSMITH_USAGE_METADATA = exports.LANGSMITH_PARENT_RUN_ID = exports.LANGSMITH_DOTTED_ORDER = exports.LANGSMITH_TRACE_ID = exports.LANGSMITH_RUN_ID = exports.LANGSMITH_REQUEST_HEADERS = exports.LANGSMITH_REQUEST_STREAMING = exports.LANGSMITH_RUNTIME = exports.LANGSMITH_TAGS = exports.LANGSMITH_METADATA = exports.LANGSMITH_NAME = exports.LANGSMITH_RUN_TYPE = exports.LANGSMITH_SESSION_NAME = exports.LANGSMITH_SESSION_ID = exports.GEN_AI_USAGE_OUTPUT_TOKEN_DETAILS = exports.GEN_AI_USAGE_INPUT_TOKEN_DETAILS = exports.GEN_AI_RESPONSE_SYSTEM_FINGERPRINT = exports.GEN_AI_RESPONSE_SERVICE_TIER = exports.GEN_AI_RESPONSE_ID = exports.GEN_AI_SERIALIZED_DOC = exports.GEN_AI_SERIALIZED_SIGNATURE = exports.GEN_AI_SERIALIZED_NAME = exports.GEN_AI_REQUEST_EXTRA_BODY = exports.GEN_AI_REQUEST_EXTRA_QUERY = exports.GENAI_COMPLETION = exports.GENAI_PROMPT = exports.GEN_AI_RESPONSE_FINISH_REASONS = exports.GEN_AI_REQUEST_PRESENCE_PENALTY = exports.GEN_AI_REQUEST_FREQUENCY_PENALTY = exports.GEN_AI_REQUEST_TOP_P = exports.GEN_AI_REQUEST_TEMPERATURE = exports.GEN_AI_REQUEST_MAX_TOKENS = exports.GEN_AI_USAGE_TOTAL_TOKENS = exports.GEN_AI_USAGE_OUTPUT_TOKENS = exports.GEN_AI_USAGE_INPUT_TOKENS = exports.GEN_AI_RESPONSE_MODEL = exports.GEN_AI_REQUEST_MODEL = exports.GEN_AI_SYSTEM = exports.GEN_AI_OPERATION_NAME = void 0;
3
+ exports.GEN_AI_CHOICE = exports.GEN_AI_ASSISTANT_MESSAGE = exports.GEN_AI_USER_MESSAGE = exports.GEN_AI_SYSTEM_MESSAGE = exports.LANGSMITH_TRACEABLE_PARENT_OTEL_SPAN_ID = exports.LANGSMITH_IS_ROOT = exports.LANGSMITH_TRACEABLE = exports.LANGSMITH_REFERENCE_EXAMPLE_ID = exports.LANGSMITH_USAGE_METADATA = exports.LANGSMITH_PARENT_RUN_ID = exports.LANGSMITH_DOTTED_ORDER = exports.LANGSMITH_TRACE_ID = exports.LANGSMITH_RUN_ID = exports.LANGSMITH_REQUEST_HEADERS = exports.LANGSMITH_REQUEST_STREAMING = exports.LANGSMITH_RUNTIME = exports.LANGSMITH_TAGS = exports.LANGSMITH_METADATA = exports.LANGSMITH_NAME = exports.LANGSMITH_RUN_TYPE = exports.LANGSMITH_SESSION_NAME = exports.LANGSMITH_SESSION_ID = exports.GEN_AI_USAGE_OUTPUT_TOKEN_DETAILS = exports.GEN_AI_USAGE_INPUT_TOKEN_DETAILS = exports.GEN_AI_RESPONSE_SYSTEM_FINGERPRINT = exports.GEN_AI_RESPONSE_SERVICE_TIER = exports.GEN_AI_TOOL_DEFINITIONS = exports.GEN_AI_TOOL_CALL_ID = exports.GEN_AI_TOOL_NAME = exports.GEN_AI_RESPONSE_ID = exports.GEN_AI_SERIALIZED_DOC = exports.GEN_AI_SERIALIZED_SIGNATURE = exports.GEN_AI_SERIALIZED_NAME = exports.GEN_AI_REQUEST_EXTRA_BODY = exports.GEN_AI_REQUEST_EXTRA_QUERY = exports.GENAI_COMPLETION = exports.GENAI_PROMPT = exports.GEN_AI_RESPONSE_FINISH_REASONS = exports.GEN_AI_REQUEST_PRESENCE_PENALTY = exports.GEN_AI_REQUEST_FREQUENCY_PENALTY = exports.GEN_AI_REQUEST_TOP_P = exports.GEN_AI_REQUEST_TEMPERATURE = exports.GEN_AI_REQUEST_MAX_TOKENS = exports.GEN_AI_USAGE_TOTAL_TOKENS = exports.GEN_AI_USAGE_OUTPUT_TOKENS = exports.GEN_AI_USAGE_INPUT_TOKENS = exports.GEN_AI_RESPONSE_MODEL = exports.GEN_AI_REQUEST_MODEL = exports.GEN_AI_SYSTEM = exports.GEN_AI_OPERATION_NAME = void 0;
4
+ exports.AI_SDK_TOOL_OPERATIONS = exports.AI_SDK_LLM_OPERATIONS = void 0;
4
5
  // OpenTelemetry GenAI semantic convention attribute names
5
6
  exports.GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
6
7
  exports.GEN_AI_SYSTEM = "gen_ai.system";
@@ -23,6 +24,9 @@ exports.GEN_AI_SERIALIZED_NAME = "gen_ai.serialized.name";
23
24
  exports.GEN_AI_SERIALIZED_SIGNATURE = "gen_ai.serialized.signature";
24
25
  exports.GEN_AI_SERIALIZED_DOC = "gen_ai.serialized.doc";
25
26
  exports.GEN_AI_RESPONSE_ID = "gen_ai.response.id";
27
+ exports.GEN_AI_TOOL_NAME = "gen_ai.tool.name";
28
+ exports.GEN_AI_TOOL_CALL_ID = "gen_ai.tool.call.id";
29
+ exports.GEN_AI_TOOL_DEFINITIONS = "gen_ai.tool.definitions";
26
30
  exports.GEN_AI_RESPONSE_SERVICE_TIER = "gen_ai.response.service_tier";
27
31
  exports.GEN_AI_RESPONSE_SYSTEM_FINGERPRINT = "gen_ai.response.system_fingerprint";
28
32
  exports.GEN_AI_USAGE_INPUT_TOKEN_DETAILS = "gen_ai.usage.input_token_details";
@@ -19,6 +19,9 @@ export declare const GEN_AI_SERIALIZED_NAME = "gen_ai.serialized.name";
19
19
  export declare const GEN_AI_SERIALIZED_SIGNATURE = "gen_ai.serialized.signature";
20
20
  export declare const GEN_AI_SERIALIZED_DOC = "gen_ai.serialized.doc";
21
21
  export declare const GEN_AI_RESPONSE_ID = "gen_ai.response.id";
22
+ export declare const GEN_AI_TOOL_NAME = "gen_ai.tool.name";
23
+ export declare const GEN_AI_TOOL_CALL_ID = "gen_ai.tool.call.id";
24
+ export declare const GEN_AI_TOOL_DEFINITIONS = "gen_ai.tool.definitions";
22
25
  export declare const GEN_AI_RESPONSE_SERVICE_TIER = "gen_ai.response.service_tier";
23
26
  export declare const GEN_AI_RESPONSE_SYSTEM_FINGERPRINT = "gen_ai.response.system_fingerprint";
24
27
  export declare const GEN_AI_USAGE_INPUT_TOKEN_DETAILS = "gen_ai.usage.input_token_details";
@@ -20,6 +20,9 @@ export const GEN_AI_SERIALIZED_NAME = "gen_ai.serialized.name";
20
20
  export const GEN_AI_SERIALIZED_SIGNATURE = "gen_ai.serialized.signature";
21
21
  export const GEN_AI_SERIALIZED_DOC = "gen_ai.serialized.doc";
22
22
  export const GEN_AI_RESPONSE_ID = "gen_ai.response.id";
23
+ export const GEN_AI_TOOL_NAME = "gen_ai.tool.name";
24
+ export const GEN_AI_TOOL_CALL_ID = "gen_ai.tool.call.id";
25
+ export const GEN_AI_TOOL_DEFINITIONS = "gen_ai.tool.definitions";
23
26
  export const GEN_AI_RESPONSE_SERVICE_TIER = "gen_ai.response.service_tier";
24
27
  export const GEN_AI_RESPONSE_SYSTEM_FINGERPRINT = "gen_ai.response.system_fingerprint";
25
28
  export const GEN_AI_USAGE_INPUT_TOKEN_DETAILS = "gen_ai.usage.input_token_details";
@@ -203,6 +203,16 @@ class LangSmithToOTELTranslator {
203
203
  }
204
204
  // Set other parameters from invocation_params
205
205
  this.setInvocationParameters(span, runInfo);
206
+ if ("run_type" in runInfo && runInfo.run_type === "tool") {
207
+ if ("name" in runInfo && runInfo.name) {
208
+ span.setAttribute(constants.GEN_AI_TOOL_NAME, runInfo.name);
209
+ }
210
+ // Match Python: prefer extra.tool_call_id over metadata.tool_call_id.
211
+ const toolCallId = runInfo.extra?.tool_call_id || runInfo.extra?.metadata?.tool_call_id;
212
+ if (toolCallId != null) {
213
+ span.setAttribute(constants.GEN_AI_TOOL_CALL_ID, String(toolCallId));
214
+ }
215
+ }
206
216
  // Set metadata and tags if available
207
217
  const metadata = runInfo.extra?.metadata || {};
208
218
  for (const [key, value] of Object.entries(metadata)) {
@@ -289,6 +299,10 @@ class LangSmithToOTELTranslator {
289
299
  span.setAttribute(constants.GEN_AI_SYSTEM, system);
290
300
  }
291
301
  setInvocationParameters(span, runInfo) {
302
+ const tools = runInfo.extra?.invocation_params?.tools;
303
+ if (Array.isArray(tools) && tools.length > 0) {
304
+ span.setAttribute(constants.GEN_AI_TOOL_DEFINITIONS, JSON.stringify(tools));
305
+ }
292
306
  if (!runInfo.extra?.metadata?.invocation_params) {
293
307
  return;
294
308
  }
@@ -167,6 +167,16 @@ export class LangSmithToOTELTranslator {
167
167
  }
168
168
  // Set other parameters from invocation_params
169
169
  this.setInvocationParameters(span, runInfo);
170
+ if ("run_type" in runInfo && runInfo.run_type === "tool") {
171
+ if ("name" in runInfo && runInfo.name) {
172
+ span.setAttribute(constants.GEN_AI_TOOL_NAME, runInfo.name);
173
+ }
174
+ // Match Python: prefer extra.tool_call_id over metadata.tool_call_id.
175
+ const toolCallId = runInfo.extra?.tool_call_id || runInfo.extra?.metadata?.tool_call_id;
176
+ if (toolCallId != null) {
177
+ span.setAttribute(constants.GEN_AI_TOOL_CALL_ID, String(toolCallId));
178
+ }
179
+ }
170
180
  // Set metadata and tags if available
171
181
  const metadata = runInfo.extra?.metadata || {};
172
182
  for (const [key, value] of Object.entries(metadata)) {
@@ -253,6 +263,10 @@ export class LangSmithToOTELTranslator {
253
263
  span.setAttribute(constants.GEN_AI_SYSTEM, system);
254
264
  }
255
265
  setInvocationParameters(span, runInfo) {
266
+ const tools = runInfo.extra?.invocation_params?.tools;
267
+ if (Array.isArray(tools) && tools.length > 0) {
268
+ span.setAttribute(constants.GEN_AI_TOOL_DEFINITIONS, JSON.stringify(tools));
269
+ }
256
270
  if (!runInfo.extra?.metadata?.invocation_params) {
257
271
  return;
258
272
  }
package/dist/index.cjs CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LS_MESSAGE_VIEW_EXCLUDE = exports.__version__ = exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIUserAbortError = exports.APIError = exports.LangsmithError = exports.promptCacheSingleton = exports.configureGlobalPromptCache = exports.PromptCache = exports.Cache = exports.isTracingEnabled = exports.uuid7FromTime = exports.uuid7 = exports.computeRunIdForSecondaryReplica = exports.getDefaultProjectName = exports.overrideFetchImplementation = exports.RunTree = exports.Client = void 0;
3
+ exports.LS_MESSAGE_VIEW_EXCLUDE = exports.__version__ = exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIUserAbortError = exports.APIError = exports.LangsmithError = exports.promptCacheSingleton = exports.configureGlobalPromptCache = exports.PromptCache = exports.Cache = exports.isTracingEnabled = exports.uuid7FromTime = exports.uuid7 = exports.computeRunIdForSecondaryReplica = exports.getDefaultProjectName = exports.overrideFetchImplementation = exports.EnvAddressError = exports.RunTree = exports.Client = void 0;
4
4
  var client_js_1 = require("./client.cjs");
5
5
  Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_js_1.Client; } });
6
6
  var run_trees_js_1 = require("./run_trees.cjs");
7
7
  Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () { return run_trees_js_1.RunTree; } });
8
+ var address_js_1 = require("./address.cjs");
9
+ Object.defineProperty(exports, "EnvAddressError", { enumerable: true, get: function () { return address_js_1.EnvAddressError; } });
8
10
  var fetch_js_1 = require("./singletons/fetch.cjs");
9
11
  Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true, get: function () { return fetch_js_1.overrideFetchImplementation; } });
10
12
  var project_js_1 = require("./utils/project.cjs");
@@ -35,6 +37,6 @@ Object.defineProperty(exports, "UnprocessableEntityError", { enumerable: true, g
35
37
  Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return error_js_1.RateLimitError; } });
36
38
  Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return error_js_1.InternalServerError; } });
37
39
  // Update using pnpm bump-version
38
- exports.__version__ = "0.10.4";
40
+ exports.__version__ = "0.10.6";
39
41
  // Metadata key to hide a traced run from LangSmith's Messages View.
40
42
  exports.LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  export { Client, type ClientConfig, type LangSmithTracingClientInterface, } from "./client.js";
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, FeedbackConfigSchema, RetrieverOutput, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig, type WriteReplica } from "./run_trees.js";
4
+ export { type Address, EnvAddressError } from "./address.js";
4
5
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
6
  export { getDefaultProjectName } from "./utils/project.js";
6
7
  export { computeRunIdForSecondaryReplica, uuid7, uuid7FromTime, } from "./uuid.js";
7
8
  export { isTracingEnabled } from "./utils/guard.js";
8
9
  export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
9
10
  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.10.4";
11
+ export declare const __version__ = "0.10.6";
11
12
  export declare const LS_MESSAGE_VIEW_EXCLUDE: "ls_message_view_exclude";