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
@@ -653,8 +653,6 @@ function newGlobalTracingChannel(nameOrChannels) {
653
653
  var DefaultAsyncLocalStorage = class {
654
654
  constructor() {
655
655
  }
656
- enterWith(_) {
657
- }
658
656
  run(_, callback) {
659
657
  return callback();
660
658
  }
@@ -2576,7 +2574,9 @@ var AclObjectType = z6.union([
2576
2574
  "project_log",
2577
2575
  "org_project",
2578
2576
  "org_audit_logs",
2579
- "project_group"
2577
+ "project_group",
2578
+ "ai_secret",
2579
+ "org_ai_secret"
2580
2580
  ]),
2581
2581
  z6.null()
2582
2582
  ]);
@@ -3409,7 +3409,7 @@ var PromptParserNullish = z6.union([
3409
3409
  }),
3410
3410
  z6.null()
3411
3411
  ]);
3412
- var PreprocessorSavedFunctionId = z6.union([
3412
+ var PreprocessorId = z6.union([
3413
3413
  z6.object({
3414
3414
  type: z6.literal("function"),
3415
3415
  id: z6.string(),
@@ -3420,6 +3420,7 @@ var PreprocessorSavedFunctionId = z6.union([
3420
3420
  name: z6.string(),
3421
3421
  function_type: z6.literal("preprocessor").optional().default("preprocessor")
3422
3422
  }),
3423
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
3423
3424
  z6.null()
3424
3425
  ]);
3425
3426
  var PromptDataNullish = z6.union([
@@ -3427,7 +3428,7 @@ var PromptDataNullish = z6.union([
3427
3428
  prompt: PromptBlockDataNullish,
3428
3429
  options: PromptOptionsNullish,
3429
3430
  parser: PromptParserNullish,
3430
- preprocessor: PreprocessorSavedFunctionId,
3431
+ preprocessor: PreprocessorId,
3431
3432
  tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
3432
3433
  template_format: z6.union([
3433
3434
  z6.enum(["mustache", "nunjucks", "none"]),
@@ -3629,7 +3630,7 @@ var PromptData = z6.object({
3629
3630
  prompt: PromptBlockDataNullish,
3630
3631
  options: PromptOptionsNullish,
3631
3632
  parser: PromptParserNullish,
3632
- preprocessor: PreprocessorSavedFunctionId,
3633
+ preprocessor: PreprocessorId,
3633
3634
  tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
3634
3635
  template_format: z6.union([
3635
3636
  z6.enum(["mustache", "nunjucks", "none"]),
@@ -4573,6 +4574,7 @@ var View = z6.object({
4573
4574
  ]),
4574
4575
  name: z6.string(),
4575
4576
  description: z6.union([z6.string(), z6.null()]).optional(),
4577
+ starred: z6.boolean().optional(),
4576
4578
  created: z6.union([z6.string(), z6.null()]).optional(),
4577
4579
  updated_at: z6.union([z6.string(), z6.null()]).optional(),
4578
4580
  view_data: ViewData.optional(),
@@ -4662,6 +4664,34 @@ var registerTemplatePlugin = templateRegistry.register.bind(templateRegistry);
4662
4664
  var getTemplateRenderer = templateRegistry.get.bind(templateRegistry);
4663
4665
  registerTemplatePlugin(mustachePlugin);
4664
4666
 
4667
+ // src/template/renderer.ts
4668
+ function isTemplateFormat(v) {
4669
+ return v === "mustache" || v === "nunjucks" || v === "none";
4670
+ }
4671
+ function parseTemplateFormat(value, defaultFormat = "mustache") {
4672
+ return isTemplateFormat(value) ? value : defaultFormat;
4673
+ }
4674
+ function renderTemplateContent(template, variables, escape, options) {
4675
+ const strict = !!options.strict;
4676
+ const templateFormat = parseTemplateFormat(options.templateFormat);
4677
+ if (templateFormat === "none") {
4678
+ return template;
4679
+ }
4680
+ const renderer = getTemplateRenderer(templateFormat);
4681
+ if (!renderer) {
4682
+ if (templateFormat === "nunjucks") {
4683
+ throw new Error(
4684
+ "Nunjucks templating requires @braintrust/template-nunjucks. Install and import it to enable templateFormat: 'nunjucks'."
4685
+ );
4686
+ }
4687
+ throw new Error(`No template renderer registered for ${templateFormat}`);
4688
+ }
4689
+ if (strict && renderer.lint) {
4690
+ renderer.lint(template, variables);
4691
+ }
4692
+ return renderer.render(template, variables, escape, strict);
4693
+ }
4694
+
4665
4695
  // src/logger.ts
4666
4696
  import { z as z8, ZodError } from "zod/v3";
4667
4697
 
@@ -5248,44 +5278,72 @@ function createCacheLayers({
5248
5278
  }
5249
5279
 
5250
5280
  // src/prompt-cache/prompt-cache.ts
5251
- function createCacheKey(key) {
5281
+ function createCacheKey(key, namespace) {
5282
+ let cacheKey;
5252
5283
  if (key.id) {
5253
- return `id:${key.id}`;
5254
- }
5255
- const prefix = key.projectId ?? key.projectName;
5256
- if (!prefix) {
5257
- throw new Error("Either projectId or projectName must be provided");
5258
- }
5259
- if (!key.slug) {
5260
- throw new Error("Slug must be provided when not using ID");
5284
+ cacheKey = `id:${key.id}`;
5285
+ } else {
5286
+ const prefix = key.projectId ?? key.projectName;
5287
+ if (!prefix) {
5288
+ throw new Error("Either projectId or projectName must be provided");
5289
+ }
5290
+ if (!key.slug) {
5291
+ throw new Error("Slug must be provided when not using ID");
5292
+ }
5293
+ cacheKey = `${prefix}:${key.slug}:${key.version ?? "latest"}`;
5261
5294
  }
5262
- return `${prefix}:${key.slug}:${key.version ?? "latest"}`;
5295
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
5263
5296
  }
5264
- var PromptCache = class {
5297
+ var PromptCache = class _PromptCache {
5265
5298
  memoryCache;
5266
5299
  diskCache;
5300
+ namespace;
5301
+ expectedResolvedOrgIdentity;
5267
5302
  constructor(options) {
5268
5303
  this.memoryCache = options.memoryCache;
5269
5304
  this.diskCache = options.diskCache;
5305
+ this.namespace = options.namespace;
5306
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
5307
+ }
5308
+ /**
5309
+ * Returns a cache view that shares the same storage layers but isolates all
5310
+ * entries under the provided namespace.
5311
+ */
5312
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
5313
+ return new _PromptCache({
5314
+ memoryCache: this.memoryCache,
5315
+ diskCache: this.diskCache,
5316
+ namespace,
5317
+ expectedResolvedOrgIdentity
5318
+ });
5270
5319
  }
5271
5320
  /**
5272
5321
  * Retrieves a prompt from the cache.
5273
5322
  * First checks the in-memory LRU cache, then falls back to checking the disk cache if available.
5274
5323
  */
5275
5324
  async get(key) {
5276
- const cacheKey = createCacheKey(key);
5325
+ const cacheKey = createCacheKey(key, this.namespace);
5277
5326
  if (this.memoryCache) {
5278
- const memoryPrompt = this.memoryCache.get(cacheKey);
5279
- if (memoryPrompt !== void 0) {
5280
- return memoryPrompt;
5327
+ const memoryEntry = this.memoryCache.get(cacheKey);
5328
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
5329
+ return memoryEntry.value;
5281
5330
  }
5282
5331
  }
5283
5332
  if (this.diskCache) {
5284
- const diskPrompt = await this.diskCache.get(cacheKey);
5285
- if (!diskPrompt) {
5333
+ const diskEntry = await this.diskCache.get(cacheKey);
5334
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
5286
5335
  return void 0;
5287
5336
  }
5288
- this.memoryCache?.set(cacheKey, diskPrompt);
5337
+ const serializedPrompt = diskEntry.value;
5338
+ const diskPrompt = new Prompt2(
5339
+ serializedPrompt.metadata,
5340
+ serializedPrompt.defaults,
5341
+ serializedPrompt.noTrace
5342
+ );
5343
+ this.memoryCache?.set(cacheKey, {
5344
+ value: diskPrompt,
5345
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
5346
+ });
5289
5347
  return diskPrompt;
5290
5348
  }
5291
5349
  return void 0;
@@ -5299,58 +5357,91 @@ var PromptCache = class {
5299
5357
  * @throws If there is an error writing to the disk cache.
5300
5358
  */
5301
5359
  async set(key, value) {
5302
- const cacheKey = createCacheKey(key);
5303
- this.memoryCache?.set(cacheKey, value);
5360
+ const cacheKey = createCacheKey(key, this.namespace);
5361
+ const memoryEntry = {
5362
+ value,
5363
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5364
+ };
5365
+ this.memoryCache?.set(cacheKey, memoryEntry);
5304
5366
  if (this.diskCache) {
5305
- await this.diskCache.set(cacheKey, value);
5367
+ await this.diskCache.set(cacheKey, {
5368
+ value: value._internalSerializeForCache(),
5369
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5370
+ });
5306
5371
  }
5307
5372
  }
5308
5373
  };
5309
5374
 
5310
5375
  // src/prompt-cache/parameters-cache.ts
5311
- function createCacheKey2(key) {
5376
+ function createCacheKey2(key, namespace) {
5377
+ let cacheKey;
5312
5378
  if (key.id) {
5313
- return `parameters:id:${key.id}`;
5314
- }
5315
- const prefix = key.projectId ?? key.projectName;
5316
- if (!prefix) {
5317
- throw new Error("Either projectId or projectName must be provided");
5318
- }
5319
- if (!key.slug) {
5320
- throw new Error("Slug must be provided when not using ID");
5379
+ cacheKey = `parameters:id:${key.id}`;
5380
+ } else {
5381
+ const prefix = key.projectId ?? key.projectName;
5382
+ if (!prefix) {
5383
+ throw new Error("Either projectId or projectName must be provided");
5384
+ }
5385
+ if (!key.slug) {
5386
+ throw new Error("Slug must be provided when not using ID");
5387
+ }
5388
+ cacheKey = `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
5321
5389
  }
5322
- return `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
5390
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
5323
5391
  }
5324
- var ParametersCache = class {
5392
+ var ParametersCache = class _ParametersCache {
5325
5393
  memoryCache;
5326
5394
  diskCache;
5395
+ namespace;
5396
+ expectedResolvedOrgIdentity;
5327
5397
  constructor(options) {
5328
5398
  this.memoryCache = options.memoryCache;
5329
5399
  this.diskCache = options.diskCache;
5400
+ this.namespace = options.namespace;
5401
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
5402
+ }
5403
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
5404
+ return new _ParametersCache({
5405
+ memoryCache: this.memoryCache,
5406
+ diskCache: this.diskCache,
5407
+ namespace,
5408
+ expectedResolvedOrgIdentity
5409
+ });
5330
5410
  }
5331
5411
  async get(key) {
5332
- const cacheKey = createCacheKey2(key);
5412
+ const cacheKey = createCacheKey2(key, this.namespace);
5333
5413
  if (this.memoryCache) {
5334
- const memoryParams = this.memoryCache.get(cacheKey);
5335
- if (memoryParams !== void 0) {
5336
- return memoryParams;
5414
+ const memoryEntry = this.memoryCache.get(cacheKey);
5415
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
5416
+ return memoryEntry.value;
5337
5417
  }
5338
5418
  }
5339
5419
  if (this.diskCache) {
5340
- const diskParams = await this.diskCache.get(cacheKey);
5341
- if (!diskParams) {
5420
+ const diskEntry = await this.diskCache.get(cacheKey);
5421
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
5342
5422
  return void 0;
5343
5423
  }
5344
- this.memoryCache?.set(cacheKey, diskParams);
5345
- return diskParams;
5424
+ const diskParameters = new RemoteEvalParameters(diskEntry.value.metadata);
5425
+ this.memoryCache?.set(cacheKey, {
5426
+ value: diskParameters,
5427
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
5428
+ });
5429
+ return diskParameters;
5346
5430
  }
5347
5431
  return void 0;
5348
5432
  }
5349
5433
  async set(key, value) {
5350
- const cacheKey = createCacheKey2(key);
5351
- this.memoryCache?.set(cacheKey, value);
5434
+ const cacheKey = createCacheKey2(key, this.namespace);
5435
+ const memoryEntry = {
5436
+ value,
5437
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5438
+ };
5439
+ this.memoryCache?.set(cacheKey, memoryEntry);
5352
5440
  if (this.diskCache) {
5353
- await this.diskCache.set(cacheKey, value);
5441
+ await this.diskCache.set(cacheKey, {
5442
+ value: value._internalSerializeForCache(),
5443
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5444
+ });
5354
5445
  }
5355
5446
  }
5356
5447
  };
@@ -5654,6 +5745,7 @@ var INSTRUMENTATION_NAMES = {
5654
5745
  CLOUDFLARE_THINK: "cloudflare-think",
5655
5746
  COHERE: "cohere",
5656
5747
  CURSOR_SDK: "cursor-sdk",
5748
+ DEEPSEEK_HARNESS: "deepseek-harness",
5657
5749
  EVE: "eve",
5658
5750
  FLUE: "flue",
5659
5751
  GENKIT: "genkit",
@@ -5679,7 +5771,7 @@ var INSTRUMENTATION_NAMES = {
5679
5771
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5680
5772
  "braintrust.spanInstrumentationName"
5681
5773
  );
5682
- var SDK_VERSION = true ? "3.28.0" : "0.0.0";
5774
+ var SDK_VERSION = true ? "3.29.0" : "0.0.0";
5683
5775
  function withSpanInstrumentationName(args, instrumentationName) {
5684
5776
  return {
5685
5777
  ...args,
@@ -5798,6 +5890,16 @@ var datasetSnapshotRegisterResponseSchema = z8.object({
5798
5890
  dataset_snapshot: DatasetSnapshot,
5799
5891
  found_existing: z8.boolean().optional()
5800
5892
  });
5893
+ var datasetObjectInfoSchema = z8.object({
5894
+ object_id: z8.string(),
5895
+ object_name: z8.string(),
5896
+ parent_cols: z8.object({
5897
+ project: z8.object({
5898
+ id: z8.string(),
5899
+ name: z8.string()
5900
+ })
5901
+ })
5902
+ });
5801
5903
  var datasetRestorePreviewResultSchema = z8.object({
5802
5904
  rows_to_restore: z8.number(),
5803
5905
  rows_to_delete: z8.number()
@@ -6011,12 +6113,53 @@ var loginSchema = z8.strictObject({
6011
6113
  });
6012
6114
  var stateNonce = 0;
6013
6115
  var V1_PROXY_SUFFIX = "/v1/proxy";
6116
+ var LOADER_LOGIN_CACHE_MAX = 16;
6014
6117
  function normalizeProxyConnUrl(proxyUrl) {
6015
6118
  return proxyUrl.endsWith(V1_PROXY_SUFFIX) ? proxyUrl.slice(0, proxyUrl.length - V1_PROXY_SUFFIX.length) : proxyUrl;
6016
6119
  }
6017
6120
  var BraintrustState = class _BraintrustState {
6121
+ id;
6122
+ currentExperiment;
6123
+ // Note: the value of IsAsyncFlush doesn't really matter here, since we
6124
+ // (safely) dynamically cast it whenever retrieving the logger.
6125
+ currentLogger;
6126
+ currentParent;
6127
+ currentSpan;
6128
+ // Any time we re-log in, we directly update the apiConn inside the logger.
6129
+ // This is preferable to replacing the whole logger, which would create the
6130
+ // possibility of multiple loggers floating around, which may not log in a
6131
+ // deterministic order.
6132
+ _bgLogger;
6133
+ _overrideBgLogger = null;
6134
+ appUrl = null;
6135
+ appPublicUrl = null;
6136
+ loginToken = null;
6137
+ orgId = null;
6138
+ orgName = null;
6139
+ apiUrl = null;
6140
+ proxyUrl = null;
6141
+ loggedIn = false;
6142
+ gitMetadataSettings;
6143
+ debugLogLevel;
6144
+ debugLogLevelConfigured = false;
6145
+ fetch = globalThis.fetch;
6146
+ _appConn = null;
6147
+ _apiConn = null;
6148
+ _proxyConn = null;
6149
+ promptCache;
6150
+ parametersCache;
6151
+ spanCache;
6152
+ _idGenerator = null;
6153
+ _contextManager = null;
6154
+ _otelFlushCallback = null;
6155
+ spanOriginEnvironment;
6156
+ traceContextSigningSecret;
6157
+ loaderLoginCache = /* @__PURE__ */ new WeakMap();
6158
+ loginParams;
6159
+ activeLoginOrgNameSelector;
6018
6160
  constructor(loginParams) {
6019
- this.loginParams = loginParams;
6161
+ this.loginParams = { ...loginParams };
6162
+ this.activeLoginOrgNameSelector = loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
6020
6163
  this.id = `${(/* @__PURE__ */ new Date()).toLocaleString()}-${stateNonce++}`;
6021
6164
  this.currentExperiment = void 0;
6022
6165
  this.currentLogger = void 0;
@@ -6053,12 +6196,14 @@ var BraintrustState = class _BraintrustState {
6053
6196
  const {
6054
6197
  memoryCache: parametersMemoryCache,
6055
6198
  diskCache: parametersDiskCache
6056
- } = createCacheLayers({
6057
- memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
6058
- diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
6059
- diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
6060
- getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
6061
- });
6199
+ } = createCacheLayers(
6200
+ {
6201
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
6202
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
6203
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
6204
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
6205
+ }
6206
+ );
6062
6207
  this.parametersCache = new ParametersCache({
6063
6208
  memoryCache: parametersMemoryCache,
6064
6209
  diskCache: parametersDiskCache
@@ -6067,43 +6212,6 @@ var BraintrustState = class _BraintrustState {
6067
6212
  this.spanOriginEnvironment = detectSpanOriginEnvironment();
6068
6213
  this._internalSetTraceContextSigningSecret(loginParams.apiKey);
6069
6214
  }
6070
- loginParams;
6071
- id;
6072
- currentExperiment;
6073
- // Note: the value of IsAsyncFlush doesn't really matter here, since we
6074
- // (safely) dynamically cast it whenever retrieving the logger.
6075
- currentLogger;
6076
- currentParent;
6077
- currentSpan;
6078
- // Any time we re-log in, we directly update the apiConn inside the logger.
6079
- // This is preferable to replacing the whole logger, which would create the
6080
- // possibility of multiple loggers floating around, which may not log in a
6081
- // deterministic order.
6082
- _bgLogger;
6083
- _overrideBgLogger = null;
6084
- appUrl = null;
6085
- appPublicUrl = null;
6086
- loginToken = null;
6087
- orgId = null;
6088
- orgName = null;
6089
- apiUrl = null;
6090
- proxyUrl = null;
6091
- loggedIn = false;
6092
- gitMetadataSettings;
6093
- debugLogLevel;
6094
- debugLogLevelConfigured = false;
6095
- fetch = globalThis.fetch;
6096
- _appConn = null;
6097
- _apiConn = null;
6098
- _proxyConn = null;
6099
- promptCache;
6100
- parametersCache;
6101
- spanCache;
6102
- _idGenerator = null;
6103
- _contextManager = null;
6104
- _otelFlushCallback = null;
6105
- spanOriginEnvironment;
6106
- traceContextSigningSecret;
6107
6215
  /** @internal */
6108
6216
  _internalSetTraceContextSigningSecret(secret) {
6109
6217
  const normalizedSecret = secret?.trim();
@@ -6128,6 +6236,101 @@ var BraintrustState = class _BraintrustState {
6128
6236
  this._appConn = null;
6129
6237
  this._apiConn = null;
6130
6238
  this._proxyConn = null;
6239
+ this.loaderLoginCache = /* @__PURE__ */ new WeakMap();
6240
+ }
6241
+ /** @internal */
6242
+ async _internalResolveLoaderLoginOptions({
6243
+ apiKey,
6244
+ appUrl,
6245
+ orgName,
6246
+ fetch: fetch2,
6247
+ forceLogin
6248
+ }) {
6249
+ const resolvedAppUrl = appUrl ?? (this.loggedIn ? this.appUrl ?? void 0 : void 0) ?? this.loginParams.appUrl ?? isomorph_default.getEnv("BRAINTRUST_APP_URL") ?? "https://www.braintrust.dev";
6250
+ const resolvedApiKey = apiKey ?? (this.loggedIn ? this.loginToken ?? void 0 : void 0) ?? this.loginParams.apiKey ?? await isomorph_default.getBraintrustApiKey();
6251
+ if (!resolvedApiKey) {
6252
+ throw new Error(
6253
+ "Please specify an api key (e.g. by setting BRAINTRUST_API_KEY)."
6254
+ );
6255
+ }
6256
+ const normalizedApiKey = HTTPConnection.sanitize_token(resolvedApiKey);
6257
+ const usesActiveCredential = this.loggedIn && normalizedApiKey === this.loginToken;
6258
+ const requestedOrgName = orgName ?? (usesActiveCredential ? this.activeLoginOrgNameSelector : void 0) ?? this.loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
6259
+ const resolvedOrgName = orgName ?? (usesActiveCredential ? this.orgName ?? void 0 : void 0) ?? requestedOrgName;
6260
+ const resolvedFetch = fetch2 ?? (this.loggedIn ? this.fetch : void 0) ?? this.loginParams.fetch ?? globalThis.fetch;
6261
+ const credentialCacheNamespace = JSON.stringify([
6262
+ "loader-credential",
6263
+ resolvedAppUrl,
6264
+ requestedOrgName,
6265
+ normalizedApiKey
6266
+ ]);
6267
+ return {
6268
+ apiKey: normalizedApiKey,
6269
+ appUrl: resolvedAppUrl,
6270
+ orgName: resolvedOrgName,
6271
+ fetch: resolvedFetch,
6272
+ forceLogin,
6273
+ credentialCacheNamespace,
6274
+ existingState: !forceLogin && usesActiveCredential && resolvedAppUrl === this.appUrl && resolvedOrgName === this.orgName && resolvedFetch === this.fetch ? this : void 0
6275
+ };
6276
+ }
6277
+ /** @internal */
6278
+ _internalGetLoaderCacheViews(loginOptions, requestState) {
6279
+ const expectedResolvedOrgIdentity = requestState?.orgId && requestState.appUrl ? JSON.stringify([
6280
+ "loader-org",
6281
+ requestState.appUrl,
6282
+ requestState.orgId
6283
+ ]) : void 0;
6284
+ return {
6285
+ promptCache: this.promptCache.withNamespace(
6286
+ loginOptions.credentialCacheNamespace,
6287
+ expectedResolvedOrgIdentity
6288
+ ),
6289
+ parametersCache: this.parametersCache.withNamespace(
6290
+ loginOptions.credentialCacheNamespace,
6291
+ expectedResolvedOrgIdentity
6292
+ )
6293
+ };
6294
+ }
6295
+ /** @internal */
6296
+ async _internalGetLoaderState({
6297
+ apiKey,
6298
+ appUrl,
6299
+ orgName,
6300
+ fetch: fetch2,
6301
+ forceLogin,
6302
+ existingState
6303
+ }) {
6304
+ if (existingState) {
6305
+ return existingState;
6306
+ }
6307
+ let cache = this.loaderLoginCache.get(fetch2);
6308
+ if (!cache) {
6309
+ cache = new LRUCache({ max: LOADER_LOGIN_CACHE_MAX });
6310
+ this.loaderLoginCache.set(fetch2, cache);
6311
+ }
6312
+ const cacheKey = JSON.stringify([appUrl, orgName, apiKey]);
6313
+ if (!forceLogin) {
6314
+ const cachedState = cache.get(cacheKey);
6315
+ if (cachedState) {
6316
+ return cachedState;
6317
+ }
6318
+ }
6319
+ const statePromise = loginToLoaderRequestState({
6320
+ orgName,
6321
+ apiKey,
6322
+ appUrl,
6323
+ fetch: fetch2
6324
+ });
6325
+ cache.set(cacheKey, statePromise);
6326
+ try {
6327
+ return await statePromise;
6328
+ } catch (error) {
6329
+ if (cache.get(cacheKey) === statePromise) {
6330
+ cache.delete(cacheKey);
6331
+ }
6332
+ throw error;
6333
+ }
6131
6334
  }
6132
6335
  resetIdGenState() {
6133
6336
  this._idGenerator = null;
@@ -6176,6 +6379,8 @@ var BraintrustState = class _BraintrustState {
6176
6379
  this.debugLogLevel = other.debugLogLevel;
6177
6380
  this.debugLogLevelConfigured = other.debugLogLevelConfigured;
6178
6381
  this.traceContextSigningSecret = other.traceContextSigningSecret;
6382
+ this.fetch = other.fetch;
6383
+ this.activeLoginOrgNameSelector = other.activeLoginOrgNameSelector;
6179
6384
  setGlobalDebugLogLevel(
6180
6385
  this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
6181
6386
  );
@@ -6370,36 +6575,76 @@ var FailedHTTPResponse = class extends Error {
6370
6575
  status;
6371
6576
  text;
6372
6577
  data;
6373
- constructor(status, text, data) {
6578
+ cause;
6579
+ constructor(status, text, data, cause) {
6374
6580
  super(`${status}: ${text} (${data})`);
6375
6581
  this.status = status;
6376
6582
  this.text = text;
6377
6583
  this.data = data;
6584
+ this.cause = cause;
6585
+ }
6586
+ };
6587
+ var HTTPTransportError = class extends Error {
6588
+ cause;
6589
+ constructor(cause) {
6590
+ super(cause instanceof Error ? cause.message : String(cause));
6591
+ this.name = "HTTPTransportError";
6592
+ this.cause = cause;
6378
6593
  }
6379
6594
  };
6595
+ var httpTransportErrorCauses = /* @__PURE__ */ new WeakSet();
6596
+ function recordHTTPTransportError(error) {
6597
+ if (typeof error === "object" && error !== null || typeof error === "function") {
6598
+ httpTransportErrorCauses.add(error);
6599
+ }
6600
+ }
6601
+ function rethrowHTTPTransportError(error, classifyTransportErrors) {
6602
+ if (classifyTransportErrors) {
6603
+ throw new HTTPTransportError(error);
6604
+ }
6605
+ recordHTTPTransportError(error);
6606
+ throw error;
6607
+ }
6608
+ async function readJSONResponse(response, classifyTransportErrors = false) {
6609
+ let data;
6610
+ try {
6611
+ data = await response.text();
6612
+ } catch (error) {
6613
+ rethrowHTTPTransportError(error, classifyTransportErrors);
6614
+ }
6615
+ return JSON.parse(data);
6616
+ }
6380
6617
  async function checkResponse(resp) {
6381
6618
  if (resp.ok) {
6382
6619
  return resp;
6383
- } else {
6620
+ }
6621
+ let data;
6622
+ try {
6623
+ data = await resp.text();
6624
+ } catch (error) {
6384
6625
  throw new FailedHTTPResponse(
6385
6626
  resp.status,
6386
6627
  resp.statusText,
6387
- await resp.text()
6628
+ "Unable to read response body",
6629
+ error
6388
6630
  );
6389
6631
  }
6632
+ throw new FailedHTTPResponse(resp.status, resp.statusText, data);
6390
6633
  }
6391
6634
  var HTTPConnection = class _HTTPConnection {
6392
- base_url;
6393
- token;
6394
- headers;
6395
- fetch;
6396
- constructor(base_url, fetch2) {
6635
+ constructor(base_url, fetch2, classifyTransportErrors = false) {
6636
+ this.classifyTransportErrors = classifyTransportErrors;
6397
6637
  this.base_url = base_url;
6398
6638
  this.token = null;
6399
6639
  this.headers = {};
6400
6640
  this._reset();
6401
6641
  this.fetch = fetch2;
6402
6642
  }
6643
+ classifyTransportErrors;
6644
+ base_url;
6645
+ token;
6646
+ headers;
6647
+ fetch;
6403
6648
  setFetch(fetch2) {
6404
6649
  this.fetch = fetch2;
6405
6650
  }
@@ -6439,9 +6684,9 @@ var HTTPConnection = class _HTTPConnection {
6439
6684
  ).toString();
6440
6685
  const this_fetch = this.fetch;
6441
6686
  const this_headers = this.headers;
6442
- return await checkResponse(
6443
- // Using toString() here makes it work with isomorphic fetch
6444
- await this_fetch(url.toString(), {
6687
+ let response;
6688
+ try {
6689
+ response = await this_fetch(url.toString(), {
6445
6690
  headers: {
6446
6691
  Accept: "application/json",
6447
6692
  ...this_headers,
@@ -6449,8 +6694,14 @@ var HTTPConnection = class _HTTPConnection {
6449
6694
  },
6450
6695
  keepalive: true,
6451
6696
  ...rest
6452
- })
6453
- );
6697
+ });
6698
+ } catch (error) {
6699
+ if (config?.signal?.aborted) {
6700
+ throw getAbortReason(config.signal);
6701
+ }
6702
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
6703
+ }
6704
+ return await checkResponse(response);
6454
6705
  }
6455
6706
  async post(path, params, config, retries = 0) {
6456
6707
  const { headers, ...rest } = config || {};
@@ -6460,8 +6711,9 @@ var HTTPConnection = class _HTTPConnection {
6460
6711
  const tries = retries + 1;
6461
6712
  for (let i = 0; i < tries; i++) {
6462
6713
  try {
6463
- return await checkResponse(
6464
- await this_fetch(_urljoin(this_base_url, path), {
6714
+ let response;
6715
+ try {
6716
+ response = await this_fetch(_urljoin(this_base_url, path), {
6465
6717
  method: "POST",
6466
6718
  headers: {
6467
6719
  Accept: "application/json",
@@ -6472,8 +6724,14 @@ var HTTPConnection = class _HTTPConnection {
6472
6724
  body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
6473
6725
  keepalive: true,
6474
6726
  ...rest
6475
- })
6476
- );
6727
+ });
6728
+ } catch (error) {
6729
+ if (config?.signal?.aborted) {
6730
+ throw getAbortReason(config.signal);
6731
+ }
6732
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
6733
+ }
6734
+ return await checkResponse(response);
6477
6735
  } catch (error) {
6478
6736
  if (config?.signal?.aborted) {
6479
6737
  throw getAbortReason(config.signal);
@@ -6498,7 +6756,7 @@ var HTTPConnection = class _HTTPConnection {
6498
6756
  for (let i = 0; i < tries; i++) {
6499
6757
  try {
6500
6758
  const resp = await this.get(`${object_type}`, args);
6501
- return await resp.json();
6759
+ return await readJSONResponse(resp, this.classifyTransportErrors);
6502
6760
  } catch (e) {
6503
6761
  if (i < tries - 1) {
6504
6762
  debugLogger.debug(
@@ -6521,7 +6779,7 @@ var HTTPConnection = class _HTTPConnection {
6521
6779
  const resp = await this.post(`${object_type}`, args, {
6522
6780
  headers: { "Content-Type": "application/json" }
6523
6781
  });
6524
- return await resp.json();
6782
+ return await readJSONResponse(resp, this.classifyTransportErrors);
6525
6783
  }
6526
6784
  // Custom inspect for Node.js console.log
6527
6785
  [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
@@ -8076,6 +8334,52 @@ function initLogger(options = {}) {
8076
8334
  }
8077
8335
  return ret;
8078
8336
  }
8337
+ async function loginToLoaderRequestState({
8338
+ appUrl,
8339
+ apiKey,
8340
+ orgName,
8341
+ fetch: fetch2
8342
+ }) {
8343
+ let orgId;
8344
+ let apiUrl;
8345
+ if (apiKey === TEST_API_KEY) {
8346
+ orgId = "test-org-id";
8347
+ apiUrl = "https://braintrust.dev/fake-api-url";
8348
+ } else {
8349
+ let loginResponse;
8350
+ try {
8351
+ loginResponse = await fetch2(_urljoin(appUrl, `/api/apikey/login`), {
8352
+ method: "POST",
8353
+ headers: {
8354
+ "Content-Type": "application/json",
8355
+ Authorization: `Bearer ${apiKey}`
8356
+ }
8357
+ });
8358
+ } catch (error) {
8359
+ throw new HTTPTransportError(error);
8360
+ }
8361
+ const info = await readJSONResponse(
8362
+ await checkResponse(loginResponse),
8363
+ true
8364
+ );
8365
+ const org = selectLoginOrg(info.org_info, orgName);
8366
+ orgId = org.id;
8367
+ apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
8368
+ if (!apiUrl) {
8369
+ throw new Error(
8370
+ 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."
8371
+ );
8372
+ }
8373
+ }
8374
+ const apiConnection = new HTTPConnection(apiUrl, fetch2, true);
8375
+ apiConnection.set_token(apiKey);
8376
+ apiConnection.make_long_lived();
8377
+ return {
8378
+ appUrl,
8379
+ orgId,
8380
+ apiConn: () => apiConnection
8381
+ };
8382
+ }
8079
8383
  async function loginToState(options = {}) {
8080
8384
  const {
8081
8385
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
@@ -8107,16 +8411,18 @@ async function loginToState(options = {}) {
8107
8411
  _saveOrgInfo(state, testOrgInfo, testOrgInfo[0].name);
8108
8412
  return state;
8109
8413
  } else {
8110
- const resp = await checkResponse(
8111
- await fetch2(_urljoin(state.appUrl, `/api/apikey/login`), {
8414
+ const loginResponse = await fetch2(
8415
+ _urljoin(state.appUrl, `/api/apikey/login`),
8416
+ {
8112
8417
  method: "POST",
8113
8418
  headers: {
8114
8419
  "Content-Type": "application/json",
8115
8420
  Authorization: `Bearer ${apiKey}`
8116
8421
  }
8117
- })
8422
+ }
8118
8423
  );
8119
- const info = await resp.json();
8424
+ const resp = await checkResponse(loginResponse);
8425
+ const info = await readJSONResponse(resp);
8120
8426
  _saveOrgInfo(state, info.org_info, orgName);
8121
8427
  if (!state.apiUrl) {
8122
8428
  if (orgName) {
@@ -8484,27 +8790,28 @@ function withCurrent(span, callback, state = void 0) {
8484
8790
  const currentState = state ?? _globalState;
8485
8791
  return currentState.contextManager.runInContext(span, () => callback(span));
8486
8792
  }
8487
- function _saveOrgInfo(state, org_info, org_name) {
8488
- if (org_info.length === 0) {
8793
+ function _saveOrgInfo(state, orgInfo, orgName) {
8794
+ const org = selectLoginOrg(orgInfo, orgName);
8795
+ state.orgId = org.id;
8796
+ state.orgName = org.name;
8797
+ state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
8798
+ state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
8799
+ state.gitMetadataSettings = org.git_metadata || void 0;
8800
+ }
8801
+ function selectLoginOrg(orgInfo, orgName) {
8802
+ if (orgInfo.length === 0) {
8489
8803
  throw new LoginInvalidOrgError(
8490
8804
  "This user is not part of any organizations."
8491
8805
  );
8492
8806
  }
8493
- for (const org of org_info) {
8494
- if (org_name === void 0 || org.name === org_name) {
8495
- state.orgId = org.id;
8496
- state.orgName = org.name;
8497
- state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
8498
- state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
8499
- state.gitMetadataSettings = org.git_metadata || void 0;
8500
- break;
8807
+ for (const org of orgInfo) {
8808
+ if (orgName === void 0 || org.name === orgName) {
8809
+ return org;
8501
8810
  }
8502
8811
  }
8503
- if (state.orgId === void 0) {
8504
- throw new LoginInvalidOrgError(
8505
- `Organization ${org_name} not found. Must be one of ${org_info.map((x) => x.name).join(", ")}`
8506
- );
8507
- }
8812
+ throw new LoginInvalidOrgError(
8813
+ `Organization ${orgName} not found. Must be one of ${orgInfo.map((org) => org.name).join(", ")}`
8814
+ );
8508
8815
  }
8509
8816
  function validateTags(tags) {
8510
8817
  const seen = /* @__PURE__ */ new Set();
@@ -8669,6 +8976,19 @@ function enrichAttachments(event, state) {
8669
8976
  }
8670
8977
  return event;
8671
8978
  }
8979
+ async function resolveAttachmentsToBase64(event, state) {
8980
+ for (const [key, value] of Object.entries(event)) {
8981
+ if (value instanceof ReadonlyAttachment) {
8982
+ event[key] = await value.asBase64Url();
8983
+ continue;
8984
+ }
8985
+ if (!(value instanceof Object)) {
8986
+ continue;
8987
+ }
8988
+ await resolveAttachmentsToBase64(value, state);
8989
+ }
8990
+ return event;
8991
+ }
8672
8992
  function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
8673
8993
  if ("input" in event && !isEmpty2(event.input) && "inputs" in event && !isEmpty2(event.inputs) || !("input" in event) && !("inputs" in event)) {
8674
8994
  throw new Error(
@@ -9958,6 +10278,473 @@ var Dataset2 = class extends ObjectFetcher {
9958
10278
  return typeof data === "object" && data !== null && "__braintrust_dataset_marker" in data;
9959
10279
  }
9960
10280
  };
10281
+ function isAttachmentObject(value) {
10282
+ return BraintrustAttachmentReference.safeParse(value).success || InlineAttachmentReferenceSchema.safeParse(value).success || ExternalAttachmentReference.safeParse(value).success;
10283
+ }
10284
+ function isURL(url) {
10285
+ try {
10286
+ const parsedUrl = new URL(url.trim());
10287
+ return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
10288
+ } catch {
10289
+ return false;
10290
+ }
10291
+ }
10292
+ function expandAttachmentArrayPreTemplate(content, variables) {
10293
+ if (typeof content !== "string") return null;
10294
+ const match = content.match(/^\{\{\s*([\w.]+)\s*\}\}$/);
10295
+ if (!match) return null;
10296
+ const varPath = match[1];
10297
+ const value = varPath.includes(".") ? getObjValueByPath(variables, varPath.split(".")) : variables[varPath];
10298
+ if (!Array.isArray(value)) return null;
10299
+ const allValid = value.every(
10300
+ (v) => isAttachmentObject(v) || typeof v === "string" && isURL(v)
10301
+ );
10302
+ if (!allValid) return null;
10303
+ return value.map((item) => ({
10304
+ type: "image_url",
10305
+ image_url: { url: item }
10306
+ }));
10307
+ }
10308
+ function renderMessageImpl(render, message, variables) {
10309
+ return {
10310
+ ...message,
10311
+ ..."content" in message ? {
10312
+ content: isEmpty2(message.content) ? void 0 : typeof message.content === "string" ? render(message.content) : message.content.flatMap((c) => {
10313
+ switch (c.type) {
10314
+ case "text":
10315
+ return [{ ...c, text: render(c.text) }];
10316
+ case "image_url":
10317
+ if (isObject(c.image_url.url)) {
10318
+ throw new Error(
10319
+ "Attachments must be replaced with URLs before calling `build()`"
10320
+ );
10321
+ }
10322
+ if (variables) {
10323
+ const expanded = expandAttachmentArrayPreTemplate(
10324
+ c.image_url.url,
10325
+ variables
10326
+ );
10327
+ if (expanded) {
10328
+ return expanded;
10329
+ }
10330
+ }
10331
+ return [
10332
+ {
10333
+ ...c,
10334
+ image_url: {
10335
+ ...c.image_url,
10336
+ url: render(c.image_url.url)
10337
+ }
10338
+ }
10339
+ ];
10340
+ case "file":
10341
+ return [
10342
+ {
10343
+ ...c,
10344
+ file: {
10345
+ ...c.file.file_data && {
10346
+ file_data: render(c.file.file_data)
10347
+ },
10348
+ ...c.file.file_id && {
10349
+ file_id: render(c.file.file_id)
10350
+ },
10351
+ ...c.file.filename && {
10352
+ filename: render(c.file.filename)
10353
+ }
10354
+ }
10355
+ }
10356
+ ];
10357
+ default:
10358
+ const _exhaustiveCheck = c;
10359
+ return _exhaustiveCheck;
10360
+ }
10361
+ })
10362
+ } : {},
10363
+ ..."tool_calls" in message ? {
10364
+ tool_calls: isEmpty2(message.tool_calls) ? void 0 : message.tool_calls.map((t) => {
10365
+ return {
10366
+ type: t.type,
10367
+ id: render(t.id),
10368
+ function: {
10369
+ name: render(t.function.name),
10370
+ arguments: render(t.function.arguments)
10371
+ }
10372
+ };
10373
+ })
10374
+ } : {},
10375
+ ..."tool_call_id" in message ? {
10376
+ tool_call_id: render(message.tool_call_id)
10377
+ } : {}
10378
+ };
10379
+ }
10380
+ function deserializePlainStringAsJSON(s) {
10381
+ if (s.trim() === "") {
10382
+ return { value: null, error: void 0 };
10383
+ }
10384
+ try {
10385
+ return { value: JSON.parse(s), error: void 0 };
10386
+ } catch (e) {
10387
+ return { value: s, error: e };
10388
+ }
10389
+ }
10390
+ function renderTemplatedObject(obj, args, options) {
10391
+ if (typeof obj === "string") {
10392
+ return renderTemplateContent(
10393
+ obj,
10394
+ args,
10395
+ (value) => typeof value === "string" ? value : JSON.stringify(value),
10396
+ {
10397
+ strict: options.strict,
10398
+ templateFormat: options.templateFormat
10399
+ }
10400
+ );
10401
+ } else if (isArray(obj)) {
10402
+ return obj.map((item) => renderTemplatedObject(item, args, options));
10403
+ } else if (isObject(obj)) {
10404
+ return Object.fromEntries(
10405
+ Object.entries(obj).map(([key, value]) => [
10406
+ key,
10407
+ renderTemplatedObject(value, args, options)
10408
+ ])
10409
+ );
10410
+ }
10411
+ return obj;
10412
+ }
10413
+ function renderPromptParams(params, args, options = {}) {
10414
+ const templateFormat = parseTemplateFormat(options.templateFormat);
10415
+ const strict = !!options.strict;
10416
+ const schemaParsed = z8.object({
10417
+ response_format: z8.object({
10418
+ type: z8.literal("json_schema"),
10419
+ json_schema: ResponseFormatJsonSchema.omit({ schema: true }).extend({
10420
+ schema: z8.unknown()
10421
+ })
10422
+ })
10423
+ }).safeParse(params);
10424
+ if (schemaParsed.success) {
10425
+ const rawSchema = schemaParsed.data.response_format.json_schema.schema;
10426
+ const templatedSchema = renderTemplatedObject(rawSchema, args, {
10427
+ strict,
10428
+ templateFormat
10429
+ });
10430
+ const parsedSchema = typeof templatedSchema === "string" ? deserializePlainStringAsJSON(templatedSchema).value : templatedSchema;
10431
+ return {
10432
+ ...params,
10433
+ response_format: {
10434
+ ...schemaParsed.data.response_format,
10435
+ json_schema: {
10436
+ ...schemaParsed.data.response_format.json_schema,
10437
+ schema: parsedSchema
10438
+ }
10439
+ }
10440
+ };
10441
+ }
10442
+ return params;
10443
+ }
10444
+ var Prompt2 = class _Prompt {
10445
+ constructor(metadata, defaults, noTrace) {
10446
+ this.metadata = metadata;
10447
+ this.defaults = defaults;
10448
+ this.noTrace = noTrace;
10449
+ void this.__braintrust_prompt_marker;
10450
+ }
10451
+ metadata;
10452
+ defaults;
10453
+ noTrace;
10454
+ parsedPromptData;
10455
+ hasParsedPromptData = false;
10456
+ __braintrust_prompt_marker = true;
10457
+ get id() {
10458
+ return this.metadata.id;
10459
+ }
10460
+ get projectId() {
10461
+ return this.metadata.project_id;
10462
+ }
10463
+ get name() {
10464
+ return "name" in this.metadata ? this.metadata.name : `Playground function ${this.metadata.id}`;
10465
+ }
10466
+ get slug() {
10467
+ return "slug" in this.metadata ? this.metadata.slug : this.metadata.id;
10468
+ }
10469
+ get prompt() {
10470
+ return this.getParsedPromptData()?.prompt;
10471
+ }
10472
+ get version() {
10473
+ return this.metadata[TRANSACTION_ID_FIELD];
10474
+ }
10475
+ get options() {
10476
+ return this.getParsedPromptData()?.options || {};
10477
+ }
10478
+ get templateFormat() {
10479
+ return this.getParsedPromptData()?.template_format;
10480
+ }
10481
+ get promptData() {
10482
+ return this.getParsedPromptData();
10483
+ }
10484
+ /**
10485
+ * Build the prompt with the given formatting options. The args you pass in will
10486
+ * be forwarded to the mustache template that defines the prompt and rendered with
10487
+ * the `mustache-js` library.
10488
+ *
10489
+ * @param buildArgs Args to forward along to the prompt template.
10490
+ */
10491
+ build(buildArgs, options = {}) {
10492
+ return this.runBuild(buildArgs, {
10493
+ flavor: options.flavor ?? "chat",
10494
+ messages: options.messages,
10495
+ strict: options.strict,
10496
+ templateFormat: options.templateFormat
10497
+ });
10498
+ }
10499
+ /**
10500
+ * This is a special build method that first resolves attachment references, and then
10501
+ * calls the regular build method. You should use this if you are building prompts from
10502
+ * dataset rows that contain attachments.
10503
+ *
10504
+ * @param buildArgs Args to forward along to the prompt template.
10505
+ */
10506
+ async buildWithAttachments(buildArgs, options = {}) {
10507
+ const hydrated = buildArgs instanceof Object ? await resolveAttachmentsToBase64(buildArgs, options.state) : buildArgs;
10508
+ return this.runBuild(hydrated, {
10509
+ flavor: options.flavor ?? "chat",
10510
+ messages: options.messages,
10511
+ strict: options.strict,
10512
+ templateFormat: options.templateFormat
10513
+ });
10514
+ }
10515
+ runBuild(buildArgs, options) {
10516
+ const { flavor } = options;
10517
+ const params = Object.fromEntries(
10518
+ Object.entries({
10519
+ ...this.defaults,
10520
+ ...Object.fromEntries(
10521
+ Object.entries(this.options.params || {}).filter(
10522
+ ([k, _v]) => !BRAINTRUST_PARAMS.includes(k)
10523
+ )
10524
+ ),
10525
+ ...!isEmpty2(this.options.model) ? {
10526
+ model: this.options.model
10527
+ } : {}
10528
+ }).filter(([key, value]) => key !== "response_format" || value !== null)
10529
+ );
10530
+ if (!("model" in params) || isEmpty2(params.model)) {
10531
+ throw new Error(
10532
+ "No model specified. Either specify it in the prompt or as a default"
10533
+ );
10534
+ }
10535
+ const spanInfo = this.noTrace ? {} : {
10536
+ span_info: {
10537
+ metadata: {
10538
+ prompt: this.id ? {
10539
+ variables: buildArgs,
10540
+ id: this.id,
10541
+ project_id: this.projectId,
10542
+ version: this.version,
10543
+ ..."prompt_session_id" in this.metadata ? { prompt_session_id: this.metadata.prompt_session_id } : {}
10544
+ } : void 0
10545
+ }
10546
+ }
10547
+ };
10548
+ const prompt = this.prompt;
10549
+ if (!prompt) {
10550
+ throw new Error("Empty prompt");
10551
+ }
10552
+ const dictArgParsed = z8.record(z8.unknown()).safeParse(buildArgs);
10553
+ const variables = {
10554
+ input: buildArgs,
10555
+ ...dictArgParsed.success ? dictArgParsed.data : {}
10556
+ };
10557
+ const promptDataTemplateFormat = this.templateFormat;
10558
+ const resolvedTemplateFormat = parseTemplateFormat(
10559
+ options.templateFormat ?? promptDataTemplateFormat
10560
+ );
10561
+ const renderedPrompt = _Prompt.renderPrompt({
10562
+ prompt,
10563
+ buildArgs,
10564
+ options: { ...options, templateFormat: resolvedTemplateFormat }
10565
+ });
10566
+ if (flavor === "chat") {
10567
+ if (renderedPrompt.type !== "chat") {
10568
+ throw new Error(
10569
+ "Prompt is a completion prompt. Use buildCompletion() instead"
10570
+ );
10571
+ }
10572
+ return {
10573
+ ...renderPromptParams(params, variables, {
10574
+ strict: options.strict,
10575
+ templateFormat: resolvedTemplateFormat
10576
+ }),
10577
+ ...spanInfo,
10578
+ messages: renderedPrompt.messages,
10579
+ ...renderedPrompt.tools ? {
10580
+ tools: ChatCompletionTool.array().parse(JSON.parse(renderedPrompt.tools))
10581
+ } : void 0
10582
+ };
10583
+ } else if (flavor === "completion") {
10584
+ if (renderedPrompt.type !== "completion") {
10585
+ throw new Error(`Prompt is a chat prompt. Use flavor: 'chat' instead`);
10586
+ }
10587
+ return {
10588
+ ...renderPromptParams(params, variables, {
10589
+ strict: options.strict,
10590
+ templateFormat: resolvedTemplateFormat
10591
+ }),
10592
+ ...spanInfo,
10593
+ prompt: renderedPrompt.content
10594
+ };
10595
+ } else {
10596
+ throw new Error("never!");
10597
+ }
10598
+ }
10599
+ static renderPrompt({
10600
+ prompt,
10601
+ buildArgs,
10602
+ options
10603
+ }) {
10604
+ const escape = (v) => {
10605
+ if (v === void 0) {
10606
+ throw new Error("Missing!");
10607
+ } else if (typeof v === "string") {
10608
+ return v;
10609
+ } else if (v instanceof ReadonlyAttachment) {
10610
+ throw new Error(
10611
+ "Use buildWithAttachments() to build prompts with attachments"
10612
+ );
10613
+ } else {
10614
+ return JSON.stringify(v);
10615
+ }
10616
+ };
10617
+ const dictArgParsed = z8.record(z8.unknown()).safeParse(buildArgs);
10618
+ const variables = {
10619
+ input: buildArgs,
10620
+ ...dictArgParsed.success ? dictArgParsed.data : {}
10621
+ };
10622
+ const templateFormat = parseTemplateFormat(options.templateFormat);
10623
+ if (prompt.type === "chat") {
10624
+ const render = (template) => renderTemplateContent(template, variables, escape, {
10625
+ strict: options.strict,
10626
+ templateFormat
10627
+ });
10628
+ const baseMessages = (prompt.messages || []).map(
10629
+ (m) => renderMessageImpl(render, m, variables)
10630
+ );
10631
+ const hasSystemPrompt = baseMessages.some((m) => m.role === "system");
10632
+ const messages = [
10633
+ ...baseMessages,
10634
+ ...(options.messages ?? []).filter(
10635
+ (m) => !(hasSystemPrompt && m.role === "system")
10636
+ )
10637
+ ];
10638
+ return {
10639
+ type: "chat",
10640
+ messages,
10641
+ ...prompt.tools?.trim() ? {
10642
+ tools: render(prompt.tools)
10643
+ } : void 0
10644
+ };
10645
+ } else if (prompt.type === "completion") {
10646
+ if (options.messages) {
10647
+ throw new Error(
10648
+ "extra messages are not supported for completion prompts"
10649
+ );
10650
+ }
10651
+ const content = renderTemplateContent(prompt.content, variables, escape, {
10652
+ strict: options.strict,
10653
+ templateFormat
10654
+ });
10655
+ return {
10656
+ type: "completion",
10657
+ content
10658
+ };
10659
+ } else {
10660
+ const _ = prompt;
10661
+ throw new Error(`Invalid prompt type: ${_}`);
10662
+ }
10663
+ }
10664
+ getParsedPromptData() {
10665
+ if (!this.hasParsedPromptData) {
10666
+ this.parsedPromptData = PromptData.parse(this.metadata.prompt_data);
10667
+ this.hasParsedPromptData = true;
10668
+ }
10669
+ return this.parsedPromptData;
10670
+ }
10671
+ static isPrompt(data) {
10672
+ return typeof data === "object" && data !== null && "__braintrust_prompt_marker" in data;
10673
+ }
10674
+ /** @internal */
10675
+ _internalSerializeForCache() {
10676
+ return {
10677
+ metadata: this.metadata,
10678
+ defaults: this.defaults,
10679
+ noTrace: this.noTrace
10680
+ };
10681
+ }
10682
+ static fromPromptData(name, promptData) {
10683
+ return new _Prompt(
10684
+ {
10685
+ name,
10686
+ slug: name,
10687
+ prompt_data: promptData
10688
+ },
10689
+ {},
10690
+ false
10691
+ );
10692
+ }
10693
+ };
10694
+ var RemoteEvalParameters = class {
10695
+ constructor(metadata) {
10696
+ this.metadata = metadata;
10697
+ void this.__braintrust_parameters_marker;
10698
+ }
10699
+ metadata;
10700
+ __braintrust_parameters_marker = true;
10701
+ get id() {
10702
+ return this.metadata.id;
10703
+ }
10704
+ get projectId() {
10705
+ return this.metadata.project_id;
10706
+ }
10707
+ get name() {
10708
+ return this.metadata.name;
10709
+ }
10710
+ get slug() {
10711
+ return this.metadata.slug;
10712
+ }
10713
+ get version() {
10714
+ return this.metadata[TRANSACTION_ID_FIELD];
10715
+ }
10716
+ get schema() {
10717
+ return this.metadata.function_data.__schema;
10718
+ }
10719
+ get data() {
10720
+ return this.metadata.function_data.data ?? {};
10721
+ }
10722
+ /** @internal */
10723
+ _internalSerializeForCache() {
10724
+ return { metadata: this.metadata };
10725
+ }
10726
+ validate(data) {
10727
+ if (typeof data !== "object" || data === null) {
10728
+ return false;
10729
+ }
10730
+ const schemaProps = this.schema.properties;
10731
+ if (typeof schemaProps !== "object" || schemaProps === null) {
10732
+ return true;
10733
+ }
10734
+ for (const key of Object.keys(schemaProps)) {
10735
+ if (!(key in data)) {
10736
+ const required = Array.isArray(this.schema.required) ? this.schema.required : [];
10737
+ if (required.includes(key)) {
10738
+ return false;
10739
+ }
10740
+ }
10741
+ }
10742
+ return true;
10743
+ }
10744
+ static isParameters(x) {
10745
+ return typeof x === "object" && x !== null && "__braintrust_parameters_marker" in x && x.__braintrust_parameters_marker === true;
10746
+ }
10747
+ };
9961
10748
  var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
9962
10749
 
9963
10750
  // src/instrumentation/core/channel-tracing-utils.ts
@@ -10403,56 +11190,14 @@ function suppressionStore() {
10403
11190
  autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
10404
11191
  return autoInstrumentationSuppressionStore;
10405
11192
  }
10406
- function currentFrames() {
10407
- return suppressionStore().getStore()?.frames ?? [];
10408
- }
10409
11193
  function isAutoInstrumentationSuppressed() {
10410
- const frames = currentFrames();
10411
- return frames[frames.length - 1]?.mode === "suppress";
11194
+ return suppressionStore().getStore() === true;
10412
11195
  }
10413
11196
  function runWithAutoInstrumentationSuppressed(callback) {
10414
- const frame = {
10415
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10416
- mode: "suppress"
10417
- };
10418
- return suppressionStore().run(
10419
- { frames: [...currentFrames(), frame] },
10420
- callback
10421
- );
11197
+ return suppressionStore().run(true, callback);
10422
11198
  }
10423
- function bindAutoInstrumentationSuppressionToStart(tracingChannel) {
10424
- const startChannel = tracingChannel.start;
10425
- if (!startChannel) {
10426
- return void 0;
10427
- }
10428
- const store = suppressionStore();
10429
- startChannel.bindStore(store, () => ({
10430
- frames: [
10431
- ...currentFrames(),
10432
- {
10433
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10434
- mode: "suppress"
10435
- }
10436
- ]
10437
- }));
10438
- return () => {
10439
- startChannel.unbindStore(store);
10440
- };
10441
- }
10442
- function enterAutoInstrumentationAllowed() {
10443
- const frame = {
10444
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
10445
- mode: "allow"
10446
- };
10447
- suppressionStore().enterWith({
10448
- frames: [...currentFrames(), frame]
10449
- });
10450
- return () => {
10451
- const frames = currentFrames().filter(
10452
- (candidate) => candidate.id !== frame.id
10453
- );
10454
- suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
10455
- };
11199
+ function runWithAutoInstrumentationAllowed(callback) {
11200
+ return suppressionStore().run(void 0, callback);
10456
11201
  }
10457
11202
 
10458
11203
  // src/instrumentation/core/channel-tracing.ts
@@ -11741,13 +12486,33 @@ function aggregateChatLogprobs(existing, incoming) {
11741
12486
  }
11742
12487
  return aggregated;
11743
12488
  }
12489
+ function createAggregatedChatChoice(index) {
12490
+ return {
12491
+ index,
12492
+ role: void 0,
12493
+ content: void 0,
12494
+ refusal: void 0,
12495
+ toolCallsByIndex: /* @__PURE__ */ new Map(),
12496
+ logprobs: void 0,
12497
+ finish_reason: void 0
12498
+ };
12499
+ }
12500
+ function toChatChoice(choice) {
12501
+ const toolCalls = Array.from(choice.toolCallsByIndex.entries()).sort(([left], [right]) => left - right).map(([, toolCall]) => toolCall);
12502
+ return {
12503
+ index: choice.index,
12504
+ message: {
12505
+ role: choice.role,
12506
+ content: choice.content,
12507
+ ...choice.refusal !== void 0 ? { refusal: choice.refusal } : {},
12508
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
12509
+ },
12510
+ logprobs: choice.logprobs ?? null,
12511
+ finish_reason: choice.finish_reason
12512
+ };
12513
+ }
11744
12514
  function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
11745
- let role = void 0;
11746
- let content = void 0;
11747
- let refusal = void 0;
11748
- let tool_calls = void 0;
11749
- let logprobs = void 0;
11750
- let finish_reason = void 0;
12515
+ const choicesByIndex = /* @__PURE__ */ new Map();
11751
12516
  let metrics = {};
11752
12517
  for (const chunk of chunks) {
11753
12518
  if (chunk.usage) {
@@ -11756,62 +12521,75 @@ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
11756
12521
  ...parseMetricsFromUsage(chunk.usage)
11757
12522
  };
11758
12523
  }
11759
- const choice = chunk.choices?.[0];
11760
- if (!choice) {
11761
- continue;
11762
- }
11763
- if (choice.finish_reason) {
11764
- finish_reason = choice.finish_reason;
11765
- }
11766
- logprobs = aggregateChatLogprobs(logprobs, choice.logprobs);
11767
- const delta = choice.delta;
11768
- if (!delta) {
12524
+ const choices = chunk.choices;
12525
+ if (!choices?.length) {
11769
12526
  continue;
11770
12527
  }
11771
- if (delta.finish_reason) {
11772
- finish_reason = delta.finish_reason;
11773
- }
11774
- if (!role && delta.role) {
11775
- role = delta.role;
11776
- }
11777
- if (delta.content) {
11778
- content = (content || "") + delta.content;
11779
- }
11780
- if (delta.refusal) {
11781
- refusal = (refusal || "") + delta.refusal;
11782
- }
11783
- if (delta.tool_calls) {
11784
- const toolDelta = delta.tool_calls[0];
11785
- if (!tool_calls || toolDelta.id && tool_calls[tool_calls.length - 1].id !== toolDelta.id) {
11786
- tool_calls = [
11787
- ...tool_calls || [],
11788
- {
11789
- id: toolDelta.id,
11790
- type: toolDelta.type,
11791
- function: toolDelta.function
12528
+ for (const choice of choices) {
12529
+ const choiceIndex = choice.index;
12530
+ let aggregatedChoice = choicesByIndex.get(choiceIndex);
12531
+ if (!aggregatedChoice) {
12532
+ aggregatedChoice = createAggregatedChatChoice(choiceIndex);
12533
+ choicesByIndex.set(choiceIndex, aggregatedChoice);
12534
+ }
12535
+ if (choice.finish_reason) {
12536
+ aggregatedChoice.finish_reason = choice.finish_reason;
12537
+ }
12538
+ aggregatedChoice.logprobs = aggregateChatLogprobs(
12539
+ aggregatedChoice.logprobs,
12540
+ choice.logprobs
12541
+ );
12542
+ const delta = choice.delta;
12543
+ if (!delta) {
12544
+ continue;
12545
+ }
12546
+ if (delta.finish_reason) {
12547
+ aggregatedChoice.finish_reason = delta.finish_reason;
12548
+ }
12549
+ if (!aggregatedChoice.role && delta.role) {
12550
+ aggregatedChoice.role = delta.role;
12551
+ }
12552
+ if (delta.content) {
12553
+ aggregatedChoice.content = (aggregatedChoice.content || "") + delta.content;
12554
+ }
12555
+ if (delta.refusal) {
12556
+ aggregatedChoice.refusal = (aggregatedChoice.refusal || "") + delta.refusal;
12557
+ }
12558
+ if (delta.tool_calls) {
12559
+ for (const toolDelta of delta.tool_calls) {
12560
+ let aggregatedToolCall = aggregatedChoice.toolCallsByIndex.get(
12561
+ toolDelta.index
12562
+ );
12563
+ if (!aggregatedToolCall) {
12564
+ aggregatedToolCall = {
12565
+ function: { arguments: "" }
12566
+ };
12567
+ aggregatedChoice.toolCallsByIndex.set(
12568
+ toolDelta.index,
12569
+ aggregatedToolCall
12570
+ );
11792
12571
  }
11793
- ];
11794
- } else {
11795
- tool_calls[tool_calls.length - 1].function.arguments += toolDelta.function.arguments;
12572
+ if (toolDelta.id !== void 0) {
12573
+ aggregatedToolCall.id = toolDelta.id;
12574
+ }
12575
+ if (toolDelta.type !== void 0) {
12576
+ aggregatedToolCall.type = toolDelta.type;
12577
+ }
12578
+ if (toolDelta.function?.name !== void 0) {
12579
+ aggregatedToolCall.function.name = toolDelta.function.name;
12580
+ }
12581
+ if (toolDelta.function?.arguments !== void 0) {
12582
+ aggregatedToolCall.function.arguments += toolDelta.function.arguments;
12583
+ }
12584
+ }
11796
12585
  }
11797
12586
  }
11798
12587
  }
11799
12588
  metrics = withCachedMetric(metrics, streamResult, endEvent);
12589
+ const output = Array.from(choicesByIndex.values()).sort((left, right) => left.index - right.index).map(toChatChoice);
11800
12590
  return {
11801
12591
  metrics,
11802
- output: [
11803
- {
11804
- index: 0,
11805
- message: {
11806
- role,
11807
- content,
11808
- ...refusal !== void 0 ? { refusal } : {},
11809
- tool_calls
11810
- },
11811
- logprobs: logprobs ?? null,
11812
- finish_reason
11813
- }
11814
- ]
12592
+ output: output.length > 0 ? output : [toChatChoice(createAggregatedChatChoice(0))]
11815
12593
  };
11816
12594
  }
11817
12595
  function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
@@ -13134,6 +13912,12 @@ function parseMetricsFromUsage2(usage) {
13134
13912
  }
13135
13913
  }
13136
13914
  }
13915
+ if (isObject(usage.output_tokens_details)) {
13916
+ const thinkingTokens = usage.output_tokens_details.thinking_tokens;
13917
+ if (typeof thinkingTokens === "number") {
13918
+ metrics.completion_reasoning_tokens = thinkingTokens;
13919
+ }
13920
+ }
13137
13921
  if (isObject(usage.server_tool_use)) {
13138
13922
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
13139
13923
  if (typeof value === "number") {
@@ -14090,7 +14874,6 @@ function endHarnessTurn(parent) {
14090
14874
  function braintrustAISDKTelemetry() {
14091
14875
  const operations = /* @__PURE__ */ new Map();
14092
14876
  const operationKeysByCallId = /* @__PURE__ */ new Map();
14093
- const workflowOperationKeyStore = isomorph_default.newAsyncLocalStorage();
14094
14877
  const modelSpans = /* @__PURE__ */ new Map();
14095
14878
  const objectSpans = /* @__PURE__ */ new Map();
14096
14879
  const embedSpans = /* @__PURE__ */ new Map();
@@ -14133,9 +14916,6 @@ function braintrustAISDKTelemetry() {
14133
14916
  return;
14134
14917
  }
14135
14918
  operations.delete(operationKey);
14136
- if (workflowOperationKeyStore.getStore() === operationKey) {
14137
- workflowOperationKeyStore.enterWith(void 0);
14138
- }
14139
14919
  const keys = operationKeysByCallId.get(state.callId);
14140
14920
  if (!keys) {
14141
14921
  return;
@@ -14183,14 +14963,7 @@ function braintrustAISDKTelemetry() {
14183
14963
  return key;
14184
14964
  }
14185
14965
  }
14186
- const workflowOperationKey = workflowOperationKeyStore.getStore();
14187
- if (workflowOperationKey && keys.includes(workflowOperationKey)) {
14188
- return workflowOperationKey;
14189
- }
14190
- if (callId === "workflow-agent") {
14191
- return void 0;
14192
- }
14193
- return mode === "finish" ? keys[0] : keys[keys.length - 1];
14966
+ return callId === "workflow-agent" || mode === "active" ? keys[keys.length - 1] : keys[0];
14194
14967
  };
14195
14968
  const operationKeyFromEvent = (event, mode = "active") => {
14196
14969
  const explicit = explicitOperationKey(event);
@@ -14204,17 +14977,13 @@ function braintrustAISDKTelemetry() {
14204
14977
  if (operationKey) {
14205
14978
  return operationKey;
14206
14979
  }
14207
- const workflowOperationKey2 = workflowOperationKeyStore.getStore();
14208
- if (workflowOperationKey2 && operations.has(workflowOperationKey2)) {
14209
- return workflowOperationKey2;
14980
+ const workflowAgentKeys2 = operationKeysByCallId.get("workflow-agent");
14981
+ if (workflowAgentKeys2?.length) {
14982
+ return workflowAgentKeys2[workflowAgentKeys2.length - 1];
14210
14983
  }
14211
14984
  return callId === "workflow-agent" ? void 0 : callId;
14212
14985
  }
14213
14986
  }
14214
- const workflowOperationKey = workflowOperationKeyStore.getStore();
14215
- if (workflowOperationKey && operations.has(workflowOperationKey)) {
14216
- return workflowOperationKey;
14217
- }
14218
14987
  const wrapperSpan = currentWorkflowAgentWrapperSpan();
14219
14988
  if (wrapperSpan?.spanId) {
14220
14989
  for (const [operationKey, state] of operations) {
@@ -14224,8 +14993,8 @@ function braintrustAISDKTelemetry() {
14224
14993
  }
14225
14994
  }
14226
14995
  const workflowAgentKeys = operationKeysByCallId.get("workflow-agent");
14227
- if (workflowAgentKeys?.length === 1) {
14228
- return workflowAgentKeys[0];
14996
+ if (workflowAgentKeys?.length) {
14997
+ return workflowAgentKeys[workflowAgentKeys.length - 1];
14229
14998
  }
14230
14999
  if (operations.size === 1) {
14231
15000
  return operations.keys().next().value;
@@ -14428,9 +15197,6 @@ function braintrustAISDKTelemetry() {
14428
15197
  if (!ownsSpan) {
14429
15198
  return;
14430
15199
  }
14431
- if (workflowAgent) {
14432
- workflowOperationKeyStore.enterWith(operationKey);
14433
- }
14434
15200
  let metadata = metadataFromEvent(event);
14435
15201
  const logPayload = { metadata };
14436
15202
  const workflowAgentCallInput = workflowAgent ? operationInput(event, operationName) : void 0;
@@ -14902,6 +15668,10 @@ var aiSDKChannels = defineChannels(
14902
15668
  channelName: "generateText",
14903
15669
  kind: "async"
14904
15670
  }),
15671
+ generateImage: channel({
15672
+ channelName: "generateImage",
15673
+ kind: "async"
15674
+ }),
14905
15675
  streamText: channel({
14906
15676
  channelName: "streamText",
14907
15677
  kind: "async"
@@ -15089,7 +15859,7 @@ var AISDKPlugin = class extends BasePlugin {
15089
15859
  }
15090
15860
  subscribeToAISDK() {
15091
15861
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
15092
- this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
15862
+ this.unsubscribers.push(interceptAISDKV7TelemetryDispatcher());
15093
15863
  this.unsubscribers.push(subscribeToHarnessAgentCreateSession());
15094
15864
  this.unsubscribers.push(
15095
15865
  subscribeToHarnessContinuation(
@@ -15117,6 +15887,18 @@ var AISDKPlugin = class extends BasePlugin {
15117
15887
  aggregateChunks: aggregateAISDKChunks
15118
15888
  })
15119
15889
  );
15890
+ this.unsubscribers.push(
15891
+ traceAsyncChannel(aiSDKChannels.generateImage, {
15892
+ name: "generateImage",
15893
+ type: "llm" /* LLM */,
15894
+ extractInput: ([params], event) => prepareAISDKGenerateImageInput(params, event.self),
15895
+ extractOutput: (result, endEvent) => processAISDKGenerateImageOutput(
15896
+ result,
15897
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15898
+ ),
15899
+ extractMetrics: (result) => extractTokenMetrics(result)
15900
+ })
15901
+ );
15120
15902
  this.unsubscribers.push(
15121
15903
  traceStreamingChannel(aiSDKChannels.streamText, {
15122
15904
  name: "streamText",
@@ -15606,26 +16388,29 @@ function subscribeToHarnessContinuation(continuationChannel, defaultDenyOutputPa
15606
16388
  channel2.unsubscribe(handlers);
15607
16389
  };
15608
16390
  }
15609
- function subscribeToAISDKV7TelemetryDispatcher() {
15610
- const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
16391
+ function interceptAISDKV7TelemetryDispatcher() {
15611
16392
  const telemetry = braintrustAISDKTelemetry();
15612
- const handlers = {
15613
- end: (event) => {
15614
- const telemetryOptions = event.arguments?.[0]?.telemetry;
15615
- if (telemetryOptions?.isEnabled === false) {
15616
- return;
16393
+ return aiSDKChannels.v7CreateTelemetryDispatcher.intercept(
16394
+ (target, thisArg, args) => {
16395
+ const dispatcher = Reflect.apply(target, thisArg, args);
16396
+ const telemetryOptions = args[0]?.telemetry;
16397
+ if (telemetryOptions?.isEnabled !== false) {
16398
+ try {
16399
+ patchAISDKV7TelemetryDispatcher(
16400
+ dispatcher,
16401
+ telemetry,
16402
+ telemetryOptions
16403
+ );
16404
+ } catch (error) {
16405
+ debugLogger.error(
16406
+ "Error instrumenting AI SDK v7 telemetry dispatcher:",
16407
+ error
16408
+ );
16409
+ }
15617
16410
  }
15618
- patchAISDKV7TelemetryDispatcher(
15619
- event.result,
15620
- telemetry,
15621
- telemetryOptions
15622
- );
16411
+ return dispatcher;
15623
16412
  }
15624
- };
15625
- channel2.subscribe(handlers);
15626
- return () => {
15627
- channel2.unsubscribe(handlers);
15628
- };
16413
+ );
15629
16414
  }
15630
16415
  function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry, telemetryOptions) {
15631
16416
  if (!isObject(dispatcher)) {
@@ -15950,16 +16735,10 @@ var convertImageToAttachment = (image, explicitMimeType) => {
15950
16735
  }
15951
16736
  }
15952
16737
  if (explicitMimeType) {
15953
- if (image instanceof Uint8Array) {
15954
- return new Attachment({
15955
- data: new Blob([image], { type: explicitMimeType }),
15956
- filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
15957
- contentType: explicitMimeType
15958
- });
15959
- }
15960
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
16738
+ const blob = convertDataToBlob(image, explicitMimeType);
16739
+ if (blob) {
15961
16740
  return new Attachment({
15962
- data: new Blob([image], { type: explicitMimeType }),
16741
+ data: blob,
15963
16742
  filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
15964
16743
  contentType: explicitMimeType
15965
16744
  });
@@ -16013,6 +16792,25 @@ var convertDataToAttachment = (data, mimeType, filename) => {
16013
16792
  function processAISDKCallInput(params) {
16014
16793
  return processInputAttachmentsSync(params);
16015
16794
  }
16795
+ function processAISDKGenerateImageInput(params) {
16796
+ const prompt = params.prompt;
16797
+ if (!isObject(prompt) || Array.isArray(prompt)) {
16798
+ return processAISDKCallInput(params);
16799
+ }
16800
+ const processedPrompt = { ...prompt };
16801
+ if (Array.isArray(prompt.images)) {
16802
+ processedPrompt.images = prompt.images.map(
16803
+ (image) => convertImageToAttachment(image, "image/png") ?? image
16804
+ );
16805
+ }
16806
+ if (prompt.mask !== void 0) {
16807
+ processedPrompt.mask = convertImageToAttachment(prompt.mask, "image/png") ?? prompt.mask;
16808
+ }
16809
+ return processAISDKCallInput({
16810
+ ...params,
16811
+ prompt: processedPrompt
16812
+ });
16813
+ }
16016
16814
  function processAISDKWorkflowAgentCallInput(params) {
16017
16815
  const processed = processAISDKCallInput(params);
16018
16816
  return {
@@ -16151,6 +16949,12 @@ function prepareAISDKEmbedInput(params, self) {
16151
16949
  metadata: extractMetadataFromEmbedParams(params, self)
16152
16950
  };
16153
16951
  }
16952
+ function prepareAISDKGenerateImageInput(params, self) {
16953
+ return {
16954
+ input: processAISDKGenerateImageInput(params).input,
16955
+ metadata: extractMetadataFromCallParams(params, self)
16956
+ };
16957
+ }
16154
16958
  function prepareAISDKRerankInput(params, self) {
16155
16959
  const { documents, query } = params;
16156
16960
  return {
@@ -17526,6 +18330,57 @@ function processAISDKOutput(output, denyOutputPaths) {
17526
18330
  }
17527
18331
  return normalizeAISDKLoggedOutput(sanitized);
17528
18332
  }
18333
+ function processAISDKGenerateImageOutput(output, denyOutputPaths) {
18334
+ if (!output || typeof output !== "object") {
18335
+ return output;
18336
+ }
18337
+ const summarized = {};
18338
+ for (const field of [
18339
+ "usage",
18340
+ "warnings",
18341
+ "providerMetadata",
18342
+ "experimental_providerMetadata",
18343
+ "responses"
18344
+ ]) {
18345
+ const value = safeSerializableFieldRead(output, field);
18346
+ if (value !== void 0 && isSerializableOutputValue(value)) {
18347
+ summarized[field] = value;
18348
+ }
18349
+ }
18350
+ const images = safeSerializableFieldRead(output, "images");
18351
+ const image = safeSerializableFieldRead(output, "image");
18352
+ const generatedFiles = Array.isArray(images) && images.length > 0 ? images : image !== void 0 ? [image] : [];
18353
+ const loggedOutput = normalizeAISDKLoggedOutput(
18354
+ omit(summarized, denyOutputPaths)
18355
+ );
18356
+ if (generatedFiles.length > 0) {
18357
+ loggedOutput.images = generatedFiles.map(
18358
+ (file, index) => convertAISDKGeneratedFileToAttachment(file, index)
18359
+ );
18360
+ }
18361
+ return loggedOutput;
18362
+ }
18363
+ function convertAISDKGeneratedFileToAttachment(file, index) {
18364
+ if (!file || typeof file !== "object") {
18365
+ return file;
18366
+ }
18367
+ const generatedFile = file;
18368
+ const generatedMediaType = safeSerializableFieldRead(
18369
+ generatedFile,
18370
+ "mediaType"
18371
+ );
18372
+ const mediaType = typeof generatedMediaType === "string" ? generatedMediaType : "application/octet-stream";
18373
+ const data = safeSerializableFieldRead(generatedFile, "base64") ?? safeSerializableFieldRead(generatedFile, "uint8Array");
18374
+ const blob = convertDataToBlob(data, mediaType);
18375
+ if (blob) {
18376
+ return new Attachment({
18377
+ data: blob,
18378
+ filename: `generated_image_${index}.${getExtensionFromMediaType(mediaType)}`,
18379
+ contentType: mediaType
18380
+ });
18381
+ }
18382
+ return file;
18383
+ }
17529
18384
  function processAISDKEmbeddingOutput(output, denyOutputPaths) {
17530
18385
  if (!output || typeof output !== "object") {
17531
18386
  return output;
@@ -18026,118 +18881,22 @@ var claudeAgentSDKChannels = defineChannels(
18026
18881
  var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
18027
18882
 
18028
18883
  // src/instrumentation/plugins/claude-agent-sdk-local-tool-context.ts
18029
- var LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED = /* @__PURE__ */ Symbol.for(
18030
- "braintrust.claude_agent_sdk.local_tool_context_async_iterator_patched"
18031
- );
18032
- function createLocalToolContextStore() {
18033
- const maybeIsoWithAsyncLocalStorage = isomorph_default;
18034
- if (typeof maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage === "function") {
18035
- return maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage();
18036
- }
18037
- let currentStore;
18038
- return {
18039
- enterWith(store) {
18040
- currentStore = store;
18041
- },
18042
- getStore() {
18043
- return currentStore;
18044
- },
18045
- run(store, callback) {
18046
- const previousStore = currentStore;
18047
- currentStore = store;
18048
- try {
18049
- return callback();
18050
- } finally {
18051
- currentStore = previousStore;
18052
- }
18053
- }
18054
- };
18055
- }
18056
- var localToolContextStore = createLocalToolContextStore();
18057
- var fallbackLocalToolParentResolver;
18058
- function createClaudeLocalToolContext() {
18059
- return {};
18060
- }
18061
- function runWithClaudeLocalToolContext(callback, context) {
18062
- return localToolContextStore.run(
18063
- context ?? createClaudeLocalToolContext(),
18064
- callback
18065
- );
18884
+ var localToolContextStore = isomorph_default.newAsyncLocalStorage();
18885
+ var localToolParentResolversByToolUseId = /* @__PURE__ */ new Map();
18886
+ function runWithClaudeLocalToolContext(callback, resolver) {
18887
+ return localToolContextStore.run(resolver, callback);
18066
18888
  }
18067
- function ensureClaudeLocalToolContext() {
18068
- const existing = localToolContextStore.getStore();
18069
- if (existing) {
18070
- return existing;
18071
- }
18072
- const created = {};
18073
- localToolContextStore.enterWith(created);
18074
- return created;
18889
+ function registerClaudeLocalToolParentResolver(toolUseId, resolver) {
18890
+ localToolParentResolversByToolUseId.set(toolUseId, resolver);
18075
18891
  }
18076
- function setClaudeLocalToolParentResolver(resolver) {
18077
- fallbackLocalToolParentResolver = resolver;
18078
- const context = ensureClaudeLocalToolContext();
18079
- if (!context) {
18080
- return;
18892
+ function getClaudeLocalToolParentResolver(toolUseId) {
18893
+ const currentResolver = localToolContextStore.getStore();
18894
+ if (!toolUseId) {
18895
+ return currentResolver;
18081
18896
  }
18082
- context.resolveLocalToolParent = resolver;
18083
- }
18084
- function getClaudeLocalToolParentResolver() {
18085
- return localToolContextStore.getStore()?.resolveLocalToolParent ?? fallbackLocalToolParentResolver;
18086
- }
18087
- function isAsyncIterable3(value) {
18088
- return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
18089
- }
18090
- function bindClaudeLocalToolContextToAsyncIterable(result, localToolContext) {
18091
- if (!isAsyncIterable3(result) || Object.isFrozen(result) || Object.isSealed(result)) {
18092
- return result;
18093
- }
18094
- const stream = result;
18095
- const originalAsyncIterator = stream[Symbol.asyncIterator];
18096
- if (originalAsyncIterator[LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED]) {
18097
- return result;
18098
- }
18099
- const patchedAsyncIterator = function() {
18100
- return runWithClaudeLocalToolContext(() => {
18101
- const iterator = Reflect.apply(originalAsyncIterator, this, []);
18102
- if (!iterator || typeof iterator !== "object") {
18103
- return iterator;
18104
- }
18105
- const patchMethod = (methodName) => {
18106
- const originalMethod = Reflect.get(iterator, methodName);
18107
- if (typeof originalMethod !== "function") {
18108
- return;
18109
- }
18110
- Reflect.set(
18111
- iterator,
18112
- methodName,
18113
- (...args) => runWithClaudeLocalToolContext(
18114
- () => Reflect.apply(
18115
- originalMethod,
18116
- iterator,
18117
- args
18118
- ),
18119
- localToolContext
18120
- )
18121
- );
18122
- };
18123
- patchMethod("next");
18124
- patchMethod("return");
18125
- patchMethod("throw");
18126
- return iterator;
18127
- }, localToolContext);
18128
- };
18129
- Object.defineProperty(
18130
- patchedAsyncIterator,
18131
- LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED,
18132
- {
18133
- configurable: false,
18134
- enumerable: false,
18135
- value: true,
18136
- writable: false
18137
- }
18138
- );
18139
- Reflect.set(stream, Symbol.asyncIterator, patchedAsyncIterator);
18140
- return result;
18897
+ const registeredResolver = localToolParentResolversByToolUseId.get(toolUseId);
18898
+ localToolParentResolversByToolUseId.delete(toolUseId);
18899
+ return currentResolver ?? registeredResolver;
18141
18900
  }
18142
18901
 
18143
18902
  // src/instrumentation/plugins/claude-agent-sdk-local-tool-spans.ts
@@ -18163,7 +18922,7 @@ function wrapLocalClaudeToolHandler(handler, getMetadata) {
18163
18922
  const metadata = getMetadata();
18164
18923
  const rawToolName = metadata.serverName ? `mcp__${metadata.serverName}__${metadata.toolName}` : metadata.toolName;
18165
18924
  const toolUseId = getToolUseIdFromExtra(handlerArgs[1]);
18166
- const localToolParentResolver = getClaudeLocalToolParentResolver();
18925
+ const localToolParentResolver = getClaudeLocalToolParentResolver(toolUseId);
18167
18926
  const spanName = metadata.serverName ? `tool: ${metadata.serverName}/${metadata.toolName}` : `tool: ${metadata.toolName}`;
18168
18927
  const runWithResolvedParent = async () => {
18169
18928
  const parent = toolUseId && localToolParentResolver ? await localToolParentResolver(toolUseId).catch(() => void 0) : void 0;
@@ -18690,6 +19449,7 @@ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToP
18690
19449
  }
18691
19450
  }
18692
19451
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
19452
+ registerClaudeLocalToolParentResolver(toolUseID, resolveParentSpan);
18693
19453
  return {};
18694
19454
  }
18695
19455
  const parsed = parseToolName(input.tool_name);
@@ -19400,7 +20160,7 @@ async function finalizeQuerySpan(state) {
19400
20160
  }
19401
20161
  var ClaudeAgentSDKPlugin = class extends BasePlugin {
19402
20162
  onEnable() {
19403
- this.subscribeToQuery();
20163
+ this.interceptQuery();
19404
20164
  }
19405
20165
  onDisable() {
19406
20166
  for (const unsubscribe of this.unsubscribers) {
@@ -19408,211 +20168,218 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19408
20168
  }
19409
20169
  this.unsubscribers = [];
19410
20170
  }
19411
- subscribeToQuery() {
19412
- const channel2 = claudeAgentSDKChannels.query.tracingChannel();
19413
- const spans = /* @__PURE__ */ new WeakMap();
19414
- const handlers = {
19415
- start: (event) => {
19416
- const params = event.arguments[0] ?? {};
19417
- const originalPrompt = params.prompt;
19418
- const options = params.options ?? {};
19419
- const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
19420
- let promptStarted = false;
19421
- let capturedPromptMessages;
19422
- let resolvePromptDone;
19423
- const promptDone = new Promise((resolve) => {
19424
- resolvePromptDone = resolve;
19425
- });
19426
- if (promptIsAsyncIterable) {
19427
- capturedPromptMessages = [];
19428
- const promptStream = originalPrompt;
19429
- params.prompt = (async function* () {
19430
- promptStarted = true;
19431
- try {
19432
- for await (const message of promptStream) {
19433
- capturedPromptMessages.push(message);
19434
- yield message;
19435
- }
19436
- } finally {
19437
- resolvePromptDone?.();
20171
+ interceptQuery() {
20172
+ const startQuery = (params) => {
20173
+ const originalPrompt = params.prompt;
20174
+ const options = params.options ?? {};
20175
+ const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
20176
+ let promptStarted = false;
20177
+ let capturedPromptMessages;
20178
+ let resolvePromptDone;
20179
+ const promptDone = new Promise((resolve) => {
20180
+ resolvePromptDone = resolve;
20181
+ });
20182
+ if (promptIsAsyncIterable) {
20183
+ capturedPromptMessages = [];
20184
+ const promptStream = originalPrompt;
20185
+ params.prompt = (async function* () {
20186
+ promptStarted = true;
20187
+ try {
20188
+ for await (const message of promptStream) {
20189
+ capturedPromptMessages.push(message);
20190
+ yield message;
19438
20191
  }
19439
- })();
19440
- }
19441
- const span = startSpan(
19442
- withSpanInstrumentationName(
19443
- {
19444
- name: "Claude Agent",
19445
- spanAttributes: {
19446
- type: "task" /* TASK */
19447
- }
19448
- },
19449
- INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
19450
- )
19451
- );
19452
- const startTime = getCurrentUnixTimestamp();
19453
- try {
19454
- span.log({
19455
- input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
19456
- metadata: filterSerializableOptions(options)
19457
- });
19458
- } catch (error) {
19459
- console.error("Error extracting input for Claude Agent SDK:", error);
19460
- }
19461
- const activeToolSpans = /* @__PURE__ */ new Map();
19462
- const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
19463
- const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
19464
- const subAgentSpans = /* @__PURE__ */ new Map();
19465
- const endedSubAgentSpans = /* @__PURE__ */ new Set();
19466
- const toolUseToParent = /* @__PURE__ */ new Map();
19467
- const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
19468
- const latestRootLlmParentRef = {
19469
- value: void 0
19470
- };
19471
- const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
19472
- const taskIdToToolUseId = /* @__PURE__ */ new Map();
19473
- const promptMessagesByParentKey = /* @__PURE__ */ new Map();
19474
- const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
19475
- const localToolContext = createClaudeLocalToolContext();
19476
- const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
19477
- const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
19478
- const resolveToolUseParentSpan = async (toolUseID, context) => {
19479
- const trackedParentToolUseId = toolUseToParent.get(toolUseID);
19480
- const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
19481
- const parentKey = llmParentKey(parentToolUseId);
19482
- const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
19483
- const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
19484
- if (!activeLlmSpan && !latestLlmParent) {
19485
- await ensureActiveLlmSpanForParentToolUse(
19486
- span,
19487
- activeLlmSpansByParentToolUse,
19488
- subAgentDetailsByToolUseId,
19489
- activeToolSpans,
19490
- subAgentSpans,
19491
- parentToolUseId,
19492
- getCurrentUnixTimestamp()
19493
- );
19494
- }
19495
- if (parentToolUseId) {
19496
- const subAgentSpan = await ensureSubAgentSpan(
19497
- subAgentDetailsByToolUseId,
19498
- span,
19499
- activeToolSpans,
19500
- subAgentSpans,
19501
- parentToolUseId
19502
- );
19503
- return subAgentSpan.export();
20192
+ } finally {
20193
+ resolvePromptDone?.();
19504
20194
  }
19505
- return span.export();
19506
- };
19507
- localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
19508
- setClaudeLocalToolParentResolver(resolveToolUseParentSpan);
19509
- const optionsWithHooks = injectTracingHooks(
19510
- options,
19511
- resolveToolUseParentSpan,
19512
- taskIdToToolUseId,
19513
- toolUseToParent,
19514
- activeToolSpans,
19515
- localToolHookNames,
19516
- skipLocalToolHooks,
19517
- subAgentDetailsByToolUseId,
19518
- subAgentSpans,
19519
- endedSubAgentSpans
19520
- );
19521
- params.options = optionsWithHooks;
19522
- event.arguments[0] = params;
19523
- spans.set(event, {
19524
- activeLlmSpansByParentToolUse,
19525
- activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
19526
- activeToolSpans,
19527
- conversationHistoryByParentKey,
19528
- capturedPromptMessages,
19529
- currentMessageId: void 0,
19530
- currentMessageStartTime: startTime,
19531
- currentMessages: [],
19532
- endedSubAgentSpans,
19533
- finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
19534
- finalResults: [],
19535
- options: optionsWithHooks,
19536
- originalPrompt,
19537
- processing: Promise.resolve(),
19538
- promptDone,
19539
- promptMessagesByParentKey,
19540
- promptStarted: () => promptStarted,
19541
- promptSourcePriorityByParentKey,
19542
- span,
19543
- subAgentDetailsByToolUseId,
19544
- subAgentSpans,
19545
- taskIdToToolUseId,
19546
- latestLlmParentBySubAgentToolUse,
19547
- latestRootLlmParentRef,
19548
- toolUseToParent,
19549
- usageByMessageId: /* @__PURE__ */ new Map(),
19550
- localToolContext
20195
+ })();
20196
+ }
20197
+ const span = startSpan(
20198
+ withSpanInstrumentationName(
20199
+ {
20200
+ name: "Claude Agent",
20201
+ spanAttributes: {
20202
+ type: "task" /* TASK */
20203
+ }
20204
+ },
20205
+ INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
20206
+ )
20207
+ );
20208
+ const startTime = getCurrentUnixTimestamp();
20209
+ try {
20210
+ span.log({
20211
+ input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
20212
+ metadata: filterSerializableOptions(options)
19551
20213
  });
19552
- },
19553
- end: (event) => {
19554
- const state = spans.get(event);
19555
- if (!state) {
19556
- return;
19557
- }
19558
- const eventResult = bindClaudeLocalToolContextToAsyncIterable(
19559
- event.result,
19560
- state.localToolContext
19561
- );
19562
- if (eventResult === void 0) {
19563
- state.span.end();
19564
- spans.delete(event);
19565
- return;
19566
- }
19567
- if (isAsyncIterable(eventResult)) {
19568
- patchStreamIfNeeded(eventResult, {
19569
- onChunk: (message) => {
19570
- maybeTrackToolUseContext(state, message);
19571
- state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
19572
- console.error(
19573
- "Error processing Claude Agent SDK stream chunk:",
19574
- error
19575
- );
19576
- });
19577
- },
19578
- onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
19579
- spans.delete(event);
19580
- }),
19581
- onError: (error) => state.processing.then(() => {
19582
- state.span.log({
19583
- error: error.message
19584
- });
19585
- }).then(() => finalizeQuerySpan(state)).finally(() => {
19586
- spans.delete(event);
19587
- })
19588
- });
19589
- return;
19590
- }
19591
- try {
19592
- state.span.log({ output: eventResult });
19593
- } catch (error) {
19594
- console.error("Error extracting output for Claude Agent SDK:", error);
19595
- } finally {
19596
- state.span.end();
19597
- spans.delete(event);
20214
+ } catch (error) {
20215
+ console.error("Error extracting input for Claude Agent SDK:", error);
20216
+ }
20217
+ const activeToolSpans = /* @__PURE__ */ new Map();
20218
+ const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
20219
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
20220
+ const subAgentSpans = /* @__PURE__ */ new Map();
20221
+ const endedSubAgentSpans = /* @__PURE__ */ new Set();
20222
+ const toolUseToParent = /* @__PURE__ */ new Map();
20223
+ const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
20224
+ const latestRootLlmParentRef = {
20225
+ value: void 0
20226
+ };
20227
+ const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
20228
+ const taskIdToToolUseId = /* @__PURE__ */ new Map();
20229
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
20230
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
20231
+ const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
20232
+ const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
20233
+ const resolveToolUseParentSpan = async (toolUseID, context) => {
20234
+ const trackedParentToolUseId = toolUseToParent.get(toolUseID);
20235
+ const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
20236
+ const parentKey = llmParentKey(parentToolUseId);
20237
+ const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
20238
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
20239
+ if (!activeLlmSpan && !latestLlmParent) {
20240
+ await ensureActiveLlmSpanForParentToolUse(
20241
+ span,
20242
+ activeLlmSpansByParentToolUse,
20243
+ subAgentDetailsByToolUseId,
20244
+ activeToolSpans,
20245
+ subAgentSpans,
20246
+ parentToolUseId,
20247
+ getCurrentUnixTimestamp()
20248
+ );
19598
20249
  }
19599
- },
19600
- error: (event) => {
19601
- const state = spans.get(event);
19602
- if (!state || !event.error) {
19603
- return;
20250
+ if (parentToolUseId) {
20251
+ const subAgentSpan = await ensureSubAgentSpan(
20252
+ subAgentDetailsByToolUseId,
20253
+ span,
20254
+ activeToolSpans,
20255
+ subAgentSpans,
20256
+ parentToolUseId
20257
+ );
20258
+ return subAgentSpan.export();
19604
20259
  }
19605
- state.span.log({
19606
- error: event.error.message
20260
+ return span.export();
20261
+ };
20262
+ const optionsWithHooks = injectTracingHooks(
20263
+ options,
20264
+ resolveToolUseParentSpan,
20265
+ taskIdToToolUseId,
20266
+ toolUseToParent,
20267
+ activeToolSpans,
20268
+ localToolHookNames,
20269
+ skipLocalToolHooks,
20270
+ subAgentDetailsByToolUseId,
20271
+ subAgentSpans,
20272
+ endedSubAgentSpans
20273
+ );
20274
+ params.options = optionsWithHooks;
20275
+ return {
20276
+ activeLlmSpansByParentToolUse,
20277
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
20278
+ activeToolSpans,
20279
+ conversationHistoryByParentKey,
20280
+ capturedPromptMessages,
20281
+ currentMessageId: void 0,
20282
+ currentMessageStartTime: startTime,
20283
+ currentMessages: [],
20284
+ endedSubAgentSpans,
20285
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
20286
+ finalResults: [],
20287
+ options: optionsWithHooks,
20288
+ originalPrompt,
20289
+ processing: Promise.resolve(),
20290
+ promptDone,
20291
+ promptMessagesByParentKey,
20292
+ promptStarted: () => promptStarted,
20293
+ promptSourcePriorityByParentKey,
20294
+ span,
20295
+ subAgentDetailsByToolUseId,
20296
+ subAgentSpans,
20297
+ taskIdToToolUseId,
20298
+ latestLlmParentBySubAgentToolUse,
20299
+ latestRootLlmParentRef,
20300
+ toolUseToParent,
20301
+ usageByMessageId: /* @__PURE__ */ new Map(),
20302
+ localToolParentResolver: resolveToolUseParentSpan
20303
+ };
20304
+ };
20305
+ const finishQuery = (state, result) => {
20306
+ if (isAsyncIterable(result)) {
20307
+ patchStreamIfNeeded(result, {
20308
+ aroundNext: (callback) => runWithClaudeLocalToolContext(
20309
+ callback,
20310
+ state.localToolParentResolver
20311
+ ),
20312
+ onChunk: (message) => {
20313
+ maybeTrackToolUseContext(state, message);
20314
+ state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
20315
+ console.error(
20316
+ "Error processing Claude Agent SDK stream chunk:",
20317
+ error
20318
+ );
20319
+ });
20320
+ },
20321
+ onComplete: () => state.processing.then(() => finalizeQuerySpan(state)),
20322
+ onError: (error) => state.processing.then(() => {
20323
+ state.span.log({ error: error.message });
20324
+ }).then(() => finalizeQuerySpan(state))
19607
20325
  });
20326
+ return;
20327
+ }
20328
+ try {
20329
+ state.span.log({ output: result });
20330
+ } catch (error) {
20331
+ console.error("Error extracting output for Claude Agent SDK:", error);
20332
+ } finally {
19608
20333
  state.span.end();
19609
- spans.delete(event);
19610
20334
  }
19611
20335
  };
19612
- channel2.subscribe(handlers);
19613
- this.unsubscribers.push(() => {
19614
- channel2.unsubscribe(handlers);
19615
- });
20336
+ this.unsubscribers.push(
20337
+ claudeAgentSDKChannels.query.intercept((target, thisArg, args) => {
20338
+ let state;
20339
+ try {
20340
+ args[0] ??= {};
20341
+ state = startQuery(args[0]);
20342
+ } catch (error) {
20343
+ debugLogger.error(
20344
+ "Error starting Claude Agent SDK instrumentation:",
20345
+ error
20346
+ );
20347
+ }
20348
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
20349
+ try {
20350
+ const result = state ? runWithClaudeLocalToolContext(
20351
+ invokeTarget,
20352
+ state.localToolParentResolver
20353
+ ) : invokeTarget();
20354
+ if (state) {
20355
+ try {
20356
+ finishQuery(state, result);
20357
+ } catch (error) {
20358
+ debugLogger.error(
20359
+ "Error finalizing Claude Agent SDK instrumentation:",
20360
+ error
20361
+ );
20362
+ }
20363
+ }
20364
+ return result;
20365
+ } catch (error) {
20366
+ if (state) {
20367
+ try {
20368
+ state.span.log({
20369
+ error: error instanceof Error ? error.message : String(error)
20370
+ });
20371
+ state.span.end();
20372
+ } catch (instrumentationError) {
20373
+ debugLogger.error(
20374
+ "Error handling Claude Agent SDK instrumentation failure:",
20375
+ instrumentationError
20376
+ );
20377
+ }
20378
+ }
20379
+ throw error;
20380
+ }
20381
+ })
20382
+ );
19616
20383
  }
19617
20384
  };
19618
20385
 
@@ -23726,7 +24493,7 @@ function patchOpenRouterCallModelResult(args) {
23726
24493
  span,
23727
24494
  () => originalMethod.apply(resultLike, args2)
23728
24495
  );
23729
- if (!isAsyncIterable4(stream)) {
24496
+ if (!isAsyncIterable3(stream)) {
23730
24497
  return stream;
23731
24498
  }
23732
24499
  return wrapAsyncIterableWithSpan({
@@ -23921,7 +24688,7 @@ function wrapAsyncIterableWithSpan(args) {
23921
24688
  }
23922
24689
  };
23923
24690
  }
23924
- function isAsyncIterable4(value) {
24691
+ function isAsyncIterable3(value) {
23925
24692
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
23926
24693
  }
23927
24694
  function normalizeError(error) {
@@ -24799,7 +25566,7 @@ function patchOpenRouterCallModelResult2(args) {
24799
25566
  span,
24800
25567
  () => originalMethod.apply(resultLike, args2)
24801
25568
  );
24802
- if (!isAsyncIterable5(stream)) {
25569
+ if (!isAsyncIterable4(stream)) {
24803
25570
  return stream;
24804
25571
  }
24805
25572
  return wrapAsyncIterableWithSpan2({
@@ -24994,7 +25761,7 @@ function wrapAsyncIterableWithSpan2(args) {
24994
25761
  }
24995
25762
  };
24996
25763
  }
24997
- function isAsyncIterable5(value) {
25764
+ function isAsyncIterable4(value) {
24998
25765
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
24999
25766
  }
25000
25767
  function normalizeError2(error) {
@@ -30986,12 +31753,14 @@ function getMetricsFromResponse(response) {
30986
31753
  continue;
30987
31754
  }
30988
31755
  const inputTokenDetails = usageMetadata.input_token_details;
31756
+ const outputTokenDetails = usageMetadata.output_token_details;
30989
31757
  return normalizeTokenMetrics({
30990
31758
  total_tokens: usageMetadata.total_tokens,
30991
31759
  prompt_tokens: usageMetadata.input_tokens,
30992
31760
  completion_tokens: usageMetadata.output_tokens,
30993
31761
  prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
30994
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
31762
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
31763
+ completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
30995
31764
  });
30996
31765
  }
30997
31766
  const llmOutput = response.llmOutput || {};
@@ -31578,6 +32347,9 @@ var piCodingAgentChannels = defineChannels(
31578
32347
  // src/instrumentation/plugins/pi-coding-agent-plugin.ts
31579
32348
  var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
31580
32349
  var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
32350
+ var PI_TOOL_EXECUTE_WRAPPED = /* @__PURE__ */ Symbol.for(
32351
+ "braintrust.pi_coding_agent.tool_execute_wrapped"
32352
+ );
31581
32353
  var piPromptContextStore;
31582
32354
  var PiCodingAgentPlugin = class extends BasePlugin {
31583
32355
  activePromptStates = /* @__PURE__ */ new Set();
@@ -31658,6 +32430,7 @@ function startPiPromptRun(event, onFinalize) {
31658
32430
  return void 0;
31659
32431
  }
31660
32432
  installPiAgentInstrumentation(agent);
32433
+ wrapPiToolExecutors(agent.state?.tools);
31661
32434
  const metadata = {
31662
32435
  ...extractSessionMetadata(session),
31663
32436
  ...extractPromptOptionsMetadata(event.arguments[1]),
@@ -31754,6 +32527,7 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
31754
32527
  if (!state || state.agent !== agent || state.finalized) {
31755
32528
  return invokeOriginal();
31756
32529
  }
32530
+ wrapPiToolExecutors(context.tools);
31757
32531
  const llmState = await startPiLlmSpan(state, model, context, options);
31758
32532
  try {
31759
32533
  const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
@@ -31764,6 +32538,33 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
31764
32538
  }
31765
32539
  };
31766
32540
  }
32541
+ function wrapPiToolExecutors(tools) {
32542
+ if (!tools) {
32543
+ return;
32544
+ }
32545
+ for (const tool of tools) {
32546
+ try {
32547
+ const execute = tool.execute;
32548
+ if (typeof execute !== "function" || execute[PI_TOOL_EXECUTE_WRAPPED]) {
32549
+ continue;
32550
+ }
32551
+ const wrappedExecute = function(...args) {
32552
+ return runWithAutoInstrumentationAllowed(
32553
+ () => Reflect.apply(execute, this, args)
32554
+ );
32555
+ };
32556
+ Object.defineProperty(wrappedExecute, PI_TOOL_EXECUTE_WRAPPED, {
32557
+ configurable: false,
32558
+ enumerable: false,
32559
+ value: true,
32560
+ writable: false
32561
+ });
32562
+ tool.execute = wrappedExecute;
32563
+ } catch (error) {
32564
+ logInstrumentationError4("Pi Coding Agent tool wrapping", error);
32565
+ }
32566
+ }
32567
+ }
31767
32568
  async function startPiLlmSpan(state, model, context, options) {
31768
32569
  const metadata = {
31769
32570
  ...extractModelMetadata2(model),
@@ -31935,35 +32736,26 @@ async function startPiToolSpan(state, event) {
31935
32736
  if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
31936
32737
  return;
31937
32738
  }
31938
- const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
31939
32739
  const metadata = {
31940
32740
  "gen_ai.tool.call.id": event.toolCallId,
31941
32741
  "gen_ai.tool.name": event.toolName,
31942
32742
  "pi_coding_agent.tool.name": event.toolName
31943
32743
  };
31944
- try {
31945
- const span = startSpan(
31946
- withSpanInstrumentationName(
31947
- {
31948
- event: {
31949
- input: event.args,
31950
- metadata
31951
- },
31952
- name: event.toolName || "tool",
31953
- parent: await state.span.export(),
31954
- spanAttributes: { type: "tool" /* TOOL */ }
32744
+ const span = startSpan(
32745
+ withSpanInstrumentationName(
32746
+ {
32747
+ event: {
32748
+ input: event.args,
32749
+ metadata
31955
32750
  },
31956
- INSTRUMENTATION_NAMES.PI_CODING_AGENT
31957
- )
31958
- );
31959
- state.activeToolSpans.set(event.toolCallId, {
31960
- restoreAutoInstrumentation,
31961
- span
31962
- });
31963
- } catch (error) {
31964
- restoreAutoInstrumentation();
31965
- throw error;
31966
- }
32751
+ name: event.toolName || "tool",
32752
+ parent: await state.span.export(),
32753
+ spanAttributes: { type: "tool" /* TOOL */ }
32754
+ },
32755
+ INSTRUMENTATION_NAMES.PI_CODING_AGENT
32756
+ )
32757
+ );
32758
+ state.activeToolSpans.set(event.toolCallId, { span });
31967
32759
  }
31968
32760
  function finishPiToolSpan(state, event) {
31969
32761
  const toolState = state.activeToolSpans.get(event.toolCallId);
@@ -31984,11 +32776,7 @@ function finishPiToolSpan(state, event) {
31984
32776
  output: event.result
31985
32777
  });
31986
32778
  } finally {
31987
- try {
31988
- toolState.span.end();
31989
- } finally {
31990
- toolState.restoreAutoInstrumentation?.();
31991
- }
32779
+ toolState.span.end();
31992
32780
  }
31993
32781
  }
31994
32782
  function finishPiPromptRun(state, error) {
@@ -32038,10 +32826,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
32038
32826
  ...cleanMetrics5(llmState.metrics),
32039
32827
  ...buildDurationMetrics3(llmState.startTime)
32040
32828
  };
32041
- const usageMetrics = extractUsageMetrics2(message?.usage);
32042
- if (Object.keys(usageMetrics).length > 0) {
32829
+ const usageMetrics2 = extractUsageMetrics2(message?.usage);
32830
+ if (Object.keys(usageMetrics2).length > 0) {
32043
32831
  promptState.collectedLlmUsageMetrics = true;
32044
- addMetrics(promptState.metrics, usageMetrics);
32832
+ addMetrics(promptState.metrics, usageMetrics2);
32045
32833
  }
32046
32834
  try {
32047
32835
  safeLog4(llmState.span, {
@@ -32059,14 +32847,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
32059
32847
  }
32060
32848
  function finishOpenToolSpans(state, error) {
32061
32849
  for (const [, toolState] of state.activeToolSpans) {
32062
- try {
32063
- safeLog4(toolState.span, {
32064
- error: error ? toLoggedError(error) : "Pi tool did not complete"
32065
- });
32066
- toolState.span.end();
32067
- } finally {
32068
- toolState.restoreAutoInstrumentation?.();
32069
- }
32850
+ safeLog4(toolState.span, {
32851
+ error: error ? toLoggedError(error) : "Pi tool did not complete"
32852
+ });
32853
+ toolState.span.end();
32070
32854
  }
32071
32855
  state.activeToolSpans.clear();
32072
32856
  }
@@ -32385,12 +33169,12 @@ var MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES = 32;
32385
33169
  var StrandsAgentSDKPlugin = class extends BasePlugin {
32386
33170
  activeChildParents = /* @__PURE__ */ new WeakMap();
32387
33171
  onEnable() {
32388
- this.subscribeToAgentStream();
32389
- this.subscribeToMultiAgentStream(
33172
+ this.interceptAgentStream();
33173
+ this.interceptMultiAgentStream(
32390
33174
  strandsAgentSDKChannels.graphStream,
32391
33175
  "Graph.stream"
32392
33176
  );
32393
- this.subscribeToMultiAgentStream(
33177
+ this.interceptMultiAgentStream(
32394
33178
  strandsAgentSDKChannels.swarmStream,
32395
33179
  "Swarm.stream"
32396
33180
  );
@@ -32401,122 +33185,92 @@ var StrandsAgentSDKPlugin = class extends BasePlugin {
32401
33185
  }
32402
33186
  this.unsubscribers = [];
32403
33187
  }
32404
- subscribeToAgentStream() {
32405
- const channel2 = strandsAgentSDKChannels.agentStream.tracingChannel();
32406
- const states = /* @__PURE__ */ new WeakMap();
32407
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
32408
- const handlers = {
32409
- start: (event) => {
32410
- const state = startAgentStream(event, this.activeChildParents);
32411
- if (state) {
32412
- states.set(event, state);
32413
- }
32414
- },
32415
- end: (event) => {
32416
- const state = states.get(event);
32417
- if (!state) {
32418
- return;
32419
- }
32420
- const result = event.result;
32421
- if (isAsyncIterable(result)) {
32422
- patchStreamIfNeeded(result, {
32423
- aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
32424
- onChunk: (chunk) => handleAgentStreamEvent(state, chunk),
32425
- onComplete: () => {
32426
- finalizeAgentStream(state);
32427
- states.delete(event);
32428
- },
32429
- onError: (error) => {
32430
- finalizeAgentStream(state, error);
32431
- states.delete(event);
32432
- }
32433
- });
32434
- return;
32435
- }
32436
- finalizeAgentStream(state, void 0, result);
32437
- states.delete(event);
32438
- },
32439
- error: (event) => {
32440
- const state = states.get(event);
32441
- if (!state || !event.error) {
32442
- return;
32443
- }
32444
- finalizeAgentStream(state, event.error);
32445
- states.delete(event);
32446
- }
32447
- };
32448
- channel2.subscribe(handlers);
32449
- this.unsubscribers.push(() => {
32450
- unbindAutoInstrumentationSuppression?.();
32451
- channel2.unsubscribe(handlers);
32452
- });
33188
+ interceptAgentStream() {
33189
+ this.unsubscribers.push(
33190
+ strandsAgentSDKChannels.agentStream.intercept(
33191
+ (target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
33192
+ finalize: finalizeAgentStream,
33193
+ handleChunk: handleAgentStreamEvent,
33194
+ invoke: () => Reflect.apply(target, thisArg, args),
33195
+ name: "Strands Agent SDK",
33196
+ start: () => startAgentStream(
33197
+ args[0],
33198
+ extractAgent(additional.agent, thisArg),
33199
+ this.activeChildParents
33200
+ )
33201
+ })
33202
+ )
33203
+ );
32453
33204
  }
32454
- subscribeToMultiAgentStream(channel2, operation) {
32455
- const tracingChannel = channel2.tracingChannel();
32456
- const states = /* @__PURE__ */ new WeakMap();
32457
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(tracingChannel);
32458
- const handlers = {
32459
- start: (event) => {
32460
- const state = startMultiAgentStream(
32461
- event,
32462
- operation,
32463
- this.activeChildParents
32464
- );
32465
- if (state) {
32466
- states.set(event, state);
32467
- }
32468
- },
32469
- end: (event) => {
32470
- const state = states.get(event);
32471
- if (!state) {
32472
- return;
32473
- }
32474
- const result = event.result;
32475
- if (isAsyncIterable(result)) {
32476
- patchStreamIfNeeded(result, {
32477
- aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
32478
- onChunk: (chunk) => handleMultiAgentStreamEvent(
32479
- state,
32480
- chunk,
32481
- this.activeChildParents
32482
- ),
32483
- onComplete: () => {
32484
- finalizeMultiAgentStream(state, this.activeChildParents);
32485
- states.delete(event);
32486
- },
32487
- onError: (error) => {
32488
- finalizeMultiAgentStream(state, this.activeChildParents, error);
32489
- states.delete(event);
32490
- }
32491
- });
32492
- return;
32493
- }
32494
- finalizeMultiAgentStream(
32495
- state,
32496
- this.activeChildParents,
32497
- void 0,
32498
- result
33205
+ interceptMultiAgentStream(channel2, operation) {
33206
+ this.unsubscribers.push(
33207
+ channel2.intercept(
33208
+ (target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
33209
+ finalize: (state, error, output) => finalizeMultiAgentStream(
33210
+ state,
33211
+ this.activeChildParents,
33212
+ error,
33213
+ output
33214
+ ),
33215
+ handleChunk: (state, chunk) => handleMultiAgentStreamEvent(state, chunk, this.activeChildParents),
33216
+ invoke: () => Reflect.apply(target, thisArg, args),
33217
+ name: "Strands multi-agent",
33218
+ start: () => startMultiAgentStream(
33219
+ args[0],
33220
+ extractOrchestrator(additional.orchestrator, thisArg),
33221
+ operation,
33222
+ this.activeChildParents
33223
+ )
33224
+ })
33225
+ )
33226
+ );
33227
+ }
33228
+ };
33229
+ function instrumentStrandsStreamInvocation(options) {
33230
+ let state;
33231
+ try {
33232
+ state = options.start();
33233
+ } catch (error) {
33234
+ debugLogger.error(`Error starting ${options.name} instrumentation:`, error);
33235
+ }
33236
+ let result;
33237
+ try {
33238
+ result = runWithAutoInstrumentationSuppressed(options.invoke);
33239
+ } catch (error) {
33240
+ if (state) {
33241
+ try {
33242
+ options.finalize(state, error);
33243
+ } catch (instrumentationError) {
33244
+ debugLogger.error(
33245
+ `Error handling ${options.name} instrumentation failure:`,
33246
+ instrumentationError
32499
33247
  );
32500
- states.delete(event);
32501
- },
32502
- error: (event) => {
32503
- const state = states.get(event);
32504
- if (!state || !event.error) {
32505
- return;
32506
- }
32507
- finalizeMultiAgentStream(state, this.activeChildParents, event.error);
32508
- states.delete(event);
32509
33248
  }
32510
- };
32511
- tracingChannel.subscribe(handlers);
32512
- this.unsubscribers.push(() => {
32513
- unbindAutoInstrumentationSuppression?.();
32514
- tracingChannel.unsubscribe(handlers);
32515
- });
33249
+ }
33250
+ throw error;
32516
33251
  }
32517
- };
32518
- function startAgentStream(event, activeChildParents) {
32519
- const agent = extractAgent(event);
33252
+ if (state) {
33253
+ try {
33254
+ if (isAsyncIterable(result)) {
33255
+ patchStreamIfNeeded(result, {
33256
+ aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
33257
+ onChunk: (chunk) => options.handleChunk(state, chunk),
33258
+ onComplete: () => options.finalize(state),
33259
+ onError: (error) => options.finalize(state, error)
33260
+ });
33261
+ } else {
33262
+ options.finalize(state, void 0, result);
33263
+ }
33264
+ } catch (error) {
33265
+ debugLogger.error(
33266
+ `Error finalizing ${options.name} instrumentation:`,
33267
+ error
33268
+ );
33269
+ }
33270
+ }
33271
+ return result;
33272
+ }
33273
+ function startAgentStream(input, agent, activeChildParents) {
32520
33274
  const model = agent?.model;
32521
33275
  const metadata = {
32522
33276
  ...extractAgentMetadata2(agent),
@@ -32526,17 +33280,14 @@ function startAgentStream(event, activeChildParents) {
32526
33280
  };
32527
33281
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
32528
33282
  const attachmentCache = createStrandsAttachmentCache();
32529
- const input = processStrandsInputAttachments(
32530
- event.arguments[0],
32531
- attachmentCache
32532
- );
33283
+ const processedInput = processStrandsInputAttachments(input, attachmentCache);
32533
33284
  const span = parentSpan ? withCurrent(
32534
33285
  parentSpan,
32535
33286
  () => startSpan(
32536
33287
  withSpanInstrumentationName(
32537
33288
  {
32538
33289
  event: {
32539
- input,
33290
+ input: processedInput,
32540
33291
  metadata
32541
33292
  },
32542
33293
  name: formatAgentSpanName(agent),
@@ -32549,7 +33300,7 @@ function startAgentStream(event, activeChildParents) {
32549
33300
  withSpanInstrumentationName(
32550
33301
  {
32551
33302
  event: {
32552
- input,
33303
+ input: processedInput,
32553
33304
  metadata
32554
33305
  },
32555
33306
  name: formatAgentSpanName(agent),
@@ -32567,22 +33318,21 @@ function startAgentStream(event, activeChildParents) {
32567
33318
  startTime: getCurrentUnixTimestamp()
32568
33319
  };
32569
33320
  }
32570
- function startMultiAgentStream(event, operation, activeChildParents) {
32571
- const orchestrator = extractOrchestrator(event);
33321
+ function startMultiAgentStream(input, orchestrator, operation, activeChildParents) {
32572
33322
  const metadata = {
32573
33323
  "strands.operation": operation,
32574
33324
  provider: "strands",
32575
33325
  ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
32576
33326
  };
32577
33327
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
32578
- const input = processStrandsInputAttachments(event.arguments[0]);
33328
+ const processedInput = processStrandsInputAttachments(input);
32579
33329
  const span = parentSpan ? withCurrent(
32580
33330
  parentSpan,
32581
33331
  () => startSpan(
32582
33332
  withSpanInstrumentationName(
32583
33333
  {
32584
33334
  event: {
32585
- input,
33335
+ input: processedInput,
32586
33336
  metadata
32587
33337
  },
32588
33338
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -32595,7 +33345,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
32595
33345
  withSpanInstrumentationName(
32596
33346
  {
32597
33347
  event: {
32598
- input,
33348
+ input: processedInput,
32599
33349
  metadata
32600
33350
  },
32601
33351
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -32966,12 +33716,12 @@ function finalizeMultiAgentStream(state, activeChildParents, error, output) {
32966
33716
  });
32967
33717
  state.span.end();
32968
33718
  }
32969
- function extractAgent(event) {
32970
- const candidate = event.agent ?? event.self;
33719
+ function extractAgent(agent, self) {
33720
+ const candidate = agent ?? self;
32971
33721
  return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
32972
33722
  }
32973
- function extractOrchestrator(event) {
32974
- const candidate = event.orchestrator ?? event.self;
33723
+ function extractOrchestrator(orchestrator, self) {
33724
+ const candidate = orchestrator ?? self;
32975
33725
  return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
32976
33726
  }
32977
33727
  function extractAgentMetadata2(agent) {
@@ -34491,7 +35241,7 @@ function braintrustEveHook(options) {
34491
35241
  }
34492
35242
  };
34493
35243
  }
34494
- function braintrustEveInstrumentation(options) {
35244
+ function createLegacyEveInstrumentation(options) {
34495
35245
  const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
34496
35246
  return {
34497
35247
  events: {
@@ -35879,8 +36629,10 @@ function capturedModelInput(modelInput) {
35879
36629
  const value = [];
35880
36630
  if (typeof instructions === "string") {
35881
36631
  value.push({ content: instructions, role: "system" });
35882
- } else if (instructions) {
36632
+ } else if (Array.isArray(instructions)) {
35883
36633
  value.push(...instructions.map(capturedEveModelMessage));
36634
+ } else if (instructions) {
36635
+ value.push(capturedEveModelMessage(instructions));
35884
36636
  }
35885
36637
  value.push(...messages.map(capturedEveModelMessage));
35886
36638
  try {
@@ -36124,6 +36876,464 @@ async function deterministicEveId(...parts) {
36124
36876
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
36125
36877
  }
36126
36878
 
36879
+ // src/instrumentation/plugins/eve-provider.ts
36880
+ var MAX_EVE_PROVIDER_CACHE_ENTRIES = 1e4;
36881
+ function createEveInstrumentationProvider(options = {}) {
36882
+ const bridge = new EveProviderBridge(options.metadata);
36883
+ return {
36884
+ capture: "content",
36885
+ events: {
36886
+ "action.completed": (event, context) => bridge.handleActionTerminal(event, context),
36887
+ "action.failed": (event, context) => bridge.handleActionTerminal(event, context),
36888
+ "action.started": (event, context) => bridge.handleActionStarted(event, context),
36889
+ "model.call.completed": (event, context) => bridge.handleModelTerminal(event, context),
36890
+ "model.call.failed": (event, context) => bridge.handleModelTerminal(event, context),
36891
+ "model.call.started": (event, context) => bridge.handleModelStarted(event, context),
36892
+ "step.attempt.completed": (event) => bridge.handleStepAttemptTerminal(event),
36893
+ "step.attempt.failed": (event) => bridge.handleStepAttemptTerminal(event),
36894
+ "turn.cancelled": (event, context) => bridge.handleTurnTerminal(event, context),
36895
+ "turn.completed": (event, context) => bridge.handleTurnTerminal(event, context),
36896
+ "turn.failed": (event, context) => bridge.handleTurnTerminal(event, context),
36897
+ "turn.started": (event, context) => bridge.handleTurnStarted(event, context)
36898
+ },
36899
+ flush,
36900
+ setup: options.setup
36901
+ };
36902
+ }
36903
+ var EveProviderBridge = class {
36904
+ constructor(metadata) {
36905
+ this.metadata = metadata;
36906
+ }
36907
+ metadata;
36908
+ activeActions = /* @__PURE__ */ new Map();
36909
+ activeModels = /* @__PURE__ */ new Map();
36910
+ modelsByAttempt = /* @__PURE__ */ new Map();
36911
+ settledOperations = new LRUCache({
36912
+ max: MAX_EVE_PROVIDER_CACHE_ENTRIES
36913
+ });
36914
+ turns = new LRUCache({
36915
+ max: MAX_EVE_PROVIDER_CACHE_ENTRIES
36916
+ });
36917
+ async handleTurnStarted(event, context) {
36918
+ await this.contain("turn start", async () => {
36919
+ if (this.settledOperations.has(event.idempotencyKey)) {
36920
+ context.state.set({ skip: true });
36921
+ return;
36922
+ }
36923
+ const { rowId, spanId } = await generateEveIds(
36924
+ "turn",
36925
+ event.idempotencyKey
36926
+ );
36927
+ const key = turnKey3(event.sessionId, event.turnId);
36928
+ const stored = storedSpan(context);
36929
+ if (stored && "exported" in stored && stored.rootSpanId) {
36930
+ this.turns.set(key, { rootSpanId: stored.rootSpanId, spanId });
36931
+ return;
36932
+ }
36933
+ let rootSpanId = spanId;
36934
+ let parentSpanId;
36935
+ if (event.parentLineage) {
36936
+ const parentTurnKey = turnKey3(
36937
+ event.parentLineage.sessionId,
36938
+ event.parentLineage.turnId
36939
+ );
36940
+ const parentTurn = this.turns.get(parentTurnKey);
36941
+ rootSpanId = parentTurn?.rootSpanId ?? // Eve propagates the root session through every nested subagent. Use
36942
+ // it instead of the immediate parent session when no ancestor ran
36943
+ // in-process.
36944
+ (await generateEveIds(
36945
+ "turn",
36946
+ turnIdempotencyKey(
36947
+ event.rootSessionId,
36948
+ event.parentLineage.turnId
36949
+ )
36950
+ )).spanId;
36951
+ parentSpanId = (await generateEveIds(
36952
+ "subagent",
36953
+ actionIdempotencyKey(
36954
+ event.parentLineage.sessionId,
36955
+ event.parentLineage.turnId,
36956
+ event.parentLineage.callId
36957
+ )
36958
+ )).spanId;
36959
+ }
36960
+ const metadata = this.spanMetadata(event.sessionId);
36961
+ const span = await this.startSpan(
36962
+ context,
36963
+ {
36964
+ event: { id: rowId, metadata },
36965
+ name: "eve.turn",
36966
+ parentSpanIds: parentSpanId ? { rootSpanId, spanId: parentSpanId } : { parentSpanIds: [], rootSpanId },
36967
+ spanAttributes: { type: "task" /* TASK */ },
36968
+ spanId
36969
+ },
36970
+ rootSpanId
36971
+ );
36972
+ span?.log({ metadata });
36973
+ this.turns.set(key, {
36974
+ rootSpanId,
36975
+ spanId
36976
+ });
36977
+ });
36978
+ }
36979
+ async handleTurnTerminal(event, context) {
36980
+ await this.contain("turn terminal", async () => {
36981
+ if (this.settledOperations.has(event.idempotencyKey)) {
36982
+ context.state.set(void 0);
36983
+ return;
36984
+ }
36985
+ const error = event.type === "turn.failed" ? event.error : void 0;
36986
+ this.drainActionsForTurn(event.sessionId, event.turnId, error);
36987
+ const stored = storedSpan(context);
36988
+ if (stored && "exported" in stored) {
36989
+ updateSpan({
36990
+ exported: stored.exported,
36991
+ ...error !== void 0 ? { error } : {},
36992
+ metrics: { end: Date.now() / 1e3 }
36993
+ });
36994
+ }
36995
+ this.settledOperations.set(event.idempotencyKey, true);
36996
+ context.state.set(void 0);
36997
+ this.turns.delete(turnKey3(event.sessionId, event.turnId));
36998
+ });
36999
+ }
37000
+ async handleModelStarted(event, context) {
37001
+ await this.contain("model start", async () => {
37002
+ if (this.settledOperations.has(event.idempotencyKey)) {
37003
+ context.state.set({ skip: true });
37004
+ return;
37005
+ }
37006
+ const parent = await this.parentForScope(event.scope);
37007
+ const { rowId, spanId } = await generateEveIds(
37008
+ "step",
37009
+ event.idempotencyKey
37010
+ );
37011
+ const input = event.input ? capturedModelInput(event.input) : void 0;
37012
+ const metadata = {
37013
+ ...this.spanMetadata(event.scope.sessionId),
37014
+ model: event.model.modelId,
37015
+ provider: event.model.provider
37016
+ };
37017
+ const span = await this.startSpan(context, {
37018
+ event: {
37019
+ id: rowId,
37020
+ ...input !== void 0 ? { input } : {},
37021
+ metadata
37022
+ },
37023
+ name: "eve.step",
37024
+ parentSpanIds: parent,
37025
+ spanAttributes: { type: "llm" /* LLM */ },
37026
+ spanId
37027
+ });
37028
+ if (!span) return;
37029
+ span.log({ ...input !== void 0 ? { input } : {}, metadata });
37030
+ this.activeModels.set(event.idempotencyKey, {
37031
+ span,
37032
+ turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
37033
+ });
37034
+ const keys = this.modelsByAttempt.get(event.scope.attemptId) ?? /* @__PURE__ */ new Set();
37035
+ keys.add(event.idempotencyKey);
37036
+ this.modelsByAttempt.set(event.scope.attemptId, keys);
37037
+ });
37038
+ }
37039
+ async handleModelTerminal(event, context) {
37040
+ await this.contain("model terminal", async () => {
37041
+ if (this.settledOperations.has(event.idempotencyKey)) {
37042
+ context.state.set(void 0);
37043
+ return;
37044
+ }
37045
+ const active = this.activeModels.get(event.idempotencyKey);
37046
+ if (active) {
37047
+ const span = active.span;
37048
+ if (event.type === "model.call.failed") {
37049
+ if (event.error !== void 0) span.log({ error: event.error });
37050
+ } else {
37051
+ span.log({
37052
+ metrics: usageMetrics(event.usage),
37053
+ output: modelOutput(event)
37054
+ });
37055
+ }
37056
+ span.end();
37057
+ } else {
37058
+ const stored = storedSpan(context);
37059
+ if (stored && "exported" in stored) {
37060
+ updateSpan({
37061
+ exported: stored.exported,
37062
+ ...event.type === "model.call.failed" ? event.error !== void 0 ? { error: event.error } : {} : { output: modelOutput(event) },
37063
+ metrics: {
37064
+ ...event.type === "model.call.completed" ? usageMetrics(event.usage) : {},
37065
+ end: Date.now() / 1e3
37066
+ }
37067
+ });
37068
+ }
37069
+ }
37070
+ this.settledOperations.set(event.idempotencyKey, true);
37071
+ this.forgetModel(event.scope.attemptId, event.idempotencyKey);
37072
+ context.state.set(void 0);
37073
+ });
37074
+ }
37075
+ async handleActionStarted(event, context) {
37076
+ await this.contain("action start", async () => {
37077
+ if (event.kind === "load-skill" || this.settledOperations.has(event.idempotencyKey)) {
37078
+ context.state.set({ skip: true });
37079
+ return;
37080
+ }
37081
+ const parent = await this.parentForScope(event.scope);
37082
+ const { rowId, spanId } = await generateEveIds(
37083
+ event.kind === "subagent-call" ? "subagent" : "tool",
37084
+ event.idempotencyKey
37085
+ );
37086
+ const metadata = {
37087
+ ...this.spanMetadata(event.scope.sessionId),
37088
+ "eve.action_kind": event.kind
37089
+ };
37090
+ const span = await this.startSpan(context, {
37091
+ event: {
37092
+ id: rowId,
37093
+ ...event.input !== void 0 ? { input: event.input } : {},
37094
+ metadata
37095
+ },
37096
+ name: event.name,
37097
+ parentSpanIds: parent,
37098
+ spanAttributes: { type: "tool" /* TOOL */ },
37099
+ spanId
37100
+ });
37101
+ if (!span) return;
37102
+ span.log({
37103
+ ...event.input !== void 0 ? { input: event.input } : {},
37104
+ metadata
37105
+ });
37106
+ this.activeActions.set(event.idempotencyKey, {
37107
+ span,
37108
+ turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
37109
+ });
37110
+ });
37111
+ }
37112
+ async handleActionTerminal(event, context) {
37113
+ await this.contain("action terminal", async () => {
37114
+ if (this.settledOperations.has(event.idempotencyKey)) {
37115
+ context.state.set(void 0);
37116
+ return;
37117
+ }
37118
+ const stored = storedSpan(context);
37119
+ if (stored?.skip) {
37120
+ context.state.set(void 0);
37121
+ return;
37122
+ }
37123
+ const active = this.activeActions.get(event.idempotencyKey);
37124
+ const end = finiteTimestamp(event.acceptedAtMs) ?? Date.now();
37125
+ if (active) {
37126
+ const span = active.span;
37127
+ if (event.type === "action.failed") {
37128
+ span.log({
37129
+ error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
37130
+ });
37131
+ } else if (event.output.type === "error") {
37132
+ span.log({
37133
+ error: event.output.error ?? new Error("Eve action returned an error")
37134
+ });
37135
+ } else {
37136
+ span.log({ output: event.output.output });
37137
+ }
37138
+ span.end({ endTime: end / 1e3 });
37139
+ } else {
37140
+ const stored2 = storedSpan(context);
37141
+ if (stored2 && "exported" in stored2) {
37142
+ updateSpan({
37143
+ exported: stored2.exported,
37144
+ ...event.type === "action.failed" ? {
37145
+ error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
37146
+ } : event.output.type === "error" ? {
37147
+ error: event.output.error ?? new Error("Eve action returned an error")
37148
+ } : { output: event.output.output },
37149
+ metrics: { end: end / 1e3 }
37150
+ });
37151
+ }
37152
+ }
37153
+ this.settledOperations.set(event.idempotencyKey, true);
37154
+ this.activeActions.delete(event.idempotencyKey);
37155
+ context.state.set(void 0);
37156
+ });
37157
+ }
37158
+ handleStepAttemptTerminal(event) {
37159
+ void this.contain("step attempt terminal", () => {
37160
+ const keys = this.modelsByAttempt.get(event.scope.attemptId);
37161
+ if (!keys) return;
37162
+ for (const key of keys) {
37163
+ const active = this.activeModels.get(key);
37164
+ if (!active) continue;
37165
+ if (event.type === "step.attempt.failed" && event.error !== void 0) {
37166
+ active.span.log({ error: event.error });
37167
+ }
37168
+ active.span.end();
37169
+ this.activeModels.delete(key);
37170
+ }
37171
+ this.modelsByAttempt.delete(event.scope.attemptId);
37172
+ });
37173
+ }
37174
+ async parentForScope(scope) {
37175
+ const key = turnKey3(scope.sessionId, scope.turnId);
37176
+ const known = this.turns.get(key);
37177
+ if (known) {
37178
+ return { rootSpanId: known.rootSpanId, spanId: known.spanId };
37179
+ }
37180
+ const [{ spanId }, { spanId: rootSpanId }] = await Promise.all([
37181
+ generateEveIds("turn", turnIdempotencyKey(scope.sessionId, scope.turnId)),
37182
+ generateEveIds(
37183
+ "turn",
37184
+ turnIdempotencyKey(
37185
+ scope.rootSessionId ?? scope.sessionId,
37186
+ scope.turnId
37187
+ )
37188
+ )
37189
+ ]);
37190
+ return { rootSpanId, spanId };
37191
+ }
37192
+ async startSpan(context, args, rootSpanId) {
37193
+ const span = withCurrent(
37194
+ NOOP_SPAN,
37195
+ () => _internalStartSpanWithInitialMerge(
37196
+ withSpanInstrumentationName(args ?? {}, INSTRUMENTATION_NAMES.EVE)
37197
+ )
37198
+ );
37199
+ try {
37200
+ context.state.set({
37201
+ exported: await span.export(),
37202
+ ...rootSpanId ? { rootSpanId } : {}
37203
+ });
37204
+ } catch (error) {
37205
+ debugLogger.warn("Error exporting Eve provider span:", error);
37206
+ }
37207
+ return span;
37208
+ }
37209
+ drainActionsForTurn(sessionId, turnId, error) {
37210
+ const key = turnKey3(sessionId, turnId);
37211
+ for (const [idempotencyKey, active] of this.activeActions) {
37212
+ if (active.turnKey !== key) continue;
37213
+ if (error !== void 0) active.span.log({ error });
37214
+ active.span.end();
37215
+ this.activeActions.delete(idempotencyKey);
37216
+ }
37217
+ }
37218
+ forgetModel(attemptId, idempotencyKey) {
37219
+ this.activeModels.delete(idempotencyKey);
37220
+ const keys = this.modelsByAttempt.get(attemptId);
37221
+ keys?.delete(idempotencyKey);
37222
+ if (keys?.size === 0) this.modelsByAttempt.delete(attemptId);
37223
+ }
37224
+ spanMetadata(sessionId) {
37225
+ return {
37226
+ ...this.metadata ?? {},
37227
+ "eve.session_id": sessionId
37228
+ };
37229
+ }
37230
+ async contain(operation, fn) {
37231
+ try {
37232
+ await fn();
37233
+ } catch (error) {
37234
+ debugLogger.warn(`Error in Eve provider ${operation}:`, error);
37235
+ }
37236
+ }
37237
+ };
37238
+ function storedSpan(context) {
37239
+ const value = context.state.get();
37240
+ if (!isObject(value)) return void 0;
37241
+ if (value["skip"] === true) return { skip: true };
37242
+ return typeof value["exported"] === "string" ? {
37243
+ exported: value["exported"],
37244
+ ...typeof value["rootSpanId"] === "string" && value["rootSpanId"].length > 0 ? { rootSpanId: value["rootSpanId"] } : {}
37245
+ } : void 0;
37246
+ }
37247
+ function modelOutput(event) {
37248
+ const content = event.content ?? [];
37249
+ let text = "";
37250
+ const reasoning = [];
37251
+ const toolCalls = [];
37252
+ for (const part of content) {
37253
+ if (part.type === "text") {
37254
+ text += part.text;
37255
+ } else if (part.type === "reasoning" && part.text.trim().length > 0) {
37256
+ reasoning.push({ content: part.text });
37257
+ } else if (part.type === "tool-call") {
37258
+ toolCalls.push({
37259
+ function: {
37260
+ arguments: safeJsonStringify(part.input),
37261
+ name: part.toolName
37262
+ },
37263
+ id: part.callId,
37264
+ type: "function"
37265
+ });
37266
+ }
37267
+ }
37268
+ return [
37269
+ {
37270
+ finish_reason: normalizeFinishReason2(event.finishReason),
37271
+ index: 0,
37272
+ message: {
37273
+ content: text || null,
37274
+ ...reasoning.length > 0 ? { reasoning } : {},
37275
+ role: "assistant",
37276
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
37277
+ }
37278
+ }
37279
+ ];
37280
+ }
37281
+ function usageMetrics(usage) {
37282
+ const promptTokens = nonNegativeNumber(usage.inputTokens);
37283
+ const completionTokens = nonNegativeNumber(usage.outputTokens);
37284
+ const cachedTokens = nonNegativeNumber(
37285
+ usage.inputTokenDetails?.cacheReadTokens
37286
+ );
37287
+ const cacheCreationTokens = nonNegativeNumber(
37288
+ usage.inputTokenDetails?.cacheWriteTokens
37289
+ );
37290
+ return {
37291
+ ...promptTokens !== void 0 ? { prompt_tokens: promptTokens } : {},
37292
+ ...completionTokens !== void 0 ? { completion_tokens: completionTokens } : {},
37293
+ ...promptTokens !== void 0 && completionTokens !== void 0 ? { tokens: promptTokens + completionTokens } : {},
37294
+ ...cachedTokens !== void 0 ? { prompt_cached_tokens: cachedTokens } : {},
37295
+ ...cacheCreationTokens !== void 0 ? { prompt_cache_creation_tokens: cacheCreationTokens } : {}
37296
+ };
37297
+ }
37298
+ function nonNegativeNumber(value) {
37299
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
37300
+ }
37301
+ function finiteTimestamp(value) {
37302
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
37303
+ }
37304
+ function normalizeFinishReason2(value) {
37305
+ if (value === "content-filter") return "content_filter";
37306
+ if (value === "tool-calls") return "tool_calls";
37307
+ return value;
37308
+ }
37309
+ function safeJsonStringify(value) {
37310
+ try {
37311
+ return JSON.stringify(value) ?? "null";
37312
+ } catch {
37313
+ return "null";
37314
+ }
37315
+ }
37316
+ function turnKey3(sessionId, turnId) {
37317
+ return `${sessionId}:${turnId}`;
37318
+ }
37319
+ function turnIdempotencyKey(sessionId, turnId) {
37320
+ return `turn:${sessionId}:${turnId}`;
37321
+ }
37322
+ function actionIdempotencyKey(sessionId, turnId, callId) {
37323
+ return `action:${sessionId}:${turnId}:${callId}`;
37324
+ }
37325
+
37326
+ // src/instrumentation/plugins/eve-instrumentation.ts
37327
+ var EVE_INSTRUMENTATION_PROVIDER = /* @__PURE__ */ Symbol.for("eve.instrumentation.provider");
37328
+ function braintrustEveInstrumentation(options) {
37329
+ const definition = "defineState" in options ? createLegacyEveInstrumentation(options) : createEveInstrumentationProvider(options);
37330
+ const declaration = {
37331
+ ...definition,
37332
+ [EVE_INSTRUMENTATION_PROVIDER]: true
37333
+ };
37334
+ return declaration;
37335
+ }
37336
+
36127
37337
  // src/instrumentation/config.ts
36128
37338
  var envIntegrationAliases = {
36129
37339
  openai: "openai",