braintrust 0.4.1 → 0.4.2

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/browser.js CHANGED
@@ -5124,7 +5124,6 @@ var init_context3 = __esm({
5124
5124
  "src/otel/context.ts"() {
5125
5125
  "use strict";
5126
5126
  init_logger();
5127
- init_util();
5128
5127
  OTEL_NOT_INSTALLED_MESSAGE = "OpenTelemetry packages are not installed. Install them with: npm install @opentelemetry/api @opentelemetry/sdk-trace-base";
5129
5128
  otelTrace = null;
5130
5129
  otelContext = null;
@@ -5187,6 +5186,10 @@ var init_context3 = __esm({
5187
5186
  const currentContext = otelContext.active();
5188
5187
  let newContext = otelTrace.setSpan(currentContext, wrappedContext);
5189
5188
  newContext = newContext.setValue("braintrust_span", span);
5189
+ const parentValue = span._getOtelParent();
5190
+ if (parentValue) {
5191
+ newContext = newContext.setValue("braintrust.parent", parentValue);
5192
+ }
5190
5193
  return otelContext.with(newContext, callback);
5191
5194
  }
5192
5195
  } catch (error) {
@@ -5202,34 +5205,6 @@ var init_context3 = __esm({
5202
5205
  }
5203
5206
  return void 0;
5204
5207
  }
5205
- _getOtelParent(span) {
5206
- if (!span.parentObjectType || !span.parentObjectId) {
5207
- return void 0;
5208
- }
5209
- try {
5210
- const parentType = span.parentObjectType;
5211
- const parentId = span.parentObjectId;
5212
- if (parentType === 2 /* PROJECT_LOGS */) {
5213
- const id = typeof parentId === "object" && parentId !== null && "get" in parentId ? (
5214
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type guard ensures object has get method
5215
- parentId.get()
5216
- ) : parentId;
5217
- if (typeof id === "string") {
5218
- return `project_id:${id}`;
5219
- }
5220
- } else if (parentType === 1 /* EXPERIMENT */) {
5221
- const id = typeof parentId === "object" && parentId !== null && "get" in parentId ? (
5222
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type guard ensures object has get method
5223
- parentId.get()
5224
- ) : parentId;
5225
- if (typeof id === "string") {
5226
- return `experiment_id:${id}`;
5227
- }
5228
- }
5229
- } catch (e9) {
5230
- }
5231
- return void 0;
5232
- }
5233
5208
  };
5234
5209
  }
5235
5210
  });
