braintrust 3.28.0 → 3.29.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 (50) 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 +1815 -1548
  5. package/dev/dist/index.mjs +1054 -787
  6. package/dist/apply-auto-instrumentation.js +297 -264
  7. package/dist/apply-auto-instrumentation.mjs +84 -51
  8. package/dist/auto-instrumentations/bundler/esbuild.cjs +43 -5
  9. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/next.cjs +43 -5
  11. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  12. package/dist/auto-instrumentations/bundler/rollup.cjs +43 -5
  13. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.cjs +43 -5
  15. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  16. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +43 -5
  17. package/dist/auto-instrumentations/bundler/webpack.cjs +43 -5
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  19. package/dist/auto-instrumentations/{chunk-NP7V4XB2.mjs → chunk-AOIYCVEL.mjs} +32 -2
  20. package/dist/auto-instrumentations/{chunk-26PKVUKB.mjs → chunk-DKTGDNA7.mjs} +12 -4
  21. package/dist/auto-instrumentations/{chunk-HD35AM3M.mjs → chunk-OMCZ3MV2.mjs} +1 -1
  22. package/dist/auto-instrumentations/hook.mjs +952 -133
  23. package/dist/auto-instrumentations/index.cjs +32 -2
  24. package/dist/auto-instrumentations/index.mjs +1 -1
  25. package/dist/browser.d.mts +760 -22
  26. package/dist/browser.d.ts +760 -22
  27. package/dist/browser.js +1661 -848
  28. package/dist/browser.mjs +1661 -848
  29. package/dist/{chunk-BBE7SNRV.js → chunk-6Z5S7VOU.js} +143 -23
  30. package/dist/{chunk-ZHUHZWFY.mjs → chunk-7FA6VP2S.mjs} +140 -20
  31. package/dist/{chunk-UPFNQCGB.mjs → chunk-M6XPNJC4.mjs} +1144 -931
  32. package/dist/{chunk-OBBWQW6K.js → chunk-XLLGRXGR.js} +2335 -2122
  33. package/dist/cli.js +5134 -1090
  34. package/dist/edge-light.js +1661 -848
  35. package/dist/edge-light.mjs +1661 -848
  36. package/dist/index.d.mts +760 -22
  37. package/dist/index.d.ts +760 -22
  38. package/dist/index.js +1054 -567
  39. package/dist/index.mjs +514 -27
  40. package/dist/instrumentation/index.d.mts +548 -9
  41. package/dist/instrumentation/index.d.ts +548 -9
  42. package/dist/instrumentation/index.js +1975 -765
  43. package/dist/instrumentation/index.mjs +1975 -765
  44. package/dist/vitest-evals-reporter.js +16 -16
  45. package/dist/vitest-evals-reporter.mjs +2 -2
  46. package/dist/workerd.js +1661 -848
  47. package/dist/workerd.mjs +1661 -848
  48. package/package.json +1 -1
  49. package/util/dist/index.d.mts +42 -0
  50. package/util/dist/index.d.ts +42 -0
@@ -699,8 +699,6 @@ function newGlobalTracingChannel(nameOrChannels) {
699
699
  var DefaultAsyncLocalStorage = class {
700
700
  constructor() {
701
701
  }
702
- enterWith(_) {
703
- }
704
702
  run(_, callback) {
705
703
  return callback();
706
704
  }
@@ -2622,7 +2620,9 @@ var AclObjectType = import_v36.z.union([
2622
2620
  "project_log",
2623
2621
  "org_project",
2624
2622
  "org_audit_logs",
2625
- "project_group"
2623
+ "project_group",
2624
+ "ai_secret",
2625
+ "org_ai_secret"
2626
2626
  ]),
2627
2627
  import_v36.z.null()
2628
2628
  ]);
@@ -3455,7 +3455,7 @@ var PromptParserNullish = import_v36.z.union([
3455
3455
  }),
3456
3456
  import_v36.z.null()
3457
3457
  ]);
