braintrust 3.23.1 → 3.24.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 (51) hide show
  1. package/dev/dist/index.d.mts +6 -0
  2. package/dev/dist/index.d.ts +6 -0
  3. package/dev/dist/index.js +902 -586
  4. package/dev/dist/index.mjs +320 -4
  5. package/dist/apply-auto-instrumentation.js +211 -189
  6. package/dist/apply-auto-instrumentation.mjs +23 -1
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +40 -0
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +40 -0
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +40 -0
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +40 -0
  14. package/dist/auto-instrumentations/bundler/vite.d.mts +1 -1
  15. package/dist/auto-instrumentations/bundler/vite.d.ts +1 -1
  16. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  17. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +40 -0
  18. package/dist/auto-instrumentations/bundler/webpack.cjs +40 -0
  19. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  20. package/dist/auto-instrumentations/{chunk-KIMLYPRW.mjs → chunk-BURMPO7L.mjs} +1 -1
  21. package/dist/auto-instrumentations/{chunk-YXLNSAMJ.mjs → chunk-F43DNLPD.mjs} +40 -0
  22. package/dist/auto-instrumentations/{chunk-EXY7QCJD.mjs → chunk-GSZHTAQW.mjs} +1 -1
  23. package/dist/auto-instrumentations/hook.mjs +150 -1
  24. package/dist/auto-instrumentations/index.cjs +40 -0
  25. package/dist/auto-instrumentations/index.mjs +1 -1
  26. package/dist/browser.d.mts +131 -9
  27. package/dist/browser.d.ts +131 -9
  28. package/dist/browser.js +703 -65
  29. package/dist/browser.mjs +703 -65
  30. package/dist/{chunk-CDIKAHDZ.js → chunk-7AUY2XWX.js} +21 -1
  31. package/dist/{chunk-36IPYKMG.mjs → chunk-7F6GCRHH.mjs} +20 -0
  32. package/dist/{chunk-B6ZQIAK3.js → chunk-SU6EHKJV.js} +1085 -799
  33. package/dist/{chunk-RBXD2KYN.mjs → chunk-XE5FS7QY.mjs} +291 -5
  34. package/dist/cli.js +328 -8
  35. package/dist/edge-light.js +703 -65
  36. package/dist/edge-light.mjs +703 -65
  37. package/dist/index.d.mts +131 -9
  38. package/dist/index.d.ts +131 -9
  39. package/dist/index.js +891 -532
  40. package/dist/index.mjs +423 -64
  41. package/dist/instrumentation/index.d.mts +130 -9
  42. package/dist/instrumentation/index.d.ts +130 -9
  43. package/dist/instrumentation/index.js +601 -65
  44. package/dist/instrumentation/index.mjs +601 -65
  45. package/dist/vitest-evals-reporter.js +17 -16
  46. package/dist/vitest-evals-reporter.mjs +3 -2
  47. package/dist/workerd.js +703 -65
  48. package/dist/workerd.mjs +703 -65
  49. package/package.json +3 -3
  50. package/util/dist/index.js +4 -0
  51. package/util/dist/index.mjs +4 -0
@@ -13,6 +13,7 @@ import {
13
13
  googleADKChannels,
14
14
  googleGenAIChannels,
15
15
  groqChannels,
16
+ harnessAgentChannels,
16
17
  huggingFaceChannels,
17
18
  installMastraExporterFactory,
18
19
  isInstrumentationIntegrationDisabled,
@@ -31,7 +32,7 @@ import {
31
32
  smithyClientChannels,
32
33
  smithyCoreChannels,
33
34
  strandsAgentSDKChannels
34
- } from "./chunk-36IPYKMG.mjs";
35
+ } from "./chunk-7F6GCRHH.mjs";
35
36
 
36
37
  // src/id-gen.ts
37
38
  import { v4 as uuidv4 } from "uuid";