@@ -5265,7 +5240,7 @@ function getContextManager() {
5265
5240
  try {
5266
5241
  const { OtelContextManager: OtelContextManager2 } = (init_context3(), __toCommonJS(context_exports));
5267
5242
  return new OtelContextManager2();
5268
- } catch (e10) {
5243
+ } catch (e9) {
5269
5244
  console.warn(
5270
5245
  "OTEL not available, falling back to Braintrust-only context manager"
5271
5246
  );
@@ -7040,6 +7015,9 @@ var init_logger = __esm({
7040
7015
  state() {
7041
7016
  return _internalGetGlobalState();
7042
7017
  }
7018
+ _getOtelParent() {
7019
+ return void 0;
7020
+ }
7043
7021
  // Custom inspect for Node.js console.log
7044
7022
  [Symbol.for("nodejs.util.inspect.custom")]() {
7045
7023
  return `NoopSpan {
@@ -8547,6 +8525,15 @@ Error: ${errorText}`;
8547
8525
  return (await this.lazyMetadata.get()).experiment.id;
8548
8526
  })();
8549
8527
  }
8528
+ /**
8529
+ * Wait for the experiment ID to be resolved. This is useful for ensuring the ID
8530
+ * is available synchronously in child spans (for OTEL parent attributes).
8531
+ * @internal
8532
+ */
8533
+ async _waitForId() {
8534
+ await this.lazyId.get().catch(() => {
8535
+ });
8536
+ }
8550
8537
  get name() {
8551
8538
  return (async () => {
8552
8539
  return (await this.lazyMetadata.get()).experiment.name;
@@ -9099,6 +9086,42 @@ View complete results in Braintrust or run experiment.summarize() again.`
9099
9086
  state() {
9100
9087
  return this._state;
9101
9088
  }
9089
+ /**
9090
+ * Internal method to get the OTEL parent string for this span.
9091
+ * This is used by OtelContextManager to set the braintrust.parent attribute.
9092
+ * @returns A string like "project_id:X" or "experiment_id:X", or undefined if no parent
9093
+ */
9094
+ _getOtelParent() {
9095
+ if (!this.parentObjectType) {
9096
+ return void 0;
9097
+ }
9098
+ try {
9099
+ if (this.parentObjectType === 2 /* PROJECT_LOGS */) {
9100
+ const syncResult = this.parentObjectId.getSync();
9101
+ const id = syncResult.value;
9102
+ const args = this.parentComputeObjectMetadataArgs;
9103
+ if (id) {
9104
+ return `project_id:${id}`;
9105
+ }
9106
+ const projectName = _optionalChain([args, 'optionalAccess', _106 => _106.project_name]);
9107
+ if (projectName) {
9108
+ return `project_name:${projectName}`;
9109
+ }
9110
+ } else if (this.parentObjectType === 1 /* EXPERIMENT */) {
9111
+ const syncResult = this.parentObjectId.getSync();
9112
+ const id = syncResult.value;
9113
+ if (!syncResult.resolved) {
9114
+ this.parentObjectId.get().catch(() => {
9115
+ });
9116
+ }
9117
+ if (id) {
9118
+ return `experiment_id:${id}`;
9119
+ }
9120
+ }
9121
+ } catch (e) {
9122
+ }
9123
+ return void 0;
9124
+ }
9102
9125
  // Custom inspect for Node.js console.log
9103
9126
  [Symbol.for("nodejs.util.inspect.custom")]() {
9104
9127
  return `SpanImpl {
@@ -9377,13 +9400,13 @@ View complete results in Braintrust or run experiment.summarize() again.`
9377
9400
  return "slug" in this.metadata ? this.metadata.slug : this.metadata.id;
9378
9401
  }
9379
9402
  get prompt() {
9380
- return _optionalChain([this, 'access', _106 => _106.getParsedPromptData, 'call', _107 => _107(), 'optionalAccess', _108 => _108.prompt]);
9403
+ return _optionalChain([this, 'access', _107 => _107.getParsedPromptData, 'call', _108 => _108(), 'optionalAccess', _109 => _109.prompt]);
9381
9404
  }
9382
9405
  get version() {
9383
9406
  return this.metadata[TRANSACTION_ID_FIELD];
9384
9407
  }
9385
9408
  get options() {
9386
- return _optionalChain([this, 'access', _109 => _109.getParsedPromptData, 'call', _110 => _110(), 'optionalAccess', _111 => _111.options]) || {};
9409
+ return _optionalChain([this, 'access', _110 => _110.getParsedPromptData, 'call', _111 => _111(), 'optionalAccess', _112 => _112.options]) || {};
9387
9410
  }
9388
9411
  get promptData() {
9389
9412
  return this.getParsedPromptData();
@@ -9534,7 +9557,7 @@ View complete results in Braintrust or run experiment.summarize() again.`
9534
9557
  return {
9535
9558
  type: "chat",
9536
9559
  messages,
9537
- ..._optionalChain([prompt, 'access', _112 => _112.tools, 'optionalAccess', _113 => _113.trim, 'call', _114 => _114()]) ? {
9560
+ ..._optionalChain([prompt, 'access', _113 => _113.tools, 'optionalAccess', _114 => _114.trim, 'call', _115 => _115()]) ? {
9538
9561
  tools: render(prompt.tools)
9539
9562
  } : void 0
9540
9563
  };
@@ -9609,7 +9632,7 @@ function configureBrowser() {
9609
9632
  if (typeof AsyncLocalStorage !== "undefined") {
9610
9633
  isomorph_default.newAsyncLocalStorage = () => new AsyncLocalStorage();
9611
9634
  }
9612
- } catch (e11) {
9635
+ } catch (e10) {
9613
9636
  }
9614
9637
  isomorph_default.getEnv = (name) => {
9615
9638
  if (typeof process === "undefined" || typeof process.env === "undefined") {
@@ -9862,7 +9885,7 @@ function parseSpanFromResponseCreateParams(params) {
9862
9885
  }
9863
9886
  function parseEventFromResponseCreateResult(result) {
9864
9887
  const data = {};
9865
- if (_optionalChain([result, 'optionalAccess', _115 => _115.output]) !== void 0) {
9888
+ if (_optionalChain([result, 'optionalAccess', _116 => _116.output]) !== void 0) {
9866
9889
  data.output = processImagesInOutput(result.output);
9867
9890
  }
9868
9891
  if (result) {
@@ -9871,7 +9894,7 @@ function parseEventFromResponseCreateResult(result) {
9871
9894
  data.metadata = metadata;
9872
9895
  }
9873
9896
  }
9874
- data.metrics = parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _116 => _116.usage]));
9897
+ data.metrics = parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _117 => _117.usage]));
9875
9898
  return data;
9876
9899
  }
9877
9900
  function processImagesInOutput(output) {
@@ -9925,7 +9948,7 @@ function parseSpanFromResponseParseParams(params) {
9925
9948
  }
9926
9949
  function parseEventFromResponseParseResult(result) {
9927
9950
  const data = {};
9928
- if (_optionalChain([result, 'optionalAccess', _117 => _117.output]) !== void 0) {
9951
+ if (_optionalChain([result, 'optionalAccess', _118 => _118.output]) !== void 0) {
9929
9952
  data.output = processImagesInOutput(result.output);
9930
9953
  }
9931
9954
  if (result) {
@@ -9934,7 +9957,7 @@ function parseEventFromResponseParseResult(result) {
9934
9957
  data.metadata = metadata;
9935
9958
  }
9936
9959
  }
9937
- data.metrics = parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _118 => _118.usage]));
9960
+ data.metrics = parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _119 => _119.usage]));
9938
9961
  return data;
9939
9962
  }