3458
- var PreprocessorSavedFunctionId = import_v36.z.union([
3458
+ var PreprocessorId = import_v36.z.union([
3459
3459
  import_v36.z.object({
3460
3460
  type: import_v36.z.literal("function"),
3461
3461
  id: import_v36.z.string(),
@@ -3466,6 +3466,7 @@ var PreprocessorSavedFunctionId = import_v36.z.union([
3466
3466
  name: import_v36.z.string(),
3467
3467
  function_type: import_v36.z.literal("preprocessor").optional().default("preprocessor")
3468
3468
  }),
3469
+ import_v36.z.object({ type: import_v36.z.literal("inline"), code: import_v36.z.string().min(1) }),
3469
3470
  import_v36.z.null()
3470
3471
  ]);
3471
3472
  var PromptDataNullish = import_v36.z.union([
@@ -3473,7 +3474,7 @@ var PromptDataNullish = import_v36.z.union([
3473
3474
  prompt: PromptBlockDataNullish,
3474
3475
  options: PromptOptionsNullish,
3475
3476
  parser: PromptParserNullish,
3476
- preprocessor: PreprocessorSavedFunctionId,
3477
+ preprocessor: PreprocessorId,
3477
3478
  tool_functions: import_v36.z.union([import_v36.z.array(SavedFunctionId), import_v36.z.null()]),
3478
3479
  template_format: import_v36.z.union([
3479
3480
  import_v36.z.enum(["mustache", "nunjucks", "none"]),
@@ -3675,7 +3676,7 @@ var PromptData = import_v36.z.object({
3675
3676
  prompt: PromptBlockDataNullish,
3676
3677
  options: PromptOptionsNullish,
3677
3678
  parser: PromptParserNullish,
3678
- preprocessor: PreprocessorSavedFunctionId,
3679
+ preprocessor: PreprocessorId,
3679
3680
  tool_functions: import_v36.z.union([import_v36.z.array(SavedFunctionId), import_v36.z.null()]),
3680
3681
  template_format: import_v36.z.union([
3681
3682
  import_v36.z.enum(["mustache", "nunjucks", "none"]),
@@ -4619,6 +4620,7 @@ var View = import_v36.z.object({
4619
4620
  ]),
4620
4621
  name: import_v36.z.string(),
4621
4622
  description: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4623
+ starred: import_v36.z.boolean().optional(),
4622
4624
  created: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4623
4625
  updated_at: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4624
4626
  view_data: ViewData.optional(),
@@ -4708,6 +4710,34 @@ var registerTemplatePlugin = templateRegistry.register.bind(templateRegistry);
4708
4710
  var getTemplateRenderer = templateRegistry.get.bind(templateRegistry);
4709
4711
  registerTemplatePlugin(mustachePlugin);
4710
4712
 
4713
+ // src/template/renderer.ts
4714
+ function isTemplateFormat(v) {
4715
+ return v === "mustache" || v === "nunjucks" || v === "none";
4716
+ }
4717
+ function parseTemplateFormat(value, defaultFormat = "mustache") {
4718
+ return isTemplateFormat(value) ? value : defaultFormat;
4719
+ }
4720
+ function renderTemplateContent(template, variables, escape, options) {
4721
+ const strict = !!options.strict;
4722
+ const templateFormat = parseTemplateFormat(options.templateFormat);
4723
+ if (templateFormat === "none") {
4724
+ return template;
4725
+ }
4726
+ const renderer = getTemplateRenderer(templateFormat);
4727
+ if (!renderer) {
4728
+ if (templateFormat === "nunjucks") {
4729
+ throw new Error(
4730
+ "Nunjucks templating requires @braintrust/template-nunjucks. Install and import it to enable templateFormat: 'nunjucks'."
4731
+ );
4732
+ }
4733
+ throw new Error(`No template renderer registered for ${templateFormat}`);
4734
+ }
4735
+ if (strict && renderer.lint) {
4736
+ renderer.lint(template, variables);
4737
+ }
4738
+ return renderer.render(template, variables, escape, strict);
4739
+ }
4740
+
4711
4741
  // src/logger.ts
4712
4742
  var import_v38 = require("zod/v3");
4713
4743
 
@@ -5292,44 +5322,72 @@ function createCacheLayers({
5292
5322
  }
5293
5323
 
5294
5324
  // src/prompt-cache/prompt-cache.ts
5295
- function createCacheKey(key) {
5325
+ function createCacheKey(key, namespace) {
5326
+ let cacheKey;
5296
5327
  if (key.id) {
5297
- return `id:${key.id}`;
5298
- }
5299
- const prefix = key.projectId ?? key.projectName;
5300
- if (!prefix) {
5301
- throw new Error("Either projectId or projectName must be provided");
5302
- }
5303
- if (!key.slug) {
5304
- throw new Error("Slug must be provided when not using ID");
5328
+ cacheKey = `id:${key.id}`;
5329
+ } else {
5330
+ const prefix = key.projectId ?? key.projectName;
5331
+ if (!prefix) {
5332
+ throw new Error("Either projectId or projectName must be provided");
5333
+ }
5334
+ if (!key.slug) {
5335
+ throw new Error("Slug must be provided when not using ID");
5336
+ }
5337
+ cacheKey = `${prefix}:${key.slug}:${key.version ?? "latest"}`;
5305
5338
  }
5306
- return `${prefix}:${key.slug}:${key.version ?? "latest"}`;
5339
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
5307
5340
  }
5308
- var PromptCache = class {
5341
+ var PromptCache = class _PromptCache {
5309
5342
  memoryCache;
5310
5343
  diskCache;
5344
+ namespace;
5345
+ expectedResolvedOrgIdentity;
5311
5346
  constructor(options) {
5312
5347
  this.memoryCache = options.memoryCache;
5313
5348
  this.diskCache = options.diskCache;
5349
+ this.namespace = options.namespace;
5350
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
5351
+ }
5352
+ /**
5353
+ * Returns a cache view that shares the same storage layers but isolates all
5354
+ * entries under the provided namespace.
5355
+ */
5356
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
5357
+ return new _PromptCache({
5358
+ memoryCache: this.memoryCache,
5359
+ diskCache: this.diskCache,
5360
+ namespace,
5361
+ expectedResolvedOrgIdentity
5362
+ });
5314
5363
  }
5315
5364
  /**
5316
5365
  * Retrieves a prompt from the cache.
5317
5366
  * First checks the in-memory LRU cache, then falls back to checking the disk cache if available.
5318
5367
  */
5319
5368
  async get(key) {
5320
- const cacheKey = createCacheKey(key);
5369
+ const cacheKey = createCacheKey(key, this.namespace);
5321
5370
  if (this.memoryCache) {
5322
- const memoryPrompt = this.memoryCache.get(cacheKey);
5323
- if (memoryPrompt !== void 0) {
5324
- return memoryPrompt;
5371
+ const memoryEntry = this.memoryCache.get(cacheKey);
5372
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
5373
+ return memoryEntry.value;
5325
5374
  }
5326
5375
  }
5327
5376
  if (this.diskCache) {
5328
- const diskPrompt = await this.diskCache.get(cacheKey);
5329
- if (!diskPrompt) {
5377
+ const diskEntry = await this.diskCache.get(cacheKey);
5378
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
5330
5379
  return void 0;
5331
5380
  }
5332
- this.memoryCache?.set(cacheKey, diskPrompt);
5381
+ const serializedPrompt = diskEntry.value;
5382
+ const diskPrompt = new Prompt2(
5383
+ serializedPrompt.metadata,
5384
+ serializedPrompt.defaults,
5385
+ serializedPrompt.noTrace
5386
+ );
5387
+ this.memoryCache?.set(cacheKey, {
5388
+ value: diskPrompt,
5389
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
5390
+ });
5333
5391
  return diskPrompt;
5334
5392
  }
5335
5393
  return void 0;
@@ -5343,58 +5401,91 @@ var PromptCache = class {
5343
5401
  * @throws If there is an error writing to the disk cache.
5344
5402
  */
5345
5403
  async set(key, value) {
5346
- const cacheKey = createCacheKey(key);
5347
- this.memoryCache?.set(cacheKey, value);
5404
+ const cacheKey = createCacheKey(key, this.namespace);
5405
+ const memoryEntry = {
5406
+ value,
5407
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5408
+ };
5409
+ this.memoryCache?.set(cacheKey, memoryEntry);
5348
5410
  if (this.diskCache) {
5349
- await this.diskCache.set(cacheKey, value);
5411
+ await this.diskCache.set(cacheKey, {
5412
+ value: value._internalSerializeForCache(),
5413
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5414
+ });
5350
5415
  }
5351
5416
  }
5352
5417
  };
5353
5418
 
5354
5419
  // src/prompt-cache/parameters-cache.ts
5355
- function createCacheKey2(key) {
5420
+ function createCacheKey2(key, namespace) {
5421
+ let cacheKey;
5356
5422
  if (key.id) {
5357
- return `parameters:id:${key.id}`;
5358
- }
5359
- const prefix = key.projectId ?? key.projectName;
5360
- if (!prefix) {
5361
- throw new Error("Either projectId or projectName must be provided");
5362
- }
5363
- if (!key.slug) {
5364
- throw new Error("Slug must be provided when not using ID");
5423
+ cacheKey = `parameters:id:${key.id}`;
5424
+ } else {
5425
+ const prefix = key.projectId ?? key.projectName;
5426
+ if (!prefix) {
5427
+ throw new Error("Either projectId or projectName must be provided");
5428
+ }
5429
+ if (!key.slug) {
5430
+ throw new Error("Slug must be provided when not using ID");
5431
+ }
5432
+ cacheKey = `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
5365
5433
  }
5366
- return `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
5434
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
5367
5435
  }
5368
- var ParametersCache = class {
5436
+ var ParametersCache = class _ParametersCache {
5369
5437
  memoryCache;
5370
5438
  diskCache;
5439
+ namespace;
5440
+ expectedResolvedOrgIdentity;
5371
5441
  constructor(options) {
5372
5442
  this.memoryCache = options.memoryCache;
5373
5443
  this.diskCache = options.diskCache;
5444
+ this.namespace = options.namespace;
5445
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
5446
+ }
5447
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
5448
+ return new _ParametersCache({
5449
+ memoryCache: this.memoryCache,
5450
+ diskCache: this.diskCache,
5451
+ namespace,
5452
+ expectedResolvedOrgIdentity
5453
+ });
5374
5454
  }
5375
5455
  async get(key) {
5376
- const cacheKey = createCacheKey2(key);
5456
+ const cacheKey = createCacheKey2(key, this.namespace);
5377
5457
  if (this.memoryCache) {
5378
- const memoryParams = this.memoryCache.get(cacheKey);
5379
- if (memoryParams !== void 0) {
5380
- return memoryParams;
5458
+ const memoryEntry = this.memoryCache.get(cacheKey);
5459
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
5460
+ return memoryEntry.value;
5381
5461
  }
5382
5462
  }
5383
5463
  if (this.diskCache) {
5384
- const diskParams = await this.diskCache.get(cacheKey);
5385
- if (!diskParams) {
5464
+ const diskEntry = await this.diskCache.get(cacheKey);
5465
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
5386
5466
  return void 0;
5387
5467
  }
5388
- this.memoryCache?.set(cacheKey, diskParams);
5389
- return diskParams;
5468
+ const diskParameters = new RemoteEvalParameters(diskEntry.value.metadata);
5469
+ this.memoryCache?.set(cacheKey, {
5470
+ value: diskParameters,
5471
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
5472
+ });
5473
+ return diskParameters;
5390
5474
  }
5391
5475
  return void 0;
5392
5476
  }
5393
5477
  async set(key, value) {
5394
- const cacheKey = createCacheKey2(key);
5395
- this.memoryCache?.set(cacheKey, value);
5478
+ const cacheKey = createCacheKey2(key, this.namespace);
5479
+ const memoryEntry = {
5480
+ value,
5481
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5482
+ };
5483
+ this.memoryCache?.set(cacheKey, memoryEntry);
5396
5484
  if (this.diskCache) {
5397
- await this.diskCache.set(cacheKey, value);
5485
+ await this.diskCache.set(cacheKey, {
5486
+ value: value._internalSerializeForCache(),
5487
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5488
+ });
5398
5489
  }
5399
5490
  }
5400
5491
  };
@@ -5698,6 +5789,7 @@ var INSTRUMENTATION_NAMES = {
5698
5789
  CLOUDFLARE_THINK: "cloudflare-think",
5699
5790
  COHERE: "cohere",
5700
5791
  CURSOR_SDK: "cursor-sdk",
5792
+ DEEPSEEK_HARNESS: "deepseek-harness",
5701
5793
  EVE: "eve",
5702
5794
  FLUE: "flue",
5703
5795
  GENKIT: "genkit",
@@ -5723,7 +5815,7 @@ var INSTRUMENTATION_NAMES = {
5723
5815
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5724
5816
  "braintrust.spanInstrumentationName"
5725
5817
  );
5726
- var SDK_VERSION = true ? "3.28.0" : "0.0.0";
5818
+ var SDK_VERSION = true ? "3.29.0" : "0.0.0";
5727
5819
  function withSpanInstrumentationName(args, instrumentationName) {
5728
5820
  return {
5729
5821
  ...args,
@@ -5842,6 +5934,16 @@ var datasetSnapshotRegisterResponseSchema = import_v38.z.object({
5842
5934
  dataset_snapshot: DatasetSnapshot,
5843
5935
  found_existing: import_v38.z.boolean().optional()
5844
5936
  });
5937
+ var datasetObjectInfoSchema = import_v38.z.object({
5938
+ object_id: import_v38.z.string(),
5939
+ object_name: import_v38.z.string(),
5940
+ parent_cols: import_v38.z.object({
5941
+ project: import_v38.z.object({
5942
+ id: import_v38.z.string(),
5943
+ name: import_v38.z.string()
5944
+ })
5945
+ })
5946
+ });
5845
5947
  var datasetRestorePreviewResultSchema = import_v38.z.object({
5846
5948
  rows_to_restore: import_v38.z.number(),
5847
5949
  rows_to_delete: import_v38.z.number()
@@ -6055,12 +6157,53 @@ var loginSchema = import_v38.z.strictObject({
6055
6157
  });
6056
6158
  var stateNonce = 0;
6057
6159
  var V1_PROXY_SUFFIX = "/v1/proxy";
6160
+ var LOADER_LOGIN_CACHE_MAX = 16;
6058
6161
  function normalizeProxyConnUrl(proxyUrl) {
6059
6162
  return proxyUrl.endsWith(V1_PROXY_SUFFIX) ? proxyUrl.slice(0, proxyUrl.length - V1_PROXY_SUFFIX.length) : proxyUrl;
6060
6163
  }
6061
6164
  var BraintrustState = class _BraintrustState {
6165
+ id;
6166
+ currentExperiment;
6167
+ // Note: the value of IsAsyncFlush doesn't really matter here, since we
6168
+ // (safely) dynamically cast it whenever retrieving the logger.
6169
+ currentLogger;
6170
+ currentParent;
6171
+ currentSpan;
6172
+ // Any time we re-log in, we directly update the apiConn inside the logger.
6173
+ // This is preferable to replacing the whole logger, which would create the
6174
+ // possibility of multiple loggers floating around, which may not log in a
6175
+ // deterministic order.
6176
+ _bgLogger;
6177
+ _overrideBgLogger = null;
6178
+ appUrl = null;
6179
+ appPublicUrl = null;
6180
+ loginToken = null;
6181
+ orgId = null;
6182
+ orgName = null;
6183
+ apiUrl = null;
6184
+ proxyUrl = null;
6185
+ loggedIn = false;
6186
+ gitMetadataSettings;
6187
+ debugLogLevel;
6188
+ debugLogLevelConfigured = false;
6189
+ fetch = globalThis.fetch;
6190
+ _appConn = null;
6191
+ _apiConn = null;
6192
+ _proxyConn = null;
6193
+ promptCache;
6194
+ parametersCache;
6195
+ spanCache;
6196
+ _idGenerator = null;
6197
+ _contextManager = null;
6198
+ _otelFlushCallback = null;
6199
+ spanOriginEnvironment;
6200
+ traceContextSigningSecret;
6201
+ loaderLoginCache = /* @__PURE__ */ new WeakMap();
6202
+ loginParams;
6203
+ activeLoginOrgNameSelector;
6062
6204
  constructor(loginParams) {
6063
- this.loginParams = loginParams;
6205
+ this.loginParams = { ...loginParams };
6206
+ this.activeLoginOrgNameSelector = loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
6064
6207
  this.id = `${(/* @__PURE__ */ new Date()).toLocaleString()}-${stateNonce++}`;
6065
6208
  this.currentExperiment = void 0;
6066
6209
  this.currentLogger = void 0;
@@ -6097,12 +6240,14 @@ var BraintrustState = class _BraintrustState {
6097
6240
  const {
6098
6241
  memoryCache: parametersMemoryCache,
6099
6242
  diskCache: parametersDiskCache
6100
- } = createCacheLayers({
6101
- memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
6102
- diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
6103
- diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
6104
- getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
6105
- });
6243
+ } = createCacheLayers(
6244
+ {
6245
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
6246
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
6247
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
6248
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
6249
+ }
6250
+ );
6106
6251
  this.parametersCache = new ParametersCache({
6107
6252
  memoryCache: parametersMemoryCache,
6108
6253
  diskCache: parametersDiskCache
@@ -6111,43 +6256,6 @@ var BraintrustState = class _BraintrustState {
6111
6256
  this.spanOriginEnvironment = detectSpanOriginEnvironment();
6112
6257
  this._internalSetTraceContextSigningSecret(loginParams.apiKey);
6113
6258
  }
6114
- loginParams;
6115
- id;
6116
- currentExperiment;
6117
- // Note: the value of IsAsyncFlush doesn't really matter here, since we
6118
- // (safely) dynamically cast it whenever retrieving the logger.
6119
- currentLogger;
6120
- currentParent;
6121
- currentSpan;
6122
- // Any time we re-log in, we directly update the apiConn inside the logger.
6123
- // This is preferable to replacing the whole logger, which would create the
6124
- // possibility of multiple loggers floating around, which may not log in a
6125
- // deterministic order.
6126
- _bgLogger;
6127
- _overrideBgLogger = null;
6128
- appUrl = null;
6129
- appPublicUrl = null;
6130
- loginToken = null;
6131
- orgId = null;
6132
- orgName = null;
6133
- apiUrl = null;
6134
- proxyUrl = null;
6135
- loggedIn = false;
6136
- gitMetadataSettings;
6137
- debugLogLevel;
6138
- debugLogLevelConfigured = false;
6139
- fetch = globalThis.fetch;
6140
- _appConn = null;
6141
- _apiConn = null;
6142
- _proxyConn = null;
6143
- promptCache;
6144
- parametersCache;
6145
- spanCache;
6146
- _idGenerator = null;
6147
- _contextManager = null;
6148
- _otelFlushCallback = null;
6149
- spanOriginEnvironment;
6150
- traceContextSigningSecret;
6151
6259
  /** @internal */
6152
6260
  _internalSetTraceContextSigningSecret(secret) {
6153
6261
  const normalizedSecret = secret?.trim();
@@ -6172,6 +6280,101 @@ var BraintrustState = class _BraintrustState {
6172
6280
  this._appConn = null;
6173
6281
  this._apiConn = null;
6174
6282
  this._proxyConn = null;
6283
+ this.loaderLoginCache = /* @__PURE__ */ new WeakMap();
6284
+ }
6285
+ /** @internal */
6286
+ async _internalResolveLoaderLoginOptions({
6287
+ apiKey,
6288
+ appUrl,
6289
+ orgName,
6290
+ fetch: fetch2,
6291
+ forceLogin
6292
+ }) {
6293
+ const resolvedAppUrl = appUrl ?? (this.loggedIn ? this.appUrl ?? void 0 : void 0) ?? this.loginParams.appUrl ?? isomorph_default.getEnv("BRAINTRUST_APP_URL") ?? "https://www.braintrust.dev";
6294
+ const resolvedApiKey = apiKey ?? (this.loggedIn ? this.loginToken ?? void 0 : void 0) ?? this.loginParams.apiKey ?? await isomorph_default.getBraintrustApiKey();
6295
+ if (!resolvedApiKey) {
6296
+ throw new Error(
6297
+ "Please specify an api key (e.g. by setting BRAINTRUST_API_KEY)."
6298
+ );
6299
+ }
6300
+ const normalizedApiKey = HTTPConnection.sanitize_token(resolvedApiKey);
6301
+ const usesActiveCredential = this.loggedIn && normalizedApiKey === this.loginToken;
6302
+ const requestedOrgName = orgName ?? (usesActiveCredential ? this.activeLoginOrgNameSelector : void 0) ?? this.loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
6303
+ const resolvedOrgName = orgName ?? (usesActiveCredential ? this.orgName ?? void 0 : void 0) ?? requestedOrgName;
6304
+ const resolvedFetch = fetch2 ?? (this.loggedIn ? this.fetch : void 0) ?? this.loginParams.fetch ?? globalThis.fetch;
6305
+ const credentialCacheNamespace = JSON.stringify([
6306
+ "loader-credential",
6307
+ resolvedAppUrl,
6308
+ requestedOrgName,
6309
+ normalizedApiKey
6310
+ ]);
6311
+ return {
6312
+ apiKey: normalizedApiKey,
6313
+ appUrl: resolvedAppUrl,
6314
+ orgName: resolvedOrgName,
6315
+ fetch: resolvedFetch,
6316
+ forceLogin,
6317
+ credentialCacheNamespace,
6318
+ existingState: !forceLogin && usesActiveCredential && resolvedAppUrl === this.appUrl && resolvedOrgName === this.orgName && resolvedFetch === this.fetch ? this : void 0
6319
+ };
6320
+ }
6321
+ /** @internal */
6322
+ _internalGetLoaderCacheViews(loginOptions, requestState) {
6323
+ const expectedResolvedOrgIdentity = requestState?.orgId && requestState.appUrl ? JSON.stringify([
6324
+ "loader-org",
6325
+ requestState.appUrl,
6326
+ requestState.orgId
6327
+ ]) : void 0;
6328
+ return {
6329
+ promptCache: this.promptCache.withNamespace(
6330
+ loginOptions.credentialCacheNamespace,
6331
+ expectedResolvedOrgIdentity
6332
+ ),
6333
+ parametersCache: this.parametersCache.withNamespace(
6334
+ loginOptions.credentialCacheNamespace,
6335
+ expectedResolvedOrgIdentity
6336
+ )
6337
+ };
6338
+ }
6339
+ /** @internal */
6340
+ async _internalGetLoaderState({
6341
+ apiKey,
6342
+ appUrl,
6343
+ orgName,
6344
+ fetch: fetch2,
6345
+ forceLogin,
6346
+ existingState
6347
+ }) {
6348
+ if (existingState) {
6349
+ return existingState;
6350
+ }
6351
+ let cache = this.loaderLoginCache.get(fetch2);
6352
+ if (!cache) {
6353
+ cache = new LRUCache({ max: LOADER_LOGIN_CACHE_MAX });
6354
+ this.loaderLoginCache.set(fetch2, cache);
6355
+ }
6356
+ const cacheKey = JSON.stringify([appUrl, orgName, apiKey]);
6357
+ if (!forceLogin) {
6358
+ const cachedState = cache.get(cacheKey);
6359
+ if (cachedState) {
6360
+ return cachedState;
6361
+ }
6362
+ }
6363
+ const statePromise = loginToLoaderRequestState({
6364
+ orgName,
6365
+ apiKey,
6366
+ appUrl,
6367
+ fetch: fetch2
6368
+ });
6369
+ cache.set(cacheKey, statePromise);
6370
+ try {
6371
+ return await statePromise;
6372
+ } catch (error) {
6373
+ if (cache.get(cacheKey) === statePromise) {
6374
+ cache.delete(cacheKey);
6375
+ }
6376
+ throw error;
6377
+ }
6175
6378
  }
6176
6379
  resetIdGenState() {
6177
6380
  this._idGenerator = null;
@@ -6220,6 +6423,8 @@ var BraintrustState = class _BraintrustState {
6220
6423
  this.debugLogLevel = other.debugLogLevel;
6221
6424
  this.debugLogLevelConfigured = other.debugLogLevelConfigured;
6222
6425
  this.traceContextSigningSecret = other.traceContextSigningSecret;
6426
+ this.fetch = other.fetch;
6427
+ this.activeLoginOrgNameSelector = other.activeLoginOrgNameSelector;
6223
6428
  setGlobalDebugLogLevel(
6224
6429
  this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
6225
6430
  );
@@ -6414,36 +6619,76 @@ var FailedHTTPResponse = class extends Error {
6414
6619
  status;
6415
6620
  text;
6416
6621
  data;
6417
- constructor(status, text, data) {
6622
+ cause;
6623
+ constructor(status, text, data, cause) {
6418
6624
  super(`${status}: ${text} (${data})`);
6419
6625
  this.status = status;
6420
6626
  this.text = text;
6421
6627
  this.data = data;
6628
+ this.cause = cause;
6629
+ }
6630
+ };
6631
+ var HTTPTransportError = class extends Error {
6632
+ cause;
6633
+ constructor(cause) {
6634
+ super(cause instanceof Error ? cause.message : String(cause));
6635
+ this.name = "HTTPTransportError";
6636
+ this.cause = cause;
6422
6637
  }
6423
6638
  };
6639
+ var httpTransportErrorCauses = /* @__PURE__ */ new WeakSet();
6640
+ function recordHTTPTransportError(error) {
6641
+ if (typeof error === "object" && error !== null || typeof error === "function") {
6642
+ httpTransportErrorCauses.add(error);
6643
+ }
6644
+ }
6645
+ function rethrowHTTPTransportError(error, classifyTransportErrors) {
6646
+ if (classifyTransportErrors) {
6647
+ throw new HTTPTransportError(error);
6648
+ }
6649
+ recordHTTPTransportError(error);
6650
+ throw error;
6651
+ }
6652
+ async function readJSONResponse(response, classifyTransportErrors = false) {
6653
+ let data;
6654
+ try {
6655
+ data = await response.text();
6656
+ } catch (error) {
6657
+ rethrowHTTPTransportError(error, classifyTransportErrors);
6658
+ }
6659
+ return JSON.parse(data);
6660
+ }
6424
6661
  async function checkResponse(resp) {
6425
6662
  if (resp.ok) {
6426
6663
  return resp;
6427
- } else {
6664
+ }
6665
+ let data;
6666
+ try {
6667
+ data = await resp.text();
6668
+ } catch (error) {
6428
6669
  throw new FailedHTTPResponse(
6429
6670
  resp.status,
6430
6671
  resp.statusText,
6431
- await resp.text()
6672
+ "Unable to read response body",
6673
+ error
6432
6674
  );
6433
6675
  }
6676
+ throw new FailedHTTPResponse(resp.status, resp.statusText, data);
6434
6677
  }
6435
6678
  var HTTPConnection = class _HTTPConnection {
6436
- base_url;
6437
- token;
6438
- headers;
6439
- fetch;
6440
- constructor(base_url, fetch2) {
6679
+ constructor(base_url, fetch2, classifyTransportErrors = false) {
6680
+ this.classifyTransportErrors = classifyTransportErrors;
6441
6681
  this.base_url = base_url;
6442
6682
  this.token = null;
6443
6683
  this.headers = {};
6444
6684
  this._reset();
6445
6685
  this.fetch = fetch2;
6446
6686
  }
6687
+ classifyTransportErrors;
6688
+ base_url;
6689
+ token;
6690
+ headers;
6691
+ fetch;
6447
6692
  setFetch(fetch2) {
6448
6693
  this.fetch = fetch2;
6449
6694
  }
@@ -6483,9 +6728,9 @@ var HTTPConnection = class _HTTPConnection {
6483
6728
  ).toString();
6484
6729
  const this_fetch = this.fetch;
6485
6730
  const this_headers = this.headers;
6486
- return await checkResponse(
6487
- // Using toString() here makes it work with isomorphic fetch
6488
- await this_fetch(url.toString(), {
6731
+ let response;
6732
+ try {
6733
+ response = await this_fetch(url.toString(), {
6489
6734
  headers: {
6490
6735
  Accept: "application/json",
6491
6736
  ...this_headers,
@@ -6493,8 +6738,14 @@ var HTTPConnection = class _HTTPConnection {
6493
6738
  },
6494
6739
  keepalive: true,
6495
6740
  ...rest
6496
- })
6497
- );
6741
+ });
6742
+ } catch (error) {
6743
+ if (config?.signal?.aborted) {
6744
+ throw getAbortReason(config.signal);
6745
+ }
6746
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
6747
+ }
6748
+ return await checkResponse(response);
6498
6749
  }
6499
6750
  async post(path, params, config, retries = 0) {
6500
6751
  const { headers, ...rest } = config || {};
@@ -6504,8 +6755,9 @@ var HTTPConnection = class _HTTPConnection {
6504
6755
  const tries = retries + 1;
6505
6756
  for (let i = 0; i < tries; i++) {
6506
6757
  try {
6507
- return await checkResponse(
6508
- await this_fetch(_urljoin(this_base_url, path), {
6758
+ let response;
6759
+ try {
6760
+ response = await this_fetch(_urljoin(this_base_url, path), {
6509
6761
  method: "POST",
6510
6762
  headers: {
6511
6763
  Accept: "application/json",
@@ -6516,8 +6768,14 @@ var HTTPConnection = class _HTTPConnection {
6516
6768
  body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
6517
6769
  keepalive: true,
6518
6770
  ...rest
6519
- })
6520
- );
6771
+ });
6772
+ } catch (error) {
6773
+ if (config?.signal?.aborted) {
6774
+ throw getAbortReason(config.signal);
6775
+ }
6776
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
6777
+ }
6778
+ return await checkResponse(response);
6521
6779
  } catch (error) {
6522
6780
  if (config?.signal?.aborted) {
6523
6781
  throw getAbortReason(config.signal);
@@ -6542,7 +6800,7 @@ var HTTPConnection = class _HTTPConnection {
6542
6800
  for (let i = 0; i < tries; i++) {
6543
6801
  try {
6544
6802
  const resp = await this.get(`${object_type}`, args);
6545
- return await resp.json();
6803
+ return await readJSONResponse(resp, this.classifyTransportErrors);
6546
6804
  } catch (e) {
6547
6805
  if (i < tries - 1) {
6548
6806
  debugLogger.debug(
@@ -6565,7 +6823,7 @@ var HTTPConnection = class _HTTPConnection {
6565
6823
  const resp = await this.post(`${object_type}`, args, {
6566
6824
  headers: { "Content-Type": "application/json" }
6567
6825
  });
6568
- return await resp.json();
6826
+ return await readJSONResponse(resp, this.classifyTransportErrors);
6569
6827
  }
6570
6828
  // Custom inspect for Node.js console.log
6571
6829
  [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
@@ -8120,6 +8378,52 @@ function initLogger(options = {}) {
8120
8378
  }
8121
8379
  return ret;
8122
8380
  }
8381
+ async function loginToLoaderRequestState({
8382
+ appUrl,
8383
+ apiKey,
8384
+ orgName,
8385
+ fetch: fetch2
8386
+ }) {
8387
+ let orgId;
8388
+ let apiUrl;
8389
+ if (apiKey === TEST_API_KEY) {
8390
+ orgId = "test-org-id";
8391
+ apiUrl = "https://braintrust.dev/fake-api-url";
8392
+ } else {
8393
+ let loginResponse;
8394
+ try {
8395
+ loginResponse = await fetch2(_urljoin(appUrl, `/api/apikey/login`), {
8396
+ method: "POST",
8397
+ headers: {
8398
+ "Content-Type": "application/json",
8399
+ Authorization: `Bearer ${apiKey}`
8400
+ }
8401
+ });
8402
+ } catch (error) {
8403
+ throw new HTTPTransportError(error);
8404
+ }
8405
+ const info = await readJSONResponse(
8406
+ await checkResponse(loginResponse),
8407
+ true
8408
+ );
8409
+ const org = selectLoginOrg(info.org_info, orgName);
8410
+ orgId = org.id;
8411
+ apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
8412
+ if (!apiUrl) {
8413
+ throw new Error(
8414
+ 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."
8415
+ );
8416
+ }
8417
+ }
8418
+ const apiConnection = new HTTPConnection(apiUrl, fetch2, true);
8419
+ apiConnection.set_token(apiKey);
8420
+ apiConnection.make_long_lived();
8421
+ return {
8422
+ appUrl,
8423
+ orgId,
8424
+ apiConn: () => apiConnection
8425
+ };
8426
+ }
8123
8427
  async function loginToState(options = {}) {
8124
8428
  const {
8125
8429
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
@@ -8151,16 +8455,18 @@ async function loginToState(options = {}) {
8151
8455
  _saveOrgInfo(state, testOrgInfo, testOrgInfo[0].name);
8152
8456
  return state;
8153
8457
  } else {
8154
- const resp = await checkResponse(
8155
- await fetch2(_urljoin(state.appUrl, `/api/apikey/login`), {
8458
+ const loginResponse = await fetch2(
8459
+ _urljoin(state.appUrl, `/api/apikey/login`),
8460
+ {
8156
8461
  method: "POST",
8157
8462
  headers: {
8158
8463
  "Content-Type": "application/json",
8159
8464
  Authorization: `Bearer ${apiKey}`
8160
8465
  }
8161
- })
8466
+ }
8162
8467
  );
8163
- const info = await resp.json();
8468
+ const resp = await checkResponse(loginResponse);
8469
+ const info = await readJSONResponse(resp);
8164
8470
  _saveOrgInfo(state, info.org_info, orgName);
8165
8471
  if (!state.apiUrl) {
8166
8472
  if (orgName) {
@@ -8528,27 +8834,28 @@ function withCurrent(span, callback, state = void 0) {
8528
8834
  const currentState = state ?? _globalState;
8529
8835
  return currentState.contextManager.runInContext(span, () => callback(span));
8530
8836
  }
8531
- function _saveOrgInfo(state, org_info, org_name) {
8532
- if (org_info.length === 0) {
8837
+ function _saveOrgInfo(state, orgInfo, orgName) {
8838
+ const org = selectLoginOrg(orgInfo, orgName);
8839
+ state.orgId = org.id;
8840
+ state.orgName = org.name;
8841
+ state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
8842
+ state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
8843
+ state.gitMetadataSettings = org.git_metadata || void 0;
8844
+ }
8845
+ function selectLoginOrg(orgInfo, orgName) {
8846
+ if (orgInfo.length === 0) {
8533
8847
  throw new LoginInvalidOrgError(
8534
8848
  "This user is not part of any organizations."
8535
8849
  );
8536
8850
  }
8537
- for (const org of org_info) {
8538
- if (org_name === void 0 || org.name === org_name) {
8539
- state.orgId = org.id;
8540
- state.orgName = org.name;
8541
- state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
8542
- state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
8543
- state.gitMetadataSettings = org.git_metadata || void 0;
8544
- break;
8851
+ for (const org of orgInfo) {
8852
+ if (orgName === void 0 || org.name === orgName) {
8853
+ return org;
8545
8854
  }
8546
8855
  }
8547
- if (state.orgId === void 0) {
8548
- throw new LoginInvalidOrgError(
8549
- `Organization ${org_name} not found. Must be one of ${org_info.map((x) => x.name).join(", ")}`
8550
- );
8551
- }
8856
+ throw new LoginInvalidOrgError(
8857
+ `Organization ${orgName} not found. Must be one of ${orgInfo.map((org) => org.name).join(", ")}`
8858
+ );
8552
8859
  }
8553
8860
  function validateTags(tags) {
8554
8861
  const seen = /* @__PURE__ */ new Set();
@@ -8713,6 +9020,19 @@ function enrichAttachments(event, state) {
8713
9020
  }
8714
9021
  return event;
8715
9022
  }
9023
+ async function resolveAttachmentsToBase64(event, state) {
9024
+ for (const [key, value] of Object.entries(event)) {
9025
+ if (value instanceof ReadonlyAttachment) {
9026
+ event[key] = await value.asBase64Url();
9027
+ continue;
9028
+ }
9029
+ if (!(value instanceof Object)) {
9030
+ continue;
9031
+ }
9032
+ await resolveAttachmentsToBase64(value, state);
9033
+ }
9034
+ return event;
9035
+ }
8716
9036
  function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
8717
9037
  if ("input" in event && !isEmpty2(event.input) && "inputs" in event && !isEmpty2(event.inputs) || !("input" in event) && !("inputs" in event)) {
8718
9038
  throw new Error(
@@ -10002,6 +10322,473 @@ var Dataset2 = class extends ObjectFetcher {
10002
10322
  return typeof data === "object" && data !== null && "__braintrust_dataset_marker" in data;
10003
10323
  }
10004
10324
  };
10325
+ function isAttachmentObject(value) {
10326
+ return BraintrustAttachmentReference.safeParse(value).success || InlineAttachmentReferenceSchema.safeParse(value).success || ExternalAttachmentReference.safeParse(value).success;
10327
+ }
10328
+ function isURL(url) {
10329
+ try {
10330
+ const parsedUrl = new URL(url.trim());
10331
+ return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
10332
+ } catch {
10333
+ return false;
10334
+ }
10335
+ }
10336
+ function expandAttachmentArrayPreTemplate(content, variables) {
10337
+ if (typeof content !== "string") return null;
10338
+ const match = content.match(/^\{\{\s*([\w.]+)\s*\}\}$/);
10339
+ if (!match) return null;
10340
+ const varPath = match[1];
10341
+ const value = varPath.includes(".") ? getObjValueByPath(variables, varPath.split(".")) : variables[varPath];
10342
+ if (!Array.isArray(value)) return null;
10343
+ const allValid = value.every(
10344
+ (v) => isAttachmentObject(v) || typeof v === "string" && isURL(v)
10345
+ );
10346
+ if (!allValid) return null;
10347
+ return value.map((item) => ({
10348
+ type: "image_url",
10349
+ image_url: { url: item }
10350
+ }));
10351
+ }
10352
+ function renderMessageImpl(render, message, variables) {
10353
+ return {
10354
+ ...message,
10355
+ ..."content" in message ? {
10356
+ content: isEmpty2(message.content) ? void 0 : typeof message.content === "string" ? render(message.content) : message.content.flatMap((c) => {
10357
+ switch (c.type) {
10358
+ case "text":
10359
+ return [{ ...c, text: render(c.text) }];
10360
+ case "image_url":
10361
+ if (isObject(c.image_url.url)) {
10362
+ throw new Error(
10363
+ "Attachments must be replaced with URLs before calling `build()`"
10364
+ );
10365
+ }
10366
+ if (variables) {
10367
+ const expanded = expandAttachmentArrayPreTemplate(
10368
+ c.image_url.url,
10369
+ variables
10370
+ );
10371
+ if (expanded) {
10372
+ return expanded;
10373
+ }
10374
+ }
10375
+ return [
10376
+ {
10377
+ ...c,
10378
+ image_url: {
10379
+ ...c.image_url,
10380
+ url: render(c.image_url.url)
10381
+ }
10382
+ }
10383
+ ];
10384
+ case "file":
10385
+ return [
10386
+ {
10387
+ ...c,
10388
+ file: {
10389
+ ...c.file.file_data && {
10390
+ file_data: render(c.file.file_data)
10391
+ },
10392
+ ...c.file.file_id && {
10393
+ file_id: render(c.file.file_id)
10394
+ },
10395
+ ...c.file.filename && {
10396
+ filename: render(c.file.filename)
10397
+ }
10398
+ }
10399
+ }
10400
+ ];
10401
+ default:
10402
+ const _exhaustiveCheck = c;
10403
+ return _exhaustiveCheck;
10404
+ }
10405
+ })
10406
+ } : {},
10407
+ ..."tool_calls" in message ? {
10408
+ tool_calls: isEmpty2(message.tool_calls) ? void 0 : message.tool_calls.map((t) => {
10409
+ return {
10410
+ type: t.type,
10411
+ id: render(t.id),
10412
+ function: {
10413
+ name: render(t.function.name),
10414
+ arguments: render(t.function.arguments)
10415
+ }
10416
+ };
10417
+ })
10418
+ } : {},
10419
+ ..."tool_call_id" in message ? {
10420
+ tool_call_id: render(message.tool_call_id)
10421
+ } : {}
10422
+ };
10423
+ }
10424
+ function deserializePlainStringAsJSON(s) {
10425
+ if (s.trim() === "") {
10426
+ return { value: null, error: void 0 };
10427
+ }
10428
+ try {
10429
+ return { value: JSON.parse(s), error: void 0 };
10430
+ } catch (e) {
10431
+ return { value: s, error: e };
10432
+ }
10433
+ }
10434
+ function renderTemplatedObject(obj, args, options) {
10435
+ if (typeof obj === "string") {
10436
+ return renderTemplateContent(
10437
+ obj,
10438
+ args,
10439
+ (value) => typeof value === "string" ? value : JSON.stringify(value),
10440
+ {
10441
+ strict: options.strict,
10442
+ templateFormat: options.templateFormat
10443
+ }
10444
+ );
10445
+ } else if (isArray(obj)) {
10446
+ return obj.map((item) => renderTemplatedObject(item, args, options));
10447
+ } else if (isObject(obj)) {
10448
+ return Object.fromEntries(
10449
+ Object.entries(obj).map(([key, value]) => [
10450
+ key,
10451
+ renderTemplatedObject(value, args, options)
10452
+ ])
10453
+ );
10454
+ }
10455
+ return obj;
10456
+ }
10457
+ function renderPromptParams(params, args, options = {}) {
10458
+ const templateFormat = parseTemplateFormat(options.templateFormat);
10459
+ const strict = !!options.strict;
10460
+ const schemaParsed = import_v38.z.object({
10461
+ response_format: import_v38.z.object({
10462
+ type: import_v38.z.literal("json_schema"),
10463
+ json_schema: ResponseFormatJsonSchema.omit({ schema: true }).extend({
10464
+ schema: import_v38.z.unknown()
10465
+ })
10466
+ })
10467
+ }).safeParse(params);
10468
+ if (schemaParsed.success) {
10469
+ const rawSchema = schemaParsed.data.response_format.json_schema.schema;
10470
+ const templatedSchema = renderTemplatedObject(rawSchema, args, {
10471
+ strict,
10472
+ templateFormat
10473
+ });
10474
+ const parsedSchema = typeof templatedSchema === "string" ? deserializePlainStringAsJSON(templatedSchema).value : templatedSchema;
10475
+ return {
10476
+ ...params,
10477
+ response_format: {
10478
+ ...schemaParsed.data.response_format,
10479
+ json_schema: {
10480
+ ...schemaParsed.data.response_format.json_schema,
10481
+ schema: parsedSchema
10482
+ }
10483
+ }
10484
+ };
10485
+ }
10486
+ return params;
10487
+ }
10488
+ var Prompt2 = class _Prompt {
10489
+ constructor(metadata, defaults, noTrace) {
10490
+ this.metadata = metadata;
10491
+ this.defaults = defaults;
10492
+ this.noTrace = noTrace;
10493
+ void this.__braintrust_prompt_marker;
10494
+ }
10495
+ metadata;
10496
+ defaults;
10497
+ noTrace;
10498
+ parsedPromptData;
10499
+ hasParsedPromptData = false;
10500
+ __braintrust_prompt_marker = true;
10501
+ get id() {
10502
+ return this.metadata.id;
10503
+ }
10504
+ get projectId() {
10505
+ return this.metadata.project_id;
10506
+ }
10507
+ get name() {
10508
+ return "name" in this.metadata ? this.metadata.name : `Playground function ${this.metadata.id}`;
10509
+ }
10510
+ get slug() {
10511
+ return "slug" in this.metadata ? this.metadata.slug : this.metadata.id;
10512
+ }
10513
+ get prompt() {
10514
+ return this.getParsedPromptData()?.prompt;
10515
+ }
10516
+ get version() {
10517
+ return this.metadata[TRANSACTION_ID_FIELD];
10518
+ }
10519
+ get options() {
10520
+ return this.getParsedPromptData()?.options || {};
10521
+ }
10522
+ get templateFormat() {
10523
+ return this.getParsedPromptData()?.template_format;
10524
+ }
10525
+ get promptData() {
10526
+ return this.getParsedPromptData();
10527
+ }
10528
+ /**
10529
+ * Build the prompt with the given formatting options. The args you pass in will
10530
+ * be forwarded to the mustache template that defines the prompt and rendered with
10531
+ * the `mustache-js` library.
10532
+ *
10533
+ * @param buildArgs Args to forward along to the prompt template.
10534
+ */
10535
+ build(buildArgs, options = {}) {
10536
+ return this.runBuild(buildArgs, {
10537
+ flavor: options.flavor ?? "chat",
10538
+ messages: options.messages,
10539
+ strict: options.strict,
10540
+ templateFormat: options.templateFormat
10541
+ });
10542
+ }
10543
+ /**
10544
+ * This is a special build method that first resolves attachment references, and then
10545
+ * calls the regular build method. You should use this if you are building prompts from
10546
+ * dataset rows that contain attachments.
10547
+ *
10548
+ * @param buildArgs Args to forward along to the prompt template.
10549
+ */
10550
+ async buildWithAttachments(buildArgs, options = {}) {
10551
+ const hydrated = buildArgs instanceof Object ? await resolveAttachmentsToBase64(buildArgs, options.state) : buildArgs;
10552
+ return this.runBuild(hydrated, {
10553
+ flavor: options.flavor ?? "chat",
10554
+ messages: options.messages,
10555
+ strict: options.strict,
10556
+ templateFormat: options.templateFormat
10557
+ });
10558
+ }
10559
+ runBuild(buildArgs, options) {
10560
+ const { flavor } = options;
10561
+ const params = Object.fromEntries(
10562
+ Object.entries({
10563
+ ...this.defaults,
10564
+ ...Object.fromEntries(
10565
+ Object.entries(this.options.params || {}).filter(
10566
+ ([k, _v]) => !BRAINTRUST_PARAMS.includes(k)
10567
+ )
10568
+ ),
10569
+ ...!isEmpty2(this.options.model) ? {
10570
+ model: this.options.model
10571
+ } : {}
10572
+ }).filter(([key, value]) => key !== "response_format" || value !== null)
10573
+ );
10574
+ if (!("model" in params) || isEmpty2(params.model)) {
10575
+ throw new Error(
10576
+ "No model specified. Either specify it in the prompt or as a default"
10577
+ );
10578
+ }
10579
+ const spanInfo = this.noTrace ? {} : {
10580
+ span_info: {
10581
+ metadata: {
10582
+ prompt: this.id ? {
10583
+ variables: buildArgs,
10584
+ id: this.id,
10585
+ project_id: this.projectId,
10586
+ version: this.version,
10587
+ ..."prompt_session_id" in this.metadata ? { prompt_session_id: this.metadata.prompt_session_id } : {}
10588
+ } : void 0
10589
+ }
10590
+ }
10591
+ };
10592
+ const prompt = this.prompt;
10593
+ if (!prompt) {
10594
+ throw new Error("Empty prompt");
10595
+ }
10596
+ const dictArgParsed = import_v38.z.record(import_v38.z.unknown()).safeParse(buildArgs);
10597
+ const variables = {
10598
+ input: buildArgs,
10599
+ ...dictArgParsed.success ? dictArgParsed.data : {}
10600
+ };
10601
+ const promptDataTemplateFormat = this.templateFormat;
10602
+ const resolvedTemplateFormat = parseTemplateFormat(
10603
+ options.templateFormat ?? promptDataTemplateFormat
10604
+ );
10605
+ const renderedPrompt = _Prompt.renderPrompt({
10606
+ prompt,
10607
+ buildArgs,
10608
+ options: { ...options, templateFormat: resolvedTemplateFormat }
10609
+ });
10610
+ if (flavor === "chat") {
10611
+ if (renderedPrompt.type !== "chat") {
10612
+ throw new Error(
10613
+ "Prompt is a completion prompt. Use buildCompletion() instead"
10614
+ );
10615
+ }
10616
+ return {
10617
+ ...renderPromptParams(params, variables, {
10618
+ strict: options.strict,
10619
+ templateFormat: resolvedTemplateFormat
10620
+ }),
10621
+ ...spanInfo,
10622
+ messages: renderedPrompt.messages,
10623
+ ...renderedPrompt.tools ? {
10624
+ tools: ChatCompletionTool.array().parse(JSON.parse(renderedPrompt.tools))
10625
+ } : void 0
10626
+ };
10627
+ } else if (flavor === "completion") {
10628
+ if (renderedPrompt.type !== "completion") {
10629
+ throw new Error(`Prompt is a chat prompt. Use flavor: 'chat' instead`);
10630
+ }
10631
+ return {
10632
+ ...renderPromptParams(params, variables, {
10633
+ strict: options.strict,
10634
+ templateFormat: resolvedTemplateFormat
10635
+ }),
10636
+ ...spanInfo,
10637
+ prompt: renderedPrompt.content
10638
+ };
10639
+ } else {
10640
+ throw new Error("never!");
10641
+ }
10642
+ }
10643
+ static renderPrompt({
10644
+ prompt,
10645
+ buildArgs,
10646
+ options
10647
+ }) {
10648
+ const escape = (v) => {
10649
+ if (v === void 0) {
10650
+ throw new Error("Missing!");
10651
+ } else if (typeof v === "string") {
10652
+ return v;
10653
+ } else if (v instanceof ReadonlyAttachment) {
10654
+ throw new Error(
10655
+ "Use buildWithAttachments() to build prompts with attachments"
10656
+ );
10657
+ } else {
10658
+ return JSON.stringify(v);
10659
+ }
10660
+ };
10661
+ const dictArgParsed = import_v38.z.record(import_v38.z.unknown()).safeParse(buildArgs);
10662
+ const variables = {
10663
+ input: buildArgs,
10664
+ ...dictArgParsed.success ? dictArgParsed.data : {}
10665
+ };
10666
+ const templateFormat = parseTemplateFormat(options.templateFormat);
10667
+ if (prompt.type === "chat") {
10668
+ const render = (template) => renderTemplateContent(template, variables, escape, {
10669
+ strict: options.strict,
10670
+ templateFormat
10671
+ });
10672
+ const baseMessages = (prompt.messages || []).map(
10673
+ (m) => renderMessageImpl(render, m, variables)
10674
+ );
10675
+ const hasSystemPrompt = baseMessages.some((m) => m.role === "system");
10676
+ const messages = [
10677
+ ...baseMessages,
10678
+ ...(options.messages ?? []).filter(
10679
+ (m) => !(hasSystemPrompt && m.role === "system")
10680
+ )
10681
+ ];
10682
+ return {
10683
+ type: "chat",
10684
+ messages,
10685
+ ...prompt.tools?.trim() ? {
10686
+ tools: render(prompt.tools)
10687
+ } : void 0
10688
+ };
10689
+ } else if (prompt.type === "completion") {
10690
+ if (options.messages) {
10691
+ throw new Error(
10692
+ "extra messages are not supported for completion prompts"
10693
+ );
10694
+ }
10695
+ const content = renderTemplateContent(prompt.content, variables, escape, {
10696
+ strict: options.strict,
10697
+ templateFormat
10698
+ });
10699
+ return {
10700
+ type: "completion",
10701
+ content
10702
+ };
10703
+ } else {
10704
+ const _ = prompt;
10705
+ throw new Error(`Invalid prompt type: ${_}`);
10706
+ }
10707
+ }
10708
+ getParsedPromptData() {
10709
+ if (!this.hasParsedPromptData) {
10710
+ this.parsedPromptData = PromptData.parse(this.metadata.prompt_data);
10711
+ this.hasParsedPromptData = true;
10712
+ }
10713
+ return this.parsedPromptData;
10714
+ }
10715
+ static isPrompt(data) {
10716
+ return typeof data === "object" && data !== null && "__braintrust_prompt_marker" in data;
10717
+ }
10718
+ /** @internal */
10719
+ _internalSerializeForCache() {
10720
+ return {
10721
+ metadata: this.metadata,
10722
+ defaults: this.defaults,
10723
+ noTrace: this.noTrace
10724
+ };
10725
+ }
10726
+ static fromPromptData(name, promptData) {
10727
+ return new _Prompt(
10728
+ {
10729
+ name,
10730
+ slug: name,
10731
+ prompt_data: promptData
10732
+ },
10733
+ {},
10734
+ false
10735
+ );
10736
+ }
10737
+ };
10738
+ var RemoteEvalParameters = class {
10739
+ constructor(metadata) {
10740
+ this.metadata = metadata;
10741
+ void this.__braintrust_parameters_marker;
10742
+ }
10743
+ metadata;
10744
+ __braintrust_parameters_marker = true;
10745
+ get id() {
10746
+ return this.metadata.id;
10747
+ }
10748
+ get projectId() {
10749
+ return this.metadata.project_id;
10750
+ }
10751
+ get name() {
10752
+ return this.metadata.name;
10753
+ }
10754
+ get slug() {
10755
+ return this.metadata.slug;
10756
+ }
10757
+ get version() {
10758
+ return this.metadata[TRANSACTION_ID_FIELD];
10759
+ }
10760
+ get schema() {
10761
+ return this.metadata.function_data.__schema;
10762
+ }
10763
+ get data() {
10764
+ return this.metadata.function_data.data ?? {};
10765
+ }
10766
+ /** @internal */
10767
+ _internalSerializeForCache() {
10768
+ return { metadata: this.metadata };
10769
+ }
10770
+ validate(data) {
10771
+ if (typeof data !== "object" || data === null) {
10772
+ return false;
10773
+ }
10774
+ const schemaProps = this.schema.properties;
10775
+ if (typeof schemaProps !== "object" || schemaProps === null) {
10776
+ return true;
10777
+ }
10778
+ for (const key of Object.keys(schemaProps)) {
10779
+ if (!(key in data)) {
10780
+ const required = Array.isArray(this.schema.required) ? this.schema.required : [];
10781
+ if (required.includes(key)) {
10782
+ return false;
10783
+ }
10784
+ }
10785
+ }
10786
+ return true;
10787
+ }
10788
+ static isParameters(x) {
10789
+ return typeof x === "object" && x !== null && "__braintrust_parameters_marker" in x && x.__braintrust_parameters_marker === true;
10790
+ }
10791
+ };
10005
10792
  var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
10006
10793
 
10007
10794
  // src/instrumentation/core/channel-tracing-utils.ts
@@ -10447,56 +11234,14 @@ function suppressionStore() {
10447
11234
  autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
10448
11235
  return autoInstrumentationSuppressionStore;
10449
11236
  }
10450
- function currentFrames() {
10451
- return suppressionStore().getStore()?.frames ?? [];
10452
- }
10453
11237
  function isAutoInstrumentationSuppressed() {
10454
- const frames = currentFrames();
10455
- return frames[frames.length - 1]?.mode === "suppress";
11238
+ return suppressionStore().getStore() === true;
10456
11239
  }
10457
11240
  function runWithAutoInstrumentationSuppressed(callback) {
10458
- const frame = {
10459
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10460
- mode: "suppress"
10461
- };
10462
- return suppressionStore().run(
10463
- { frames: [...currentFrames(), frame] },
10464
- callback
10465
- );
11241
+ return suppressionStore().run(true, callback);
10466
11242
  }
10467
- function bindAutoInstrumentationSuppressionToStart(tracingChannel) {
10468
- const startChannel = tracingChannel.start;
10469
- if (!startChannel) {
10470
- return void 0;
10471
- }
10472
- const store = suppressionStore();
10473
- startChannel.bindStore(store, () => ({
10474
- frames: [
10475
- ...currentFrames(),
10476
- {
10477
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10478
- mode: "suppress"
10479
- }
10480
- ]
10481
- }));
10482
- return () => {
10483
- startChannel.unbindStore(store);
10484
- };
10485
- }
10486
- function enterAutoInstrumentationAllowed() {
10487
- const frame = {
10488
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
10489
- mode: "allow"
10490
- };
10491
- suppressionStore().enterWith({
10492
- frames: [...currentFrames(), frame]
10493
- });
10494
- return () => {
10495
- const frames = currentFrames().filter(
10496
- (candidate) => candidate.id !== frame.id
10497
- );
10498
- suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
10499
- };
11243
+ function runWithAutoInstrumentationAllowed(callback) {
11244
+ return suppressionStore().run(void 0, callback);
10500
11245
  }
10501
11246
 
10502
11247
  // src/instrumentation/core/channel-tracing.ts
@@ -11785,13 +12530,33 @@ function aggregateChatLogprobs(existing, incoming) {
11785
12530
  }
11786
12531
  return aggregated;
11787
12532
  }
12533
+ function createAggregatedChatChoice(index) {
12534
+ return {
12535
+ index,
12536
+ role: void 0,
12537
+ content: void 0,
12538
+ refusal: void 0,
12539
+ toolCallsByIndex: /* @__PURE__ */ new Map(),
12540
+ logprobs: void 0,
12541
+ finish_reason: void 0
12542
+ };
12543
+ }
12544
+ function toChatChoice(choice) {
12545
+ const toolCalls = Array.from(choice.toolCallsByIndex.entries()).sort(([left], [right]) => left - right).map(([, toolCall]) => toolCall);
12546
+ return {
12547
+ index: choice.index,
12548
+ message: {
12549
+ role: choice.role,
12550
+ content: choice.content,
12551
+ ...choice.refusal !== void 0 ? { refusal: choice.refusal } : {},
12552
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
12553
+ },
12554
+ logprobs: choice.logprobs ?? null,
12555
+ finish_reason: choice.finish_reason
12556
+ };
12557
+ }
11788
12558
  function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
11789
- let role = void 0;
11790
- let content = void 0;
11791
- let refusal = void 0;
11792
- let tool_calls = void 0;
11793
- let logprobs = void 0;
11794
- let finish_reason = void 0;
12559
+ const choicesByIndex = /* @__PURE__ */ new Map();
11795
12560
  let metrics = {};
11796
12561
  for (const chunk of chunks) {
11797
12562
  if (chunk.usage) {
@@ -11800,62 +12565,75 @@ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
11800
12565
  ...parseMetricsFromUsage(chunk.usage)
11801
12566
  };
11802
12567
  }
11803
- const choice = chunk.choices?.[0];
11804
- if (!choice) {
11805
- continue;
11806
- }
11807
- if (choice.finish_reason) {
11808
- finish_reason = choice.finish_reason;
11809
- }
11810
- logprobs = aggregateChatLogprobs(logprobs, choice.logprobs);
11811
- const delta = choice.delta;
11812
- if (!delta) {
12568
+ const choices = chunk.choices;
12569
+ if (!choices?.length) {
11813
12570
  continue;
11814
12571
  }
11815
- if (delta.finish_reason) {
11816
- finish_reason = delta.finish_reason;
11817
- }
11818
- if (!role && delta.role) {
11819
- role = delta.role;
11820
- }
11821
- if (delta.content) {
11822
- content = (content || "") + delta.content;
11823
- }
11824
- if (delta.refusal) {
11825
- refusal = (refusal || "") + delta.refusal;
11826
- }
11827
- if (delta.tool_calls) {
11828
- const toolDelta = delta.tool_calls[0];
11829
- if (!tool_calls || toolDelta.id && tool_calls[tool_calls.length - 1].id !== toolDelta.id) {
11830
- tool_calls = [
11831
- ...tool_calls || [],
11832
- {
11833
- id: toolDelta.id,
11834
- type: toolDelta.type,
11835
- function: toolDelta.function
12572
+ for (const choice of choices) {
12573
+ const choiceIndex = choice.index;
12574
+ let aggregatedChoice = choicesByIndex.get(choiceIndex);
12575
+ if (!aggregatedChoice) {
12576
+ aggregatedChoice = createAggregatedChatChoice(choiceIndex);
12577
+ choicesByIndex.set(choiceIndex, aggregatedChoice);
12578
+ }
12579
+ if (choice.finish_reason) {
12580
+ aggregatedChoice.finish_reason = choice.finish_reason;
12581
+ }
12582
+ aggregatedChoice.logprobs = aggregateChatLogprobs(
12583
+ aggregatedChoice.logprobs,
12584
+ choice.logprobs
12585
+ );
12586
+ const delta = choice.delta;
12587
+ if (!delta) {
12588
+ continue;
12589
+ }
12590
+ if (delta.finish_reason) {
12591
+ aggregatedChoice.finish_reason = delta.finish_reason;
12592
+ }
12593
+ if (!aggregatedChoice.role && delta.role) {
12594
+ aggregatedChoice.role = delta.role;
12595
+ }
12596
+ if (delta.content) {
12597
+ aggregatedChoice.content = (aggregatedChoice.content || "") + delta.content;
12598
+ }
12599
+ if (delta.refusal) {
12600
+ aggregatedChoice.refusal = (aggregatedChoice.refusal || "") + delta.refusal;
12601
+ }
12602
+ if (delta.tool_calls) {
12603
+ for (const toolDelta of delta.tool_calls) {
12604
+ let aggregatedToolCall = aggregatedChoice.toolCallsByIndex.get(
12605
+ toolDelta.index
12606
+ );
12607
+ if (!aggregatedToolCall) {
12608
+ aggregatedToolCall = {
12609
+ function: { arguments: "" }
12610
+ };
12611
+ aggregatedChoice.toolCallsByIndex.set(
12612
+ toolDelta.index,
12613
+ aggregatedToolCall
12614
+ );
11836
12615
  }
11837
- ];
11838
- } else {
11839
- tool_calls[tool_calls.length - 1].function.arguments += toolDelta.function.arguments;
12616
+ if (toolDelta.id !== void 0) {
12617
+ aggregatedToolCall.id = toolDelta.id;
12618
+ }
12619
+ if (toolDelta.type !== void 0) {
12620
+ aggregatedToolCall.type = toolDelta.type;
12621
+ }
12622
+ if (toolDelta.function?.name !== void 0) {
12623
+ aggregatedToolCall.function.name = toolDelta.function.name;
12624
+ }
12625
+ if (toolDelta.function?.arguments !== void 0) {
12626
+ aggregatedToolCall.function.arguments += toolDelta.function.arguments;
12627
+ }
12628
+ }
11840
12629
  }
11841
12630
  }
11842
12631
  }
11843
12632
  metrics = withCachedMetric(metrics, streamResult, endEvent);
12633
+ const output = Array.from(choicesByIndex.values()).sort((left, right) => left.index - right.index).map(toChatChoice);
11844
12634
  return {
11845
12635
  metrics,
11846
- output: [
11847
- {
11848
- index: 0,
11849
- message: {
11850
- role,
11851
- content,
11852
- ...refusal !== void 0 ? { refusal } : {},
11853
- tool_calls
11854
- },
11855
- logprobs: logprobs ?? null,
11856
- finish_reason
11857
- }
11858
- ]
12636
+ output: output.length > 0 ? output : [toChatChoice(createAggregatedChatChoice(0))]
11859
12637
  };
11860
12638
  }
11861
12639
  function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
@@ -13178,6 +13956,12 @@ function parseMetricsFromUsage2(usage) {
13178
13956
  }
13179
13957
  }
13180
13958
  }
13959
+ if (isObject(usage.output_tokens_details)) {
13960
+ const thinkingTokens = usage.output_tokens_details.thinking_tokens;
13961
+ if (typeof thinkingTokens === "number") {
13962
+ metrics.completion_reasoning_tokens = thinkingTokens;
13963
+ }
13964
+ }
13181
13965
  if (isObject(usage.server_tool_use)) {
13182
13966
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
13183
13967
  if (typeof value === "number") {
@@ -14134,7 +14918,6 @@ function endHarnessTurn(parent) {
14134
14918
  function braintrustAISDKTelemetry() {
14135
14919
  const operations = /* @__PURE__ */ new Map();
14136
14920
  const operationKeysByCallId = /* @__PURE__ */ new Map();
14137
- const workflowOperationKeyStore = isomorph_default.newAsyncLocalStorage();
14138
14921
  const modelSpans = /* @__PURE__ */ new Map();
14139
14922
  const objectSpans = /* @__PURE__ */ new Map();
14140
14923
  const embedSpans = /* @__PURE__ */ new Map();
@@ -14177,9 +14960,6 @@ function braintrustAISDKTelemetry() {
14177
14960
  return;
14178
14961
  }
14179
14962
  operations.delete(operationKey);
14180
- if (workflowOperationKeyStore.getStore() === operationKey) {
14181
- workflowOperationKeyStore.enterWith(void 0);
14182
- }
14183
14963
  const keys = operationKeysByCallId.get(state.callId);
14184
14964
  if (!keys) {
14185
14965
  return;
@@ -14227,14 +15007,7 @@ function braintrustAISDKTelemetry() {
14227
15007
  return key;
14228
15008
  }
14229
15009
  }
14230
- const workflowOperationKey = workflowOperationKeyStore.getStore();
14231
- if (workflowOperationKey && keys.includes(workflowOperationKey)) {
14232
- return workflowOperationKey;
14233
- }
14234
- if (callId === "workflow-agent") {
14235
- return void 0;
14236
- }
14237
- return mode === "finish" ? keys[0] : keys[keys.length - 1];
15010
+ return callId === "workflow-agent" || mode === "active" ? keys[keys.length - 1] : keys[0];
14238
15011
  };
14239
15012
  const operationKeyFromEvent = (event, mode = "active") => {
14240
15013
  const explicit = explicitOperationKey(event);
@@ -14248,17 +15021,13 @@ function braintrustAISDKTelemetry() {
14248
15021
  if (operationKey) {
14249
15022
  return operationKey;
14250
15023
  }
14251
- const workflowOperationKey2 = workflowOperationKeyStore.getStore();
14252
- if (workflowOperationKey2 && operations.has(workflowOperationKey2)) {
14253
- return workflowOperationKey2;
15024
+ const workflowAgentKeys2 = operationKeysByCallId.get("workflow-agent");
15025
+ if (workflowAgentKeys2?.length) {
15026
+ return workflowAgentKeys2[workflowAgentKeys2.length - 1];
14254
15027
  }
14255
15028
  return callId === "workflow-agent" ? void 0 : callId;
14256
15029
  }
14257
15030
  }
14258
- const workflowOperationKey = workflowOperationKeyStore.getStore();
14259
- if (workflowOperationKey && operations.has(workflowOperationKey)) {
14260
- return workflowOperationKey;
14261
- }
14262
15031
  const wrapperSpan = currentWorkflowAgentWrapperSpan();
14263
15032
  if (wrapperSpan?.spanId) {
14264
15033
  for (const [operationKey, state] of operations) {
@@ -14268,8 +15037,8 @@ function braintrustAISDKTelemetry() {
14268
15037
  }
14269
15038
  }
14270
15039
  const workflowAgentKeys = operationKeysByCallId.get("workflow-agent");
14271
- if (workflowAgentKeys?.length === 1) {
14272
- return workflowAgentKeys[0];
15040
+ if (workflowAgentKeys?.length) {
15041
+ return workflowAgentKeys[workflowAgentKeys.length - 1];
14273
15042
  }
14274
15043
  if (operations.size === 1) {
14275
15044
  return operations.keys().next().value;
@@ -14472,9 +15241,6 @@ function braintrustAISDKTelemetry() {
14472
15241
  if (!ownsSpan) {
14473
15242
  return;
14474
15243
  }
14475
- if (workflowAgent) {
14476
- workflowOperationKeyStore.enterWith(operationKey);
14477
- }
14478
15244
  let metadata = metadataFromEvent(event);
14479
15245
  const logPayload = { metadata };
14480
15246
  const workflowAgentCallInput = workflowAgent ? operationInput(event, operationName) : void 0;
@@ -14946,6 +15712,10 @@ var aiSDKChannels = defineChannels(
14946
15712
  channelName: "generateText",
14947
15713
  kind: "async"
14948
15714
  }),
15715
+ generateImage: channel({
15716
+ channelName: "generateImage",
15717
+ kind: "async"
15718
+ }),
14949
15719
  streamText: channel({
14950
15720
  channelName: "streamText",
14951
15721
  kind: "async"
@@ -15133,7 +15903,7 @@ var AISDKPlugin = class extends BasePlugin {
15133
15903
  }
15134
15904
  subscribeToAISDK() {
15135
15905
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
15136
- this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
15906
+ this.unsubscribers.push(interceptAISDKV7TelemetryDispatcher());
15137
15907
  this.unsubscribers.push(subscribeToHarnessAgentCreateSession());
15138
15908
  this.unsubscribers.push(
15139
15909
  subscribeToHarnessContinuation(
@@ -15161,6 +15931,18 @@ var AISDKPlugin = class extends BasePlugin {
15161
15931
  aggregateChunks: aggregateAISDKChunks
15162
15932
  })
15163
15933
  );
15934
+ this.unsubscribers.push(
15935
+ traceAsyncChannel(aiSDKChannels.generateImage, {
15936
+ name: "generateImage",
15937
+ type: "llm" /* LLM */,
15938
+ extractInput: ([params], event) => prepareAISDKGenerateImageInput(params, event.self),
15939
+ extractOutput: (result, endEvent) => processAISDKGenerateImageOutput(
15940
+ result,
15941
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15942
+ ),
15943
+ extractMetrics: (result) => extractTokenMetrics(result)
15944
+ })
15945
+ );
15164
15946
  this.unsubscribers.push(
15165
15947
  traceStreamingChannel(aiSDKChannels.streamText, {
15166
15948
  name: "streamText",
@@ -15650,26 +16432,29 @@ function subscribeToHarnessContinuation(continuationChannel, defaultDenyOutputPa
15650
16432
  channel2.unsubscribe(handlers);
15651
16433
  };
15652
16434
  }
15653
- function subscribeToAISDKV7TelemetryDispatcher() {
15654
- const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
16435
+ function interceptAISDKV7TelemetryDispatcher() {
15655
16436
  const telemetry = braintrustAISDKTelemetry();
15656
- const handlers = {
15657
- end: (event) => {
15658
- const telemetryOptions = event.arguments?.[0]?.telemetry;
15659
- if (telemetryOptions?.isEnabled === false) {
15660
- return;
16437
+ return aiSDKChannels.v7CreateTelemetryDispatcher.intercept(
16438
+ (target, thisArg, args) => {
16439
+ const dispatcher = Reflect.apply(target, thisArg, args);
16440
+ const telemetryOptions = args[0]?.telemetry;
16441
+ if (telemetryOptions?.isEnabled !== false) {
16442
+ try {
16443
+ patchAISDKV7TelemetryDispatcher(
16444
+ dispatcher,
16445
+ telemetry,
16446
+ telemetryOptions
16447
+ );
16448
+ } catch (error) {
16449
+ debugLogger.error(
16450
+ "Error instrumenting AI SDK v7 telemetry dispatcher:",
16451
+ error
16452
+ );
16453
+ }
15661
16454
  }
15662
- patchAISDKV7TelemetryDispatcher(
15663
- event.result,
15664
- telemetry,
15665
- telemetryOptions
15666
- );
16455
+ return dispatcher;
15667
16456
  }
15668
- };
15669
- channel2.subscribe(handlers);
15670
- return () => {
15671
- channel2.unsubscribe(handlers);
15672
- };
16457
+ );
15673
16458
  }
15674
16459
  function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry, telemetryOptions) {
15675
16460
  if (!isObject(dispatcher)) {
@@ -15994,16 +16779,10 @@ var convertImageToAttachment = (image, explicitMimeType) => {
15994
16779
  }
15995
16780
  }
15996
16781
  if (explicitMimeType) {
15997
- if (image instanceof Uint8Array) {
15998
- return new Attachment({
15999
- data: new Blob([image], { type: explicitMimeType }),
16000
- filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
16001
- contentType: explicitMimeType
16002
- });
16003
- }
16004
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
16782
+ const blob = convertDataToBlob(image, explicitMimeType);
16783
+ if (blob) {
16005
16784
  return new Attachment({
16006
- data: new Blob([image], { type: explicitMimeType }),
16785
+ data: blob,
16007
16786
  filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
16008
16787
  contentType: explicitMimeType
16009
16788
  });
@@ -16057,6 +16836,25 @@ var convertDataToAttachment = (data, mimeType, filename) => {
16057
16836
  function processAISDKCallInput(params) {
16058
16837
  return processInputAttachmentsSync(params);
16059
16838
  }
16839
+ function processAISDKGenerateImageInput(params) {
16840
+ const prompt = params.prompt;
16841
+ if (!isObject(prompt) || Array.isArray(prompt)) {
16842
+ return processAISDKCallInput(params);
16843
+ }
16844
+ const processedPrompt = { ...prompt };
16845
+ if (Array.isArray(prompt.images)) {
16846
+ processedPrompt.images = prompt.images.map(
16847
+ (image) => convertImageToAttachment(image, "image/png") ?? image
16848
+ );
16849
+ }
16850
+ if (prompt.mask !== void 0) {
16851
+ processedPrompt.mask = convertImageToAttachment(prompt.mask, "image/png") ?? prompt.mask;
16852
+ }
16853
+ return processAISDKCallInput({
16854
+ ...params,
16855
+ prompt: processedPrompt
16856
+ });
16857
+ }
16060
16858
  function processAISDKWorkflowAgentCallInput(params) {
16061
16859
  const processed = processAISDKCallInput(params);
16062
16860
  return {
@@ -16195,6 +16993,12 @@ function prepareAISDKEmbedInput(params, self) {
16195
16993
  metadata: extractMetadataFromEmbedParams(params, self)
16196
16994
  };
16197
16995
  }
16996
+ function prepareAISDKGenerateImageInput(params, self) {
16997
+ return {
16998
+ input: processAISDKGenerateImageInput(params).input,
16999
+ metadata: extractMetadataFromCallParams(params, self)
17000
+ };
17001
+ }
16198
17002
  function prepareAISDKRerankInput(params, self) {
16199
17003
  const { documents, query } = params;
16200
17004
  return {
@@ -17570,6 +18374,57 @@ function processAISDKOutput(output, denyOutputPaths) {
17570
18374
  }
17571
18375
  return normalizeAISDKLoggedOutput(sanitized);
17572
18376
  }
18377
+ function processAISDKGenerateImageOutput(output, denyOutputPaths) {
18378
+ if (!output || typeof output !== "object") {
18379
+ return output;
18380
+ }
18381
+ const summarized = {};
18382
+ for (const field of [
18383
+ "usage",
18384
+ "warnings",
18385
+ "providerMetadata",
18386
+ "experimental_providerMetadata",
18387
+ "responses"
18388
+ ]) {
18389
+ const value = safeSerializableFieldRead(output, field);
18390
+ if (value !== void 0 && isSerializableOutputValue(value)) {
18391
+ summarized[field] = value;
18392
+ }
18393
+ }
18394
+ const images = safeSerializableFieldRead(output, "images");
18395
+ const image = safeSerializableFieldRead(output, "image");
18396
+ const generatedFiles = Array.isArray(images) && images.length > 0 ? images : image !== void 0 ? [image] : [];
18397
+ const loggedOutput = normalizeAISDKLoggedOutput(
18398
+ omit(summarized, denyOutputPaths)
18399
+ );
18400
+ if (generatedFiles.length > 0) {
18401
+ loggedOutput.images = generatedFiles.map(
18402
+ (file, index) => convertAISDKGeneratedFileToAttachment(file, index)
18403
+ );
18404
+ }
18405
+ return loggedOutput;
18406
+ }
18407
+ function convertAISDKGeneratedFileToAttachment(file, index) {
18408
+ if (!file || typeof file !== "object") {
18409
+ return file;
18410
+ }
18411
+ const generatedFile = file;
18412
+ const generatedMediaType = safeSerializableFieldRead(
18413
+ generatedFile,
18414
+ "mediaType"
18415
+ );
18416
+ const mediaType = typeof generatedMediaType === "string" ? generatedMediaType : "application/octet-stream";
18417
+ const data = safeSerializableFieldRead(generatedFile, "base64") ?? safeSerializableFieldRead(generatedFile, "uint8Array");
18418
+ const blob = convertDataToBlob(data, mediaType);
18419
+ if (blob) {
18420
+ return new Attachment({
18421
+ data: blob,
18422
+ filename: `generated_image_${index}.${getExtensionFromMediaType(mediaType)}`,
18423
+ contentType: mediaType
18424
+ });
18425
+ }
18426
+ return file;
18427
+ }
17573
18428
  function processAISDKEmbeddingOutput(output, denyOutputPaths) {
17574
18429
  if (!output || typeof output !== "object") {
17575
18430
  return output;
@@ -18070,118 +18925,22 @@ var claudeAgentSDKChannels = defineChannels(
18070
18925
  var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
18071
18926
 
18072
18927
  // src/instrumentation/plugins/claude-agent-sdk-local-tool-context.ts
18073
- var LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED = /* @__PURE__ */ Symbol.for(
18074
- "braintrust.claude_agent_sdk.local_tool_context_async_iterator_patched"
18075
- );
18076
- function createLocalToolContextStore() {
18077
- const maybeIsoWithAsyncLocalStorage = isomorph_default;
18078
- if (typeof maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage === "function") {
18079
- return maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage();
18080
- }
18081
- let currentStore;
18082
- return {
18083
- enterWith(store) {
18084
- currentStore = store;
18085
- },
18086
- getStore() {
18087
- return currentStore;
18088
- },
18089
- run(store, callback) {
18090
- const previousStore = currentStore;
18091
- currentStore = store;
18092
- try {
18093
- return callback();
18094
- } finally {
18095
- currentStore = previousStore;
18096
- }
18097
- }
18098
- };
18099
- }
18100
- var localToolContextStore = createLocalToolContextStore();
18101
- var fallbackLocalToolParentResolver;
18102
- function createClaudeLocalToolContext() {
18103
- return {};
18104
- }
18105
- function runWithClaudeLocalToolContext(callback, context) {
18106
- return localToolContextStore.run(
18107
- context ?? createClaudeLocalToolContext(),
18108
- callback
18109
- );
18928
+ var localToolContextStore = isomorph_default.newAsyncLocalStorage();
18929
+ var localToolParentResolversByToolUseId = /* @__PURE__ */ new Map();
18930
+ function runWithClaudeLocalToolContext(callback, resolver) {
18931
+ return localToolContextStore.run(resolver, callback);
18110
18932
  }
18111
- function ensureClaudeLocalToolContext() {
18112
- const existing = localToolContextStore.getStore();
18113
- if (existing) {
18114
- return existing;
18115
- }
18116
- const created = {};
18117
- localToolContextStore.enterWith(created);
18118
- return created;
18933
+ function registerClaudeLocalToolParentResolver(toolUseId, resolver) {
18934
+ localToolParentResolversByToolUseId.set(toolUseId, resolver);
18119
18935
  }
18120
- function setClaudeLocalToolParentResolver(resolver) {
18121
- fallbackLocalToolParentResolver = resolver;
18122
- const context = ensureClaudeLocalToolContext();
18123
- if (!context) {
18124
- return;
18936
+ function getClaudeLocalToolParentResolver(toolUseId) {
18937
+ const currentResolver = localToolContextStore.getStore();
18938
+ if (!toolUseId) {
18939
+ return currentResolver;
18125
18940
  }
18126
- context.resolveLocalToolParent = resolver;
18127
- }
18128
- function getClaudeLocalToolParentResolver() {
18129
- return localToolContextStore.getStore()?.resolveLocalToolParent ?? fallbackLocalToolParentResolver;
18130
- }
18131
- function isAsyncIterable3(value) {
18132
- return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
18133
- }
18134
- function bindClaudeLocalToolContextToAsyncIterable(result, localToolContext) {
18135
- if (!isAsyncIterable3(result) || Object.isFrozen(result) || Object.isSealed(result)) {
18136
- return result;
18137
- }
18138
- const stream = result;
18139
- const originalAsyncIterator = stream[Symbol.asyncIterator];
18140
- if (originalAsyncIterator[LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED]) {
18141
- return result;
18142
- }
18143
- const patchedAsyncIterator = function() {
18144
- return runWithClaudeLocalToolContext(() => {
18145
- const iterator = Reflect.apply(originalAsyncIterator, this, []);
18146
- if (!iterator || typeof iterator !== "object") {
18147
- return iterator;
18148
- }
18149
- const patchMethod = (methodName) => {
18150
- const originalMethod = Reflect.get(iterator, methodName);
18151
- if (typeof originalMethod !== "function") {
18152
- return;
18153
- }
18154
- Reflect.set(
18155
- iterator,
18156
- methodName,
18157
- (...args) => runWithClaudeLocalToolContext(
18158
- () => Reflect.apply(
18159
- originalMethod,
18160
- iterator,
18161
- args
18162
- ),
18163
- localToolContext
18164
- )
18165
- );
18166
- };
18167
- patchMethod("next");
18168
- patchMethod("return");
18169
- patchMethod("throw");
18170
- return iterator;
18171
- }, localToolContext);
18172
- };
18173
- Object.defineProperty(
18174
- patchedAsyncIterator,
18175
- LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED,
18176
- {
18177
- configurable: false,
18178
- enumerable: false,
18179
- value: true,
18180
- writable: false
18181
- }
18182
- );
18183
- Reflect.set(stream, Symbol.asyncIterator, patchedAsyncIterator);
18184
- return result;
18941
+ const registeredResolver = localToolParentResolversByToolUseId.get(toolUseId);
18942
+ localToolParentResolversByToolUseId.delete(toolUseId);
18943
+ return currentResolver ?? registeredResolver;
18185
18944
  }
18186
18945
 
18187
18946
  // src/instrumentation/plugins/claude-agent-sdk-local-tool-spans.ts
@@ -18207,7 +18966,7 @@ function wrapLocalClaudeToolHandler(handler, getMetadata) {
18207
18966
  const metadata = getMetadata();
18208
18967
  const rawToolName = metadata.serverName ? `mcp__${metadata.serverName}__${metadata.toolName}` : metadata.toolName;
18209
18968
  const toolUseId = getToolUseIdFromExtra(handlerArgs[1]);
18210
- const localToolParentResolver = getClaudeLocalToolParentResolver();
18969
+ const localToolParentResolver = getClaudeLocalToolParentResolver(toolUseId);
18211
18970
  const spanName = metadata.serverName ? `tool: ${metadata.serverName}/${metadata.toolName}` : `tool: ${metadata.toolName}`;
18212
18971
  const runWithResolvedParent = async () => {
18213
18972
  const parent = toolUseId && localToolParentResolver ? await localToolParentResolver(toolUseId).catch(() => void 0) : void 0;
@@ -18734,6 +19493,7 @@ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToP
18734
19493
  }
18735
19494
  }
18736
19495
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
19496
+ registerClaudeLocalToolParentResolver(toolUseID, resolveParentSpan);
18737
19497
  return {};
18738
19498
  }
18739
19499
  const parsed = parseToolName(input.tool_name);
@@ -19444,7 +20204,7 @@ async function finalizeQuerySpan(state) {
19444
20204
  }
19445
20205
  var ClaudeAgentSDKPlugin = class extends BasePlugin {
19446
20206
  onEnable() {
19447
- this.subscribeToQuery();
20207
+ this.interceptQuery();
19448
20208
  }
19449
20209
  onDisable() {
19450
20210
  for (const unsubscribe of this.unsubscribers) {
@@ -19452,211 +20212,218 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19452
20212
  }
19453
20213
  this.unsubscribers = [];
19454
20214
  }
19455
- subscribeToQuery() {
19456
- const channel2 = claudeAgentSDKChannels.query.tracingChannel();
19457
- const spans = /* @__PURE__ */ new WeakMap();
19458
- const handlers = {
19459
- start: (event) => {
19460
- const params = event.arguments[0] ?? {};
19461
- const originalPrompt = params.prompt;
19462
- const options = params.options ?? {};
19463
- const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
19464
- let promptStarted = false;
19465
- let capturedPromptMessages;
19466
- let resolvePromptDone;
19467
- const promptDone = new Promise((resolve) => {
19468
- resolvePromptDone = resolve;
19469
- });
19470
- if (promptIsAsyncIterable) {
19471
- capturedPromptMessages = [];
19472
- const promptStream = originalPrompt;
19473
- params.prompt = (async function* () {
19474
- promptStarted = true;
19475
- try {
19476
- for await (const message of promptStream) {
19477
- capturedPromptMessages.push(message);
19478
- yield message;
19479
- }
19480
- } finally {
19481
- resolvePromptDone?.();
20215
+ interceptQuery() {
20216
+ const startQuery = (params) => {
20217
+ const originalPrompt = params.prompt;
20218
+ const options = params.options ?? {};
20219
+ const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
20220
+ let promptStarted = false;
20221
+ let capturedPromptMessages;
20222
+ let resolvePromptDone;
20223
+ const promptDone = new Promise((resolve) => {
20224
+ resolvePromptDone = resolve;
20225
+ });
20226
+ if (promptIsAsyncIterable) {
20227
+ capturedPromptMessages = [];
20228
+ const promptStream = originalPrompt;
20229
+ params.prompt = (async function* () {
20230
+ promptStarted = true;
20231
+ try {
20232
+ for await (const message of promptStream) {
20233
+ capturedPromptMessages.push(message);
20234
+ yield message;
19482
20235
  }
19483
- })();
19484
- }
19485
- const span = startSpan(
19486
- withSpanInstrumentationName(
19487
- {
19488
- name: "Claude Agent",
19489
- spanAttributes: {
19490
- type: "task" /* TASK */
19491
- }
19492
- },
19493
- INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
19494
- )
19495
- );
19496
- const startTime = getCurrentUnixTimestamp();
19497
- try {
19498
- span.log({
19499
- input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
19500
- metadata: filterSerializableOptions(options)
19501
- });
19502
- } catch (error) {
19503
- console.error("Error extracting input for Claude Agent SDK:", error);
19504
- }
19505
- const activeToolSpans = /* @__PURE__ */ new Map();
19506
- const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
19507
- const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
19508
- const subAgentSpans = /* @__PURE__ */ new Map();
19509
- const endedSubAgentSpans = /* @__PURE__ */ new Set();
19510
- const toolUseToParent = /* @__PURE__ */ new Map();
19511
- const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
19512
- const latestRootLlmParentRef = {
19513
- value: void 0
19514
- };
19515
- const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
19516
- const taskIdToToolUseId = /* @__PURE__ */ new Map();
19517
- const promptMessagesByParentKey = /* @__PURE__ */ new Map();
19518
- const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
19519
- const localToolContext = createClaudeLocalToolContext();
19520
- const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
19521
- const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
19522
- const resolveToolUseParentSpan = async (toolUseID, context) => {
19523
- const trackedParentToolUseId = toolUseToParent.get(toolUseID);
19524
- const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
19525
- const parentKey = llmParentKey(parentToolUseId);
19526
- const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
19527
- const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
19528
- if (!activeLlmSpan && !latestLlmParent) {
19529
- await ensureActiveLlmSpanForParentToolUse(
19530
- span,
19531
- activeLlmSpansByParentToolUse,
19532
- subAgentDetailsByToolUseId,
19533
- activeToolSpans,
19534
- subAgentSpans,
19535
- parentToolUseId,
19536
- getCurrentUnixTimestamp()
19537
- );
19538
- }
19539
- if (parentToolUseId) {
19540
- const subAgentSpan = await ensureSubAgentSpan(
19541
- subAgentDetailsByToolUseId,
19542
- span,
19543
- activeToolSpans,
19544
- subAgentSpans,
19545
- parentToolUseId
19546
- );
19547
- return subAgentSpan.export();
20236
+ } finally {
20237
+ resolvePromptDone?.();
19548
20238
  }
19549
- return span.export();
19550
- };
19551
- localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
19552
- setClaudeLocalToolParentResolver(resolveToolUseParentSpan);
19553
- const optionsWithHooks = injectTracingHooks(
19554
- options,
19555
- resolveToolUseParentSpan,
19556
- taskIdToToolUseId,
19557
- toolUseToParent,
19558
- activeToolSpans,
19559
- localToolHookNames,
19560
- skipLocalToolHooks,
19561
- subAgentDetailsByToolUseId,
19562
- subAgentSpans,
19563
- endedSubAgentSpans
19564
- );
19565
- params.options = optionsWithHooks;
19566
- event.arguments[0] = params;
19567
- spans.set(event, {
19568
- activeLlmSpansByParentToolUse,
19569
- activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
19570
- activeToolSpans,
19571
- conversationHistoryByParentKey,
19572
- capturedPromptMessages,
19573
- currentMessageId: void 0,
19574
- currentMessageStartTime: startTime,
19575
- currentMessages: [],
19576
- endedSubAgentSpans,
19577
- finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
19578
- finalResults: [],
19579
- options: optionsWithHooks,
19580
- originalPrompt,
19581
- processing: Promise.resolve(),
19582
- promptDone,
19583
- promptMessagesByParentKey,
19584
- promptStarted: () => promptStarted,
19585
- promptSourcePriorityByParentKey,
19586
- span,
19587
- subAgentDetailsByToolUseId,
19588
- subAgentSpans,
19589
- taskIdToToolUseId,
19590
- latestLlmParentBySubAgentToolUse,
19591
- latestRootLlmParentRef,
19592
- toolUseToParent,
19593
- usageByMessageId: /* @__PURE__ */ new Map(),
19594
- localToolContext
20239
+ })();
20240
+ }
20241
+ const span = startSpan(
20242
+ withSpanInstrumentationName(
20243
+ {
20244
+ name: "Claude Agent",
20245
+ spanAttributes: {
20246
+ type: "task" /* TASK */
20247
+ }
20248
+ },
20249
+ INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
20250
+ )
20251
+ );
20252
+ const startTime = getCurrentUnixTimestamp();
20253
+ try {
20254
+ span.log({
20255
+ input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
20256
+ metadata: filterSerializableOptions(options)
19595
20257
  });
19596
- },
19597
- end: (event) => {
19598
- const state = spans.get(event);
19599
- if (!state) {
19600
- return;
19601
- }
19602
- const eventResult = bindClaudeLocalToolContextToAsyncIterable(
19603
- event.result,
19604
- state.localToolContext
19605
- );
19606
- if (eventResult === void 0) {
19607
- state.span.end();
19608
- spans.delete(event);
19609
- return;
19610
- }
19611
- if (isAsyncIterable(eventResult)) {
19612
- patchStreamIfNeeded(eventResult, {
19613
- onChunk: (message) => {
19614
- maybeTrackToolUseContext(state, message);
19615
- state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
19616
- console.error(
19617
- "Error processing Claude Agent SDK stream chunk:",
19618
- error
19619
- );
19620
- });
19621
- },
19622
- onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
19623
- spans.delete(event);
19624
- }),
19625
- onError: (error) => state.processing.then(() => {
19626
- state.span.log({
19627
- error: error.message
19628
- });
19629
- }).then(() => finalizeQuerySpan(state)).finally(() => {
19630
- spans.delete(event);
19631
- })
19632
- });
19633
- return;
19634
- }
19635
- try {
19636
- state.span.log({ output: eventResult });
19637
- } catch (error) {
19638
- console.error("Error extracting output for Claude Agent SDK:", error);
19639
- } finally {
19640
- state.span.end();
19641
- spans.delete(event);
20258
+ } catch (error) {
20259
+ console.error("Error extracting input for Claude Agent SDK:", error);
20260
+ }
20261
+ const activeToolSpans = /* @__PURE__ */ new Map();
20262
+ const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
20263
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
20264
+ const subAgentSpans = /* @__PURE__ */ new Map();
20265
+ const endedSubAgentSpans = /* @__PURE__ */ new Set();
20266
+ const toolUseToParent = /* @__PURE__ */ new Map();
20267
+ const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
20268
+ const latestRootLlmParentRef = {
20269
+ value: void 0
20270
+ };
20271
+ const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
20272
+ const taskIdToToolUseId = /* @__PURE__ */ new Map();
20273
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
20274
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
20275
+ const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
20276
+ const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
20277
+ const resolveToolUseParentSpan = async (toolUseID, context) => {
20278
+ const trackedParentToolUseId = toolUseToParent.get(toolUseID);
20279
+ const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
20280
+ const parentKey = llmParentKey(parentToolUseId);
20281
+ const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
20282
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
20283
+ if (!activeLlmSpan && !latestLlmParent) {
20284
+ await ensureActiveLlmSpanForParentToolUse(
20285
+ span,
20286
+ activeLlmSpansByParentToolUse,
20287
+ subAgentDetailsByToolUseId,
20288
+ activeToolSpans,
20289
+ subAgentSpans,
20290
+ parentToolUseId,
20291
+ getCurrentUnixTimestamp()
20292
+ );
19642
20293
  }
19643
- },
19644
- error: (event) => {
19645
- const state = spans.get(event);
19646
- if (!state || !event.error) {
19647
- return;
20294
+ if (parentToolUseId) {
20295
+ const subAgentSpan = await ensureSubAgentSpan(
20296
+ subAgentDetailsByToolUseId,
20297
+ span,
20298
+ activeToolSpans,
20299
+ subAgentSpans,
20300
+ parentToolUseId
20301
+ );
20302
+ return subAgentSpan.export();
19648
20303
  }
19649
- state.span.log({
19650
- error: event.error.message
20304
+ return span.export();
20305
+ };
20306
+ const optionsWithHooks = injectTracingHooks(
20307
+ options,
20308
+ resolveToolUseParentSpan,
20309
+ taskIdToToolUseId,
20310
+ toolUseToParent,
20311
+ activeToolSpans,
20312
+ localToolHookNames,
20313
+ skipLocalToolHooks,
20314
+ subAgentDetailsByToolUseId,
20315
+ subAgentSpans,
20316
+ endedSubAgentSpans
20317
+ );
20318
+ params.options = optionsWithHooks;
20319
+ return {
20320
+ activeLlmSpansByParentToolUse,
20321
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
20322
+ activeToolSpans,
20323
+ conversationHistoryByParentKey,
20324
+ capturedPromptMessages,
20325
+ currentMessageId: void 0,
20326
+ currentMessageStartTime: startTime,
20327
+ currentMessages: [],
20328
+ endedSubAgentSpans,
20329
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
20330
+ finalResults: [],
20331
+ options: optionsWithHooks,
20332
+ originalPrompt,
20333
+ processing: Promise.resolve(),
20334
+ promptDone,
20335
+ promptMessagesByParentKey,
20336
+ promptStarted: () => promptStarted,
20337
+ promptSourcePriorityByParentKey,
20338
+ span,
20339
+ subAgentDetailsByToolUseId,
20340
+ subAgentSpans,
20341
+ taskIdToToolUseId,
20342
+ latestLlmParentBySubAgentToolUse,
20343
+ latestRootLlmParentRef,
20344
+ toolUseToParent,
20345
+ usageByMessageId: /* @__PURE__ */ new Map(),
20346
+ localToolParentResolver: resolveToolUseParentSpan
20347
+ };
20348
+ };
20349
+ const finishQuery = (state, result) => {
20350
+ if (isAsyncIterable(result)) {
20351
+ patchStreamIfNeeded(result, {
20352
+ aroundNext: (callback) => runWithClaudeLocalToolContext(
20353
+ callback,
20354
+ state.localToolParentResolver
20355
+ ),
20356
+ onChunk: (message) => {
20357
+ maybeTrackToolUseContext(state, message);
20358
+ state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
20359
+ console.error(
20360
+ "Error processing Claude Agent SDK stream chunk:",
20361
+ error
20362
+ );
20363
+ });
20364
+ },
20365
+ onComplete: () => state.processing.then(() => finalizeQuerySpan(state)),
20366
+ onError: (error) => state.processing.then(() => {
20367
+ state.span.log({ error: error.message });
20368
+ }).then(() => finalizeQuerySpan(state))
19651
20369
  });
20370
+ return;
20371
+ }
20372
+ try {
20373
+ state.span.log({ output: result });
20374
+ } catch (error) {
20375
+ console.error("Error extracting output for Claude Agent SDK:", error);
20376
+ } finally {
19652
20377
  state.span.end();
19653
- spans.delete(event);
19654
20378
  }
19655
20379
  };
19656
- channel2.subscribe(handlers);
19657
- this.unsubscribers.push(() => {
19658
- channel2.unsubscribe(handlers);
19659
- });
20380
+ this.unsubscribers.push(
20381
+ claudeAgentSDKChannels.query.intercept((target, thisArg, args) => {
20382
+ let state;
20383
+ try {
20384
+ args[0] ??= {};
20385
+ state = startQuery(args[0]);
20386
+ } catch (error) {
20387
+ debugLogger.error(
20388
+ "Error starting Claude Agent SDK instrumentation:",
20389
+ error
20390
+ );
20391
+ }
20392
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
20393
+ try {
20394
+ const result = state ? runWithClaudeLocalToolContext(
20395
+ invokeTarget,
20396
+ state.localToolParentResolver
20397
+ ) : invokeTarget();
20398
+ if (state) {
20399
+ try {
20400
+ finishQuery(state, result);
20401
+ } catch (error) {
20402
+ debugLogger.error(
20403
+ "Error finalizing Claude Agent SDK instrumentation:",
20404
+ error
20405
+ );
20406
+ }
20407
+ }
20408
+ return result;
20409
+ } catch (error) {
20410
+ if (state) {
20411
+ try {
20412
+ state.span.log({
20413
+ error: error instanceof Error ? error.message : String(error)
20414
+ });
20415
+ state.span.end();
20416
+ } catch (instrumentationError) {
20417
+ debugLogger.error(
20418
+ "Error handling Claude Agent SDK instrumentation failure:",
20419
+ instrumentationError
20420
+ );
20421
+ }
20422
+ }
20423
+ throw error;
20424
+ }
20425
+ })
20426
+ );
19660
20427
  }
19661
20428
  };
19662
20429
 
@@ -23770,7 +24537,7 @@ function patchOpenRouterCallModelResult(args) {
23770
24537
  span,
23771
24538
  () => originalMethod.apply(resultLike, args2)
23772
24539
  );
23773
- if (!isAsyncIterable4(stream)) {
24540
+ if (!isAsyncIterable3(stream)) {
23774
24541
  return stream;
23775
24542
  }
23776
24543
  return wrapAsyncIterableWithSpan({
@@ -23965,7 +24732,7 @@ function wrapAsyncIterableWithSpan(args) {
23965
24732
  }
23966
24733
  };
23967
24734
  }
23968
- function isAsyncIterable4(value) {
24735
+ function isAsyncIterable3(value) {
23969
24736
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
23970
24737
  }
23971
24738
  function normalizeError(error) {
@@ -24843,7 +25610,7 @@ function patchOpenRouterCallModelResult2(args) {
24843
25610
  span,
24844
25611
  () => originalMethod.apply(resultLike, args2)
24845
25612
  );
24846
- if (!isAsyncIterable5(stream)) {
25613
+ if (!isAsyncIterable4(stream)) {
24847
25614
  return stream;
24848
25615
  }
24849
25616
  return wrapAsyncIterableWithSpan2({
@@ -25038,7 +25805,7 @@ function wrapAsyncIterableWithSpan2(args) {
25038
25805
  }
25039
25806
  };
25040
25807
  }
25041
- function isAsyncIterable5(value) {
25808
+ function isAsyncIterable4(value) {
25042
25809
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
25043
25810
  }
25044
25811
  function normalizeError2(error) {
@@ -31030,12 +31797,14 @@ function getMetricsFromResponse(response) {
31030
31797
  continue;
31031
31798
  }
31032
31799
  const inputTokenDetails = usageMetadata.input_token_details;
31800
+ const outputTokenDetails = usageMetadata.output_token_details;
31033
31801
  return normalizeTokenMetrics({
31034
31802
  total_tokens: usageMetadata.total_tokens,
31035
31803
  prompt_tokens: usageMetadata.input_tokens,
31036
31804
  completion_tokens: usageMetadata.output_tokens,
31037
31805
  prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
31038
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
31806
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
31807
+ completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
31039
31808
  });
31040
31809
  }
31041
31810
  const llmOutput = response.llmOutput || {};
@@ -31622,6 +32391,9 @@ var piCodingAgentChannels = defineChannels(
31622
32391
  // src/instrumentation/plugins/pi-coding-agent-plugin.ts
31623
32392
  var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
31624
32393
  var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
32394
+ var PI_TOOL_EXECUTE_WRAPPED = /* @__PURE__ */ Symbol.for(
32395
+ "braintrust.pi_coding_agent.tool_execute_wrapped"
32396
+ );
31625
32397
  var piPromptContextStore;
31626
32398
  var PiCodingAgentPlugin = class extends BasePlugin {
31627
32399
  activePromptStates = /* @__PURE__ */ new Set();
@@ -31702,6 +32474,7 @@ function startPiPromptRun(event, onFinalize) {
31702
32474
  return void 0;
31703
32475
  }
31704
32476
  installPiAgentInstrumentation(agent);
32477
+ wrapPiToolExecutors(agent.state?.tools);
31705
32478
  const metadata = {
31706
32479
  ...extractSessionMetadata(session),
31707
32480
  ...extractPromptOptionsMetadata(event.arguments[1]),
@@ -31798,6 +32571,7 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
31798
32571
  if (!state || state.agent !== agent || state.finalized) {
31799
32572
  return invokeOriginal();
31800
32573
  }
32574
+ wrapPiToolExecutors(context.tools);
31801
32575
  const llmState = await startPiLlmSpan(state, model, context, options);
31802
32576
  try {
31803
32577
  const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
@@ -31808,6 +32582,33 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
31808
32582
  }
31809
32583
  };
31810
32584
  }
32585
+ function wrapPiToolExecutors(tools) {
32586
+ if (!tools) {
32587
+ return;
32588
+ }
32589
+ for (const tool of tools) {
32590
+ try {
32591
+ const execute = tool.execute;
32592
+ if (typeof execute !== "function" || execute[PI_TOOL_EXECUTE_WRAPPED]) {
32593
+ continue;
32594
+ }
32595
+ const wrappedExecute = function(...args) {
32596
+ return runWithAutoInstrumentationAllowed(
32597
+ () => Reflect.apply(execute, this, args)
32598
+ );
32599
+ };
32600
+ Object.defineProperty(wrappedExecute, PI_TOOL_EXECUTE_WRAPPED, {
32601
+ configurable: false,
32602
+ enumerable: false,
32603
+ value: true,
32604
+ writable: false
32605
+ });
32606
+ tool.execute = wrappedExecute;
32607
+ } catch (error) {
32608
+ logInstrumentationError4("Pi Coding Agent tool wrapping", error);
32609
+ }
32610
+ }
32611
+ }
31811
32612
  async function startPiLlmSpan(state, model, context, options) {
31812
32613
  const metadata = {
31813
32614
  ...extractModelMetadata2(model),
@@ -31979,35 +32780,26 @@ async function startPiToolSpan(state, event) {
31979
32780
  if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
31980
32781
  return;
31981
32782
  }
31982
- const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
31983
32783
  const metadata = {
31984
32784
  "gen_ai.tool.call.id": event.toolCallId,
31985
32785
  "gen_ai.tool.name": event.toolName,
31986
32786
  "pi_coding_agent.tool.name": event.toolName
31987
32787
  };
31988
- try {
31989
- const span = startSpan(
31990
- withSpanInstrumentationName(
31991
- {
31992
- event: {
31993
- input: event.args,
31994
- metadata
31995
- },
31996
- name: event.toolName || "tool",
31997
- parent: await state.span.export(),
31998
- spanAttributes: { type: "tool" /* TOOL */ }
32788
+ const span = startSpan(
32789
+ withSpanInstrumentationName(
32790
+ {
32791
+ event: {
32792
+ input: event.args,
32793
+ metadata
31999
32794
  },
32000
- INSTRUMENTATION_NAMES.PI_CODING_AGENT
32001
- )
32002
- );
32003
- state.activeToolSpans.set(event.toolCallId, {
32004
- restoreAutoInstrumentation,
32005
- span
32006
- });
32007
- } catch (error) {
32008
- restoreAutoInstrumentation();
32009
- throw error;
32010
- }
32795
+ name: event.toolName || "tool",
32796
+ parent: await state.span.export(),
32797
+ spanAttributes: { type: "tool" /* TOOL */ }
32798
+ },
32799
+ INSTRUMENTATION_NAMES.PI_CODING_AGENT
32800
+ )
32801
+ );
32802
+ state.activeToolSpans.set(event.toolCallId, { span });
32011
32803
  }
32012
32804
  function finishPiToolSpan(state, event) {
32013
32805
  const toolState = state.activeToolSpans.get(event.toolCallId);
@@ -32028,11 +32820,7 @@ function finishPiToolSpan(state, event) {
32028
32820
  output: event.result
32029
32821
  });
32030
32822
  } finally {
32031
- try {
32032
- toolState.span.end();
32033
- } finally {
32034
- toolState.restoreAutoInstrumentation?.();
32035
- }
32823
+ toolState.span.end();
32036
32824
  }
32037
32825
  }
32038
32826
  function finishPiPromptRun(state, error) {
@@ -32082,10 +32870,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
32082
32870
  ...cleanMetrics5(llmState.metrics),
32083
32871
  ...buildDurationMetrics3(llmState.startTime)
32084
32872
  };
32085
- const usageMetrics = extractUsageMetrics2(message?.usage);
32086
- if (Object.keys(usageMetrics).length > 0) {
32873
+ const usageMetrics2 = extractUsageMetrics2(message?.usage);
32874
+ if (Object.keys(usageMetrics2).length > 0) {
32087
32875
  promptState.collectedLlmUsageMetrics = true;
32088
- addMetrics(promptState.metrics, usageMetrics);
32876
+ addMetrics(promptState.metrics, usageMetrics2);
32089
32877
  }
32090
32878
  try {
32091
32879
  safeLog4(llmState.span, {
@@ -32103,14 +32891,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
32103
32891
  }
32104
32892
  function finishOpenToolSpans(state, error) {
32105
32893
  for (const [, toolState] of state.activeToolSpans) {
32106
- try {
32107
- safeLog4(toolState.span, {
32108
- error: error ? toLoggedError(error) : "Pi tool did not complete"
32109
- });
32110
- toolState.span.end();
32111
- } finally {
32112
- toolState.restoreAutoInstrumentation?.();
32113
- }
32894
+ safeLog4(toolState.span, {
32895
+ error: error ? toLoggedError(error) : "Pi tool did not complete"
32896
+ });
32897
+ toolState.span.end();
32114
32898
  }
32115
32899
  state.activeToolSpans.clear();
32116
32900
  }
@@ -32429,12 +33213,12 @@ var MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES = 32;
32429
33213
  var StrandsAgentSDKPlugin = class extends BasePlugin {
32430
33214
  activeChildParents = /* @__PURE__ */ new WeakMap();
32431
33215
  onEnable() {
32432
- this.subscribeToAgentStream();
32433
- this.subscribeToMultiAgentStream(
33216
+ this.interceptAgentStream();
33217
+ this.interceptMultiAgentStream(
32434
33218
  strandsAgentSDKChannels.graphStream,
32435
33219
  "Graph.stream"
32436
33220
  );
32437
- this.subscribeToMultiAgentStream(
33221
+ this.interceptMultiAgentStream(
32438
33222
  strandsAgentSDKChannels.swarmStream,
32439
33223
  "Swarm.stream"
32440
33224
  );
@@ -32445,122 +33229,92 @@ var StrandsAgentSDKPlugin = class extends BasePlugin {
32445
33229
  }
32446
33230
  this.unsubscribers = [];
32447
33231
  }
32448
- subscribeToAgentStream() {
32449
- const channel2 = strandsAgentSDKChannels.agentStream.tracingChannel();
32450
- const states = /* @__PURE__ */ new WeakMap();
32451
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
32452
- const handlers = {
32453
- start: (event) => {
32454
- const state = startAgentStream(event, this.activeChildParents);
32455
- if (state) {
32456
- states.set(event, state);
32457
- }
32458
- },
32459
- end: (event) => {
32460
- const state = states.get(event);
32461
- if (!state) {
32462
- return;
32463
- }
32464
- const result = event.result;
32465
- if (isAsyncIterable(result)) {
32466
- patchStreamIfNeeded(result, {
32467
- aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
32468
- onChunk: (chunk) => handleAgentStreamEvent(state, chunk),
32469
- onComplete: () => {
32470
- finalizeAgentStream(state);
32471
- states.delete(event);
32472
- },
32473
- onError: (error) => {
32474
- finalizeAgentStream(state, error);
32475
- states.delete(event);
32476
- }
32477
- });
32478
- return;
32479
- }
32480
- finalizeAgentStream(state, void 0, result);
32481
- states.delete(event);
32482
- },
32483
- error: (event) => {
32484
- const state = states.get(event);
32485
- if (!state || !event.error) {
32486
- return;
32487
- }
32488
- finalizeAgentStream(state, event.error);
32489
- states.delete(event);
32490
- }
32491
- };
32492
- channel2.subscribe(handlers);
32493
- this.unsubscribers.push(() => {
32494
- unbindAutoInstrumentationSuppression?.();
32495
- channel2.unsubscribe(handlers);
32496
- });
33232
+ interceptAgentStream() {
33233
+ this.unsubscribers.push(
33234
+ strandsAgentSDKChannels.agentStream.intercept(
33235
+ (target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
33236
+ finalize: finalizeAgentStream,
33237
+ handleChunk: handleAgentStreamEvent,
33238
+ invoke: () => Reflect.apply(target, thisArg, args),
33239
+ name: "Strands Agent SDK",
33240
+ start: () => startAgentStream(
33241
+ args[0],
33242
+ extractAgent(additional.agent, thisArg),
33243
+ this.activeChildParents
33244
+ )
33245
+ })
33246
+ )
33247
+ );
32497
33248
  }
32498
- subscribeToMultiAgentStream(channel2, operation) {
32499
- const tracingChannel = channel2.tracingChannel();
32500
- const states = /* @__PURE__ */ new WeakMap();
32501
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(tracingChannel);
32502
- const handlers = {
32503
- start: (event) => {
32504
- const state = startMultiAgentStream(
32505
- event,
32506
- operation,
32507
- this.activeChildParents
32508
- );
32509
- if (state) {
32510
- states.set(event, state);
32511
- }
32512
- },
32513
- end: (event) => {
32514
- const state = states.get(event);
32515
- if (!state) {
32516
- return;
32517
- }
32518
- const result = event.result;
32519
- if (isAsyncIterable(result)) {
32520
- patchStreamIfNeeded(result, {
32521
- aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
32522
- onChunk: (chunk) => handleMultiAgentStreamEvent(
32523
- state,
32524
- chunk,
32525
- this.activeChildParents
32526
- ),
32527
- onComplete: () => {
32528
- finalizeMultiAgentStream(state, this.activeChildParents);
32529
- states.delete(event);
32530
- },
32531
- onError: (error) => {
32532
- finalizeMultiAgentStream(state, this.activeChildParents, error);
32533
- states.delete(event);
32534
- }
32535
- });
32536
- return;
32537
- }
32538
- finalizeMultiAgentStream(
32539
- state,
32540
- this.activeChildParents,
32541
- void 0,
32542
- result
33249
+ interceptMultiAgentStream(channel2, operation) {
33250
+ this.unsubscribers.push(
33251
+ channel2.intercept(
33252
+ (target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
33253
+ finalize: (state, error, output) => finalizeMultiAgentStream(
33254
+ state,
33255
+ this.activeChildParents,
33256
+ error,
33257
+ output
33258
+ ),
33259
+ handleChunk: (state, chunk) => handleMultiAgentStreamEvent(state, chunk, this.activeChildParents),
33260
+ invoke: () => Reflect.apply(target, thisArg, args),
33261
+ name: "Strands multi-agent",
33262
+ start: () => startMultiAgentStream(
33263
+ args[0],
33264
+ extractOrchestrator(additional.orchestrator, thisArg),
33265
+ operation,
33266
+ this.activeChildParents
33267
+ )
33268
+ })
33269
+ )
33270
+ );
33271
+ }
33272
+ };
33273
+ function instrumentStrandsStreamInvocation(options) {
33274
+ let state;
33275
+ try {
33276
+ state = options.start();
33277
+ } catch (error) {
33278
+ debugLogger.error(`Error starting ${options.name} instrumentation:`, error);
33279
+ }
33280
+ let result;
33281
+ try {
33282
+ result = runWithAutoInstrumentationSuppressed(options.invoke);
33283
+ } catch (error) {
33284
+ if (state) {
33285
+ try {
33286
+ options.finalize(state, error);
33287
+ } catch (instrumentationError) {
33288
+ debugLogger.error(
33289
+ `Error handling ${options.name} instrumentation failure:`,
33290
+ instrumentationError
32543
33291
  );
32544
- states.delete(event);
32545
- },
32546
- error: (event) => {
32547
- const state = states.get(event);
32548
- if (!state || !event.error) {
32549
- return;
32550
- }
32551
- finalizeMultiAgentStream(state, this.activeChildParents, event.error);
32552
- states.delete(event);
32553
33292
  }
32554
- };
32555
- tracingChannel.subscribe(handlers);
32556
- this.unsubscribers.push(() => {
32557
- unbindAutoInstrumentationSuppression?.();
32558
- tracingChannel.unsubscribe(handlers);
32559
- });
33293
+ }
33294
+ throw error;
32560
33295
  }
32561
- };
32562
- function startAgentStream(event, activeChildParents) {
32563
- const agent = extractAgent(event);
33296
+ if (state) {
33297
+ try {
33298
+ if (isAsyncIterable(result)) {
33299
+ patchStreamIfNeeded(result, {
33300
+ aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
33301
+ onChunk: (chunk) => options.handleChunk(state, chunk),
33302
+ onComplete: () => options.finalize(state),
33303
+ onError: (error) => options.finalize(state, error)
33304
+ });
33305
+ } else {
33306
+ options.finalize(state, void 0, result);
33307
+ }
33308
+ } catch (error) {
33309
+ debugLogger.error(
33310
+ `Error finalizing ${options.name} instrumentation:`,
33311
+ error
33312
+ );
33313
+ }
33314
+ }
33315
+ return result;
33316
+ }
33317
+ function startAgentStream(input, agent, activeChildParents) {
32564
33318
  const model = agent?.model;
32565
33319
  const metadata = {
32566
33320
  ...extractAgentMetadata2(agent),
@@ -32570,17 +33324,14 @@ function startAgentStream(event, activeChildParents) {
32570
33324
  };
32571
33325
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
32572
33326
  const attachmentCache = createStrandsAttachmentCache();
32573
- const input = processStrandsInputAttachments(
32574
- event.arguments[0],
32575
- attachmentCache
32576
- );
33327
+ const processedInput = processStrandsInputAttachments(input, attachmentCache);
32577
33328
  const span = parentSpan ? withCurrent(
32578
33329
  parentSpan,
32579
33330
  () => startSpan(
32580
33331
  withSpanInstrumentationName(
32581
33332
  {
32582
33333
  event: {
32583
- input,
33334
+ input: processedInput,
32584
33335
  metadata
32585
33336
  },
32586
33337
  name: formatAgentSpanName(agent),
@@ -32593,7 +33344,7 @@ function startAgentStream(event, activeChildParents) {
32593
33344
  withSpanInstrumentationName(
32594
33345
  {
32595
33346
  event: {
32596
- input,
33347
+ input: processedInput,
32597
33348
  metadata
32598
33349
  },
32599
33350
  name: formatAgentSpanName(agent),
@@ -32611,22 +33362,21 @@ function startAgentStream(event, activeChildParents) {
32611
33362
  startTime: getCurrentUnixTimestamp()
32612
33363
  };
32613
33364
  }
32614
- function startMultiAgentStream(event, operation, activeChildParents) {
32615
- const orchestrator = extractOrchestrator(event);
33365
+ function startMultiAgentStream(input, orchestrator, operation, activeChildParents) {
32616
33366
  const metadata = {
32617
33367
  "strands.operation": operation,
32618
33368
  provider: "strands",
32619
33369
  ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
32620
33370
  };
32621
33371
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
32622
- const input = processStrandsInputAttachments(event.arguments[0]);
33372
+ const processedInput = processStrandsInputAttachments(input);
32623
33373
  const span = parentSpan ? withCurrent(
32624
33374
  parentSpan,
32625
33375
  () => startSpan(
32626
33376
  withSpanInstrumentationName(
32627
33377
  {
32628
33378
  event: {
32629
- input,
33379
+ input: processedInput,
32630
33380
  metadata
32631
33381
  },
32632
33382
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -32639,7 +33389,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
32639
33389
  withSpanInstrumentationName(
32640
33390
  {
32641
33391
  event: {
32642
- input,
33392
+ input: processedInput,
32643
33393
  metadata
32644
33394
  },
32645
33395
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -33010,12 +33760,12 @@ function finalizeMultiAgentStream(state, activeChildParents, error, output) {
33010
33760
  });
33011
33761
  state.span.end();
33012
33762
  }
33013
- function extractAgent(event) {
33014
- const candidate = event.agent ?? event.self;
33763
+ function extractAgent(agent, self) {
33764
+ const candidate = agent ?? self;
33015
33765
  return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
33016
33766
  }
33017
- function extractOrchestrator(event) {
33018
- const candidate = event.orchestrator ?? event.self;
33767
+ function extractOrchestrator(orchestrator, self) {
33768
+ const candidate = orchestrator ?? self;
33019
33769
  return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
33020
33770
  }
33021
33771
  function extractAgentMetadata2(agent) {
@@ -34535,7 +35285,7 @@ function braintrustEveHook(options) {
34535
35285
  }
34536
35286
  };
34537
35287
  }
34538
- function braintrustEveInstrumentation(options) {
35288
+ function createLegacyEveInstrumentation(options) {
34539
35289
  const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
34540
35290
  return {
34541
35291
  events: {
@@ -35923,8 +36673,10 @@ function capturedModelInput(modelInput) {
35923
36673
  const value = [];
35924
36674
  if (typeof instructions === "string") {
35925
36675
  value.push({ content: instructions, role: "system" });
35926
- } else if (instructions) {
36676
+ } else if (Array.isArray(instructions)) {
35927
36677
  value.push(...instructions.map(capturedEveModelMessage));
36678
+ } else if (instructions) {
36679
+ value.push(capturedEveModelMessage(instructions));
35928
36680
  }
35929
36681
  value.push(...messages.map(capturedEveModelMessage));
35930
36682
  try {
@@ -36168,6 +36920,464 @@ async function deterministicEveId(...parts) {
36168
36920
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
36169
36921
  }
36170
36922
 
36923
+ // src/instrumentation/plugins/eve-provider.ts
36924
+ var MAX_EVE_PROVIDER_CACHE_ENTRIES = 1e4;
36925
+ function createEveInstrumentationProvider(options = {}) {
36926
+ const bridge = new EveProviderBridge(options.metadata);
36927
+ return {
36928
+ capture: "content",
36929
+ events: {
36930
+ "action.completed": (event, context) => bridge.handleActionTerminal(event, context),
36931
+ "action.failed": (event, context) => bridge.handleActionTerminal(event, context),
36932
+ "action.started": (event, context) => bridge.handleActionStarted(event, context),
36933
+ "model.call.completed": (event, context) => bridge.handleModelTerminal(event, context),
36934
+ "model.call.failed": (event, context) => bridge.handleModelTerminal(event, context),
36935
+ "model.call.started": (event, context) => bridge.handleModelStarted(event, context),
36936
+ "step.attempt.completed": (event) => bridge.handleStepAttemptTerminal(event),
36937
+ "step.attempt.failed": (event) => bridge.handleStepAttemptTerminal(event),
36938
+ "turn.cancelled": (event, context) => bridge.handleTurnTerminal(event, context),
36939
+ "turn.completed": (event, context) => bridge.handleTurnTerminal(event, context),
36940
+ "turn.failed": (event, context) => bridge.handleTurnTerminal(event, context),
36941
+ "turn.started": (event, context) => bridge.handleTurnStarted(event, context)
36942
+ },
36943
+ flush,
36944
+ setup: options.setup
36945
+ };
36946
+ }
36947
+ var EveProviderBridge = class {
36948
+ constructor(metadata) {
36949
+ this.metadata = metadata;
36950
+ }
36951
+ metadata;
36952
+ activeActions = /* @__PURE__ */ new Map();
36953
+ activeModels = /* @__PURE__ */ new Map();
36954
+ modelsByAttempt = /* @__PURE__ */ new Map();
36955
+ settledOperations = new LRUCache({
36956
+ max: MAX_EVE_PROVIDER_CACHE_ENTRIES
36957
+ });
36958
+ turns = new LRUCache({
36959
+ max: MAX_EVE_PROVIDER_CACHE_ENTRIES
36960
+ });
36961
+ async handleTurnStarted(event, context) {
36962
+ await this.contain("turn start", async () => {
36963
+ if (this.settledOperations.has(event.idempotencyKey)) {
36964
+ context.state.set({ skip: true });
36965
+ return;
36966
+ }
36967
+ const { rowId, spanId } = await generateEveIds(
36968
+ "turn",
36969
+ event.idempotencyKey
36970
+ );
36971
+ const key = turnKey3(event.sessionId, event.turnId);
36972
+ const stored = storedSpan(context);
36973
+ if (stored && "exported" in stored && stored.rootSpanId) {
36974
+ this.turns.set(key, { rootSpanId: stored.rootSpanId, spanId });
36975
+ return;
36976
+ }
36977
+ let rootSpanId = spanId;
36978
+ let parentSpanId;
36979
+ if (event.parentLineage) {
36980
+ const parentTurnKey = turnKey3(
36981
+ event.parentLineage.sessionId,
36982
+ event.parentLineage.turnId
36983
+ );
36984
+ const parentTurn = this.turns.get(parentTurnKey);
36985
+ rootSpanId = parentTurn?.rootSpanId ?? // Eve propagates the root session through every nested subagent. Use
36986
+ // it instead of the immediate parent session when no ancestor ran
36987
+ // in-process.
36988
+ (await generateEveIds(
36989
+ "turn",
36990
+ turnIdempotencyKey(
36991
+ event.rootSessionId,
36992
+ event.parentLineage.turnId
36993
+ )
36994
+ )).spanId;
36995
+ parentSpanId = (await generateEveIds(
36996
+ "subagent",
36997
+ actionIdempotencyKey(
36998
+ event.parentLineage.sessionId,
36999
+ event.parentLineage.turnId,
37000
+ event.parentLineage.callId
37001
+ )
37002
+ )).spanId;
37003
+ }
37004
+ const metadata = this.spanMetadata(event.sessionId);
37005
+ const span = await this.startSpan(
37006
+ context,
37007
+ {
37008
+ event: { id: rowId, metadata },
37009
+ name: "eve.turn",
37010
+ parentSpanIds: parentSpanId ? { rootSpanId, spanId: parentSpanId } : { parentSpanIds: [], rootSpanId },
37011
+ spanAttributes: { type: "task" /* TASK */ },
37012
+ spanId
37013
+ },
37014
+ rootSpanId
37015
+ );
37016
+ span?.log({ metadata });
37017
+ this.turns.set(key, {
37018
+ rootSpanId,
37019
+ spanId
37020
+ });
37021
+ });
37022
+ }
37023
+ async handleTurnTerminal(event, context) {
37024
+ await this.contain("turn terminal", async () => {
37025
+ if (this.settledOperations.has(event.idempotencyKey)) {
37026
+ context.state.set(void 0);
37027
+ return;
37028
+ }
37029
+ const error = event.type === "turn.failed" ? event.error : void 0;
37030
+ this.drainActionsForTurn(event.sessionId, event.turnId, error);
37031
+ const stored = storedSpan(context);
37032
+ if (stored && "exported" in stored) {
37033
+ updateSpan({
37034
+ exported: stored.exported,
37035
+ ...error !== void 0 ? { error } : {},
37036
+ metrics: { end: Date.now() / 1e3 }
37037
+ });
37038
+ }
37039
+ this.settledOperations.set(event.idempotencyKey, true);
37040
+ context.state.set(void 0);
37041
+ this.turns.delete(turnKey3(event.sessionId, event.turnId));
37042
+ });
37043
+ }
37044
+ async handleModelStarted(event, context) {
37045
+ await this.contain("model start", async () => {
37046
+ if (this.settledOperations.has(event.idempotencyKey)) {
37047
+ context.state.set({ skip: true });
37048
+ return;
37049
+ }
37050
+ const parent = await this.parentForScope(event.scope);
37051
+ const { rowId, spanId } = await generateEveIds(
37052
+ "step",
37053
+ event.idempotencyKey
37054
+ );
37055
+ const input = event.input ? capturedModelInput(event.input) : void 0;
37056
+ const metadata = {
37057
+ ...this.spanMetadata(event.scope.sessionId),
37058
+ model: event.model.modelId,
37059
+ provider: event.model.provider
37060
+ };
37061
+ const span = await this.startSpan(context, {
37062
+ event: {
37063
+ id: rowId,
37064
+ ...input !== void 0 ? { input } : {},
37065
+ metadata
37066
+ },
37067
+ name: "eve.step",
37068
+ parentSpanIds: parent,
37069
+ spanAttributes: { type: "llm" /* LLM */ },
37070
+ spanId
37071
+ });
37072
+ if (!span) return;
37073
+ span.log({ ...input !== void 0 ? { input } : {}, metadata });
37074
+ this.activeModels.set(event.idempotencyKey, {
37075
+ span,
37076
+ turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
37077
+ });
37078
+ const keys = this.modelsByAttempt.get(event.scope.attemptId) ?? /* @__PURE__ */ new Set();
37079
+ keys.add(event.idempotencyKey);
37080
+ this.modelsByAttempt.set(event.scope.attemptId, keys);
37081
+ });
37082
+ }
37083
+ async handleModelTerminal(event, context) {
37084
+ await this.contain("model terminal", async () => {
37085
+ if (this.settledOperations.has(event.idempotencyKey)) {
37086
+ context.state.set(void 0);
37087
+ return;
37088
+ }
37089
+ const active = this.activeModels.get(event.idempotencyKey);
37090
+ if (active) {
37091
+ const span = active.span;
37092
+ if (event.type === "model.call.failed") {
37093
+ if (event.error !== void 0) span.log({ error: event.error });
37094
+ } else {
37095
+ span.log({
37096
+ metrics: usageMetrics(event.usage),
37097
+ output: modelOutput(event)
37098
+ });
37099
+ }
37100
+ span.end();
37101
+ } else {
37102
+ const stored = storedSpan(context);
37103
+ if (stored && "exported" in stored) {
37104
+ updateSpan({
37105
+ exported: stored.exported,
37106
+ ...event.type === "model.call.failed" ? event.error !== void 0 ? { error: event.error } : {} : { output: modelOutput(event) },
37107
+ metrics: {
37108
+ ...event.type === "model.call.completed" ? usageMetrics(event.usage) : {},
37109
+ end: Date.now() / 1e3
37110
+ }
37111
+ });
37112
+ }
37113
+ }
37114
+ this.settledOperations.set(event.idempotencyKey, true);
37115
+ this.forgetModel(event.scope.attemptId, event.idempotencyKey);
37116
+ context.state.set(void 0);
37117
+ });
37118
+ }
37119
+ async handleActionStarted(event, context) {
37120
+ await this.contain("action start", async () => {
37121
+ if (event.kind === "load-skill" || this.settledOperations.has(event.idempotencyKey)) {
37122
+ context.state.set({ skip: true });
37123
+ return;
37124
+ }
37125
+ const parent = await this.parentForScope(event.scope);
37126
+ const { rowId, spanId } = await generateEveIds(
37127
+ event.kind === "subagent-call" ? "subagent" : "tool",
37128
+ event.idempotencyKey
37129
+ );
37130
+ const metadata = {
37131
+ ...this.spanMetadata(event.scope.sessionId),
37132
+ "eve.action_kind": event.kind
37133
+ };
37134
+ const span = await this.startSpan(context, {
37135
+ event: {
37136
+ id: rowId,
37137
+ ...event.input !== void 0 ? { input: event.input } : {},
37138
+ metadata
37139
+ },
37140
+ name: event.name,
37141
+ parentSpanIds: parent,
37142
+ spanAttributes: { type: "tool" /* TOOL */ },
37143
+ spanId
37144
+ });
37145
+ if (!span) return;
37146
+ span.log({
37147
+ ...event.input !== void 0 ? { input: event.input } : {},
37148
+ metadata
37149
+ });
37150
+ this.activeActions.set(event.idempotencyKey, {
37151
+ span,
37152
+ turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
37153
+ });
37154
+ });
37155
+ }
37156
+ async handleActionTerminal(event, context) {
37157
+ await this.contain("action terminal", async () => {
37158
+ if (this.settledOperations.has(event.idempotencyKey)) {
37159
+ context.state.set(void 0);
37160
+ return;
37161
+ }
37162
+ const stored = storedSpan(context);
37163
+ if (stored?.skip) {
37164
+ context.state.set(void 0);
37165
+ return;
37166
+ }
37167
+ const active = this.activeActions.get(event.idempotencyKey);
37168
+ const end = finiteTimestamp(event.acceptedAtMs) ?? Date.now();
37169
+ if (active) {
37170
+ const span = active.span;
37171
+ if (event.type === "action.failed") {
37172
+ span.log({
37173
+ error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
37174
+ });
37175
+ } else if (event.output.type === "error") {
37176
+ span.log({
37177
+ error: event.output.error ?? new Error("Eve action returned an error")
37178
+ });
37179
+ } else {
37180
+ span.log({ output: event.output.output });
37181
+ }
37182
+ span.end({ endTime: end / 1e3 });
37183
+ } else {
37184
+ const stored2 = storedSpan(context);
37185
+ if (stored2 && "exported" in stored2) {
37186
+ updateSpan({
37187
+ exported: stored2.exported,
37188
+ ...event.type === "action.failed" ? {
37189
+ error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
37190
+ } : event.output.type === "error" ? {
37191
+ error: event.output.error ?? new Error("Eve action returned an error")
37192
+ } : { output: event.output.output },
37193
+ metrics: { end: end / 1e3 }
37194
+ });
37195
+ }
37196
+ }
37197
+ this.settledOperations.set(event.idempotencyKey, true);
37198
+ this.activeActions.delete(event.idempotencyKey);
37199
+ context.state.set(void 0);
37200
+ });
37201
+ }
37202
+ handleStepAttemptTerminal(event) {
37203
+ void this.contain("step attempt terminal", () => {
37204
+ const keys = this.modelsByAttempt.get(event.scope.attemptId);
37205
+ if (!keys) return;
37206
+ for (const key of keys) {
37207
+ const active = this.activeModels.get(key);
37208
+ if (!active) continue;
37209
+ if (event.type === "step.attempt.failed" && event.error !== void 0) {
37210
+ active.span.log({ error: event.error });
37211
+ }
37212
+ active.span.end();
37213
+ this.activeModels.delete(key);
37214
+ }
37215
+ this.modelsByAttempt.delete(event.scope.attemptId);
37216
+ });
37217
+ }
37218
+ async parentForScope(scope) {
37219
+ const key = turnKey3(scope.sessionId, scope.turnId);
37220
+ const known = this.turns.get(key);
37221
+ if (known) {
37222
+ return { rootSpanId: known.rootSpanId, spanId: known.spanId };
37223
+ }
37224
+ const [{ spanId }, { spanId: rootSpanId }] = await Promise.all([
37225
+ generateEveIds("turn", turnIdempotencyKey(scope.sessionId, scope.turnId)),
37226
+ generateEveIds(
37227
+ "turn",
37228
+ turnIdempotencyKey(
37229
+ scope.rootSessionId ?? scope.sessionId,
37230
+ scope.turnId
37231
+ )
37232
+ )
37233
+ ]);
37234
+ return { rootSpanId, spanId };
37235
+ }
37236
+ async startSpan(context, args, rootSpanId) {
37237
+ const span = withCurrent(
37238
+ NOOP_SPAN,
37239
+ () => _internalStartSpanWithInitialMerge(
37240
+ withSpanInstrumentationName(args ?? {}, INSTRUMENTATION_NAMES.EVE)
37241
+ )
37242
+ );
37243
+ try {
37244
+ context.state.set({
37245
+ exported: await span.export(),
37246
+ ...rootSpanId ? { rootSpanId } : {}
37247
+ });
37248
+ } catch (error) {
37249
+ debugLogger.warn("Error exporting Eve provider span:", error);
37250
+ }
37251
+ return span;
37252
+ }
37253
+ drainActionsForTurn(sessionId, turnId, error) {
37254
+ const key = turnKey3(sessionId, turnId);
37255
+ for (const [idempotencyKey, active] of this.activeActions) {
37256
+ if (active.turnKey !== key) continue;
37257
+ if (error !== void 0) active.span.log({ error });
37258
+ active.span.end();
37259
+ this.activeActions.delete(idempotencyKey);
37260
+ }
37261
+ }
37262
+ forgetModel(attemptId, idempotencyKey) {
37263
+ this.activeModels.delete(idempotencyKey);
37264
+ const keys = this.modelsByAttempt.get(attemptId);
37265
+ keys?.delete(idempotencyKey);
37266
+ if (keys?.size === 0) this.modelsByAttempt.delete(attemptId);
37267
+ }
37268
+ spanMetadata(sessionId) {
37269
+ return {
37270
+ ...this.metadata ?? {},
37271
+ "eve.session_id": sessionId
37272
+ };
37273
+ }
37274
+ async contain(operation, fn) {
37275
+ try {
37276
+ await fn();
37277
+ } catch (error) {
37278
+ debugLogger.warn(`Error in Eve provider ${operation}:`, error);
37279
+ }
37280
+ }
37281
+ };
37282
+ function storedSpan(context) {
37283
+ const value = context.state.get();
37284
+ if (!isObject(value)) return void 0;
37285
+ if (value["skip"] === true) return { skip: true };
37286
+ return typeof value["exported"] === "string" ? {
37287
+ exported: value["exported"],
37288
+ ...typeof value["rootSpanId"] === "string" && value["rootSpanId"].length > 0 ? { rootSpanId: value["rootSpanId"] } : {}
37289
+ } : void 0;
37290
+ }
37291
+ function modelOutput(event) {
37292
+ const content = event.content ?? [];
37293
+ let text = "";
37294
+ const reasoning = [];
37295
+ const toolCalls = [];
37296
+ for (const part of content) {
37297
+ if (part.type === "text") {
37298
+ text += part.text;
37299
+ } else if (part.type === "reasoning" && part.text.trim().length > 0) {
37300
+ reasoning.push({ content: part.text });
37301
+ } else if (part.type === "tool-call") {
37302
+ toolCalls.push({
37303
+ function: {
37304
+ arguments: safeJsonStringify(part.input),
37305
+ name: part.toolName
37306
+ },
37307
+ id: part.callId,
37308
+ type: "function"
37309
+ });
37310
+ }
37311
+ }
37312
+ return [
37313
+ {
37314
+ finish_reason: normalizeFinishReason2(event.finishReason),
37315
+ index: 0,
37316
+ message: {
37317
+ content: text || null,
37318
+ ...reasoning.length > 0 ? { reasoning } : {},
37319
+ role: "assistant",
37320
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
37321
+ }
37322
+ }
37323
+ ];
37324
+ }
37325
+ function usageMetrics(usage) {
37326
+ const promptTokens = nonNegativeNumber(usage.inputTokens);
37327
+ const completionTokens = nonNegativeNumber(usage.outputTokens);
37328
+ const cachedTokens = nonNegativeNumber(
37329
+ usage.inputTokenDetails?.cacheReadTokens
37330
+ );
37331
+ const cacheCreationTokens = nonNegativeNumber(
37332
+ usage.inputTokenDetails?.cacheWriteTokens
37333
+ );
37334
+ return {
37335
+ ...promptTokens !== void 0 ? { prompt_tokens: promptTokens } : {},
37336
+ ...completionTokens !== void 0 ? { completion_tokens: completionTokens } : {},
37337
+ ...promptTokens !== void 0 && completionTokens !== void 0 ? { tokens: promptTokens + completionTokens } : {},
37338
+ ...cachedTokens !== void 0 ? { prompt_cached_tokens: cachedTokens } : {},
37339
+ ...cacheCreationTokens !== void 0 ? { prompt_cache_creation_tokens: cacheCreationTokens } : {}
37340
+ };
37341
+ }
37342
+ function nonNegativeNumber(value) {
37343
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
37344
+ }
37345
+ function finiteTimestamp(value) {
37346
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
37347
+ }
37348
+ function normalizeFinishReason2(value) {
37349
+ if (value === "content-filter") return "content_filter";
37350
+ if (value === "tool-calls") return "tool_calls";
37351
+ return value;
37352
+ }
37353
+ function safeJsonStringify(value) {
37354
+ try {
37355
+ return JSON.stringify(value) ?? "null";
37356
+ } catch {
37357
+ return "null";
37358
+ }
37359
+ }
37360
+ function turnKey3(sessionId, turnId) {
37361
+ return `${sessionId}:${turnId}`;
37362
+ }
37363
+ function turnIdempotencyKey(sessionId, turnId) {
37364
+ return `turn:${sessionId}:${turnId}`;
37365
+ }
37366
+ function actionIdempotencyKey(sessionId, turnId, callId) {
37367
+ return `action:${sessionId}:${turnId}:${callId}`;
37368
+ }
37369
+
37370
+ // src/instrumentation/plugins/eve-instrumentation.ts
37371
+ var EVE_INSTRUMENTATION_PROVIDER = /* @__PURE__ */ Symbol.for("eve.instrumentation.provider");
37372
+ function braintrustEveInstrumentation(options) {
37373
+ const definition = "defineState" in options ? createLegacyEveInstrumentation(options) : createEveInstrumentationProvider(options);
37374
+ const declaration = {
37375
+ ...definition,
37376
+ [EVE_INSTRUMENTATION_PROVIDER]: true
37377
+ };
37378
+ return declaration;
37379
+ }
37380
+
36171
37381
  // src/instrumentation/config.ts
36172
37382
  var envIntegrationAliases = {
36173
37383
  openai: "openai",