braintrust 3.28.0 → 3.30.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 (54) hide show
  1. package/README.md +1 -1
  2. package/dev/dist/index.d.mts +356 -7
  3. package/dev/dist/index.d.ts +356 -7
  4. package/dev/dist/index.js +2679 -1828
  5. package/dev/dist/index.mjs +1862 -1011
  6. package/dist/apply-auto-instrumentation.js +298 -265
  7. package/dist/apply-auto-instrumentation.mjs +85 -52
  8. package/dist/auto-instrumentations/bundler/esbuild.cjs +56 -6
  9. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/next.cjs +56 -6
  11. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  12. package/dist/auto-instrumentations/bundler/rollup.cjs +56 -6
  13. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.cjs +56 -6
  15. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  16. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +56 -6
  17. package/dist/auto-instrumentations/bundler/webpack.cjs +56 -6
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  19. package/dist/auto-instrumentations/{chunk-26PKVUKB.mjs → chunk-LW4HDHXT.mjs} +12 -4
  20. package/dist/auto-instrumentations/{chunk-HD35AM3M.mjs → chunk-OXINGIEZ.mjs} +1 -1
  21. package/dist/auto-instrumentations/{chunk-NP7V4XB2.mjs → chunk-U64OYU4Q.mjs} +45 -3
  22. package/dist/auto-instrumentations/hook.mjs +967 -136
  23. package/dist/auto-instrumentations/index.cjs +45 -3
  24. package/dist/auto-instrumentations/index.mjs +1 -1
  25. package/dist/browser.d.mts +893 -24
  26. package/dist/browser.d.ts +893 -24
  27. package/dist/browser.js +2795 -1136
  28. package/dist/browser.mjs +2795 -1136
  29. package/dist/{chunk-BBE7SNRV.js → chunk-2XDW3UCG.js} +155 -23
  30. package/dist/{chunk-UPFNQCGB.mjs → chunk-BU6SM54N.mjs} +1830 -1045
  31. package/dist/{chunk-ZHUHZWFY.mjs → chunk-N3JKQ3D3.mjs} +152 -20
  32. package/dist/{chunk-OBBWQW6K.js → chunk-TWCDSYJN.js} +2890 -2105
  33. package/dist/cli.js +5976 -1348
  34. package/dist/edge-light.d.mts +1 -1
  35. package/dist/edge-light.d.ts +1 -1
  36. package/dist/edge-light.js +2795 -1136
  37. package/dist/edge-light.mjs +2795 -1136
  38. package/dist/index.d.mts +893 -24
  39. package/dist/index.d.ts +893 -24
  40. package/dist/index.js +1448 -699
  41. package/dist/index.mjs +848 -99
  42. package/dist/instrumentation/index.d.mts +563 -9
  43. package/dist/instrumentation/index.d.ts +563 -9
  44. package/dist/instrumentation/index.js +2794 -989
  45. package/dist/instrumentation/index.mjs +2794 -989
  46. package/dist/vitest-evals-reporter.js +16 -16
  47. package/dist/vitest-evals-reporter.mjs +2 -2
  48. package/dist/workerd.d.mts +1 -1
  49. package/dist/workerd.d.ts +1 -1
  50. package/dist/workerd.js +2795 -1136
  51. package/dist/workerd.mjs +2795 -1136
  52. package/package.json +1 -1
  53. package/util/dist/index.d.mts +42 -0
  54. package/util/dist/index.d.ts +42 -0
@@ -110,8 +110,6 @@ function isInstrumentationIntegrationDisabled(integrations, ...names) {
110
110
  var DefaultAsyncLocalStorage = class {
111
111
  constructor() {
112
112
  }
113
- enterWith(_) {
114
- }
115
113
  run(_, callback) {
116
114
  return callback();
117
115
  }
@@ -1779,7 +1777,9 @@ var AclObjectType = z6.union([
1779
1777
  "project_log",
1780
1778
  "org_project",
1781
1779
  "org_audit_logs",
1782
- "project_group"
1780
+ "project_group",
1781
+ "ai_secret",
1782
+ "org_ai_secret"
1783
1783
  ]),
1784
1784
  z6.null()
1785
1785
  ]);
@@ -2612,7 +2612,7 @@ var PromptParserNullish = z6.union([
2612
2612
  }),
2613
2613
  z6.null()
2614
2614
  ]);