9940
9963
  function traceResponseCreateStream(stream, timedSpan) {
@@ -9951,7 +9974,7 @@ function traceResponseCreateStream(stream, timedSpan) {
9951
9974
  return result;
9952
9975
  }
9953
9976
  const item = result.value;
9954
- if (!item || !_optionalChain([item, 'optionalAccess', _119 => _119.type]) || !_optionalChain([item, 'optionalAccess', _120 => _120.response])) {
9977
+ if (!item || !_optionalChain([item, 'optionalAccess', _120 => _120.type]) || !_optionalChain([item, 'optionalAccess', _121 => _121.response])) {
9955
9978
  return result;
9956
9979
  }
9957
9980
  const event = parseLogFromItem(item);
@@ -9962,14 +9985,14 @@ function traceResponseCreateStream(stream, timedSpan) {
9962
9985
  };
9963
9986
  }
9964
9987
  function parseLogFromItem(item) {
9965
- if (!item || !_optionalChain([item, 'optionalAccess', _121 => _121.type]) || !_optionalChain([item, 'optionalAccess', _122 => _122.response])) {
9988
+ if (!item || !_optionalChain([item, 'optionalAccess', _122 => _122.type]) || !_optionalChain([item, 'optionalAccess', _123 => _123.response])) {
9966
9989
  return {};
9967
9990
  }
9968
9991
  const response = item.response;
9969
9992
  switch (item.type) {
9970
9993
  case "response.completed":
9971
9994
  const data = {};
9972
- if (_optionalChain([response, 'optionalAccess', _123 => _123.output]) !== void 0) {
9995
+ if (_optionalChain([response, 'optionalAccess', _124 => _124.output]) !== void 0) {
9973
9996
  data.output = processImagesInOutput(response.output);
9974
9997
  }
9975
9998
  if (response) {
@@ -9978,7 +10001,7 @@ function parseLogFromItem(item) {
9978
10001
  data.metadata = metadata;
9979
10002
  }
9980
10003
  }
9981
- data.metrics = parseMetricsFromUsage(_optionalChain([response, 'optionalAccess', _124 => _124.usage]));
10004
+ data.metrics = parseMetricsFromUsage(_optionalChain([response, 'optionalAccess', _125 => _125.usage]));
9982
10005
  return data;
9983
10006
  default:
9984
10007
  return {};
@@ -10162,8 +10185,8 @@ function wrapOpenAIv4(openai) {
10162
10185
  const embeddingProxy = createEndpointProxy(openai.embeddings, wrapEmbeddings);
10163
10186
  const moderationProxy = createEndpointProxy(openai.moderations, wrapModerations);
10164
10187
  let betaProxy;
10165
- if (_optionalChain([openai, 'access', _125 => _125.beta, 'optionalAccess', _126 => _126.chat, 'optionalAccess', _127 => _127.completions, 'optionalAccess', _128 => _128.stream])) {
10166
- const betaChatCompletionProxy = new Proxy(_optionalChain([openai, 'optionalAccess', _129 => _129.beta, 'optionalAccess', _130 => _130.chat, 'access', _131 => _131.completions]), {
10188
+ if (_optionalChain([openai, 'access', _126 => _126.beta, 'optionalAccess', _127 => _127.chat, 'optionalAccess', _128 => _128.completions, 'optionalAccess', _129 => _129.stream])) {
10189
+ const betaChatCompletionProxy = new Proxy(_optionalChain([openai, 'optionalAccess', _130 => _130.beta, 'optionalAccess', _131 => _131.chat, 'access', _132 => _132.completions]), {
10167
10190
  get(target, name, receiver) {
10168
10191
  const baseVal = Reflect.get(target, name, receiver);
10169
10192
  if (name === "parse") {
@@ -10211,7 +10234,7 @@ function wrapOpenAIv4(openai) {
10211
10234
  });
10212
10235
  }
10213
10236
  function logCompletionResponse(startTime, response, span) {
10214
- const metrics2 = parseMetricsFromUsage(_optionalChain([response, 'optionalAccess', _132 => _132.usage]));
10237
+ const metrics2 = parseMetricsFromUsage(_optionalChain([response, 'optionalAccess', _133 => _133.usage]));
10215
10238
  metrics2.time_to_first_token = getCurrentUnixTimestamp() - startTime;
10216
10239
  span.log({
10217
10240
  output: response.choices,
@@ -10441,7 +10464,7 @@ function parseChatCompletionParams(params) {
10441
10464
  function processEmbeddingResponse(result, span) {
10442
10465
  span.log({
10443
10466
  output: { embedding_length: result.data[0].embedding.length },
10444
- metrics: parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _133 => _133.usage]))
10467
+ metrics: parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _134 => _134.usage]))
10445
10468
  });
10446
10469
  }
10447
10470
  function processModerationResponse(result, span) {
@@ -10471,10 +10494,10 @@ function postprocessStreamingResults(allResults) {
10471
10494
  if (result.usage) {
10472
10495
  metrics2 = {
10473
10496
  ...metrics2,
10474
- ...parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _134 => _134.usage]))
10497
+ ...parseMetricsFromUsage(_optionalChain([result, 'optionalAccess', _135 => _135.usage]))
10475
10498
  };
10476
10499
  }
10477
- const delta = _optionalChain([result, 'access', _135 => _135.choices, 'optionalAccess', _136 => _136[0], 'optionalAccess', _137 => _137.delta]);
10500
+ const delta = _optionalChain([result, 'access', _136 => _136.choices, 'optionalAccess', _137 => _137[0], 'optionalAccess', _138 => _138.delta]);
10478
10501
  if (!delta) {
10479
10502
  continue;
10480
10503
  }
package/dist/browser.mjs CHANGED
@@ -5124,7 +5124,6 @@ var init_context3 = __esm({
5124
5124
  "src/otel/context.ts"() {
5125
5125
  "use strict";
5126
5126
  init_logger();
5127
- init_util();
5128
5127
  OTEL_NOT_INSTALLED_MESSAGE = "OpenTelemetry packages are not installed. Install them with: npm install @opentelemetry/api @opentelemetry/sdk-trace-base";
5129
5128
  otelTrace = null;
5130
5129
  otelContext = null;
@@ -5187,6 +5186,10 @@ var init_context3 = __esm({
5187
5186
  const currentContext = otelContext.active();
5188
5187
  let newContext = otelTrace.setSpan(currentContext, wrappedContext);
5189
5188
  newContext = newContext.setValue("braintrust_span", span);
5189
+ const parentValue = span._getOtelParent();
5190
+ if (parentValue) {
5191
+ newContext = newContext.setValue("braintrust.parent", parentValue);
5192
+ }
5190
5193
  return otelContext.with(newContext, callback);
5191
5194
  }
5192
5195
  } catch (error) {
@@ -5202,34 +5205,6 @@ var init_context3 = __esm({
5202
5205
  }
5203
5206
  return void 0;
5204
5207
  }
5205
- _getOtelParent(span) {
5206
- if (!span.parentObjectType || !span.parentObjectId) {
5207
- return void 0;
5208
- }
5209
- try {
5210
- const parentType = span.parentObjectType;
5211
- const parentId = span.parentObjectId;
5212
- if (parentType === 2 /* PROJECT_LOGS */) {
5213
- const id = typeof parentId === "object" && parentId !== null && "get" in parentId ? (
5214
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type guard ensures object has get method
5215
- parentId.get()
5216
- ) : parentId;
5217
- if (typeof id === "string") {
5218
- return `project_id:${id}`;
5219
- }
5220
- } else if (parentType === 1 /* EXPERIMENT */) {
5221
- const id = typeof parentId === "object" && parentId !== null && "get" in parentId ? (
5222
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type guard ensures object has get method
5223
- parentId.get()
5224
- ) : parentId;
5225
- if (typeof id === "string") {
5226
- return `experiment_id:${id}`;
5227
- }
5228
- }
5229
- } catch {
5230
- }
5231
- return void 0;
5232
- }
5233
5208
  };
5234
5209
  }
5235
5210
  });
@@ -7040,6 +7015,9 @@ var init_logger = __esm({
7040
7015
  state() {
7041
7016
  return _internalGetGlobalState();
7042
7017
  }
7018
+ _getOtelParent() {
7019
+ return void 0;
7020
+ }
7043
7021
  // Custom inspect for Node.js console.log
7044
7022
  [Symbol.for("nodejs.util.inspect.custom")]() {
7045
7023
  return `NoopSpan {
@@ -8547,6 +8525,15 @@ Error: ${errorText}`;
8547
8525
  return (await this.lazyMetadata.get()).experiment.id;
8548
8526
  })();
8549
8527
  }
8528
+ /**
8529
+ * Wait for the experiment ID to be resolved. This is useful for ensuring the ID
8530
+ * is available synchronously in child spans (for OTEL parent attributes).
8531
+ * @internal
8532
+ */
8533
+ async _waitForId() {
8534
+ await this.lazyId.get().catch(() => {
8535
+ });
8536
+ }
8550
8537
  get name() {
8551
8538
  return (async () => {
8552
8539
  return (await this.lazyMetadata.get()).experiment.name;
@@ -9099,6 +9086,42 @@ View complete results in Braintrust or run experiment.summarize() again.`
9099
9086
  state() {
9100
9087
  return this._state;
9101
9088
  }
9089
+ /**
9090
+ * Internal method to get the OTEL parent string for this span.
9091
+ * This is used by OtelContextManager to set the braintrust.parent attribute.
9092
+ * @returns A string like "project_id:X" or "experiment_id:X", or undefined if no parent
9093
+ */
9094
+ _getOtelParent() {
9095
+ if (!this.parentObjectType) {
9096
+ return void 0;
9097
+ }
9098
+ try {
9099
+ if (this.parentObjectType === 2 /* PROJECT_LOGS */) {
9100
+ const syncResult = this.parentObjectId.getSync();
9101
+ const id = syncResult.value;
9102
+ const args = this.parentComputeObjectMetadataArgs;
9103
+ if (id) {
9104
+ return `project_id:${id}`;
9105
+ }
9106
+ const projectName = args?.project_name;
9107
+ if (projectName) {
9108
+ return `project_name:${projectName}`;
9109
+ }
9110
+ } else if (this.parentObjectType === 1 /* EXPERIMENT */) {
9111
+ const syncResult = this.parentObjectId.getSync();
9112
+ const id = syncResult.value;
9113
+ if (!syncResult.resolved) {
9114
+ this.parentObjectId.get().catch(() => {
9115
+ });
9116
+ }
9117
+ if (id) {
9118
+ return `experiment_id:${id}`;
9119
+ }
9120
+ }
9121
+ } catch (e) {
9122
+ }
9123
+ return void 0;
9124
+ }
9102
9125
  // Custom inspect for Node.js console.log
9103
9126
  [Symbol.for("nodejs.util.inspect.custom")]() {
9104
9127
  return `SpanImpl {
package/dist/cli.js CHANGED
@@ -6364,7 +6364,6 @@ var init_context3 = __esm({
6364
6364
  "src/otel/context.ts"() {
6365
6365
  "use strict";
6366
6366
  init_logger();
6367
- init_util();
6368
6367
  OTEL_NOT_INSTALLED_MESSAGE = "OpenTelemetry packages are not installed. Install them with: npm install @opentelemetry/api @opentelemetry/sdk-trace-base";
6369
6368
  otelTrace = null;
6370
6369
  otelContext = null;
@@ -6427,6 +6426,10 @@ var init_context3 = __esm({
6427
6426
  const currentContext = otelContext.active();
6428
6427
  let newContext = otelTrace.setSpan(currentContext, wrappedContext);
6429
6428
  newContext = newContext.setValue("braintrust_span", span);
6429
+ const parentValue = span._getOtelParent();
6430
+ if (parentValue) {
6431
+ newContext = newContext.setValue("braintrust.parent", parentValue);
6432
+ }
6430
6433
  return otelContext.with(newContext, callback);
6431
6434
  }
6432
6435
  } catch (error2) {
@@ -6442,34 +6445,6 @@ var init_context3 = __esm({
6442
6445
  }
6443
6446
  return void 0;
6444
6447
  }
6445
- _getOtelParent(span) {
6446
- if (!span.parentObjectType || !span.parentObjectId) {
6447
- return void 0;
6448
- }
6449
- try {
6450
- const parentType = span.parentObjectType;
6451
- const parentId = span.parentObjectId;
6452
- if (parentType === 2 /* PROJECT_LOGS */) {
6453
- const id = typeof parentId === "object" && parentId !== null && "get" in parentId ? (
6454
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type guard ensures object has get method
6455
- parentId.get()
6456
- ) : parentId;
6457
- if (typeof id === "string") {
6458
- return `project_id:${id}`;
6459
- }
6460
- } else if (parentType === 1 /* EXPERIMENT */) {
6461
- const id = typeof parentId === "object" && parentId !== null && "get" in parentId ? (
6462
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type guard ensures object has get method
6463
- parentId.get()
6464
- ) : parentId;
6465
- if (typeof id === "string") {
6466
- return `experiment_id:${id}`;
6467
- }
6468
- }
6469
- } catch {
6470
- }
6471
- return void 0;
6472
- }
6473
6448
  };
6474
6449
  }
6475
6450
  });
@@ -7744,6 +7719,9 @@ var init_logger = __esm({
7744
7719
  state() {
7745
7720
  return _internalGetGlobalState();
7746
7721
  }
7722
+ _getOtelParent() {
7723
+ return void 0;
7724
+ }
7747
7725
  // Custom inspect for Node.js console.log
7748
7726
  [Symbol.for("nodejs.util.inspect.custom")]() {
7749
7727
  return `NoopSpan {
@@ -9131,6 +9109,15 @@ Error: ${errorText}`;
9131
9109
  return (await this.lazyMetadata.get()).experiment.id;
9132
9110
  })();
9133
9111
  }
9112
+ /**
9113
+ * Wait for the experiment ID to be resolved. This is useful for ensuring the ID
9114
+ * is available synchronously in child spans (for OTEL parent attributes).
9115
+ * @internal
9116
+ */
9117
+ async _waitForId() {
9118
+ await this.lazyId.get().catch(() => {
9119
+ });
9120
+ }
9134
9121
  get name() {
9135
9122
  return (async () => {
9136
9123
  return (await this.lazyMetadata.get()).experiment.name;
@@ -9683,6 +9670,42 @@ View complete results in Braintrust or run experiment.summarize() again.`
9683
9670
  state() {
9684
9671
  return this._state;
9685
9672
  }
9673
+ /**
9674
+ * Internal method to get the OTEL parent string for this span.
9675
+ * This is used by OtelContextManager to set the braintrust.parent attribute.
9676
+ * @returns A string like "project_id:X" or "experiment_id:X", or undefined if no parent
9677
+ */
9678
+ _getOtelParent() {
9679
+ if (!this.parentObjectType) {
9680
+ return void 0;
9681
+ }
9682
+ try {
9683
+ if (this.parentObjectType === 2 /* PROJECT_LOGS */) {
9684
+ const syncResult = this.parentObjectId.getSync();
9685
+ const id = syncResult.value;
9686
+ const args = this.parentComputeObjectMetadataArgs;
9687
+ if (id) {
9688
+ return `project_id:${id}`;
9689
+ }
9690
+ const projectName = args?.project_name;
9691
+ if (projectName) {
9692
+ return `project_name:${projectName}`;
9693
+ }
9694
+ } else if (this.parentObjectType === 1 /* EXPERIMENT */) {
9695
+ const syncResult = this.parentObjectId.getSync();
9696
+ const id = syncResult.value;
9697
+ if (!syncResult.resolved) {
9698
+ this.parentObjectId.get().catch(() => {
9699
+ });
9700
+ }
9701
+ if (id) {
9702
+ return `experiment_id:${id}`;
9703
+ }
9704
+ }
9705
+ } catch (e) {
9706
+ }
9707
+ return void 0;
9708
+ }
9686
9709
  // Custom inspect for Node.js console.log
9687
9710
  [Symbol.for("nodejs.util.inspect.custom")]() {
9688
9711
  return `SpanImpl {
@@ -10173,7 +10196,7 @@ var require_package = __commonJS({
10173
10196
  "package.json"(exports2, module2) {
10174
10197
  module2.exports = {
10175
10198
  name: "braintrust",
10176
- version: "0.4.1",
10199
+ version: "0.4.2",
10177
10200
  description: "SDK for integrating Braintrust",
10178
10201
  repository: {
10179
10202
  type: "git",
@@ -10319,7 +10342,7 @@ var dotenv2 = __toESM(require("dotenv"));
10319
10342
  var import_fs2 = __toESM(require("fs"));
10320
10343
  var import_os = __toESM(require("os"));
10321
10344
  var import_path6 = __toESM(require("path"));
10322
- var import_util15 = __toESM(require("util"));
10345
+ var import_util14 = __toESM(require("util"));
10323
10346
  var fsWalk = __toESM(require_out3());
10324
10347
  var import_minimatch = require("minimatch");
10325
10348
  var import_argparse = require("argparse");
@@ -11922,6 +11945,9 @@ async function Eval(name, evaluator, reporterOrOpts) {
11922
11945
  repoInfo: evaluator.repoInfo,
11923
11946
  dataset: Dataset2.isDataset(data) ? data : void 0
11924
11947
  });
11948
+ if (experiment && typeof process !== "undefined" && process.env?.BRAINTRUST_OTEL_COMPAT?.toLowerCase() === "true") {
11949
+ await experiment._waitForId();
11950
+ }
11925
11951
  if (experiment && options.onStart) {
11926
11952
  const summary = await experiment.summarize({ summarizeScores: false });
11927
11953
  options.onStart(summary);
@@ -12664,7 +12690,7 @@ function getCallerLocation() {
12664
12690
 
12665
12691
  // src/node.ts
12666
12692
  init_logger();
12667
- var import_util9 = require("util");
12693
+ var import_util8 = require("util");
12668
12694
  var zlib = __toESM(require("zlib"));
12669
12695
  function configureNode() {
12670
12696
  isomorph_default.getRepoInfo = getRepoInfo;
@@ -12686,8 +12712,8 @@ function configureNode() {
12686
12712
  isomorph_default.utimes = fs.utimes;
12687
12713
  isomorph_default.unlink = fs.unlink;
12688
12714
  isomorph_default.homedir = os.homedir;
12689
- isomorph_default.gzip = (0, import_util9.promisify)(zlib.gzip);
12690
- isomorph_default.gunzip = (0, import_util9.promisify)(zlib.gunzip);
12715
+ isomorph_default.gzip = (0, import_util8.promisify)(zlib.gzip);
12716
+ isomorph_default.gunzip = (0, import_util8.promisify)(zlib.gunzip);
12691
12717
  isomorph_default.hash = (data) => crypto.createHash("sha256").update(data).digest("hex");
12692
12718
  _internalSetInitialState();
12693
12719
  }
@@ -13311,7 +13337,7 @@ init_generated_types();
13311
13337
  init_logger();
13312
13338
  var import_v311 = require("zod/v3");
13313
13339
  var import_promises = __toESM(require("fs/promises"));
13314
- var import_util12 = __toESM(require("util"));
13340
+ var import_util11 = __toESM(require("util"));
13315
13341
  var import_slugify3 = __toESM(require("slugify"));
13316
13342
  var import_path5 = __toESM(require("path"));
13317
13343
  init_util();
@@ -13584,7 +13610,7 @@ function safeStringify(obj) {
13584
13610
  return JSON.stringify(obj, null, 2);
13585
13611
  } catch (error2) {
13586
13612
  try {
13587
- return import_util12.default.inspect(obj, {
13613
+ return import_util11.default.inspect(obj, {
13588
13614
  depth: 5,
13589
13615
  maxStringLength: 1e3,
13590
13616
  breakLength: 80,
@@ -14586,7 +14612,7 @@ async function collectFiles(inputPath, mode) {
14586
14612
  }
14587
14613
  files.push(inputPath);
14588
14614
  } else {
14589
- const walked = await import_util15.default.promisify(fsWalk.walk)(inputPath, {
14615
+ const walked = await import_util14.default.promisify(fsWalk.walk)(inputPath, {
14590
14616
  deepFilter: (entry) => {
14591
14617
  return checkMatch(entry.path, null, EXCLUDE);
14592
14618
  },
package/dist/index.d.mts CHANGED
@@ -14477,6 +14477,12 @@ interface Span$1 extends Exportable {
14477
14477
  */
14478
14478
  startSpanWithParents(spanId: string, spanParents: string[], args?: StartSpanArgs): Span$1;
14479
14479
  state(): BraintrustState;
14480
+ /**
14481
+ * Internal method to get the OTEL parent string for this span.
14482
+ * This is used by OtelContextManager to set the braintrust.parent attribute.
14483
+ * @returns A string like "project_id:X" or "experiment_id:X", or undefined if no parent
14484
+ */
14485
+ _getOtelParent(): string | undefined;
14480
14486
  kind: "span";
14481
14487
  }
14482
14488
  declare abstract class ContextManager {
@@ -14508,6 +14514,7 @@ declare class NoopSpan implements Span$1 {
14508
14514
  setAttributes(_args: Omit<StartSpanArgs, "event">): void;
14509
14515
  startSpanWithParents(_spanId: string, _spanParents: string[], _args?: StartSpanArgs): Span$1;
14510
14516
  state(): BraintrustState;
14517
+ _getOtelParent(): string | undefined;
14511
14518
  toString(): string;
14512
14519
  }
14513
14520
  declare const NOOP_SPAN: NoopSpan;
@@ -15479,6 +15486,12 @@ declare class Experiment extends ObjectFetcher<ExperimentEvent> implements Expor
15479
15486
  kind: "experiment";
15480
15487
  constructor(state: BraintrustState, lazyMetadata: LazyValue<ProjectExperimentMetadata>, dataset?: AnyDataset);
15481
15488
  get id(): Promise<string>;
15489
+ /**
15490
+ * Wait for the experiment ID to be resolved. This is useful for ensuring the ID
15491
+ * is available synchronously in child spans (for OTEL parent attributes).
15492
+ * @internal
15493
+ */
15494
+ _waitForId(): Promise<void>;
15482
15495
  get name(): Promise<string>;
15483
15496
  get project(): Promise<ObjectMetadata>;
15484
15497
  private parentObjectType;
@@ -15628,6 +15641,12 @@ declare class SpanImpl implements Span$1 {
15628
15641
  flush(): Promise<void>;
15629
15642
  close(args?: EndSpanArgs): number;
15630
15643
  state(): BraintrustState;
15644
+ /**
15645
+ * Internal method to get the OTEL parent string for this span.
15646
+ * This is used by OtelContextManager to set the braintrust.parent attribute.
15647
+ * @returns A string like "project_id:X" or "experiment_id:X", or undefined if no parent
15648
+ */
15649
+ _getOtelParent(): string | undefined;
15631
15650
  toString(): string;
15632
15651
  }
15633
15652
  /**
package/dist/index.d.ts CHANGED
@@ -14477,6 +14477,12 @@ interface Span$1 extends Exportable {
14477
14477
  */
14478
14478
  startSpanWithParents(spanId: string, spanParents: string[], args?: StartSpanArgs): Span$1;
14479
14479
  state(): BraintrustState;
14480
+ /**
14481
+ * Internal method to get the OTEL parent string for this span.
14482
+ * This is used by OtelContextManager to set the braintrust.parent attribute.
14483
+ * @returns A string like "project_id:X" or "experiment_id:X", or undefined if no parent
14484
+ */
14485
+ _getOtelParent(): string | undefined;
14480
14486
  kind: "span";
14481
14487
  }
14482
14488
  declare abstract class ContextManager {
@@ -14508,6 +14514,7 @@ declare class NoopSpan implements Span$1 {
14508
14514
  setAttributes(_args: Omit<StartSpanArgs, "event">): void;
14509
14515
  startSpanWithParents(_spanId: string, _spanParents: string[], _args?: StartSpanArgs): Span$1;
14510
14516
  state(): BraintrustState;
14517
+ _getOtelParent(): string | undefined;
14511
14518
  toString(): string;
14512
14519
  }
14513
14520
  declare const NOOP_SPAN: NoopSpan;
@@ -15479,6 +15486,12 @@ declare class Experiment extends ObjectFetcher<ExperimentEvent> implements Expor
15479
15486
  kind: "experiment";
15480
15487
  constructor(state: BraintrustState, lazyMetadata: LazyValue<ProjectExperimentMetadata>, dataset?: AnyDataset);
15481
15488
  get id(): Promise<string>;
15489
+ /**
15490
+ * Wait for the experiment ID to be resolved. This is useful for ensuring the ID
15491
+ * is available synchronously in child spans (for OTEL parent attributes).
15492
+ * @internal
15493
+ */
15494
+ _waitForId(): Promise<void>;
15482
15495
  get name(): Promise<string>;
15483
15496
  get project(): Promise<ObjectMetadata>;
15484
15497
  private parentObjectType;
@@ -15628,6 +15641,12 @@ declare class SpanImpl implements Span$1 {
15628
15641
  flush(): Promise<void>;
15629
15642
  close(args?: EndSpanArgs): number;
15630
15643
  state(): BraintrustState;
15644
+ /**
15645
+ * Internal method to get the OTEL parent string for this span.
15646
+ * This is used by OtelContextManager to set the braintrust.parent attribute.
15647
+ * @returns A string like "project_id:X" or "experiment_id:X", or undefined if no parent
15648
+ */
15649
+ _getOtelParent(): string | undefined;
15631
15650
  toString(): string;
15632
15651
  }
15633
15652
  /**