@@ -965,6 +966,7 @@ var SpanComponentsV3 = class _SpanComponentsV3 {
965
966
  constructor(data) {
966
967
  this.data = data;
967
968
  }
969
+ data;
968
970
  toStr() {
969
971
  const jsonObj = {
970
972
  compute_object_metadata_args: this.data.compute_object_metadata_args || void 0,
@@ -1458,6 +1460,7 @@ var SpanComponentsV4 = class _SpanComponentsV4 {
1458
1460
  constructor(data) {
1459
1461
  this.data = data;
1460
1462
  }
1463
+ data;
1461
1464
  toStr() {
1462
1465
  const jsonObj = {
1463
1466
  compute_object_metadata_args: this.data.compute_object_metadata_args || void 0,
@@ -4750,6 +4753,97 @@ var SpanCache = class {
4750
4753
  }
4751
4754
  };
4752
4755
 
4756
+ // src/span-origin.ts
4757
+ var SDK_VERSION = true ? "3.24.0" : "0.0.0";
4758
+ function detectSpanOriginEnvironment(explicit) {
4759
+ if (explicit) return explicit;
4760
+ const envType = isomorph_default.getEnv("BRAINTRUST_ENVIRONMENT_TYPE");
4761
+ const envName = isomorph_default.getEnv("BRAINTRUST_ENVIRONMENT_NAME");
4762
+ if (envType || envName) {
4763
+ return {
4764
+ ...envType ? { type: envType } : {},
4765
+ ...envName ? { name: envName } : {}
4766
+ };
4767
+ }
4768
+ const ci = firstPresent([
4769
+ ["GITHUB_ACTIONS", "github_actions"],
4770
+ ["GITLAB_CI", "gitlab_ci"],
4771
+ ["CIRCLECI", "circleci"],
4772
+ ["BUILDKITE", "buildkite"],
4773
+ ["JENKINS_URL", "jenkins"],
4774
+ ["JENKINS_HOME", "jenkins"],
4775
+ ["TF_BUILD", "azure_pipelines"],
4776
+ ["TEAMCITY_VERSION", "teamcity"],
4777
+ ["TRAVIS", "travis"],
4778
+ ["BITBUCKET_BUILD_NUMBER", "bitbucket"]
4779
+ ]);
4780
+ if (ci) return { type: "ci", name: ci };
4781
+ if (isomorph_default.getEnv("CI")) return { type: "ci", name: "ci" };
4782
+ const earlyServer = firstPresent([
4783
+ ["VERCEL", "vercel"],
4784
+ ["NETLIFY", "netlify"]
4785
+ ]);
4786
+ if (earlyServer) return { type: "server", name: earlyServer };
4787
+ if (isomorph_default.getEnv("ECS_CONTAINER_METADATA_URI") || isomorph_default.getEnv("ECS_CONTAINER_METADATA_URI_V4")) {
4788
+ return { type: "server", name: "ecs" };
4789
+ }
4790
+ const awsExecutionEnv = isomorph_default.getEnv("AWS_EXECUTION_ENV");
4791
+ if (awsExecutionEnv?.startsWith("AWS_ECS_")) {
4792
+ return { type: "server", name: "ecs" };
4793
+ }
4794
+ if (awsExecutionEnv?.startsWith("AWS_Lambda_")) {
4795
+ return { type: "server", name: "aws_lambda" };
4796
+ }
4797
+ if (isomorph_default.getEnv("AWS_LAMBDA_FUNCTION_NAME")) {
4798
+ return { type: "server", name: "aws_lambda" };
4799
+ }
4800
+ const server = firstPresent([
4801
+ ["K_SERVICE", "cloud_run"],
4802
+ ["FUNCTION_TARGET", "gcp_functions"],
4803
+ ["KUBERNETES_SERVICE_HOST", "kubernetes"],
4804
+ ["DYNO", "heroku"],
4805
+ ["FLY_APP_NAME", "fly"],
4806
+ ["RAILWAY_ENVIRONMENT", "railway"],
4807
+ ["RENDER_SERVICE_NAME", "render"]
4808
+ ]);
4809
+ if (server) return { type: "server", name: server };
4810
+ return deploymentModeEnvironment("NODE_ENV", isomorph_default.getEnv("NODE_ENV"));
4811
+ }
4812
+ function makeSpanOrigin(instrumentationName, environment) {
4813
+ return {
4814
+ name: "braintrust.sdk.javascript",
4815
+ version: SDK_VERSION,
4816
+ instrumentation: { name: instrumentationName },
4817
+ ...environment ? { environment } : {}
4818
+ };
4819
+ }
4820
+ function mergeSpanOriginContext(context, instrumentationName, environment) {
4821
+ const next = { ...context ?? {} };
4822
+ const current = isObject2(next.span_origin) ? { ...next.span_origin } : {};
4823
+ next.span_origin = {
4824
+ ...makeSpanOrigin(instrumentationName, environment),
4825
+ ...current
4826
+ };
4827
+ return next;
4828
+ }
4829
+ function firstPresent(entries) {
4830
+ return entries.find(([key]) => Boolean(isomorph_default.getEnv(key)))?.[1];
4831
+ }
4832
+ function deploymentModeEnvironment(_key, value) {
4833
+ if (!value) return void 0;
4834
+ const normalized = value.toLowerCase();
4835
+ if (normalized === "production" || normalized === "staging") {
4836
+ return { type: "server", name: normalized };
4837
+ }
4838
+ if (normalized === "development" || normalized === "local") {
4839
+ return { type: "local", name: normalized };
4840
+ }
4841
+ return { name: value };
4842
+ }
4843
+ function isObject2(value) {
4844
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4845
+ }
4846
+
4753
4847
  // src/logger.ts
4754
4848
  var BRAINTRUST_ATTACHMENT = BraintrustAttachmentReference.shape.type.value;
4755
4849
  var EXTERNAL_ATTACHMENT = ExternalAttachmentReference.shape.type.value;
@@ -4798,6 +4892,7 @@ var LoginInvalidOrgError = class extends Error {
4798
4892
  super(message);
4799
4893
  this.message = message;
4800
4894
  }
4895
+ message;
4801
4896
  };
4802
4897
  var REDACTION_FIELDS = [
4803
4898
  "input",
@@ -4813,6 +4908,8 @@ var MaskingError = class {
4813
4908
  this.fieldName = fieldName;
4814
4909
  this.errorType = errorType;
4815
4910
  }
4911
+ fieldName;
4912
+ errorType;
4816
4913
  get errorMsg() {
4817
4914
  return `ERROR: Failed to mask field '${this.fieldName}' - ${this.errorType}`;
4818
4915
  }
@@ -5022,7 +5119,9 @@ var BraintrustState = class _BraintrustState {
5022
5119
  diskCache: parametersDiskCache
5023
5120
  });
5024
5121
  this.spanCache = new SpanCache({ disabled: loginParams.disableSpanCache });
5122
+ this.spanOriginEnvironment = detectSpanOriginEnvironment();
5025
5123
  }
5124
+ loginParams;
5026
5125
  id;
5027
5126
  currentExperiment;
5028
5127
  // Note: the value of IsAsyncFlush doesn't really matter here, since we
@@ -5057,6 +5156,7 @@ var BraintrustState = class _BraintrustState {
5057
5156
  _idGenerator = null;
5058
5157
  _contextManager = null;
5059
5158
  _otelFlushCallback = null;
5159
+ spanOriginEnvironment;
5060
5160
  resetLoginInfo() {
5061
5161
  this.appUrl = null;
5062
5162
  this.appPublicUrl = null;
@@ -7675,6 +7775,7 @@ function initLogger(options = {}) {
7675
7775
  orgName,
7676
7776
  forceLogin,
7677
7777
  debugLogLevel,
7778
+ environment,
7678
7779
  fetch: fetch2,
7679
7780
  state: stateArg
7680
7781
  } = options || {};
@@ -7691,6 +7792,7 @@ function initLogger(options = {}) {
7691
7792
  };
7692
7793
  const state = stateArg ?? _globalState;
7693
7794
  state.setDebugLogLevel(debugLogLevel);
7795
+ state.spanOriginEnvironment = detectSpanOriginEnvironment(environment);
7694
7796
  state.enforceQueueSizeLimit(true);
7695
7797
  const lazyMetadata = new LazyValue(
7696
7798
  async () => {
@@ -8882,6 +8984,11 @@ var ObjectFetcher = class {
8882
8984
  this._internal_btql = _internal_btql;
8883
8985
  this._internalBrainstoreRealtime = _internalBrainstoreRealtime;
8884
8986
  }
8987
+ objectType;
8988
+ pinnedVersion;
8989
+ mutateRecord;
8990
+ _internal_btql;
8991
+ _internalBrainstoreRealtime;
8885
8992
  _fetchedData = void 0;
8886
8993
  get id() {
8887
8994
  throw new Error("ObjectFetcher subclasses must have an 'id' attribute");
@@ -9320,6 +9427,8 @@ var ReadonlyExperiment = class extends ObjectFetcher {
9320
9427
  this.state = state;
9321
9428
  this.lazyMetadata = lazyMetadata;
9322
9429
  }
9430
+ state;
9431
+ lazyMetadata;
9323
9432
  get id() {
9324
9433
  return (async () => {
9325
9434
  return (await this.lazyMetadata.get()).experiment.id;
@@ -9442,7 +9551,11 @@ var SpanImpl = class _SpanImpl {
9442
9551
  metrics: {
9443
9552
  start: args.startTime ?? getCurrentUnixTimestamp()
9444
9553
  },
9445
- context: { ...callerLocation },
9554
+ context: mergeSpanOriginContext(
9555
+ { ...callerLocation },
9556
+ "braintrust-js-logger",
9557
+ this._state.spanOriginEnvironment
9558
+ ),
9446
9559
  span_attributes: {
9447
9560
  name,
9448
9561
  type,
@@ -9816,6 +9929,7 @@ var Dataset2 = class extends ObjectFetcher {
9816
9929
  this.pinnedEnvironment = pinState?.pinnedEnvironment;
9817
9930
  this.pinnedSnapshotName = pinState?.pinnedSnapshotName;
9818
9931
  }
9932
+ state;
9819
9933
  lazyMetadata;
9820
9934
  __braintrust_dataset_marker = true;
9821
9935
  newRecords = 0;
@@ -10330,6 +10444,9 @@ var Prompt2 = class _Prompt {
10330
10444
  this.noTrace = noTrace;
10331
10445
  void this.__braintrust_prompt_marker;
10332
10446
  }
10447
+ metadata;
10448
+ defaults;
10449
+ noTrace;
10333
10450
  parsedPromptData;
10334
10451
  hasParsedPromptData = false;
10335
10452
  __braintrust_prompt_marker = true;
@@ -10567,6 +10684,7 @@ var RemoteEvalParameters = class {
10567
10684
  this.metadata = metadata;
10568
10685
  void this.__braintrust_parameters_marker;
10569
10686
  }
10687
+ metadata;
10570
10688
  __braintrust_parameters_marker = true;
10571
10689
  get id() {
10572
10690
  return this.metadata.id;
@@ -12534,6 +12652,84 @@ var AISDKPlugin = class extends BasePlugin {
12534
12652
  })
12535
12653
  })
12536
12654
  );
12655
+ this.unsubscribers.push(
12656
+ traceStreamingChannel(harnessAgentChannels.generate, {
12657
+ name: "HarnessAgent.generate",
12658
+ type: "task" /* TASK */,
12659
+ extractInput: ([params], event) => prepareAISDKHarnessAgentInput(params, event.self),
12660
+ extractOutput: (result, endEvent) => processAISDKOutput(
12661
+ result,
12662
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
12663
+ ),
12664
+ extractMetrics: (result) => extractTokenMetrics(result),
12665
+ aggregateChunks: aggregateAISDKChunks
12666
+ })
12667
+ );
12668
+ this.unsubscribers.push(
12669
+ traceStreamingChannel(harnessAgentChannels.stream, {
12670
+ name: "HarnessAgent.stream",
12671
+ type: "task" /* TASK */,
12672
+ extractInput: ([params], event) => prepareAISDKHarnessAgentInput(params, event.self),
12673
+ extractOutput: (result, endEvent) => processAISDKOutput(
12674
+ result,
12675
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
12676
+ ),
12677
+ extractMetrics: (result, startTime) => ({
12678
+ ...extractTokenMetrics(result),
12679
+ ...startTime === void 0 ? {} : {
12680
+ time_to_first_token: getCurrentUnixTimestamp() - startTime
12681
+ }
12682
+ }),
12683
+ aggregateChunks: aggregateAISDKChunks,
12684
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
12685
+ defaultDenyOutputPaths: denyOutputPaths,
12686
+ endEvent,
12687
+ result,
12688
+ resolvePromiseUsage: true,
12689
+ span,
12690
+ startTime
12691
+ })
12692
+ })
12693
+ );
12694
+ this.unsubscribers.push(
12695
+ traceStreamingChannel(harnessAgentChannels.continueGenerate, {
12696
+ name: "HarnessAgent.continueGenerate",
12697
+ type: "task" /* TASK */,
12698
+ extractInput: ([params], event) => prepareAISDKHarnessAgentInput(params, event.self),
12699
+ extractOutput: (result, endEvent) => processAISDKOutput(
12700
+ result,
12701
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
12702
+ ),
12703
+ extractMetrics: (result) => extractTokenMetrics(result),
12704
+ aggregateChunks: aggregateAISDKChunks
12705
+ })
12706
+ );
12707
+ this.unsubscribers.push(
12708
+ traceStreamingChannel(harnessAgentChannels.continueStream, {
12709
+ name: "HarnessAgent.continueStream",
12710
+ type: "task" /* TASK */,
12711
+ extractInput: ([params], event) => prepareAISDKHarnessAgentInput(params, event.self),
12712
+ extractOutput: (result, endEvent) => processAISDKOutput(
12713
+ result,
12714
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
12715
+ ),
12716
+ extractMetrics: (result, startTime) => ({
12717
+ ...extractTokenMetrics(result),
12718
+ ...startTime === void 0 ? {} : {
12719
+ time_to_first_token: getCurrentUnixTimestamp() - startTime
12720
+ }
12721
+ }),
12722
+ aggregateChunks: aggregateAISDKChunks,
12723
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
12724
+ defaultDenyOutputPaths: denyOutputPaths,
12725
+ endEvent,
12726
+ result,
12727
+ resolvePromiseUsage: true,
12728
+ span,
12729
+ startTime
12730
+ })
12731
+ })
12732
+ );
12537
12733
  this.unsubscribers.push(
12538
12734
  traceStreamingChannel(aiSDKChannels.toolLoopAgentGenerate, {
12539
12735
  name: "ToolLoopAgent.generate",
@@ -13064,6 +13260,45 @@ function prepareAISDKCallInput(params, event, span, defaultDenyOutputPaths, chil
13064
13260
  metadata
13065
13261
  };
13066
13262
  }
13263
+ function prepareAISDKHarnessAgentInput(params, self) {
13264
+ if (isObject(self)) {
13265
+ try {
13266
+ if (isObject(self.settings)) {
13267
+ const settings = self.settings;
13268
+ if (settings.telemetry === void 0) {
13269
+ Reflect.set(self, "settings", { ...settings, telemetry: {} });
13270
+ }
13271
+ }
13272
+ } catch {
13273
+ }
13274
+ }
13275
+ const selectedInput = {};
13276
+ if (params.prompt !== void 0) {
13277
+ selectedInput.prompt = params.prompt;
13278
+ }
13279
+ if (params.messages !== void 0) {
13280
+ selectedInput.messages = params.messages;
13281
+ }
13282
+ if (params.toolApprovalContinuations !== void 0) {
13283
+ selectedInput.toolApprovalContinuations = params.toolApprovalContinuations;
13284
+ }
13285
+ const metadata = extractMetadataFromCallParams({}, self);
13286
+ if (isObject(params.session) && typeof params.session.sessionId === "string") {
13287
+ metadata.sessionId = params.session.sessionId;
13288
+ }
13289
+ if (isObject(self)) {
13290
+ if (typeof self.harnessId === "string") {
13291
+ metadata.harnessId = self.harnessId;
13292
+ }
13293
+ if (typeof self.permissionMode === "string") {
13294
+ metadata.permissionMode = self.permissionMode;
13295
+ }
13296
+ }
13297
+ return {
13298
+ input: processAISDKCallInput(selectedInput).input,
13299
+ metadata
13300
+ };
13301
+ }
13067
13302
  function prepareAISDKWorkflowAgentStreamInput(params, event, span, defaultDenyOutputPaths) {
13068
13303
  registerWorkflowAgentWrapperSpan(span);
13069
13304
  const { input } = processAISDKWorkflowAgentCallInput(params);
@@ -13911,6 +14146,7 @@ function patchAISDKStreamingResult(args) {
13911
14146
  endEvent,
13912
14147
  onComplete,
13913
14148
  result,
14149
+ resolvePromiseUsage,
13914
14150
  span,
13915
14151
  startTime
13916
14152
  } = args;
@@ -13937,6 +14173,22 @@ function patchAISDKStreamingResult(args) {
13937
14173
  outputLogged = true;
13938
14174
  try {
13939
14175
  const metrics = extractTopLevelAISDKMetrics(result, endEvent);
14176
+ if (resolvePromiseUsage) {
14177
+ try {
14178
+ const resultRecord2 = result;
14179
+ const pendingUsage = resultRecord2.totalUsage ?? resultRecord2.usage;
14180
+ if (isPromiseLike(pendingUsage)) {
14181
+ const usage = await Promise.resolve(pendingUsage);
14182
+ if (isObject(usage)) {
14183
+ Object.assign(
14184
+ metrics,
14185
+ extractTokenMetrics({ usage })
14186
+ );
14187
+ }
14188
+ }
14189
+ } catch {
14190
+ }
14191
+ }
13940
14192
  if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
13941
14193
  metrics.time_to_first_token = firstChunkTime - startTime;
13942
14194
  }
@@ -16948,6 +17200,16 @@ function cleanObject(obj) {
16948
17200
  })
16949
17201
  );
16950
17202
  }
17203
+ function normalizeTokenMetrics(obj) {
17204
+ const metrics = cleanObject(obj);
17205
+ if (metrics.total_tokens !== void 0) {
17206
+ metrics.tokens = metrics.total_tokens;
17207
+ } else if (metrics.prompt_tokens !== void 0 && metrics.completion_tokens !== void 0) {
17208
+ metrics.tokens = metrics.prompt_tokens + metrics.completion_tokens;
17209
+ }
17210
+ delete metrics.total_tokens;
17211
+ return metrics;
17212
+ }
16951
17213
  function walkGenerations(response) {
16952
17214
  const result = [];
16953
17215
  const generations = response.generations || [];
@@ -16994,7 +17256,7 @@ function getMetricsFromResponse(response) {
16994
17256
  continue;
16995
17257
  }
16996
17258
  const inputTokenDetails = usageMetadata.input_token_details;
16997
- return cleanObject({
17259
+ return normalizeTokenMetrics({
16998
17260
  total_tokens: usageMetadata.total_tokens,
16999
17261
  prompt_tokens: usageMetadata.input_tokens,
17000
17262
  completion_tokens: usageMetadata.output_tokens,
@@ -17004,7 +17266,7 @@ function getMetricsFromResponse(response) {
17004
17266
  }
17005
17267
  const llmOutput = response.llmOutput || {};
17006
17268
  const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
17007
- return cleanObject({
17269
+ return normalizeTokenMetrics({
17008
17270
  total_tokens: tokenUsage.totalTokens,
17009
17271
  prompt_tokens: tokenUsage.promptTokens,
17010
17272
  completion_tokens: tokenUsage.completionTokens
@@ -31623,7 +31885,13 @@ function configureNode() {
31623
31885
  isomorph_default.getPastNAncestors = getPastNAncestors;
31624
31886
  isomorph_default.getEnv = (name) => {
31625
31887
  const value = process.env[name];
31626
- return name === "BRAINTRUST_API_KEY" && !value?.trim() ? void 0 : value;
31888
+ if (name === "BRAINTRUST_API_KEY") {
31889
+ return value?.trim() ? value : void 0;
31890
+ }
31891
+ if ((name === "BRAINTRUST_ENVIRONMENT_TYPE" || name === "BRAINTRUST_ENVIRONMENT_NAME") && !value?.trim()) {
31892
+ return getNearestBraintrustEnvValue(name);
31893
+ }
31894
+ return value;
31627
31895
  };
31628
31896
  isomorph_default.getBraintrustApiKey = async () => {
31629
31897
  const value = process.env.BRAINTRUST_API_KEY;
@@ -31708,6 +31976,24 @@ function configureNode() {
31708
31976
  }
31709
31977
  registry.enable();
31710
31978
  }
31979
+ function getNearestBraintrustEnvValue(name) {
31980
+ for (let dir = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir = path.dirname(dir), depth++) {
31981
+ const envPath = path.join(dir, ".env.braintrust");
31982
+ try {
31983
+ const parsed = dotenv.parse(fsSync.readFileSync(envPath, "utf8"));
31984
+ const value = parsed[name];
31985
+ return value?.trim() ? value : void 0;
31986
+ } catch (e) {
31987
+ if (typeof e !== "object" || e === null || !("code" in e) || e.code !== "ENOENT") {
31988
+ return void 0;
31989
+ }
31990
+ }
31991
+ if (path.dirname(dir) === dir) {
31992
+ break;
31993
+ }
31994
+ }
31995
+ return void 0;
31996
+ }
31711
31997
 
31712
31998
  // src/wrappers/shared/format.ts
31713
31999
  function formatExperimentSummary(summary) {