2615
- var PreprocessorSavedFunctionId = z6.union([
2615
+ var PreprocessorId = z6.union([
2616
2616
  z6.object({
2617
2617
  type: z6.literal("function"),
2618
2618
  id: z6.string(),
@@ -2623,6 +2623,7 @@ var PreprocessorSavedFunctionId = z6.union([
2623
2623
  name: z6.string(),
2624
2624
  function_type: z6.literal("preprocessor").optional().default("preprocessor")
2625
2625
  }),
2626
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
2626
2627
  z6.null()
2627
2628
  ]);
2628
2629
  var PromptDataNullish = z6.union([
@@ -2630,7 +2631,7 @@ var PromptDataNullish = z6.union([
2630
2631
  prompt: PromptBlockDataNullish,
2631
2632
  options: PromptOptionsNullish,
2632
2633
  parser: PromptParserNullish,
2633
- preprocessor: PreprocessorSavedFunctionId,
2634
+ preprocessor: PreprocessorId,
2634
2635
  tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
2635
2636
  template_format: z6.union([
2636
2637
  z6.enum(["mustache", "nunjucks", "none"]),
@@ -2832,7 +2833,7 @@ var PromptData = z6.object({
2832
2833
  prompt: PromptBlockDataNullish,
2833
2834
  options: PromptOptionsNullish,
2834
2835
  parser: PromptParserNullish,
2835
- preprocessor: PreprocessorSavedFunctionId,
2836
+ preprocessor: PreprocessorId,
2836
2837
  tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
2837
2838
  template_format: z6.union([
2838
2839
  z6.enum(["mustache", "nunjucks", "none"]),
@@ -3776,6 +3777,7 @@ var View = z6.object({
3776
3777
  ]),
3777
3778
  name: z6.string(),
3778
3779
  description: z6.union([z6.string(), z6.null()]).optional(),
3780
+ starred: z6.boolean().optional(),
3779
3781
  created: z6.union([z6.string(), z6.null()]).optional(),
3780
3782
  updated_at: z6.union([z6.string(), z6.null()]).optional(),
3781
3783
  view_data: ViewData.optional(),
@@ -3865,6 +3867,34 @@ var registerTemplatePlugin = templateRegistry.register.bind(templateRegistry);
3865
3867
  var getTemplateRenderer = templateRegistry.get.bind(templateRegistry);
3866
3868
  registerTemplatePlugin(mustachePlugin);
3867
3869
 
3870
+ // src/template/renderer.ts
3871
+ function isTemplateFormat(v) {
3872
+ return v === "mustache" || v === "nunjucks" || v === "none";
3873
+ }
3874
+ function parseTemplateFormat(value, defaultFormat = "mustache") {
3875
+ return isTemplateFormat(value) ? value : defaultFormat;
3876
+ }
3877
+ function renderTemplateContent(template, variables, escape, options) {
3878
+ const strict = !!options.strict;
3879
+ const templateFormat = parseTemplateFormat(options.templateFormat);
3880
+ if (templateFormat === "none") {
3881
+ return template;
3882
+ }
3883
+ const renderer = getTemplateRenderer(templateFormat);
3884
+ if (!renderer) {
3885
+ if (templateFormat === "nunjucks") {
3886
+ throw new Error(
3887
+ "Nunjucks templating requires @braintrust/template-nunjucks. Install and import it to enable templateFormat: 'nunjucks'."
3888
+ );
3889
+ }
3890
+ throw new Error(`No template renderer registered for ${templateFormat}`);
3891
+ }
3892
+ if (strict && renderer.lint) {
3893
+ renderer.lint(template, variables);
3894
+ }
3895
+ return renderer.render(template, variables, escape, strict);
3896
+ }
3897
+
3868
3898
  // src/logger.ts
3869
3899
  import { z as z8, ZodError } from "zod/v3";
3870
3900
 
@@ -4451,44 +4481,72 @@ function createCacheLayers({
4451
4481
  }
4452
4482
 
4453
4483
  // src/prompt-cache/prompt-cache.ts
4454
- function createCacheKey(key) {
4484
+ function createCacheKey(key, namespace) {
4485
+ let cacheKey;
4455
4486
  if (key.id) {
4456
- return `id:${key.id}`;
4457
- }
4458
- const prefix = key.projectId ?? key.projectName;
4459
- if (!prefix) {
4460
- throw new Error("Either projectId or projectName must be provided");
4461
- }
4462
- if (!key.slug) {
4463
- throw new Error("Slug must be provided when not using ID");
4487
+ cacheKey = `id:${key.id}`;
4488
+ } else {
4489
+ const prefix = key.projectId ?? key.projectName;
4490
+ if (!prefix) {
4491
+ throw new Error("Either projectId or projectName must be provided");
4492
+ }
4493
+ if (!key.slug) {
4494
+ throw new Error("Slug must be provided when not using ID");
4495
+ }
4496
+ cacheKey = `${prefix}:${key.slug}:${key.version ?? "latest"}`;
4464
4497
  }
4465
- return `${prefix}:${key.slug}:${key.version ?? "latest"}`;
4498
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
4466
4499
  }
4467
- var PromptCache = class {
4500
+ var PromptCache = class _PromptCache {
4468
4501
  memoryCache;
4469
4502
  diskCache;
4503
+ namespace;
4504
+ expectedResolvedOrgIdentity;
4470
4505
  constructor(options) {
4471
4506
  this.memoryCache = options.memoryCache;
4472
4507
  this.diskCache = options.diskCache;
4508
+ this.namespace = options.namespace;
4509
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
4510
+ }
4511
+ /**
4512
+ * Returns a cache view that shares the same storage layers but isolates all
4513
+ * entries under the provided namespace.
4514
+ */
4515
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
4516
+ return new _PromptCache({
4517
+ memoryCache: this.memoryCache,
4518
+ diskCache: this.diskCache,
4519
+ namespace,
4520
+ expectedResolvedOrgIdentity
4521
+ });
4473
4522
  }
4474
4523
  /**
4475
4524
  * Retrieves a prompt from the cache.
4476
4525
  * First checks the in-memory LRU cache, then falls back to checking the disk cache if available.
4477
4526
  */
4478
4527
  async get(key) {
4479
- const cacheKey = createCacheKey(key);
4528
+ const cacheKey = createCacheKey(key, this.namespace);
4480
4529
  if (this.memoryCache) {
4481
- const memoryPrompt = this.memoryCache.get(cacheKey);
4482
- if (memoryPrompt !== void 0) {
4483
- return memoryPrompt;
4530
+ const memoryEntry = this.memoryCache.get(cacheKey);
4531
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
4532
+ return memoryEntry.value;
4484
4533
  }
4485
4534
  }
4486
4535
  if (this.diskCache) {
4487
- const diskPrompt = await this.diskCache.get(cacheKey);
4488
- if (!diskPrompt) {
4536
+ const diskEntry = await this.diskCache.get(cacheKey);
4537
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
4489
4538
  return void 0;
4490
4539
  }
4491
- this.memoryCache?.set(cacheKey, diskPrompt);
4540
+ const serializedPrompt = diskEntry.value;
4541
+ const diskPrompt = new Prompt2(
4542
+ serializedPrompt.metadata,
4543
+ serializedPrompt.defaults,
4544
+ serializedPrompt.noTrace
4545
+ );
4546
+ this.memoryCache?.set(cacheKey, {
4547
+ value: diskPrompt,
4548
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
4549
+ });
4492
4550
  return diskPrompt;
4493
4551
  }
4494
4552
  return void 0;
@@ -4502,58 +4560,91 @@ var PromptCache = class {
4502
4560
  * @throws If there is an error writing to the disk cache.
4503
4561
  */
4504
4562
  async set(key, value) {
4505
- const cacheKey = createCacheKey(key);
4506
- this.memoryCache?.set(cacheKey, value);
4563
+ const cacheKey = createCacheKey(key, this.namespace);
4564
+ const memoryEntry = {
4565
+ value,
4566
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
4567
+ };
4568
+ this.memoryCache?.set(cacheKey, memoryEntry);
4507
4569
  if (this.diskCache) {
4508
- await this.diskCache.set(cacheKey, value);
4570
+ await this.diskCache.set(cacheKey, {
4571
+ value: value._internalSerializeForCache(),
4572
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
4573
+ });
4509
4574
  }
4510
4575
  }
4511
4576
  };
4512
4577
 
4513
4578
  // src/prompt-cache/parameters-cache.ts
4514
- function createCacheKey2(key) {
4579
+ function createCacheKey2(key, namespace) {
4580
+ let cacheKey;
4515
4581
  if (key.id) {
4516
- return `parameters:id:${key.id}`;
4517
- }
4518
- const prefix = key.projectId ?? key.projectName;
4519
- if (!prefix) {
4520
- throw new Error("Either projectId or projectName must be provided");
4521
- }
4522
- if (!key.slug) {
4523
- throw new Error("Slug must be provided when not using ID");
4582
+ cacheKey = `parameters:id:${key.id}`;
4583
+ } else {
4584
+ const prefix = key.projectId ?? key.projectName;
4585
+ if (!prefix) {
4586
+ throw new Error("Either projectId or projectName must be provided");
4587
+ }
4588
+ if (!key.slug) {
4589
+ throw new Error("Slug must be provided when not using ID");
4590
+ }
4591
+ cacheKey = `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
4524
4592
  }
4525
- return `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
4593
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
4526
4594
  }
4527
- var ParametersCache = class {
4595
+ var ParametersCache = class _ParametersCache {
4528
4596
  memoryCache;
4529
4597
  diskCache;
4598
+ namespace;
4599
+ expectedResolvedOrgIdentity;
4530
4600
  constructor(options) {
4531
4601
  this.memoryCache = options.memoryCache;
4532
4602
  this.diskCache = options.diskCache;
4603
+ this.namespace = options.namespace;
4604
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
4605
+ }
4606
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
4607
+ return new _ParametersCache({
4608
+ memoryCache: this.memoryCache,
4609
+ diskCache: this.diskCache,
4610
+ namespace,
4611
+ expectedResolvedOrgIdentity
4612
+ });
4533
4613
  }
4534
4614
  async get(key) {
4535
- const cacheKey = createCacheKey2(key);
4615
+ const cacheKey = createCacheKey2(key, this.namespace);
4536
4616
  if (this.memoryCache) {
4537
- const memoryParams = this.memoryCache.get(cacheKey);
4538
- if (memoryParams !== void 0) {
4539
- return memoryParams;
4617
+ const memoryEntry = this.memoryCache.get(cacheKey);
4618
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
4619
+ return memoryEntry.value;
4540
4620
  }
4541
4621
  }
4542
4622
  if (this.diskCache) {
4543
- const diskParams = await this.diskCache.get(cacheKey);
4544
- if (!diskParams) {
4623
+ const diskEntry = await this.diskCache.get(cacheKey);
4624
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
4545
4625
  return void 0;
4546
4626
  }
4547
- this.memoryCache?.set(cacheKey, diskParams);
4548
- return diskParams;
4627
+ const diskParameters = new RemoteEvalParameters(diskEntry.value.metadata);
4628
+ this.memoryCache?.set(cacheKey, {
4629
+ value: diskParameters,
4630
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
4631
+ });
4632
+ return diskParameters;
4549
4633
  }
4550
4634
  return void 0;
4551
4635
  }
4552
4636
  async set(key, value) {
4553
- const cacheKey = createCacheKey2(key);
4554
- this.memoryCache?.set(cacheKey, value);
4637
+ const cacheKey = createCacheKey2(key, this.namespace);
4638
+ const memoryEntry = {
4639
+ value,
4640
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
4641
+ };
4642
+ this.memoryCache?.set(cacheKey, memoryEntry);
4555
4643
  if (this.diskCache) {
4556
- await this.diskCache.set(cacheKey, value);
4644
+ await this.diskCache.set(cacheKey, {
4645
+ value: value._internalSerializeForCache(),
4646
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
4647
+ });
4557
4648
  }
4558
4649
  }
4559
4650
  };
@@ -4857,6 +4948,7 @@ var INSTRUMENTATION_NAMES = {
4857
4948
  CLOUDFLARE_THINK: "cloudflare-think",
4858
4949
  COHERE: "cohere",
4859
4950
  CURSOR_SDK: "cursor-sdk",
4951
+ DEEPSEEK_HARNESS: "deepseek-harness",
4860
4952
  EVE: "eve",
4861
4953
  FLUE: "flue",
4862
4954
  GENKIT: "genkit",
@@ -4882,7 +4974,7 @@ var INSTRUMENTATION_NAMES = {
4882
4974
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
4883
4975
  "braintrust.spanInstrumentationName"
4884
4976
  );
4885
- var SDK_VERSION = true ? "3.28.0" : "0.0.0";
4977
+ var SDK_VERSION = true ? "3.30.0" : "0.0.0";
4886
4978
  function withSpanInstrumentationName(args, instrumentationName) {
4887
4979
  return {
4888
4980
  ...args,
@@ -5001,6 +5093,16 @@ var datasetSnapshotRegisterResponseSchema = z8.object({
5001
5093
  dataset_snapshot: DatasetSnapshot,
5002
5094
  found_existing: z8.boolean().optional()
5003
5095
  });
5096
+ var datasetObjectInfoSchema = z8.object({
5097
+ object_id: z8.string(),
5098
+ object_name: z8.string(),
5099
+ parent_cols: z8.object({
5100
+ project: z8.object({
5101
+ id: z8.string(),
5102
+ name: z8.string()
5103
+ })
5104
+ })
5105
+ });
5004
5106
  var datasetRestorePreviewResultSchema = z8.object({
5005
5107
  rows_to_restore: z8.number(),
5006
5108
  rows_to_delete: z8.number()
@@ -5214,12 +5316,53 @@ var loginSchema = z8.strictObject({
5214
5316
  });
5215
5317
  var stateNonce = 0;
5216
5318
  var V1_PROXY_SUFFIX = "/v1/proxy";
5319
+ var LOADER_LOGIN_CACHE_MAX = 16;
5217
5320
  function normalizeProxyConnUrl(proxyUrl) {
5218
5321
  return proxyUrl.endsWith(V1_PROXY_SUFFIX) ? proxyUrl.slice(0, proxyUrl.length - V1_PROXY_SUFFIX.length) : proxyUrl;
5219
5322
  }
5220
5323
  var BraintrustState = class _BraintrustState {
5324
+ id;
5325
+ currentExperiment;
5326
+ // Note: the value of IsAsyncFlush doesn't really matter here, since we
5327
+ // (safely) dynamically cast it whenever retrieving the logger.
5328
+ currentLogger;
5329
+ currentParent;
5330
+ currentSpan;
5331
+ // Any time we re-log in, we directly update the apiConn inside the logger.
5332
+ // This is preferable to replacing the whole logger, which would create the
5333
+ // possibility of multiple loggers floating around, which may not log in a
5334
+ // deterministic order.
5335
+ _bgLogger;
5336
+ _overrideBgLogger = null;
5337
+ appUrl = null;
5338
+ appPublicUrl = null;
5339
+ loginToken = null;
5340
+ orgId = null;
5341
+ orgName = null;
5342
+ apiUrl = null;
5343
+ proxyUrl = null;
5344
+ loggedIn = false;
5345
+ gitMetadataSettings;
5346
+ debugLogLevel;
5347
+ debugLogLevelConfigured = false;
5348
+ fetch = globalThis.fetch;
5349
+ _appConn = null;
5350
+ _apiConn = null;
5351
+ _proxyConn = null;
5352
+ promptCache;
5353
+ parametersCache;
5354
+ spanCache;
5355
+ _idGenerator = null;
5356
+ _contextManager = null;
5357
+ _otelFlushCallback = null;
5358
+ spanOriginEnvironment;
5359
+ traceContextSigningSecret;
5360
+ loaderLoginCache = /* @__PURE__ */ new WeakMap();
5361
+ loginParams;
5362
+ activeLoginOrgNameSelector;
5221
5363
  constructor(loginParams) {
5222
- this.loginParams = loginParams;
5364
+ this.loginParams = { ...loginParams };
5365
+ this.activeLoginOrgNameSelector = loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
5223
5366
  this.id = `${(/* @__PURE__ */ new Date()).toLocaleString()}-${stateNonce++}`;
5224
5367
  this.currentExperiment = void 0;
5225
5368
  this.currentLogger = void 0;
@@ -5256,12 +5399,14 @@ var BraintrustState = class _BraintrustState {
5256
5399
  const {
5257
5400
  memoryCache: parametersMemoryCache,
5258
5401
  diskCache: parametersDiskCache
5259
- } = createCacheLayers({
5260
- memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
5261
- diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
5262
- diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
5263
- getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
5264
- });
5402
+ } = createCacheLayers(
5403
+ {
5404
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
5405
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
5406
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
5407
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
5408
+ }
5409
+ );
5265
5410
  this.parametersCache = new ParametersCache({
5266
5411
  memoryCache: parametersMemoryCache,
5267
5412
  diskCache: parametersDiskCache
@@ -5270,43 +5415,6 @@ var BraintrustState = class _BraintrustState {
5270
5415
  this.spanOriginEnvironment = detectSpanOriginEnvironment();
5271
5416
  this._internalSetTraceContextSigningSecret(loginParams.apiKey);
5272
5417
  }
5273
- loginParams;
5274
- id;
5275
- currentExperiment;
5276
- // Note: the value of IsAsyncFlush doesn't really matter here, since we
5277
- // (safely) dynamically cast it whenever retrieving the logger.
5278
- currentLogger;
5279
- currentParent;
5280
- currentSpan;
5281
- // Any time we re-log in, we directly update the apiConn inside the logger.
5282
- // This is preferable to replacing the whole logger, which would create the
5283
- // possibility of multiple loggers floating around, which may not log in a
5284
- // deterministic order.
5285
- _bgLogger;
5286
- _overrideBgLogger = null;
5287
- appUrl = null;
5288
- appPublicUrl = null;
5289
- loginToken = null;
5290
- orgId = null;
5291
- orgName = null;
5292
- apiUrl = null;
5293
- proxyUrl = null;
5294
- loggedIn = false;
5295
- gitMetadataSettings;
5296
- debugLogLevel;
5297
- debugLogLevelConfigured = false;
5298
- fetch = globalThis.fetch;
5299
- _appConn = null;
5300
- _apiConn = null;
5301
- _proxyConn = null;
5302
- promptCache;
5303
- parametersCache;
5304
- spanCache;
5305
- _idGenerator = null;
5306
- _contextManager = null;
5307
- _otelFlushCallback = null;
5308
- spanOriginEnvironment;
5309
- traceContextSigningSecret;
5310
5418
  /** @internal */
5311
5419
  _internalSetTraceContextSigningSecret(secret) {
5312
5420
  const normalizedSecret = secret?.trim();
@@ -5331,6 +5439,101 @@ var BraintrustState = class _BraintrustState {
5331
5439
  this._appConn = null;
5332
5440
  this._apiConn = null;
5333
5441
  this._proxyConn = null;
5442
+ this.loaderLoginCache = /* @__PURE__ */ new WeakMap();
5443
+ }
5444
+ /** @internal */
5445
+ async _internalResolveLoaderLoginOptions({
5446
+ apiKey,
5447
+ appUrl,
5448
+ orgName,
5449
+ fetch: fetch2,
5450
+ forceLogin
5451
+ }) {
5452
+ const resolvedAppUrl = appUrl ?? (this.loggedIn ? this.appUrl ?? void 0 : void 0) ?? this.loginParams.appUrl ?? isomorph_default.getEnv("BRAINTRUST_APP_URL") ?? "https://www.braintrust.dev";
5453
+ const resolvedApiKey = apiKey ?? (this.loggedIn ? this.loginToken ?? void 0 : void 0) ?? this.loginParams.apiKey ?? await isomorph_default.getBraintrustApiKey();
5454
+ if (!resolvedApiKey) {
5455
+ throw new Error(
5456
+ "Please specify an api key (e.g. by setting BRAINTRUST_API_KEY)."
5457
+ );
5458
+ }
5459
+ const normalizedApiKey = HTTPConnection.sanitize_token(resolvedApiKey);
5460
+ const usesActiveCredential = this.loggedIn && normalizedApiKey === this.loginToken;
5461
+ const requestedOrgName = orgName ?? (usesActiveCredential ? this.activeLoginOrgNameSelector : void 0) ?? this.loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
5462
+ const resolvedOrgName = orgName ?? (usesActiveCredential ? this.orgName ?? void 0 : void 0) ?? requestedOrgName;
5463
+ const resolvedFetch = fetch2 ?? (this.loggedIn ? this.fetch : void 0) ?? this.loginParams.fetch ?? globalThis.fetch;
5464
+ const credentialCacheNamespace = JSON.stringify([
5465
+ "loader-credential",
5466
+ resolvedAppUrl,
5467
+ requestedOrgName,
5468
+ normalizedApiKey
5469
+ ]);
5470
+ return {
5471
+ apiKey: normalizedApiKey,
5472
+ appUrl: resolvedAppUrl,
5473
+ orgName: resolvedOrgName,
5474
+ fetch: resolvedFetch,
5475
+ forceLogin,
5476
+ credentialCacheNamespace,
5477
+ existingState: !forceLogin && usesActiveCredential && resolvedAppUrl === this.appUrl && resolvedOrgName === this.orgName && resolvedFetch === this.fetch ? this : void 0
5478
+ };
5479
+ }
5480
+ /** @internal */
5481
+ _internalGetLoaderCacheViews(loginOptions, requestState) {
5482
+ const expectedResolvedOrgIdentity = requestState?.orgId && requestState.appUrl ? JSON.stringify([
5483
+ "loader-org",
5484
+ requestState.appUrl,
5485
+ requestState.orgId
5486
+ ]) : void 0;
5487
+ return {
5488
+ promptCache: this.promptCache.withNamespace(
5489
+ loginOptions.credentialCacheNamespace,
5490
+ expectedResolvedOrgIdentity
5491
+ ),
5492
+ parametersCache: this.parametersCache.withNamespace(
5493
+ loginOptions.credentialCacheNamespace,
5494
+ expectedResolvedOrgIdentity
5495
+ )
5496
+ };
5497
+ }
5498
+ /** @internal */
5499
+ async _internalGetLoaderState({
5500
+ apiKey,
5501
+ appUrl,
5502
+ orgName,
5503
+ fetch: fetch2,
5504
+ forceLogin,
5505
+ existingState
5506
+ }) {
5507
+ if (existingState) {
5508
+ return existingState;
5509
+ }
5510
+ let cache = this.loaderLoginCache.get(fetch2);
5511
+ if (!cache) {
5512
+ cache = new LRUCache({ max: LOADER_LOGIN_CACHE_MAX });
5513
+ this.loaderLoginCache.set(fetch2, cache);
5514
+ }
5515
+ const cacheKey = JSON.stringify([appUrl, orgName, apiKey]);
5516
+ if (!forceLogin) {
5517
+ const cachedState = cache.get(cacheKey);
5518
+ if (cachedState) {
5519
+ return cachedState;
5520
+ }
5521
+ }
5522
+ const statePromise = loginToLoaderRequestState({
5523
+ orgName,
5524
+ apiKey,
5525
+ appUrl,
5526
+ fetch: fetch2
5527
+ });
5528
+ cache.set(cacheKey, statePromise);
5529
+ try {
5530
+ return await statePromise;
5531
+ } catch (error) {
5532
+ if (cache.get(cacheKey) === statePromise) {
5533
+ cache.delete(cacheKey);
5534
+ }
5535
+ throw error;
5536
+ }
5334
5537
  }
5335
5538
  resetIdGenState() {
5336
5539
  this._idGenerator = null;
@@ -5379,6 +5582,8 @@ var BraintrustState = class _BraintrustState {
5379
5582
  this.debugLogLevel = other.debugLogLevel;
5380
5583
  this.debugLogLevelConfigured = other.debugLogLevelConfigured;
5381
5584
  this.traceContextSigningSecret = other.traceContextSigningSecret;
5585
+ this.fetch = other.fetch;
5586
+ this.activeLoginOrgNameSelector = other.activeLoginOrgNameSelector;
5382
5587
  setGlobalDebugLogLevel(
5383
5588
  this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
5384
5589
  );
@@ -5586,36 +5791,76 @@ var FailedHTTPResponse = class extends Error {
5586
5791
  status;
5587
5792
  text;
5588
5793
  data;
5589
- constructor(status, text, data) {
5794
+ cause;
5795
+ constructor(status, text, data, cause) {
5590
5796
  super(`${status}: ${text} (${data})`);
5591
5797
  this.status = status;
5592
5798
  this.text = text;
5593
5799
  this.data = data;
5800
+ this.cause = cause;
5801
+ }
5802
+ };
5803
+ var HTTPTransportError = class extends Error {
5804
+ cause;
5805
+ constructor(cause) {
5806
+ super(cause instanceof Error ? cause.message : String(cause));
5807
+ this.name = "HTTPTransportError";
5808
+ this.cause = cause;
5594
5809
  }
5595
5810
  };
5811
+ var httpTransportErrorCauses = /* @__PURE__ */ new WeakSet();
5812
+ function recordHTTPTransportError(error) {
5813
+ if (typeof error === "object" && error !== null || typeof error === "function") {
5814
+ httpTransportErrorCauses.add(error);
5815
+ }
5816
+ }
5817
+ function rethrowHTTPTransportError(error, classifyTransportErrors) {
5818
+ if (classifyTransportErrors) {
5819
+ throw new HTTPTransportError(error);
5820
+ }
5821
+ recordHTTPTransportError(error);
5822
+ throw error;
5823
+ }
5824
+ async function readJSONResponse(response, classifyTransportErrors = false) {
5825
+ let data;
5826
+ try {
5827
+ data = await response.text();
5828
+ } catch (error) {
5829
+ rethrowHTTPTransportError(error, classifyTransportErrors);
5830
+ }
5831
+ return JSON.parse(data);
5832
+ }
5596
5833
  async function checkResponse(resp) {
5597
5834
  if (resp.ok) {
5598
5835
  return resp;
5599
- } else {
5836
+ }
5837
+ let data;
5838
+ try {
5839
+ data = await resp.text();
5840
+ } catch (error) {
5600
5841
  throw new FailedHTTPResponse(
5601
5842
  resp.status,
5602
5843
  resp.statusText,
5603
- await resp.text()
5844
+ "Unable to read response body",
5845
+ error
5604
5846
  );
5605
5847
  }
5848
+ throw new FailedHTTPResponse(resp.status, resp.statusText, data);
5606
5849
  }
5607
5850
  var HTTPConnection = class _HTTPConnection {
5608
- base_url;
5609
- token;
5610
- headers;
5611
- fetch;
5612
- constructor(base_url, fetch2) {
5851
+ constructor(base_url, fetch2, classifyTransportErrors = false) {
5852
+ this.classifyTransportErrors = classifyTransportErrors;
5613
5853
  this.base_url = base_url;
5614
5854
  this.token = null;
5615
5855
  this.headers = {};
5616
5856
  this._reset();
5617
5857
  this.fetch = fetch2;
5618
5858
  }
5859
+ classifyTransportErrors;
5860
+ base_url;
5861
+ token;
5862
+ headers;
5863
+ fetch;
5619
5864
  setFetch(fetch2) {
5620
5865
  this.fetch = fetch2;
5621
5866
  }
@@ -5655,9 +5900,9 @@ var HTTPConnection = class _HTTPConnection {
5655
5900
  ).toString();
5656
5901
  const this_fetch = this.fetch;
5657
5902
  const this_headers = this.headers;
5658
- return await checkResponse(
5659
- // Using toString() here makes it work with isomorphic fetch
5660
- await this_fetch(url.toString(), {
5903
+ let response;
5904
+ try {
5905
+ response = await this_fetch(url.toString(), {
5661
5906
  headers: {
5662
5907
  Accept: "application/json",
5663
5908
  ...this_headers,
@@ -5665,8 +5910,14 @@ var HTTPConnection = class _HTTPConnection {
5665
5910
  },
5666
5911
  keepalive: true,
5667
5912
  ...rest
5668
- })
5669
- );
5913
+ });
5914
+ } catch (error) {
5915
+ if (config?.signal?.aborted) {
5916
+ throw getAbortReason(config.signal);
5917
+ }
5918
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
5919
+ }
5920
+ return await checkResponse(response);
5670
5921
  }
5671
5922
  async post(path, params, config, retries = 0) {
5672
5923
  const { headers, ...rest } = config || {};
@@ -5676,8 +5927,9 @@ var HTTPConnection = class _HTTPConnection {
5676
5927
  const tries = retries + 1;
5677
5928
  for (let i = 0; i < tries; i++) {
5678
5929
  try {
5679
- return await checkResponse(
5680
- await this_fetch(_urljoin(this_base_url, path), {
5930
+ let response;
5931
+ try {
5932
+ response = await this_fetch(_urljoin(this_base_url, path), {
5681
5933
  method: "POST",
5682
5934
  headers: {
5683
5935
  Accept: "application/json",
@@ -5688,8 +5940,14 @@ var HTTPConnection = class _HTTPConnection {
5688
5940
  body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
5689
5941
  keepalive: true,
5690
5942
  ...rest
5691
- })
5692
- );
5943
+ });
5944
+ } catch (error) {
5945
+ if (config?.signal?.aborted) {
5946
+ throw getAbortReason(config.signal);
5947
+ }
5948
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
5949
+ }
5950
+ return await checkResponse(response);
5693
5951
  } catch (error) {
5694
5952
  if (config?.signal?.aborted) {
5695
5953
  throw getAbortReason(config.signal);
@@ -5714,7 +5972,7 @@ var HTTPConnection = class _HTTPConnection {
5714
5972
  for (let i = 0; i < tries; i++) {
5715
5973
  try {
5716
5974
  const resp = await this.get(`${object_type}`, args);
5717
- return await resp.json();
5975
+ return await readJSONResponse(resp, this.classifyTransportErrors);
5718
5976
  } catch (e) {
5719
5977
  if (i < tries - 1) {
5720
5978
  debugLogger.debug(
@@ -5737,7 +5995,7 @@ var HTTPConnection = class _HTTPConnection {
5737
5995
  const resp = await this.post(`${object_type}`, args, {
5738
5996
  headers: { "Content-Type": "application/json" }
5739
5997
  });
5740
- return await resp.json();
5998
+ return await readJSONResponse(resp, this.classifyTransportErrors);
5741
5999
  }
5742
6000
  // Custom inspect for Node.js console.log
5743
6001
  [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
@@ -7218,6 +7476,52 @@ async function computeLoggerMetadata(state2, {
7218
7476
  };
7219
7477
  }
7220
7478
  }
7479
+ async function loginToLoaderRequestState({
7480
+ appUrl,
7481
+ apiKey,
7482
+ orgName,
7483
+ fetch: fetch2
7484
+ }) {
7485
+ let orgId;
7486
+ let apiUrl;
7487
+ if (apiKey === TEST_API_KEY) {
7488
+ orgId = "test-org-id";
7489
+ apiUrl = "https://braintrust.dev/fake-api-url";
7490
+ } else {
7491
+ let loginResponse;
7492
+ try {
7493
+ loginResponse = await fetch2(_urljoin(appUrl, `/api/apikey/login`), {
7494
+ method: "POST",
7495
+ headers: {
7496
+ "Content-Type": "application/json",
7497
+ Authorization: `Bearer ${apiKey}`
7498
+ }
7499
+ });
7500
+ } catch (error) {
7501
+ throw new HTTPTransportError(error);
7502
+ }
7503
+ const info = await readJSONResponse(
7504
+ await checkResponse(loginResponse),
7505
+ true
7506
+ );
7507
+ const org = selectLoginOrg(info.org_info, orgName);
7508
+ orgId = org.id;
7509
+ apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
7510
+ if (!apiUrl) {
7511
+ throw new Error(
7512
+ orgName ? `Unable to log into organization '${orgName}'. Are you sure this credential is scoped to the organization?` : "Unable to log into any organization with the provided credential."
7513
+ );
7514
+ }
7515
+ }
7516
+ const apiConnection = new HTTPConnection(apiUrl, fetch2, true);
7517
+ apiConnection.set_token(apiKey);
7518
+ apiConnection.make_long_lived();
7519
+ return {
7520
+ appUrl,
7521
+ orgId,
7522
+ apiConn: () => apiConnection
7523
+ };
7524
+ }
7221
7525
  async function loginToState(options = {}) {
7222
7526
  const {
7223
7527
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
@@ -7249,16 +7553,18 @@ async function loginToState(options = {}) {
7249
7553
  _saveOrgInfo(state2, testOrgInfo, testOrgInfo[0].name);
7250
7554
  return state2;
7251
7555
  } else {
7252
- const resp = await checkResponse(
7253
- await fetch2(_urljoin(state2.appUrl, `/api/apikey/login`), {
7556
+ const loginResponse = await fetch2(
7557
+ _urljoin(state2.appUrl, `/api/apikey/login`),
7558
+ {
7254
7559
  method: "POST",
7255
7560
  headers: {
7256
7561
  "Content-Type": "application/json",
7257
7562
  Authorization: `Bearer ${apiKey}`
7258
7563
  }
7259
- })
7564
+ }
7260
7565
  );
7261
- const info = await resp.json();
7566
+ const resp = await checkResponse(loginResponse);
7567
+ const info = await readJSONResponse(resp);
7262
7568
  _saveOrgInfo(state2, info.org_info, orgName);
7263
7569
  if (!state2.apiUrl) {
7264
7570
  if (orgName) {
@@ -7563,7 +7869,7 @@ ${stackTrace}` });
7563
7869
  function startSpan(args) {
7564
7870
  return startSpanAndIsLogger(args).span;
7565
7871
  }
7566
- function startSpanAndIsLogger(args) {
7872
+ function startSpanAndIsLogger(args, internalOptions) {
7567
7873
  const state2 = args?.state ?? _globalState;
7568
7874
  const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
7569
7875
  asyncFlush: args?.asyncFlush,
@@ -7577,7 +7883,7 @@ function startSpanAndIsLogger(args) {
7577
7883
  ) ? {
7578
7884
  spanId: parentObject.data.span_id,
7579
7885
  rootSpanId: parentObject.data.root_span_id
7580
- } : void 0;
7886
+ } : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
7581
7887
  const { parent: _ignoredParent, ...spanArgs } = args ?? {};
7582
7888
  const span = new SpanImpl({
7583
7889
  state: state2,
@@ -7610,27 +7916,28 @@ function withCurrent(span, callback, state2 = void 0) {
7610
7916
  const currentState = state2 ?? _globalState;
7611
7917
  return currentState.contextManager.runInContext(span, () => callback(span));
7612
7918
  }
7613
- function _saveOrgInfo(state2, org_info, org_name) {
7614
- if (org_info.length === 0) {
7919
+ function _saveOrgInfo(state2, orgInfo, orgName) {
7920
+ const org = selectLoginOrg(orgInfo, orgName);
7921
+ state2.orgId = org.id;
7922
+ state2.orgName = org.name;
7923
+ state2.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
7924
+ state2.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
7925
+ state2.gitMetadataSettings = org.git_metadata || void 0;
7926
+ }
7927
+ function selectLoginOrg(orgInfo, orgName) {
7928
+ if (orgInfo.length === 0) {
7615
7929
  throw new LoginInvalidOrgError(
7616
7930
  "This user is not part of any organizations."
7617
7931
  );
7618
7932
  }
7619
- for (const org of org_info) {
7620
- if (org_name === void 0 || org.name === org_name) {
7621
- state2.orgId = org.id;
7622
- state2.orgName = org.name;
7623
- state2.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
7624
- state2.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
7625
- state2.gitMetadataSettings = org.git_metadata || void 0;
7626
- break;
7933
+ for (const org of orgInfo) {
7934
+ if (orgName === void 0 || org.name === orgName) {
7935
+ return org;
7627
7936
  }
7628
7937
  }
7629
- if (state2.orgId === void 0) {
7630
- throw new LoginInvalidOrgError(
7631
- `Organization ${org_name} not found. Must be one of ${org_info.map((x) => x.name).join(", ")}`
7632
- );
7633
- }
7938
+ throw new LoginInvalidOrgError(
7939
+ `Organization ${orgName} not found. Must be one of ${orgInfo.map((org) => org.name).join(", ")}`
7940
+ );
7634
7941
  }
7635
7942
  function validateTags(tags) {
7636
7943
  const seen = /* @__PURE__ */ new Set();
@@ -7795,6 +8102,19 @@ function enrichAttachments(event, state2) {
7795
8102
  }
7796
8103
  return event;
7797
8104
  }
8105
+ async function resolveAttachmentsToBase64(event, state2) {
8106
+ for (const [key, value] of Object.entries(event)) {
8107
+ if (value instanceof ReadonlyAttachment) {
8108
+ event[key] = await value.asBase64Url();
8109
+ continue;
8110
+ }
8111
+ if (!(value instanceof Object)) {
8112
+ continue;
8113
+ }
8114
+ await resolveAttachmentsToBase64(value, state2);
8115
+ }
8116
+ return event;
8117
+ }
7798
8118
  function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
7799
8119
  if ("input" in event && !isEmpty2(event.input) && "inputs" in event && !isEmpty2(event.inputs) || !("input" in event) && !("inputs" in event)) {
7800
8120
  throw new Error(
@@ -9084,6 +9404,473 @@ var Dataset2 = class extends ObjectFetcher {
9084
9404
  return typeof data === "object" && data !== null && "__braintrust_dataset_marker" in data;
9085
9405
  }
9086
9406
  };
9407
+ function isAttachmentObject(value) {
9408
+ return BraintrustAttachmentReference.safeParse(value).success || InlineAttachmentReferenceSchema.safeParse(value).success || ExternalAttachmentReference.safeParse(value).success;
9409
+ }
9410
+ function isURL(url) {
9411
+ try {
9412
+ const parsedUrl = new URL(url.trim());
9413
+ return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
9414
+ } catch {
9415
+ return false;
9416
+ }
9417
+ }
9418
+ function expandAttachmentArrayPreTemplate(content, variables) {
9419
+ if (typeof content !== "string") return null;
9420
+ const match = content.match(/^\{\{\s*([\w.]+)\s*\}\}$/);
9421
+ if (!match) return null;
9422
+ const varPath = match[1];
9423
+ const value = varPath.includes(".") ? getObjValueByPath(variables, varPath.split(".")) : variables[varPath];
9424
+ if (!Array.isArray(value)) return null;
9425
+ const allValid = value.every(
9426
+ (v) => isAttachmentObject(v) || typeof v === "string" && isURL(v)
9427
+ );
9428
+ if (!allValid) return null;
9429
+ return value.map((item) => ({
9430
+ type: "image_url",
9431
+ image_url: { url: item }
9432
+ }));
9433
+ }
9434
+ function renderMessageImpl(render, message, variables) {
9435
+ return {
9436
+ ...message,
9437
+ ..."content" in message ? {
9438
+ content: isEmpty2(message.content) ? void 0 : typeof message.content === "string" ? render(message.content) : message.content.flatMap((c) => {
9439
+ switch (c.type) {
9440
+ case "text":
9441
+ return [{ ...c, text: render(c.text) }];
9442
+ case "image_url":
9443
+ if (isObject(c.image_url.url)) {
9444
+ throw new Error(
9445
+ "Attachments must be replaced with URLs before calling `build()`"
9446
+ );
9447
+ }
9448
+ if (variables) {
9449
+ const expanded = expandAttachmentArrayPreTemplate(
9450
+ c.image_url.url,
9451
+ variables
9452
+ );
9453
+ if (expanded) {
9454
+ return expanded;
9455
+ }
9456
+ }
9457
+ return [
9458
+ {
9459
+ ...c,
9460
+ image_url: {
9461
+ ...c.image_url,
9462
+ url: render(c.image_url.url)
9463
+ }
9464
+ }
9465
+ ];
9466
+ case "file":
9467
+ return [
9468
+ {
9469
+ ...c,
9470
+ file: {
9471
+ ...c.file.file_data && {
9472
+ file_data: render(c.file.file_data)
9473
+ },
9474
+ ...c.file.file_id && {
9475
+ file_id: render(c.file.file_id)
9476
+ },
9477
+ ...c.file.filename && {
9478
+ filename: render(c.file.filename)
9479
+ }
9480
+ }
9481
+ }
9482
+ ];
9483
+ default:
9484
+ const _exhaustiveCheck = c;
9485
+ return _exhaustiveCheck;
9486
+ }
9487
+ })
9488
+ } : {},
9489
+ ..."tool_calls" in message ? {
9490
+ tool_calls: isEmpty2(message.tool_calls) ? void 0 : message.tool_calls.map((t) => {
9491
+ return {
9492
+ type: t.type,
9493
+ id: render(t.id),
9494
+ function: {
9495
+ name: render(t.function.name),
9496
+ arguments: render(t.function.arguments)
9497
+ }
9498
+ };
9499
+ })
9500
+ } : {},
9501
+ ..."tool_call_id" in message ? {
9502
+ tool_call_id: render(message.tool_call_id)
9503
+ } : {}
9504
+ };
9505
+ }
9506
+ function deserializePlainStringAsJSON(s) {
9507
+ if (s.trim() === "") {
9508
+ return { value: null, error: void 0 };
9509
+ }
9510
+ try {
9511
+ return { value: JSON.parse(s), error: void 0 };
9512
+ } catch (e) {
9513
+ return { value: s, error: e };
9514
+ }
9515
+ }
9516
+ function renderTemplatedObject(obj, args, options) {
9517
+ if (typeof obj === "string") {
9518
+ return renderTemplateContent(
9519
+ obj,
9520
+ args,
9521
+ (value) => typeof value === "string" ? value : JSON.stringify(value),
9522
+ {
9523
+ strict: options.strict,
9524
+ templateFormat: options.templateFormat
9525
+ }
9526
+ );
9527
+ } else if (isArray(obj)) {
9528
+ return obj.map((item) => renderTemplatedObject(item, args, options));
9529
+ } else if (isObject(obj)) {
9530
+ return Object.fromEntries(
9531
+ Object.entries(obj).map(([key, value]) => [
9532
+ key,
9533
+ renderTemplatedObject(value, args, options)
9534
+ ])
9535
+ );
9536
+ }
9537
+ return obj;
9538
+ }
9539
+ function renderPromptParams(params, args, options = {}) {
9540
+ const templateFormat = parseTemplateFormat(options.templateFormat);
9541
+ const strict = !!options.strict;
9542
+ const schemaParsed = z8.object({
9543
+ response_format: z8.object({
9544
+ type: z8.literal("json_schema"),
9545
+ json_schema: ResponseFormatJsonSchema.omit({ schema: true }).extend({
9546
+ schema: z8.unknown()
9547
+ })
9548
+ })
9549
+ }).safeParse(params);
9550
+ if (schemaParsed.success) {
9551
+ const rawSchema = schemaParsed.data.response_format.json_schema.schema;
9552
+ const templatedSchema = renderTemplatedObject(rawSchema, args, {
9553
+ strict,
9554
+ templateFormat
9555
+ });
9556
+ const parsedSchema = typeof templatedSchema === "string" ? deserializePlainStringAsJSON(templatedSchema).value : templatedSchema;
9557
+ return {
9558
+ ...params,
9559
+ response_format: {
9560
+ ...schemaParsed.data.response_format,
9561
+ json_schema: {
9562
+ ...schemaParsed.data.response_format.json_schema,
9563
+ schema: parsedSchema
9564
+ }
9565
+ }
9566
+ };
9567
+ }
9568
+ return params;
9569
+ }
9570
+ var Prompt2 = class _Prompt {
9571
+ constructor(metadata, defaults, noTrace) {
9572
+ this.metadata = metadata;
9573
+ this.defaults = defaults;
9574
+ this.noTrace = noTrace;
9575
+ void this.__braintrust_prompt_marker;
9576
+ }
9577
+ metadata;
9578
+ defaults;
9579
+ noTrace;
9580
+ parsedPromptData;
9581
+ hasParsedPromptData = false;
9582
+ __braintrust_prompt_marker = true;
9583
+ get id() {
9584
+ return this.metadata.id;
9585
+ }
9586
+ get projectId() {
9587
+ return this.metadata.project_id;
9588
+ }
9589
+ get name() {
9590
+ return "name" in this.metadata ? this.metadata.name : `Playground function ${this.metadata.id}`;
9591
+ }
9592
+ get slug() {
9593
+ return "slug" in this.metadata ? this.metadata.slug : this.metadata.id;
9594
+ }
9595
+ get prompt() {
9596
+ return this.getParsedPromptData()?.prompt;
9597
+ }
9598
+ get version() {
9599
+ return this.metadata[TRANSACTION_ID_FIELD];
9600
+ }
9601
+ get options() {
9602
+ return this.getParsedPromptData()?.options || {};
9603
+ }
9604
+ get templateFormat() {
9605
+ return this.getParsedPromptData()?.template_format;
9606
+ }
9607
+ get promptData() {
9608
+ return this.getParsedPromptData();
9609
+ }
9610
+ /**
9611
+ * Build the prompt with the given formatting options. The args you pass in will
9612
+ * be forwarded to the mustache template that defines the prompt and rendered with
9613
+ * the `mustache-js` library.
9614
+ *
9615
+ * @param buildArgs Args to forward along to the prompt template.
9616
+ */
9617
+ build(buildArgs, options = {}) {
9618
+ return this.runBuild(buildArgs, {
9619
+ flavor: options.flavor ?? "chat",
9620
+ messages: options.messages,
9621
+ strict: options.strict,
9622
+ templateFormat: options.templateFormat
9623
+ });
9624
+ }
9625
+ /**
9626
+ * This is a special build method that first resolves attachment references, and then
9627
+ * calls the regular build method. You should use this if you are building prompts from
9628
+ * dataset rows that contain attachments.
9629
+ *
9630
+ * @param buildArgs Args to forward along to the prompt template.
9631
+ */
9632
+ async buildWithAttachments(buildArgs, options = {}) {
9633
+ const hydrated = buildArgs instanceof Object ? await resolveAttachmentsToBase64(buildArgs, options.state) : buildArgs;
9634
+ return this.runBuild(hydrated, {
9635
+ flavor: options.flavor ?? "chat",
9636
+ messages: options.messages,
9637
+ strict: options.strict,
9638
+ templateFormat: options.templateFormat
9639
+ });
9640
+ }
9641
+ runBuild(buildArgs, options) {
9642
+ const { flavor } = options;
9643
+ const params = Object.fromEntries(
9644
+ Object.entries({
9645
+ ...this.defaults,
9646
+ ...Object.fromEntries(
9647
+ Object.entries(this.options.params || {}).filter(
9648
+ ([k, _v]) => !BRAINTRUST_PARAMS.includes(k)
9649
+ )
9650
+ ),
9651
+ ...!isEmpty2(this.options.model) ? {
9652
+ model: this.options.model
9653
+ } : {}
9654
+ }).filter(([key, value]) => key !== "response_format" || value !== null)
9655
+ );
9656
+ if (!("model" in params) || isEmpty2(params.model)) {
9657
+ throw new Error(
9658
+ "No model specified. Either specify it in the prompt or as a default"
9659
+ );
9660
+ }
9661
+ const spanInfo = this.noTrace ? {} : {
9662
+ span_info: {
9663
+ metadata: {
9664
+ prompt: this.id ? {
9665
+ variables: buildArgs,
9666
+ id: this.id,
9667
+ project_id: this.projectId,
9668
+ version: this.version,
9669
+ ..."prompt_session_id" in this.metadata ? { prompt_session_id: this.metadata.prompt_session_id } : {}
9670
+ } : void 0
9671
+ }
9672
+ }
9673
+ };
9674
+ const prompt = this.prompt;
9675
+ if (!prompt) {
9676
+ throw new Error("Empty prompt");
9677
+ }
9678
+ const dictArgParsed = z8.record(z8.unknown()).safeParse(buildArgs);
9679
+ const variables = {
9680
+ input: buildArgs,
9681
+ ...dictArgParsed.success ? dictArgParsed.data : {}
9682
+ };
9683
+ const promptDataTemplateFormat = this.templateFormat;
9684
+ const resolvedTemplateFormat = parseTemplateFormat(
9685
+ options.templateFormat ?? promptDataTemplateFormat
9686
+ );
9687
+ const renderedPrompt = _Prompt.renderPrompt({
9688
+ prompt,
9689
+ buildArgs,
9690
+ options: { ...options, templateFormat: resolvedTemplateFormat }
9691
+ });
9692
+ if (flavor === "chat") {
9693
+ if (renderedPrompt.type !== "chat") {
9694
+ throw new Error(
9695
+ "Prompt is a completion prompt. Use buildCompletion() instead"
9696
+ );
9697
+ }
9698
+ return {
9699
+ ...renderPromptParams(params, variables, {
9700
+ strict: options.strict,
9701
+ templateFormat: resolvedTemplateFormat
9702
+ }),
9703
+ ...spanInfo,
9704
+ messages: renderedPrompt.messages,
9705
+ ...renderedPrompt.tools ? {
9706
+ tools: ChatCompletionTool.array().parse(JSON.parse(renderedPrompt.tools))
9707
+ } : void 0
9708
+ };
9709
+ } else if (flavor === "completion") {
9710
+ if (renderedPrompt.type !== "completion") {
9711
+ throw new Error(`Prompt is a chat prompt. Use flavor: 'chat' instead`);
9712
+ }
9713
+ return {
9714
+ ...renderPromptParams(params, variables, {
9715
+ strict: options.strict,
9716
+ templateFormat: resolvedTemplateFormat
9717
+ }),
9718
+ ...spanInfo,
9719
+ prompt: renderedPrompt.content
9720
+ };
9721
+ } else {
9722
+ throw new Error("never!");
9723
+ }
9724
+ }
9725
+ static renderPrompt({
9726
+ prompt,
9727
+ buildArgs,
9728
+ options
9729
+ }) {
9730
+ const escape = (v) => {
9731
+ if (v === void 0) {
9732
+ throw new Error("Missing!");
9733
+ } else if (typeof v === "string") {
9734
+ return v;
9735
+ } else if (v instanceof ReadonlyAttachment) {
9736
+ throw new Error(
9737
+ "Use buildWithAttachments() to build prompts with attachments"
9738
+ );
9739
+ } else {
9740
+ return JSON.stringify(v);
9741
+ }
9742
+ };
9743
+ const dictArgParsed = z8.record(z8.unknown()).safeParse(buildArgs);
9744
+ const variables = {
9745
+ input: buildArgs,
9746
+ ...dictArgParsed.success ? dictArgParsed.data : {}
9747
+ };
9748
+ const templateFormat = parseTemplateFormat(options.templateFormat);
9749
+ if (prompt.type === "chat") {
9750
+ const render = (template) => renderTemplateContent(template, variables, escape, {
9751
+ strict: options.strict,
9752
+ templateFormat
9753
+ });
9754
+ const baseMessages = (prompt.messages || []).map(
9755
+ (m) => renderMessageImpl(render, m, variables)
9756
+ );
9757
+ const hasSystemPrompt = baseMessages.some((m) => m.role === "system");
9758
+ const messages = [
9759
+ ...baseMessages,
9760
+ ...(options.messages ?? []).filter(
9761
+ (m) => !(hasSystemPrompt && m.role === "system")
9762
+ )
9763
+ ];
9764
+ return {
9765
+ type: "chat",
9766
+ messages,
9767
+ ...prompt.tools?.trim() ? {
9768
+ tools: render(prompt.tools)
9769
+ } : void 0
9770
+ };
9771
+ } else if (prompt.type === "completion") {
9772
+ if (options.messages) {
9773
+ throw new Error(
9774
+ "extra messages are not supported for completion prompts"
9775
+ );
9776
+ }
9777
+ const content = renderTemplateContent(prompt.content, variables, escape, {
9778
+ strict: options.strict,
9779
+ templateFormat
9780
+ });
9781
+ return {
9782
+ type: "completion",
9783
+ content
9784
+ };
9785
+ } else {
9786
+ const _ = prompt;
9787
+ throw new Error(`Invalid prompt type: ${_}`);
9788
+ }
9789
+ }
9790
+ getParsedPromptData() {
9791
+ if (!this.hasParsedPromptData) {
9792
+ this.parsedPromptData = PromptData.parse(this.metadata.prompt_data);
9793
+ this.hasParsedPromptData = true;
9794
+ }
9795
+ return this.parsedPromptData;
9796
+ }
9797
+ static isPrompt(data) {
9798
+ return typeof data === "object" && data !== null && "__braintrust_prompt_marker" in data;
9799
+ }
9800
+ /** @internal */
9801
+ _internalSerializeForCache() {
9802
+ return {
9803
+ metadata: this.metadata,
9804
+ defaults: this.defaults,
9805
+ noTrace: this.noTrace
9806
+ };
9807
+ }
9808
+ static fromPromptData(name, promptData) {
9809
+ return new _Prompt(
9810
+ {
9811
+ name,
9812
+ slug: name,
9813
+ prompt_data: promptData
9814
+ },
9815
+ {},
9816
+ false
9817
+ );
9818
+ }
9819
+ };
9820
+ var RemoteEvalParameters = class {
9821
+ constructor(metadata) {
9822
+ this.metadata = metadata;
9823
+ void this.__braintrust_parameters_marker;
9824
+ }
9825
+ metadata;
9826
+ __braintrust_parameters_marker = true;
9827
+ get id() {
9828
+ return this.metadata.id;
9829
+ }
9830
+ get projectId() {
9831
+ return this.metadata.project_id;
9832
+ }
9833
+ get name() {
9834
+ return this.metadata.name;
9835
+ }
9836
+ get slug() {
9837
+ return this.metadata.slug;
9838
+ }
9839
+ get version() {
9840
+ return this.metadata[TRANSACTION_ID_FIELD];
9841
+ }
9842
+ get schema() {
9843
+ return this.metadata.function_data.__schema;
9844
+ }
9845
+ get data() {
9846
+ return this.metadata.function_data.data ?? {};
9847
+ }
9848
+ /** @internal */
9849
+ _internalSerializeForCache() {
9850
+ return { metadata: this.metadata };
9851
+ }
9852
+ validate(data) {
9853
+ if (typeof data !== "object" || data === null) {
9854
+ return false;
9855
+ }
9856
+ const schemaProps = this.schema.properties;
9857
+ if (typeof schemaProps !== "object" || schemaProps === null) {
9858
+ return true;
9859
+ }
9860
+ for (const key of Object.keys(schemaProps)) {
9861
+ if (!(key in data)) {
9862
+ const required = Array.isArray(this.schema.required) ? this.schema.required : [];
9863
+ if (required.includes(key)) {
9864
+ return false;
9865
+ }
9866
+ }
9867
+ }
9868
+ return true;
9869
+ }
9870
+ static isParameters(x) {
9871
+ return typeof x === "object" && x !== null && "__braintrust_parameters_marker" in x && x.__braintrust_parameters_marker === true;
9872
+ }
9873
+ };
9087
9874
  var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
9088
9875
 
9089
9876
  // src/wrappers/mastra.ts
@@ -9380,6 +10167,10 @@ var aiSDKChannels = defineChannels(
9380
10167
  channelName: "generateText",
9381
10168
  kind: "async"
9382
10169
  }),
10170
+ generateImage: channel({
10171
+ channelName: "generateImage",
10172
+ kind: "async"
10173
+ }),
9383
10174
  streamText: channel({
9384
10175
  channelName: "streamText",
9385
10176
  kind: "async"
@@ -9519,6 +10310,33 @@ var aiSDKConfigs = [
9519
10310
  kind: "Async"
9520
10311
  }
9521
10312
  },
10313
+ // generateImage - stable in v6+, experimental alias in v5
10314
+ ...[
10315
+ {
10316
+ functionName: "generateImage",
10317
+ versionRange: ">=6.0.0 <8.0.0",
10318
+ isExportAlias: false
10319
+ },
10320
+ {
10321
+ functionName: "experimental_generateImage",
10322
+ versionRange: ">=5.0.0 <6.0.0",
10323
+ isExportAlias: true
10324
+ }
10325
+ ].flatMap(
10326
+ ({ functionName, versionRange: versionRange2, isExportAlias }) => ["dist/index.mjs", "dist/index.js"].map((filePath) => ({
10327
+ channelName: aiSDKChannels.generateImage.channelName,
10328
+ module: {
10329
+ name: "ai",
10330
+ versionRange: versionRange2,
10331
+ filePath
10332
+ },
10333
+ functionQuery: {
10334
+ functionName,
10335
+ kind: "Async",
10336
+ ...isExportAlias ? { isExportAlias } : {}
10337
+ }
10338
+ }))
10339
+ ),
9522
10340
  // streamText - async function (v3 only, before the sync refactor in v4)
9523
10341
  {
9524
10342
  channelName: aiSDKChannels.streamText.channelName,
@@ -12246,6 +13064,18 @@ var openAIAgentsCoreConfigs = lifecycleMethods.flatMap(
12246
13064
  var openAIChannels = defineChannels(
12247
13065
  "openai",
12248
13066
  {
13067
+ filesCreateTraced: channel({
13068
+ channelName: "files.create-traced",
13069
+ kind: "async"
13070
+ }),
13071
+ batchesRetrieveTraced: channel({
13072
+ channelName: "batches.retrieve-traced",
13073
+ kind: "async"
13074
+ }),
13075
+ batchesCompleteTrace: channel({
13076
+ channelName: "batches.complete-trace",
13077
+ kind: "async"
13078
+ }),
12249
13079
  chatCompletionsCreate: channel({
12250
13080
  channelName: "chat.completions.create",
12251
13081
  kind: "async"
@@ -12679,7 +13509,7 @@ var piCodingAgentChannels = defineChannels(
12679
13509
  );
12680
13510
 
12681
13511
  // src/auto-instrumentations/configs/pi-coding-agent.ts
12682
- var piCodingAgentVersionRange = ">=0.79.0 <0.82.0";
13512
+ var piCodingAgentVersionRange = ">=0.79.0 <1.0.0";
12683
13513
  var piCodingAgentConfigs = [
12684
13514
  {
12685
13515
  channelName: piCodingAgentChannels.prompt.channelName,
@@ -12938,8 +13768,9 @@ function getDefaultInstrumentationConfigs({
12938
13768
  ...additionalInstrumentations ?? []
12939
13769
  ];
12940
13770
  }
12941
- function getDefaultAutoInstrumentationConfigs() {
13771
+ function getDefaultAutoInstrumentationConfigs(additionalInstrumentations) {
12942
13772
  return getDefaultInstrumentationConfigs({
13773
+ additionalInstrumentations,
12943
13774
  disabledIntegrationConfig: readDisabledInstrumentationEnvConfig(
12944
13775
  process.env.BRAINTRUST_DISABLE_INSTRUMENTATION
12945
13776
  ).integrations