braintrust 3.13.0 → 3.15.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/dev/dist/index.d.mts +6 -8
  2. package/dev/dist/index.d.ts +6 -8
  3. package/dev/dist/index.js +1399 -1466
  4. package/dev/dist/index.mjs +971 -1038
  5. package/dist/apply-auto-instrumentation.js +208 -188
  6. package/dist/apply-auto-instrumentation.mjs +40 -20
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +230 -40
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -1
  9. package/dist/auto-instrumentations/bundler/next.cjs +230 -40
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -2
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +230 -40
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -1
  13. package/dist/auto-instrumentations/bundler/vite.cjs +230 -40
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -1
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +13 -39
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +230 -40
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -2
  18. package/dist/auto-instrumentations/{chunk-WFEUJACP.mjs → chunk-CNQ7BUKN.mjs} +1 -1
  19. package/dist/auto-instrumentations/chunk-J57YF7WS.mjs +208 -0
  20. package/dist/auto-instrumentations/chunk-QFMACSOL.mjs +280 -0
  21. package/dist/auto-instrumentations/{chunk-GJOO4ESL.mjs → chunk-VXJONZVX.mjs} +28 -40
  22. package/dist/auto-instrumentations/hook.mjs +7985 -46
  23. package/dist/auto-instrumentations/loader/cjs-patch.cjs +194 -4
  24. package/dist/auto-instrumentations/loader/cjs-patch.mjs +13 -27
  25. package/dist/auto-instrumentations/loader/esm-hook.mjs +24 -10
  26. package/dist/browser.d.mts +138 -26
  27. package/dist/browser.d.ts +138 -26
  28. package/dist/browser.js +898 -1063
  29. package/dist/browser.mjs +898 -1063
  30. package/dist/{chunk-75IQCUB2.mjs → chunk-O4ZIWXO3.mjs} +179 -25
  31. package/dist/{chunk-26JGOELH.js → chunk-VMBQETG3.js} +179 -25
  32. package/dist/cli.js +990 -1077
  33. package/dist/edge-light.d.mts +1 -1
  34. package/dist/edge-light.d.ts +1 -1
  35. package/dist/edge-light.js +898 -1063
  36. package/dist/edge-light.mjs +898 -1063
  37. package/dist/index.d.mts +138 -26
  38. package/dist/index.d.ts +138 -26
  39. package/dist/index.js +1690 -1825
  40. package/dist/index.mjs +918 -1053
  41. package/dist/instrumentation/index.d.mts +18 -9
  42. package/dist/instrumentation/index.d.ts +18 -9
  43. package/dist/instrumentation/index.js +711 -1038
  44. package/dist/instrumentation/index.mjs +710 -1038
  45. package/dist/workerd.d.mts +1 -1
  46. package/dist/workerd.d.ts +1 -1
  47. package/dist/workerd.js +898 -1063
  48. package/dist/workerd.mjs +898 -1063
  49. package/package.json +1 -7
  50. package/dist/auto-instrumentations/chunk-MWZXZQUO.mjs +0 -81
@@ -4254,6 +4254,76 @@ var LRUCache = class {
4254
4254
  }
4255
4255
  };
4256
4256
 
4257
+ // src/prompt-cache/cache-config.ts
4258
+ var CACHE_LOCATION_ENV_VAR = "BRAINTRUST_CACHE_LOCATION";
4259
+ var DEFAULT_CACHE_MEMORY_MAX = 1 << 10;
4260
+ var DEFAULT_CACHE_DISK_MAX = 1 << 20;
4261
+ var warnedInvalidCacheModeEnvValue = false;
4262
+ var warnedUnavailableDiskCacheMode = false;
4263
+ function warnInvalidCacheMode(value) {
4264
+ if (warnedInvalidCacheModeEnvValue) {
4265
+ return;
4266
+ }
4267
+ warnedInvalidCacheModeEnvValue = true;
4268
+ debugLogger.warn(
4269
+ `Invalid ${CACHE_LOCATION_ENV_VAR} value "${value}". Expected "mixed", "memory", "disk", or "none". Falling back to "mixed".`
4270
+ );
4271
+ }
4272
+ function warnUnavailableDiskCache() {
4273
+ if (warnedUnavailableDiskCacheMode) {
4274
+ return;
4275
+ }
4276
+ warnedUnavailableDiskCacheMode = true;
4277
+ debugLogger.warn(
4278
+ `Disk cache is not supported on this platform, so ${CACHE_LOCATION_ENV_VAR}="disk" disables prompt and parameters caching.`
4279
+ );
4280
+ }
4281
+ function parseCacheMode() {
4282
+ const value = isomorph_default.getEnv(CACHE_LOCATION_ENV_VAR);
4283
+ const normalized = value?.trim().toLowerCase();
4284
+ if (!normalized) {
4285
+ return "mixed";
4286
+ }
4287
+ if (normalized === "mixed" || normalized === "memory" || normalized === "disk" || normalized === "none") {
4288
+ return normalized;
4289
+ }
4290
+ warnInvalidCacheMode(value ?? "");
4291
+ return "mixed";
4292
+ }
4293
+ function parsePositiveIntegerEnv(envVar, defaultValue) {
4294
+ const value = Number(isomorph_default.getEnv(envVar));
4295
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
4296
+ }
4297
+ function createCacheLayers({
4298
+ memoryMaxEnvVar,
4299
+ diskCacheDirEnvVar,
4300
+ diskMaxEnvVar,
4301
+ getDefaultDiskCacheDir
4302
+ }) {
4303
+ const mode = parseCacheMode();
4304
+ const memoryCache = mode === "mixed" || mode === "memory" ? new LRUCache({
4305
+ max: parsePositiveIntegerEnv(
4306
+ memoryMaxEnvVar,
4307
+ DEFAULT_CACHE_MEMORY_MAX
4308
+ )
4309
+ }) : void 0;
4310
+ let diskCache;
4311
+ if (mode === "mixed" || mode === "disk") {
4312
+ if (canUseDiskCache()) {
4313
+ diskCache = new DiskCache({
4314
+ cacheDir: isomorph_default.getEnv(diskCacheDirEnvVar) ?? getDefaultDiskCacheDir(),
4315
+ max: parsePositiveIntegerEnv(diskMaxEnvVar, DEFAULT_CACHE_DISK_MAX)
4316
+ });
4317
+ } else if (mode === "disk") {
4318
+ warnUnavailableDiskCache();
4319
+ }
4320
+ }
4321
+ if (diskCache) {
4322
+ return { memoryCache, diskCache };
4323
+ }
4324
+ return { memoryCache };
4325
+ }
4326
+
4257
4327
  // src/prompt-cache/prompt-cache.ts
4258
4328
  function createCacheKey(key) {
4259
4329
  if (key.id) {
@@ -4281,16 +4351,18 @@ var PromptCache = class {
4281
4351
  */
4282
4352
  async get(key) {
4283
4353
  const cacheKey = createCacheKey(key);
4284
- const memoryPrompt = this.memoryCache.get(cacheKey);
4285
- if (memoryPrompt !== void 0) {
4286
- return memoryPrompt;
4354
+ if (this.memoryCache) {
4355
+ const memoryPrompt = this.memoryCache.get(cacheKey);
4356
+ if (memoryPrompt !== void 0) {
4357
+ return memoryPrompt;
4358
+ }
4287
4359
  }
4288
4360
  if (this.diskCache) {
4289
4361
  const diskPrompt = await this.diskCache.get(cacheKey);
4290
4362
  if (!diskPrompt) {
4291
4363
  return void 0;
4292
4364
  }
4293
- this.memoryCache.set(cacheKey, diskPrompt);
4365
+ this.memoryCache?.set(cacheKey, diskPrompt);
4294
4366
  return diskPrompt;
4295
4367
  }
4296
4368
  return void 0;
@@ -4305,7 +4377,7 @@ var PromptCache = class {
4305
4377
  */
4306
4378
  async set(key, value) {
4307
4379
  const cacheKey = createCacheKey(key);
4308
- this.memoryCache.set(cacheKey, value);
4380
+ this.memoryCache?.set(cacheKey, value);
4309
4381
  if (this.diskCache) {
4310
4382
  await this.diskCache.set(cacheKey, value);
4311
4383
  }
@@ -4335,23 +4407,25 @@ var ParametersCache = class {
4335
4407
  }
4336
4408
  async get(key) {
4337
4409
  const cacheKey = createCacheKey2(key);
4338
- const memoryParams = this.memoryCache.get(cacheKey);
4339
- if (memoryParams !== void 0) {
4340
- return memoryParams;
4410
+ if (this.memoryCache) {
4411
+ const memoryParams = this.memoryCache.get(cacheKey);
4412
+ if (memoryParams !== void 0) {
4413
+ return memoryParams;
4414
+ }
4341
4415
  }
4342
4416
  if (this.diskCache) {
4343
4417
  const diskParams = await this.diskCache.get(cacheKey);
4344
4418
  if (!diskParams) {
4345
4419
  return void 0;
4346
4420
  }
4347
- this.memoryCache.set(cacheKey, diskParams);
4421
+ this.memoryCache?.set(cacheKey, diskParams);
4348
4422
  return diskParams;
4349
4423
  }
4350
4424
  return void 0;
4351
4425
  }
4352
4426
  async set(key, value) {
4353
4427
  const cacheKey = createCacheKey2(key);
4354
- this.memoryCache.set(cacheKey, value);
4428
+ this.memoryCache?.set(cacheKey, value);
4355
4429
  if (this.diskCache) {
4356
4430
  await this.diskCache.set(cacheKey, value);
4357
4431
  }
@@ -4883,21 +4957,22 @@ var BraintrustState = class _BraintrustState {
4883
4957
  setGlobalDebugLogLevel(void 0);
4884
4958
  }
4885
4959
  this.resetLoginInfo();
4886
- const memoryCache = new LRUCache({
4887
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
4960
+ const { memoryCache, diskCache } = createCacheLayers({
4961
+ memoryMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_MEMORY_MAX",
4962
+ diskCacheDirEnvVar: "BRAINTRUST_PROMPT_CACHE_DIR",
4963
+ diskMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_DISK_MAX",
4964
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`
4888
4965
  });
4889
- const diskCache = canUseDiskCache() ? new DiskCache({
4890
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`,
4891
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DISK_MAX")) ?? 1 << 20
4892
- }) : void 0;
4893
4966
  this.promptCache = new PromptCache({ memoryCache, diskCache });
4894
- const parametersMemoryCache = new LRUCache({
4895
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX")) ?? 1 << 10
4967
+ const {
4968
+ memoryCache: parametersMemoryCache,
4969
+ diskCache: parametersDiskCache
4970
+ } = createCacheLayers({
4971
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
4972
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
4973
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
4974
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
4896
4975
  });
4897
- const parametersDiskCache = canUseDiskCache() ? new DiskCache({
4898
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`,
4899
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DISK_MAX")) ?? 1 << 20
4900
- }) : void 0;
4901
4976
  this.parametersCache = new ParametersCache({
4902
4977
  memoryCache: parametersMemoryCache,
4903
4978
  diskCache: parametersDiskCache
@@ -23355,803 +23430,440 @@ var flueChannels = defineChannels("@flue/runtime", {
23355
23430
  createContext: channel({
23356
23431
  channelName: "createFlueContext",
23357
23432
  kind: "sync-stream"
23358
- }),
23359
- openSession: channel({
23360
- channelName: "Harness.openSession",
23361
- kind: "async"
23362
- }),
23363
- contextEvent: channel({
23364
- channelName: "context.event",
23365
- kind: "sync-stream"
23366
- }),
23367
- prompt: channel({
23368
- channelName: "session.prompt",
23369
- kind: "async"
23370
- }),
23371
- skill: channel({
23372
- channelName: "session.skill",
23373
- kind: "async"
23374
- }),
23375
- task: channel({
23376
- channelName: "session.task",
23377
- kind: "async"
23378
- }),
23379
- compact: channel({
23380
- channelName: "session.compact",
23381
- kind: "async"
23382
23433
  })
23383
23434
  });
23384
23435
 
23385
- // src/wrappers/flue.ts
23386
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23387
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23388
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23389
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23390
- "braintrust.flue.subscribed-context-events"
23391
- );
23392
- function patchFlueContextInPlace(ctx) {
23393
- const context = ctx;
23394
- if (context[WRAPPED_FLUE_CONTEXT]) {
23395
- return ctx;
23396
- }
23397
- const originalInit = context.init.bind(context);
23398
- try {
23399
- Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23400
- configurable: false,
23401
- enumerable: false,
23402
- value: true
23403
- });
23404
- Object.defineProperty(context, "init", {
23405
- configurable: true,
23406
- value: async function wrappedFlueInit(options) {
23407
- const harness = await originalInit(options);
23408
- return wrapFlueHarness(harness);
23409
- },
23410
- writable: true
23411
- });
23412
- } catch {
23413
- }
23414
- return ctx;
23415
- }
23416
- function subscribeFlueContextEvents(ctx, options = {}) {
23417
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23418
- return void 0;
23436
+ // src/instrumentation/plugins/flue-plugin.ts
23437
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
23438
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
23439
+ var braintrustFlueObserver = (event, ctx) => {
23440
+ getObserveBridge().handle(event, ctx);
23441
+ };
23442
+ var FluePlugin = class extends BasePlugin {
23443
+ onEnable() {
23444
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
23419
23445
  }
23420
- const context = ctx;
23421
- const captureTurnSpans = options.captureTurnSpans ?? true;
23422
- const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
23423
- if (existingSubscription) {
23424
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
23425
- return void 0;
23426
- }
23427
- try {
23428
- existingSubscription.unsubscribe();
23429
- } catch {
23446
+ onDisable() {
23447
+ for (const unsubscribe of this.unsubscribers) {
23448
+ unsubscribe();
23430
23449
  }
23450
+ this.unsubscribers = [];
23431
23451
  }
23432
- try {
23433
- const unsubscribe = ctx.subscribeEvent((event) => {
23434
- flueChannels.contextEvent.traceSync(() => void 0, {
23435
- arguments: [event],
23436
- captureTurnSpans,
23437
- context: ctx
23438
- });
23439
- });
23440
- if (existingSubscription) {
23441
- existingSubscription.captureTurnSpans = captureTurnSpans;
23442
- existingSubscription.unsubscribe = unsubscribe;
23443
- } else {
23444
- Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
23445
- configurable: false,
23446
- enumerable: false,
23447
- value: {
23448
- captureTurnSpans,
23449
- unsubscribe
23450
- }
23451
- });
23452
+ };
23453
+ function enableFlueAutoInstrumentation() {
23454
+ const state = getAutoState();
23455
+ state.refCount += 1;
23456
+ if (!state.handlers) {
23457
+ const channel2 = flueChannels.createContext.tracingChannel();
23458
+ const handlers = {
23459
+ end: (event) => {
23460
+ subscribeToFlueContext(event.result, state);
23461
+ }
23462
+ };
23463
+ channel2.subscribe(handlers);
23464
+ state.channel = channel2;
23465
+ state.handlers = handlers;
23466
+ }
23467
+ let released = false;
23468
+ return () => {
23469
+ if (released) {
23470
+ return;
23452
23471
  }
23453
- return unsubscribe;
23454
- } catch {
23455
- return void 0;
23472
+ released = true;
23473
+ releaseAutoState(state);
23474
+ };
23475
+ }
23476
+ function getAutoState() {
23477
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
23478
+ if (isAutoState(existing)) {
23479
+ return existing;
23456
23480
  }
23481
+ const state = {
23482
+ contexts: /* @__PURE__ */ new WeakSet(),
23483
+ refCount: 0
23484
+ };
23485
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
23486
+ return state;
23457
23487
  }
23458
- function wrapFlueHarness(harness) {
23459
- if (!isPlausibleFlueHarness(harness)) {
23460
- return harness;
23488
+ function getObserveBridge() {
23489
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
23490
+ if (isFlueObserveBridge(existing)) {
23491
+ return existing;
23461
23492
  }
23462
- const target = harness;
23463
- if (target[WRAPPED_FLUE_HARNESS]) {
23464
- return harness;
23493
+ const bridge = new FlueObserveBridge();
23494
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
23495
+ return bridge;
23496
+ }
23497
+ function isFlueObserveBridge(value) {
23498
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
23499
+ }
23500
+ function isAutoState(value) {
23501
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
23502
+ }
23503
+ function releaseAutoState(state) {
23504
+ state.refCount -= 1;
23505
+ if (state.refCount > 0) {
23506
+ return;
23465
23507
  }
23466
- const originalSession = target.session.bind(target);
23467
23508
  try {
23468
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
23469
- configurable: false,
23470
- enumerable: false,
23471
- value: true
23472
- });
23473
- Object.defineProperty(target, "session", {
23474
- configurable: true,
23475
- value: async function wrappedFlueHarnessSession(name, options) {
23476
- const session = await originalSession(name, options);
23477
- return patchFlueSessionInPlace(session);
23478
- },
23479
- writable: true
23480
- });
23481
- const sessions = target.sessions;
23482
- if (sessions && typeof sessions === "object") {
23483
- patchFlueSessionFactory(sessions, "get");
23484
- patchFlueSessionFactory(sessions, "create");
23509
+ if (state.channel && state.handlers) {
23510
+ state.channel.unsubscribe(state.handlers);
23485
23511
  }
23486
- } catch {
23512
+ } finally {
23513
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
23487
23514
  }
23488
- return harness;
23489
23515
  }
23490
- function patchFlueSessionInPlace(session) {
23491
- if (session[WRAPPED_FLUE_SESSION]) {
23492
- return session;
23516
+ function subscribeToFlueContext(value, state) {
23517
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
23518
+ return;
23493
23519
  }
23520
+ const ctx = flueContextFromUnknown(value);
23521
+ let released = false;
23522
+ let unsubscribe;
23523
+ const release = () => {
23524
+ if (released) {
23525
+ return;
23526
+ }
23527
+ released = true;
23528
+ try {
23529
+ unsubscribe?.();
23530
+ } catch (error) {
23531
+ logInstrumentationError3("Flue context unsubscribe", error);
23532
+ }
23533
+ };
23494
23534
  try {
23495
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
23496
- configurable: false,
23497
- enumerable: false,
23498
- value: true
23535
+ unsubscribe = value.subscribeEvent((event) => {
23536
+ if (state.refCount <= 0) {
23537
+ release();
23538
+ return;
23539
+ }
23540
+ braintrustFlueObserver(event, ctx);
23541
+ if (isAutoContextTerminalEvent(event, ctx)) {
23542
+ release();
23543
+ }
23499
23544
  });
23500
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
23501
- patchCallHandleMethod(session, "skill", flueChannels.skill);
23502
- patchCallHandleMethod(session, "task", flueChannels.task);
23503
- patchCompact(session);
23504
- } catch {
23545
+ state.contexts.add(value);
23546
+ } catch (error) {
23547
+ logInstrumentationError3("Flue context subscription", error);
23505
23548
  }
23506
- return session;
23507
23549
  }
23508
- function patchFlueSessionFactory(sessions, method) {
23509
- const original = sessions[method];
23510
- if (typeof original !== "function") {
23511
- return;
23550
+ function isAutoContextTerminalEvent(event, ctx) {
23551
+ if (!isObjectLike(event)) {
23552
+ return false;
23512
23553
  }
23513
- const bound = original.bind(sessions);
23514
- Object.defineProperty(sessions, method, {
23515
- configurable: true,
23516
- value: async function wrappedFlueSessionFactory(name, options) {
23517
- const session = await bound(name, options);
23518
- return patchFlueSessionInPlace(session);
23519
- },
23520
- writable: true
23521
- });
23522
- }
23523
- function patchCallHandleMethod(session, method, channel2) {
23524
- const original = session[method];
23525
- if (typeof original !== "function") {
23526
- return;
23554
+ const type = Reflect.get(event, "type");
23555
+ if (type === "run_end") {
23556
+ return true;
23527
23557
  }
23528
- const bound = original.bind(session);
23529
- Object.defineProperty(session, method, {
23530
- configurable: true,
23531
- value(input, options) {
23532
- const args = [input, options];
23533
- const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
23534
- context: {
23535
- arguments: args,
23536
- operation: method,
23537
- session
23538
- },
23539
- run: () => bound(input, options)
23540
- });
23541
- return preserveCallHandle(originalResult, traced2);
23542
- },
23543
- writable: true
23544
- });
23545
- }
23546
- function patchCompact(session) {
23547
- const original = session.compact;
23548
- if (typeof original !== "function") {
23549
- return;
23558
+ if (type !== "operation") {
23559
+ return false;
23550
23560
  }
23551
- const bound = original.bind(session);
23552
- Object.defineProperty(session, "compact", {
23553
- configurable: true,
23554
- value() {
23555
- const context = {
23556
- arguments: [],
23557
- operation: "compact",
23558
- session
23559
- };
23560
- return flueChannels.compact.tracePromise(() => bound(), context);
23561
- },
23562
- writable: true
23563
- });
23561
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
23564
23562
  }
23565
- function traceFlueOperation(channel2, args) {
23566
- const tracingChannel2 = channel2.tracingChannel();
23567
- const context = args.context;
23568
- let originalResult;
23569
- let traced2;
23570
- const run = () => {
23571
- try {
23572
- originalResult = args.run();
23573
- tracingChannel2.end?.publish(context);
23574
- } catch (error) {
23575
- context.error = normalizeError3(error);
23576
- tracingChannel2.error?.publish(context);
23577
- tracingChannel2.end?.publish(context);
23578
- throw error;
23579
- }
23580
- traced2 = Promise.resolve(originalResult).then(
23581
- (result) => {
23582
- context.result = result;
23583
- tracingChannel2.asyncStart?.publish(context);
23584
- tracingChannel2.asyncEnd?.publish(context);
23585
- return result;
23586
- },
23587
- (error) => {
23588
- context.error = normalizeError3(error);
23589
- tracingChannel2.error?.publish(context);
23590
- tracingChannel2.asyncStart?.publish(context);
23591
- tracingChannel2.asyncEnd?.publish(context);
23592
- throw error;
23593
- }
23594
- );
23595
- };
23596
- if (tracingChannel2.start?.runStores) {
23597
- tracingChannel2.start.runStores(context, run);
23598
- } else {
23599
- tracingChannel2.start?.publish(context);
23600
- run();
23601
- }
23602
- return { originalResult, traced: traced2 };
23563
+ function isObservableFlueContext(value) {
23564
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
23603
23565
  }
23604
- function normalizeError3(error) {
23605
- return error instanceof Error ? error : new Error(String(error));
23566
+ function isFlueEvent(event) {
23567
+ const type = Reflect.get(event, "type");
23568
+ return type === "run_start" || type === "run_end" || type === "operation_start" || type === "operation" || type === "turn_request" || type === "turn" || type === "tool_start" || type === "tool_call" || type === "task_start" || type === "task" || type === "compaction_start" || type === "compaction";
23606
23569
  }
23607
- function preserveCallHandle(originalHandle, traced2) {
23608
- if (!isFlueCallHandle(originalHandle)) {
23609
- return traced2;
23570
+ function flueContextFromUnknown(ctx) {
23571
+ if (!isObjectLike(ctx)) {
23572
+ return void 0;
23610
23573
  }
23611
- const handle = originalHandle;
23612
- const wrapped = {
23613
- get signal() {
23614
- return handle.signal;
23615
- },
23616
- abort(reason) {
23617
- return handle.abort(reason);
23618
- },
23619
- then(onfulfilled, onrejected) {
23620
- return traced2.then(onfulfilled, onrejected);
23621
- }
23574
+ const id = Reflect.get(ctx, "id");
23575
+ const runId = Reflect.get(ctx, "runId");
23576
+ return {
23577
+ ...typeof id === "string" ? { id } : {},
23578
+ ...typeof runId === "string" ? { runId } : {}
23622
23579
  };
23623
- return wrapped;
23624
23580
  }
23625
- function isPlausibleFlueHarness(value) {
23626
- return !!value && typeof value === "object" && typeof value.session === "function";
23627
- }
23628
- function isFlueCallHandle(value) {
23629
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
23581
+ function isObjectLike(value) {
23582
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23630
23583
  }
23631
-
23632
- // src/instrumentation/plugins/flue-plugin.ts
23633
- var FluePlugin = class extends BasePlugin {
23634
- activeOperationsById = /* @__PURE__ */ new Map();
23635
- activeOperationsByScope = /* @__PURE__ */ new Map();
23636
- compactionsByScope = /* @__PURE__ */ new Map();
23637
- pendingOperationsByKey = /* @__PURE__ */ new Map();
23584
+ var FlueObserveBridge = class {
23585
+ compactionsByKey = /* @__PURE__ */ new Map();
23586
+ operationsById = /* @__PURE__ */ new Map();
23587
+ runsById = /* @__PURE__ */ new Map();
23588
+ seenEvents = /* @__PURE__ */ new WeakSet();
23638
23589
  tasksById = /* @__PURE__ */ new Map();
23639
- toolsById = /* @__PURE__ */ new Map();
23640
- turnsByScope = /* @__PURE__ */ new Map();
23641
- onEnable() {
23642
- this.subscribeToContextCreation();
23643
- this.subscribeToSessionCreation();
23644
- this.subscribeToContextEvents();
23645
- this.subscribeToSessionOperations();
23646
- }
23647
- onDisable() {
23648
- for (const unsubscribe of this.unsubscribers) {
23649
- unsubscribe();
23590
+ toolsByKey = /* @__PURE__ */ new Map();
23591
+ turnsByKey = /* @__PURE__ */ new Map();
23592
+ handle(event, ctx) {
23593
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
23594
+ return;
23650
23595
  }
23651
- this.unsubscribers = [];
23652
- this.activeOperationsById.clear();
23653
- this.activeOperationsByScope.clear();
23654
- this.compactionsByScope.clear();
23655
- this.pendingOperationsByKey.clear();
23596
+ if (this.seenEvents.has(event)) {
23597
+ return;
23598
+ }
23599
+ this.seenEvents.add(event);
23600
+ try {
23601
+ this.handleEvent(event, flueContextFromUnknown(ctx));
23602
+ } catch (error) {
23603
+ logInstrumentationError3("Flue observe", error);
23604
+ }
23605
+ }
23606
+ reset() {
23607
+ this.compactionsByKey.clear();
23608
+ this.operationsById.clear();
23609
+ this.runsById.clear();
23610
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
23656
23611
  this.tasksById.clear();
23657
- this.toolsById.clear();
23658
- this.turnsByScope.clear();
23612
+ this.toolsByKey.clear();
23613
+ this.turnsByKey.clear();
23659
23614
  }
23660
- subscribeToContextCreation() {
23661
- const channel2 = flueChannels.createContext.tracingChannel();
23662
- const handlers = {
23663
- end: (event) => {
23664
- const ctx = event.result;
23665
- if (!ctx) {
23666
- return;
23667
- }
23668
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
23669
- patchFlueContextInPlace(ctx);
23670
- },
23671
- error: () => {
23672
- }
23673
- };
23674
- channel2.subscribe(handlers);
23675
- this.unsubscribers.push(() => {
23676
- channel2.unsubscribe(handlers);
23677
- });
23615
+ handleEvent(event, ctx) {
23616
+ switch (event.type) {
23617
+ case "run_start":
23618
+ this.handleRunStart(event, ctx);
23619
+ return;
23620
+ case "run_end":
23621
+ this.handleRunEnd(event);
23622
+ return;
23623
+ case "operation_start":
23624
+ this.handleOperationStart(event);
23625
+ return;
23626
+ case "operation":
23627
+ this.handleOperation(event);
23628
+ return;
23629
+ case "turn_request":
23630
+ this.handleTurnRequest(event);
23631
+ return;
23632
+ case "turn":
23633
+ this.handleTurn(event);
23634
+ return;
23635
+ case "tool_start":
23636
+ this.handleToolStart(event);
23637
+ return;
23638
+ case "tool_call":
23639
+ this.handleToolCall(event);
23640
+ return;
23641
+ case "task_start":
23642
+ this.handleTaskStart(event);
23643
+ return;
23644
+ case "task":
23645
+ this.handleTask(event);
23646
+ return;
23647
+ case "compaction_start":
23648
+ this.handleCompactionStart(event);
23649
+ return;
23650
+ case "compaction":
23651
+ this.handleCompaction(event);
23652
+ return;
23653
+ default:
23654
+ return;
23655
+ }
23678
23656
  }
23679
- subscribeToSessionCreation() {
23680
- const channel2 = flueChannels.openSession.tracingChannel();
23681
- const handlers = {
23682
- asyncEnd: (event) => {
23683
- if (event.result) {
23684
- patchFlueSessionInPlace(
23685
- event.result
23686
- );
23687
- }
23688
- if (event.harness) {
23689
- wrapFlueHarness(event.harness);
23690
- }
23691
- },
23692
- error: () => {
23693
- }
23657
+ handleRunStart(event, ctx) {
23658
+ if (!event.runId) {
23659
+ return;
23660
+ }
23661
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
23662
+ const metadata = {
23663
+ ...extractPayloadMetadata(event.payload),
23664
+ ...extractEventMetadata(event, ctx),
23665
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
23666
+ provider: "flue"
23694
23667
  };
23695
- channel2.subscribe(handlers);
23696
- this.unsubscribers.push(() => {
23697
- channel2.unsubscribe(handlers);
23668
+ const span = startSpan({
23669
+ name: `workflow:${workflowName}`,
23670
+ spanAttributes: { type: "task" /* TASK */ },
23671
+ startTime: eventTime(event.startedAt ?? event.timestamp),
23672
+ event: {
23673
+ input: event.payload,
23674
+ metadata
23675
+ }
23698
23676
  });
23677
+ this.runsById.set(event.runId, { metadata, span });
23699
23678
  }
23700
- subscribeToSessionOperations() {
23701
- this.subscribeToSessionOperation(flueChannels.prompt);
23702
- this.subscribeToSessionOperation(flueChannels.skill);
23703
- this.subscribeToSessionOperation(flueChannels.task);
23704
- this.subscribeToCompact();
23705
- }
23706
- subscribeToSessionOperation(channel2) {
23707
- const tracingChannel2 = channel2.tracingChannel();
23708
- const states = /* @__PURE__ */ new WeakMap();
23709
- const ensureState2 = (event) => {
23710
- const existing = states.get(event);
23711
- if (existing) {
23712
- return existing;
23713
- }
23714
- const state = this.startOperationState({
23715
- args: event.arguments,
23716
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23717
- operation: event.operation,
23718
- session: event.session
23679
+ handleRunEnd(event) {
23680
+ const state = this.runsById.get(event.runId);
23681
+ this.finishPendingSpansForRun(event);
23682
+ if (state) {
23683
+ safeLog3(state.span, {
23684
+ ...event.isError ? { error: errorToString(event.error) } : {},
23685
+ metadata: {
23686
+ ...state.metadata,
23687
+ ...extractEventMetadata(event),
23688
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
23689
+ },
23690
+ metrics: durationMetrics2(event.durationMs),
23691
+ output: event.result
23719
23692
  });
23720
- states.set(event, state);
23721
- return state;
23722
- };
23723
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23724
- tracingChannel2,
23725
- ensureState2
23726
- );
23727
- const handlers = {
23728
- start: (event) => {
23729
- ensureState2(event);
23730
- },
23731
- asyncEnd: (event) => {
23732
- this.endOperationState(states.get(event), event.result);
23733
- states.delete(event);
23734
- },
23735
- error: (event) => {
23736
- const state = states.get(event);
23737
- if (state && event.error) {
23738
- safeLog3(state.span, { error: errorToString(event.error) });
23739
- this.finishOperationState(state);
23740
- }
23741
- states.delete(event);
23742
- }
23743
- };
23744
- tracingChannel2.subscribe(handlers);
23745
- this.unsubscribers.push(() => {
23746
- unbindCurrentSpanStore?.();
23747
- tracingChannel2.unsubscribe(handlers);
23748
- });
23749
- }
23750
- subscribeToCompact() {
23751
- const tracingChannel2 = flueChannels.compact.tracingChannel();
23752
- const states = /* @__PURE__ */ new WeakMap();
23753
- const ensureState2 = (event) => {
23754
- const existing = states.get(event);
23755
- if (existing) {
23756
- return existing;
23757
- }
23758
- const state = this.startOperationState({
23759
- args: [],
23760
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23761
- operation: event.operation,
23762
- session: event.session
23763
- });
23764
- states.set(event, state);
23765
- return state;
23766
- };
23767
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23768
- tracingChannel2,
23769
- ensureState2
23770
- );
23771
- const handlers = {
23772
- start: (event) => {
23773
- ensureState2(event);
23774
- },
23775
- asyncEnd: (event) => {
23776
- this.endOperationState(states.get(event), void 0);
23777
- states.delete(event);
23778
- },
23779
- error: (event) => {
23780
- const state = states.get(event);
23781
- if (state && event.error) {
23782
- safeLog3(state.span, { error: errorToString(event.error) });
23783
- this.finishOperationState(state);
23784
- }
23785
- states.delete(event);
23786
- }
23787
- };
23788
- tracingChannel2.subscribe(handlers);
23789
- this.unsubscribers.push(() => {
23790
- unbindCurrentSpanStore?.();
23791
- tracingChannel2.unsubscribe(handlers);
23792
- });
23793
- }
23794
- subscribeToContextEvents() {
23795
- const channel2 = flueChannels.contextEvent.tracingChannel();
23796
- const handlers = {
23797
- start: (event) => {
23798
- const flueEvent = event.arguments[0];
23799
- if (!flueEvent) {
23800
- return;
23801
- }
23802
- try {
23803
- this.handleFlueEvent(flueEvent, {
23804
- captureTurnSpans: event.captureTurnSpans !== false
23805
- });
23806
- } catch (error) {
23807
- logInstrumentationError3("Flue event", error);
23808
- }
23809
- },
23810
- error: () => {
23811
- }
23812
- };
23813
- channel2.subscribe(handlers);
23814
- this.unsubscribers.push(() => {
23815
- channel2.unsubscribe(handlers);
23816
- });
23817
- }
23818
- bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
23819
- const state = _internalGetGlobalState();
23820
- const startChannel = tracingChannel2.start;
23821
- const contextManager = state?.contextManager;
23822
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
23823
- if (!currentSpanStore || !startChannel) {
23824
- return void 0;
23693
+ safeEnd(state.span, eventTime(event.timestamp));
23694
+ this.runsById.delete(event.runId);
23825
23695
  }
23826
- startChannel.bindStore(currentSpanStore, (event) => {
23827
- const operationState = ensureState2(event);
23828
- return contextManager.wrapSpanForStore(operationState.span);
23829
- });
23830
- return () => {
23831
- startChannel.unbindStore(currentSpanStore);
23832
- };
23833
- }
23834
- startOperationState(args) {
23835
- const sessionName = getSessionName(args.session);
23836
- const metadata = {
23837
- ...extractOperationInputMetadata(args.operation, args.args),
23838
- ...extractSessionMetadata(args.session),
23839
- "flue.operation": args.operation,
23840
- provider: "flue",
23841
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
23842
- };
23843
- const span = startSpan({
23844
- name: `flue.session.${args.operation}`,
23845
- spanAttributes: { type: "task" /* TASK */ }
23846
- });
23847
- const state = {
23848
- metadata,
23849
- operation: args.operation,
23850
- sessionName,
23851
- span,
23852
- startTime: getCurrentUnixTimestamp()
23853
- };
23854
- safeLog3(span, {
23855
- input: extractOperationInput(args.operation, args.args),
23856
- metadata
23857
- });
23858
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
23859
- state
23860
- );
23861
- addOperationToScope(
23862
- this.activeOperationsByScope,
23863
- sessionName ?? "unknown",
23864
- state
23865
- );
23866
- return state;
23867
- }
23868
- endOperationState(state, result) {
23869
- if (!state) {
23870
- return;
23871
- }
23872
- const metadata = {
23873
- ...state.metadata,
23874
- ...extractPromptResponseMetadata(result)
23875
- };
23876
- const metrics = {
23877
- ...buildDurationMetrics3(state.startTime),
23878
- ...metricsFromUsage(result?.usage)
23879
- };
23880
- safeLog3(state.span, {
23881
- metadata,
23882
- metrics,
23883
- output: extractOperationOutput(result)
23696
+ void flush().catch((error) => {
23697
+ logInstrumentationError3("Flue flush", error);
23884
23698
  });
23885
- this.finishCompactionsForOperation(state);
23886
- this.finishOperationState(state);
23887
- }
23888
- finishOperationState(state) {
23889
- removePendingOperation(this.pendingOperationsByKey, state);
23890
- if (state.operationId) {
23891
- this.activeOperationsById.delete(state.operationId);
23892
- }
23893
- removeScopedOperation(this.activeOperationsByScope, state);
23894
- state.span.end();
23895
- }
23896
- handleFlueEvent(event, options) {
23897
- switch (event.type) {
23898
- case "operation_start":
23899
- this.handleOperationStart(event);
23900
- return;
23901
- case "operation":
23902
- this.handleOperation(event);
23903
- return;
23904
- case "text_delta":
23905
- if (!options.captureTurnSpans) {
23906
- return;
23907
- }
23908
- this.ensureTurnState(event).text.push(
23909
- typeof event.text === "string" ? event.text : ""
23910
- );
23911
- return;
23912
- case "thinking_start":
23913
- if (!options.captureTurnSpans) {
23914
- return;
23915
- }
23916
- this.handleThinkingStart(event);
23917
- return;
23918
- case "thinking_delta":
23919
- if (!options.captureTurnSpans) {
23920
- return;
23921
- }
23922
- this.handleThinkingDelta(event);
23923
- return;
23924
- case "thinking_end":
23925
- if (!options.captureTurnSpans) {
23926
- return;
23927
- }
23928
- this.handleThinkingEnd(event);
23929
- return;
23930
- case "turn":
23931
- if (!options.captureTurnSpans) {
23932
- return;
23933
- }
23934
- this.handleTurn(event);
23935
- return;
23936
- case "tool_start":
23937
- this.handleToolStart(event, options);
23938
- return;
23939
- case "tool_call":
23940
- this.handleToolCall(event);
23941
- return;
23942
- case "task_start":
23943
- this.handleTaskStart(event);
23944
- return;
23945
- case "task":
23946
- this.handleTask(event);
23947
- return;
23948
- case "compaction_start":
23949
- this.handleCompactionStart(event);
23950
- return;
23951
- case "compaction":
23952
- this.handleCompaction(event);
23953
- return;
23954
- default:
23955
- return;
23956
- }
23957
23699
  }
23958
23700
  handleOperationStart(event) {
23959
- if (!isInstrumentedOperation(event.operationKind)) {
23701
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
23960
23702
  return;
23961
23703
  }
23962
- const state = this.takePendingOperationForEvent(event);
23963
- if (!state) {
23964
- return;
23965
- }
23966
- state.operationId = event.operationId;
23967
- this.activeOperationsById.set(event.operationId, state);
23968
- addScopedOperation(this.activeOperationsByScope, event, state);
23969
- state.metadata = {
23970
- ...state.metadata,
23704
+ const metadata = {
23971
23705
  ...extractEventMetadata(event),
23972
- "flue.operation_id": event.operationId
23706
+ "flue.operation": event.operationKind,
23707
+ provider: "flue"
23973
23708
  };
23974
- safeLog3(state.span, { metadata: state.metadata });
23709
+ const parent = this.parentSpanForEvent(event);
23710
+ const span = startFlueSpan(parent, {
23711
+ name: `flue.${event.operationKind}`,
23712
+ spanAttributes: { type: "task" /* TASK */ },
23713
+ startTime: eventTime(event.timestamp),
23714
+ event: { metadata }
23715
+ });
23716
+ this.operationsById.set(event.operationId, { metadata, span });
23975
23717
  }
23976
23718
  handleOperation(event) {
23977
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
23978
- if (!state) {
23719
+ if (!isInstrumentedOperation(event.operationKind)) {
23979
23720
  return;
23980
23721
  }
23722
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
23723
+ const output = operationOutput(event);
23981
23724
  const metadata = {
23982
23725
  ...state.metadata,
23983
23726
  ...extractEventMetadata(event),
23984
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
23985
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
23727
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
23728
+ ...event.usage ? { "flue.usage": event.usage } : {}
23986
23729
  };
23987
- const metrics = metricsFromUsage(event.usage);
23730
+ this.finishPendingChildrenForOperation(event, output);
23988
23731
  safeLog3(state.span, {
23989
- ...event.error ? { error: errorToString(event.error) } : {},
23732
+ ...event.isError ? { error: errorToString(event.error) } : {},
23990
23733
  metadata,
23991
- ...Object.keys(metrics).length ? { metrics } : {}
23734
+ metrics: durationMetrics2(event.durationMs),
23735
+ output
23992
23736
  });
23737
+ safeEnd(state.span, eventTime(event.timestamp));
23738
+ this.operationsById.delete(event.operationId);
23993
23739
  }
23994
- ensureTurnState(event) {
23995
- const scope = scopeKey(event);
23996
- const existing = this.turnsByScope.get(scope);
23997
- if (existing) {
23998
- return existing;
23740
+ handleTurnRequest(event) {
23741
+ const key = turnKey(event);
23742
+ if (!key) {
23743
+ return;
23999
23744
  }
24000
- const parent = this.parentSpanForEvent(event);
24001
23745
  const metadata = {
24002
23746
  ...extractEventMetadata(event),
24003
- provider: "flue"
23747
+ ...event.api ? { "flue.api": event.api } : {},
23748
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
23749
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
23750
+ ...event.provider ? { "flue.provider": event.provider } : {},
23751
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
23752
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
23753
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
23754
+ ...event.input?.tools ? { tools: event.input.tools } : {}
24004
23755
  };
23756
+ const parent = this.parentSpanForTurn(event);
24005
23757
  const span = startFlueSpan(parent, {
24006
- name: "flue.turn",
24007
- spanAttributes: { type: "llm" /* LLM */ }
23758
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
23759
+ spanAttributes: { type: "llm" /* LLM */ },
23760
+ startTime: eventTime(event.timestamp),
23761
+ event: {
23762
+ input: event.input?.messages,
23763
+ metadata
23764
+ }
24008
23765
  });
24009
- const state = {
24010
- metadata,
24011
- span,
24012
- hasThinking: false,
24013
- startTime: getCurrentUnixTimestamp(),
24014
- text: [],
24015
- thinking: [],
24016
- toolCalls: []
24017
- };
24018
- safeLog3(span, { metadata });
24019
- this.turnsByScope.set(scope, state);
24020
- return state;
23766
+ this.logOperationInput(
23767
+ event.operationId,
23768
+ event.input?.messages ?? event.input
23769
+ );
23770
+ this.turnsByKey.set(key, { metadata, span });
24021
23771
  }
24022
23772
  handleTurn(event) {
24023
- const scope = scopeKey(event);
24024
- const state = this.ensureTurnState(event);
24025
- const text = state.text.join("");
24026
- const reasoning = state.finalThinking ?? state.thinking.join("");
24027
- const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
23773
+ const key = turnKey(event);
23774
+ if (!key) {
23775
+ return;
23776
+ }
23777
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
24028
23778
  const metadata = {
24029
23779
  ...state.metadata,
24030
23780
  ...extractEventMetadata(event),
23781
+ ...event.api ? { "flue.api": event.api } : {},
24031
23782
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
23783
+ ...event.provider ? { provider: event.provider } : {},
23784
+ ...event.provider ? { "flue.provider": event.provider } : {},
23785
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24032
23786
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24033
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24034
- provider: "flue"
23787
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24035
23788
  };
24036
23789
  safeLog3(state.span, {
24037
- ...event.error ? { error: errorToString(event.error) } : {},
23790
+ ...event.isError ? { error: errorToString(event.error) } : {},
24038
23791
  metadata,
24039
23792
  metrics: {
24040
- ...durationMsMetrics(event.durationMs),
23793
+ ...durationMetrics2(event.durationMs),
24041
23794
  ...metricsFromUsage(event.usage)
24042
23795
  },
24043
- output: toAssistantOutput(
24044
- text,
24045
- event.stopReason,
24046
- outputReasoning,
24047
- state.toolCalls
24048
- )
23796
+ output: event.output
24049
23797
  });
24050
- state.span.end();
24051
- this.turnsByScope.delete(scope);
23798
+ safeEnd(state.span, eventTime(event.timestamp));
23799
+ this.turnsByKey.delete(key);
24052
23800
  }
24053
- handleThinkingDelta(event) {
24054
- const delta = event.delta;
24055
- if (typeof delta !== "string" || !delta) {
23801
+ handleToolStart(event) {
23802
+ if (!event.toolCallId) {
24056
23803
  return;
24057
23804
  }
24058
- const state = this.ensureTurnState(event);
24059
- state.hasThinking = true;
24060
- state.metadata["flue.thinking"] = true;
24061
- state.thinking.push(delta);
24062
- }
24063
- handleThinkingStart(event) {
24064
- const state = this.ensureTurnState(event);
24065
- state.hasThinking = true;
24066
- state.metadata["flue.thinking"] = true;
24067
- }
24068
- handleThinkingEnd(event) {
24069
- const state = this.ensureTurnState(event);
24070
- state.hasThinking = true;
24071
- state.metadata["flue.thinking"] = true;
24072
- if (typeof event.content === "string" && event.content) {
24073
- state.finalThinking = event.content;
24074
- }
24075
- }
24076
- handleToolStart(event, options) {
24077
- const toolCallId = event.toolCallId;
24078
- if (!toolCallId) {
24079
- return;
24080
- }
24081
- const parent = this.parentSpanForEvent(event);
24082
- const scope = scopeKey(event);
24083
- let turnState = this.turnsByScope.get(scope);
24084
- if (!turnState && parent && options.captureTurnSpans) {
24085
- turnState = this.ensureTurnState(event);
24086
- }
24087
23805
  const metadata = {
24088
23806
  ...extractEventMetadata(event),
24089
23807
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24090
- "flue.tool_call_id": toolCallId,
23808
+ "flue.tool_call_id": event.toolCallId,
24091
23809
  provider: "flue"
24092
23810
  };
23811
+ const parent = this.parentSpanForTool(event);
24093
23812
  const span = startFlueSpan(parent, {
24094
- name: `tool: ${event.toolName ?? "unknown"}`,
24095
- spanAttributes: { type: "tool" /* TOOL */ }
24096
- });
24097
- if (turnState) {
24098
- turnState.toolCalls.push({
24099
- args: event.args,
24100
- toolCallId,
24101
- toolName: event.toolName
24102
- });
24103
- }
24104
- safeLog3(span, {
24105
- input: event.args,
24106
- metadata
24107
- });
24108
- this.toolsById.set(toolKey(event), {
24109
- metadata,
24110
- span,
24111
- startTime: getCurrentUnixTimestamp()
23813
+ name: `tool:${event.toolName ?? "unknown"}`,
23814
+ spanAttributes: { type: "tool" /* TOOL */ },
23815
+ startTime: eventTime(event.timestamp),
23816
+ event: {
23817
+ input: event.args,
23818
+ metadata
23819
+ }
24112
23820
  });
23821
+ this.toolsByKey.set(toolKey(event), { metadata, span });
24113
23822
  }
24114
23823
  handleToolCall(event) {
23824
+ if (!event.toolCallId) {
23825
+ return;
23826
+ }
24115
23827
  const key = toolKey(event);
24116
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
23828
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
24117
23829
  const metadata = {
24118
23830
  ...state.metadata,
24119
23831
  ...extractEventMetadata(event),
24120
23832
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24121
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
23833
+ "flue.tool_call_id": event.toolCallId,
24122
23834
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24123
23835
  };
24124
23836
  safeLog3(state.span, {
24125
23837
  ...event.isError ? { error: errorToString(event.result) } : {},
24126
23838
  metadata,
24127
- metrics: durationMsMetrics(event.durationMs),
23839
+ metrics: durationMetrics2(event.durationMs),
24128
23840
  output: event.result
24129
23841
  });
24130
- state.span.end();
24131
- this.toolsById.delete(key);
23842
+ safeEnd(state.span, eventTime(event.timestamp));
23843
+ this.toolsByKey.delete(key);
24132
23844
  }
24133
23845
  handleTaskStart(event) {
24134
- const parent = this.parentSpanForEvent(event);
23846
+ if (!event.taskId) {
23847
+ return;
23848
+ }
24135
23849
  const metadata = {
24136
23850
  ...extractEventMetadata(event),
24137
- ...event.role ? { "flue.role": event.role } : {},
23851
+ ...event.agent ? { "flue.agent": event.agent } : {},
24138
23852
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
24139
23853
  "flue.task_id": event.taskId,
24140
23854
  provider: "flue"
24141
23855
  };
23856
+ const parent = this.parentSpanForEvent(event);
24142
23857
  const span = startFlueSpan(parent, {
24143
- name: "flue.task",
24144
- spanAttributes: { type: "task" /* TASK */ }
24145
- });
24146
- safeLog3(span, {
24147
- input: event.prompt,
24148
- metadata
24149
- });
24150
- this.tasksById.set(event.taskId, {
24151
- metadata,
24152
- span,
24153
- startTime: getCurrentUnixTimestamp()
23858
+ name: event.agent ? `task:${event.agent}` : "flue.task",
23859
+ spanAttributes: { type: "task" /* TASK */ },
23860
+ startTime: eventTime(event.timestamp),
23861
+ event: {
23862
+ input: event.prompt,
23863
+ metadata
23864
+ }
24154
23865
  });
23866
+ this.tasksById.set(event.taskId, { metadata, span });
24155
23867
  }
24156
23868
  handleTask(event) {
24157
23869
  const state = this.tasksById.get(event.taskId);
@@ -24163,426 +23875,372 @@ var FluePlugin = class extends BasePlugin {
24163
23875
  metadata: {
24164
23876
  ...state.metadata,
24165
23877
  ...extractEventMetadata(event),
23878
+ ...event.agent ? { "flue.agent": event.agent } : {},
24166
23879
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24167
23880
  },
24168
- metrics: durationMsMetrics(event.durationMs),
23881
+ metrics: durationMetrics2(event.durationMs),
24169
23882
  output: event.result
24170
23883
  });
24171
- state.span.end();
23884
+ safeEnd(state.span, eventTime(event.timestamp));
24172
23885
  this.tasksById.delete(event.taskId);
24173
23886
  }
24174
23887
  handleCompactionStart(event) {
24175
- const operationState = this.operationStateForEvent(event);
24176
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
23888
+ const key = compactionKey(event);
23889
+ const input = {
23890
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
23891
+ ...event.reason ? { reason: event.reason } : {}
23892
+ };
24177
23893
  const metadata = {
24178
23894
  ...extractEventMetadata(event),
24179
23895
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24180
23896
  provider: "flue"
24181
23897
  };
24182
- const input = {
24183
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24184
- ...event.reason ? { reason: event.reason } : {}
24185
- };
23898
+ const parent = this.parentSpanForEvent(event);
24186
23899
  const span = startFlueSpan(parent, {
24187
- name: "flue.compaction",
24188
- spanAttributes: { type: "task" /* TASK */ }
24189
- });
24190
- safeLog3(span, {
24191
- input,
24192
- metadata
24193
- });
24194
- this.compactionsByScope.set(scopeKey(event), {
24195
- input,
24196
- metadata,
24197
- operationState,
24198
- span,
24199
- startTime: getCurrentUnixTimestamp()
23900
+ name: `compaction:${event.reason ?? "unknown"}`,
23901
+ spanAttributes: { type: "task" /* TASK */ },
23902
+ startTime: eventTime(event.timestamp),
23903
+ event: {
23904
+ input,
23905
+ metadata
23906
+ }
24200
23907
  });
23908
+ this.logOperationInput(event.operationId, input);
23909
+ this.compactionsByKey.set(key, { metadata, span });
24201
23910
  }
24202
23911
  handleCompaction(event) {
24203
- const key = scopeKey(event);
24204
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24205
- if (!state) {
24206
- return;
24207
- }
23912
+ const key = compactionKey(event);
23913
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
23914
+ const metadata = {
23915
+ ...state.metadata,
23916
+ ...extractEventMetadata(event),
23917
+ ...event.usage ? { "flue.usage": event.usage } : {}
23918
+ };
24208
23919
  safeLog3(state.span, {
24209
- metadata: {
24210
- ...state.metadata,
24211
- ...extractEventMetadata(event),
24212
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24213
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24214
- },
23920
+ metadata,
24215
23921
  metrics: {
24216
- ...durationMsMetrics(event.durationMs),
24217
- ...metricsFromUsage(event.usage)
23922
+ ...durationMetrics2(event.durationMs),
23923
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
23924
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
24218
23925
  },
24219
23926
  output: {
24220
23927
  messagesAfter: event.messagesAfter,
24221
23928
  messagesBefore: event.messagesBefore
24222
23929
  }
24223
23930
  });
24224
- state.span.end();
24225
- this.deleteCompactionState(state);
23931
+ safeEnd(state.span, eventTime(event.timestamp));
23932
+ this.compactionsByKey.delete(key);
24226
23933
  }
24227
- findCompactionState(event) {
24228
- const operationState = this.operationStateForEvent(event);
24229
- for (const state of this.compactionsByScope.values()) {
24230
- if (operationState && state.operationState === operationState) {
24231
- return state;
23934
+ parentSpanForTurn(event) {
23935
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
23936
+ const compaction = this.compactionsByKey.get(compactionKey(event));
23937
+ if (compaction) {
23938
+ return compaction.span;
24232
23939
  }
24233
23940
  }
24234
- return void 0;
23941
+ return this.parentSpanForEvent(event);
24235
23942
  }
24236
- finishCompactionsForOperation(operationState) {
24237
- for (const state of [...this.compactionsByScope.values()]) {
24238
- if (state.operationState !== operationState) {
24239
- continue;
23943
+ parentSpanForEvent(event) {
23944
+ const turn = turnKey(event);
23945
+ if (turn) {
23946
+ const turnState = this.turnsByKey.get(turn);
23947
+ if (turnState) {
23948
+ return turnState.span;
24240
23949
  }
24241
- safeLog3(state.span, {
24242
- input: state.input,
24243
- metadata: state.metadata,
24244
- metrics: {
24245
- ...buildDurationMetrics3(state.startTime)
24246
- },
24247
- output: { completed: true }
24248
- });
24249
- state.span.end();
24250
- this.deleteCompactionState(state);
24251
23950
  }
24252
- }
24253
- deleteCompactionState(state) {
24254
- for (const [key, candidate] of this.compactionsByScope) {
24255
- if (candidate !== state) {
24256
- continue;
23951
+ if (event.taskId) {
23952
+ const task = this.tasksById.get(event.taskId);
23953
+ if (task) {
23954
+ return task.span;
24257
23955
  }
24258
- this.compactionsByScope.delete(key);
24259
- return;
24260
23956
  }
24261
- }
24262
- startSyntheticToolState(event, toolName) {
24263
- const parent = this.parentSpanForEvent(event);
24264
- const metadata = {
24265
- ...extractEventMetadata(event),
24266
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24267
- "flue.tool_name": toolName,
24268
- provider: "flue"
24269
- };
24270
- const span = startFlueSpan(parent, {
24271
- name: `tool: ${toolName}`,
24272
- spanAttributes: { type: "tool" /* TOOL */ }
24273
- });
24274
- safeLog3(span, { metadata });
24275
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
24276
- }
24277
- operationStateForEvent(event) {
24278
23957
  if (event.operationId) {
24279
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
23958
+ const operation = this.operationsById.get(event.operationId);
24280
23959
  if (operation) {
24281
- return operation;
23960
+ return operation.span;
24282
23961
  }
24283
23962
  }
24284
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
23963
+ if (event.runId) {
23964
+ return this.runsById.get(event.runId)?.span;
23965
+ }
23966
+ return void 0;
24285
23967
  }
24286
- parentSpanForEvent(event) {
23968
+ parentSpanForTool(event) {
23969
+ if (event.taskId) {
23970
+ const task = this.tasksById.get(event.taskId);
23971
+ if (task) {
23972
+ return task.span;
23973
+ }
23974
+ }
24287
23975
  if (event.operationId) {
24288
- const operation = this.operationStateForEvent(event);
23976
+ const operation = this.operationsById.get(event.operationId);
24289
23977
  if (operation) {
24290
23978
  return operation.span;
24291
23979
  }
24292
23980
  }
24293
- if (event.taskId) {
24294
- return this.tasksById.get(event.taskId)?.span;
23981
+ if (event.runId) {
23982
+ return this.runsById.get(event.runId)?.span;
24295
23983
  }
24296
- return this.operationStateForEvent(event)?.span;
23984
+ return void 0;
24297
23985
  }
24298
- promotePendingOperationForEvent(event) {
24299
- if (!event.operationId) {
24300
- return void 0;
23986
+ logOperationInput(operationId, input) {
23987
+ if (!operationId || input === void 0) {
23988
+ return;
23989
+ }
23990
+ const operation = this.operationsById.get(operationId);
23991
+ if (!operation || operation.loggedInput) {
23992
+ return;
23993
+ }
23994
+ safeLog3(operation.span, { input });
23995
+ operation.loggedInput = true;
23996
+ }
23997
+ startSyntheticOperation(event) {
23998
+ const metadata = {
23999
+ ...extractEventMetadata(event),
24000
+ "flue.operation": event.operationKind,
24001
+ provider: "flue"
24002
+ };
24003
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24004
+ name: `flue.${event.operationKind}`,
24005
+ spanAttributes: { type: "task" /* TASK */ },
24006
+ startTime: eventTime(event.timestamp),
24007
+ event: { metadata }
24008
+ });
24009
+ return { metadata, span };
24010
+ }
24011
+ startSyntheticTurn(event) {
24012
+ const metadata = {
24013
+ ...extractEventMetadata(event),
24014
+ ...event.api ? { "flue.api": event.api } : {},
24015
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24016
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24017
+ ...event.provider ? { "flue.provider": event.provider } : {},
24018
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
24019
+ };
24020
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24021
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24022
+ spanAttributes: { type: "llm" /* LLM */ },
24023
+ startTime: eventTime(event.timestamp),
24024
+ event: { metadata }
24025
+ });
24026
+ return { metadata, span };
24027
+ }
24028
+ startSyntheticTool(event) {
24029
+ const metadata = {
24030
+ ...extractEventMetadata(event),
24031
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24032
+ "flue.tool_call_id": event.toolCallId,
24033
+ provider: "flue"
24034
+ };
24035
+ const span = startFlueSpan(this.parentSpanForTool(event), {
24036
+ name: `tool:${event.toolName ?? "unknown"}`,
24037
+ spanAttributes: { type: "tool" /* TOOL */ },
24038
+ startTime: eventTime(event.timestamp),
24039
+ event: { metadata }
24040
+ });
24041
+ return { metadata, span };
24042
+ }
24043
+ startSyntheticCompaction(event) {
24044
+ const metadata = {
24045
+ ...extractEventMetadata(event),
24046
+ provider: "flue"
24047
+ };
24048
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24049
+ name: "compaction:unknown",
24050
+ spanAttributes: { type: "task" /* TASK */ },
24051
+ startTime: eventTime(event.timestamp),
24052
+ event: { metadata }
24053
+ });
24054
+ return { metadata, span };
24055
+ }
24056
+ finishPendingChildrenForOperation(event, operationOutput2) {
24057
+ const endTime = eventTime(event.timestamp);
24058
+ const usage = event.usage ?? usageFromOperationResult(event.result);
24059
+ const turnEntries = [...this.turnsByKey].filter(
24060
+ ([, state]) => stateMatchesOperation(state, event.operationId)
24061
+ );
24062
+ turnEntries.forEach(([key, state], index) => {
24063
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
24064
+ safeLog3(state.span, {
24065
+ metadata: state.metadata,
24066
+ metrics: metricsFromUsage(usage),
24067
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
24068
+ });
24069
+ safeEnd(state.span, endTime);
24070
+ this.turnsByKey.delete(key);
24071
+ });
24072
+ for (const [key, state] of this.toolsByKey) {
24073
+ if (!stateMatchesOperation(state, event.operationId)) {
24074
+ continue;
24075
+ }
24076
+ safeEnd(state.span, endTime);
24077
+ this.toolsByKey.delete(key);
24301
24078
  }
24302
- const scopePrefixes = operationScopePrefixes(event);
24303
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24304
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24079
+ for (const [key, state] of this.tasksById) {
24080
+ if (!stateMatchesOperation(state, event.operationId)) {
24305
24081
  continue;
24306
24082
  }
24307
- const state = candidateQueue.shift();
24308
- if (!state) {
24309
- return void 0;
24083
+ safeEnd(state.span, endTime);
24084
+ this.tasksById.delete(key);
24085
+ }
24086
+ for (const [key, state] of this.compactionsByKey) {
24087
+ if (!stateMatchesOperation(state, event.operationId)) {
24088
+ continue;
24310
24089
  }
24311
- state.operationId = event.operationId;
24312
- this.activeOperationsById.set(event.operationId, state);
24313
- addScopedOperation(this.activeOperationsByScope, event, state);
24314
- state.metadata = {
24315
- ...state.metadata,
24316
- ...extractEventMetadata(event),
24317
- "flue.operation_id": event.operationId
24318
- };
24319
- safeLog3(state.span, { metadata: state.metadata });
24320
- return state;
24090
+ safeLog3(state.span, {
24091
+ metadata: state.metadata,
24092
+ metrics: durationMetrics2(event.durationMs),
24093
+ output: { completed: true }
24094
+ });
24095
+ safeEnd(state.span, eventTime(event.timestamp));
24096
+ this.compactionsByKey.delete(key);
24321
24097
  }
24322
- return void 0;
24323
24098
  }
24324
- activeOperationForEventScope(event) {
24325
- for (const scope of operationScopeNames(event)) {
24326
- const operations = this.activeOperationsByScope.get(scope);
24327
- if (operations?.length) {
24328
- return operations[operations.length - 1];
24099
+ finishPendingSpansForRun(event) {
24100
+ const endTime = eventTime(event.timestamp);
24101
+ for (const [key, state] of this.toolsByKey) {
24102
+ if (!stateMatchesRun(state, event.runId)) {
24103
+ continue;
24329
24104
  }
24105
+ safeEnd(state.span, endTime);
24106
+ this.toolsByKey.delete(key);
24330
24107
  }
24331
- return void 0;
24332
- }
24333
- pendingOperationForEventScope(event) {
24334
- const scopePrefixes = operationScopePrefixes(event);
24335
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24336
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24108
+ for (const [key, state] of this.turnsByKey) {
24109
+ if (!stateMatchesRun(state, event.runId)) {
24337
24110
  continue;
24338
24111
  }
24339
- return candidateQueue[0];
24112
+ safeEnd(state.span, endTime);
24113
+ this.turnsByKey.delete(key);
24340
24114
  }
24341
- return void 0;
24342
- }
24343
- takePendingOperationForEvent(event) {
24344
- const key = operationKey(event.session, event.operationKind);
24345
- const queue2 = this.pendingOperationsByKey.get(key);
24346
- if (queue2?.length) {
24347
- return queue2.shift();
24115
+ for (const [key, state] of this.tasksById) {
24116
+ if (!stateMatchesRun(state, event.runId)) {
24117
+ continue;
24118
+ }
24119
+ safeEnd(state.span, endTime);
24120
+ this.tasksById.delete(key);
24348
24121
  }
24349
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24350
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24351
- return candidateQueue.shift();
24122
+ for (const [key, state] of this.compactionsByKey) {
24123
+ if (!stateMatchesRun(state, event.runId)) {
24124
+ continue;
24352
24125
  }
24126
+ safeLog3(state.span, {
24127
+ metadata: state.metadata,
24128
+ output: { completed: true }
24129
+ });
24130
+ safeEnd(state.span, endTime);
24131
+ this.compactionsByKey.delete(key);
24353
24132
  }
24354
- return void 0;
24355
- }
24356
- pendingOperationQueue(key) {
24357
- const existing = this.pendingOperationsByKey.get(key);
24358
- if (existing) {
24359
- return existing;
24133
+ for (const [key, state] of this.operationsById) {
24134
+ if (!stateMatchesRun(state, event.runId)) {
24135
+ continue;
24136
+ }
24137
+ safeLog3(state.span, {
24138
+ metadata: state.metadata,
24139
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
24140
+ });
24141
+ safeEnd(state.span, endTime);
24142
+ this.operationsById.delete(key);
24360
24143
  }
24361
- const queue2 = [];
24362
- this.pendingOperationsByKey.set(key, queue2);
24363
- return queue2;
24364
24144
  }
24365
24145
  };
24366
24146
  function isInstrumentedOperation(operation) {
24367
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24368
- }
24369
- function getSessionName(session) {
24370
- return typeof session?.name === "string" ? session.name : void 0;
24371
- }
24372
- function operationKey(sessionName, operation) {
24373
- return `${sessionName ?? "unknown"}::${operation}`;
24374
- }
24375
- function operationScopePrefixes(event) {
24376
- const scopes = /* @__PURE__ */ new Set();
24377
- for (const scope of operationScopeNames(event)) {
24378
- scopes.add(`${scope}::`);
24379
- }
24380
- return scopes;
24381
- }
24382
- function operationKeyMatchesScopes(key, scopes) {
24383
- for (const scope of scopes) {
24384
- if (key.startsWith(scope)) {
24385
- return true;
24386
- }
24387
- }
24388
- return false;
24389
- }
24390
- function operationScopeNames(event) {
24391
- const scopes = /* @__PURE__ */ new Set();
24392
- if (event.session) {
24393
- scopes.add(event.session);
24394
- }
24395
- if (event.parentSession) {
24396
- scopes.add(event.parentSession);
24397
- }
24398
- if (!scopes.size) {
24399
- scopes.add("unknown");
24400
- }
24401
- return scopes;
24402
- }
24403
- function addScopedOperation(operationsByScope, event, state) {
24404
- for (const scope of operationScopeNames(event)) {
24405
- addOperationToScope(operationsByScope, scope, state);
24406
- }
24407
- }
24408
- function addOperationToScope(operationsByScope, scope, state) {
24409
- const operations = operationsByScope.get(scope);
24410
- if (operations) {
24411
- if (!operations.includes(state)) {
24412
- operations.push(state);
24413
- }
24414
- } else {
24415
- operationsByScope.set(scope, [state]);
24416
- }
24417
- }
24418
- function removeScopedOperation(operationsByScope, state) {
24419
- for (const [scope, operations] of operationsByScope) {
24420
- const index = operations.indexOf(state);
24421
- if (index === -1) {
24422
- continue;
24423
- }
24424
- operations.splice(index, 1);
24425
- if (operations.length === 0) {
24426
- operationsByScope.delete(scope);
24427
- }
24428
- }
24429
- }
24430
- function removePendingOperation(pendingOperationsByKey, state) {
24431
- for (const [key, queue2] of pendingOperationsByKey) {
24432
- const index = queue2.indexOf(state);
24433
- if (index === -1) {
24434
- continue;
24435
- }
24436
- queue2.splice(index, 1);
24437
- if (queue2.length === 0) {
24438
- pendingOperationsByKey.delete(key);
24439
- }
24440
- return;
24441
- }
24147
+ return operation === "prompt" || operation === "skill" || operation === "compact";
24442
24148
  }
24443
- function extractSessionMetadata(session) {
24444
- const sessionName = getSessionName(session);
24445
- return sessionName ? { "flue.session": sessionName } : {};
24446
- }
24447
- function extractEventMetadata(event) {
24149
+ function extractEventMetadata(event, ctx) {
24448
24150
  return {
24449
24151
  ...event.runId ? { "flue.run_id": event.runId } : {},
24152
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
24153
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
24450
24154
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
24451
24155
  ...event.session ? { "flue.session": event.session } : {},
24452
24156
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
24453
24157
  ...event.harness ? { "flue.harness": event.harness } : {},
24454
24158
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
24455
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24159
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
24160
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
24161
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
24162
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
24456
24163
  };
24457
24164
  }
24458
- function extractOperationInput(operation, args) {
24459
- switch (operation) {
24460
- case "prompt":
24461
- case "task":
24462
- return args[0];
24463
- case "skill":
24464
- return {
24465
- args: getOptionObject(args[1])?.args,
24466
- name: args[0]
24467
- };
24468
- case "compact":
24469
- return void 0;
24165
+ function extractPayloadMetadata(payload) {
24166
+ if (!isObjectLike(payload)) {
24167
+ return {};
24470
24168
  }
24169
+ const metadata = Reflect.get(payload, "metadata");
24170
+ if (!isObjectLike(metadata)) {
24171
+ return {};
24172
+ }
24173
+ return Object.fromEntries(Object.entries(metadata));
24471
24174
  }
24472
- function extractOperationInputMetadata(operation, args) {
24473
- const options = getOptionObject(args[1]);
24474
- return {
24475
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
24476
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
24477
- ...options?.role ? { "flue.role": options.role } : {},
24478
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
24479
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
24480
- ...Array.isArray(options?.tools) ? {
24481
- "flue.tools_count": options.tools.length,
24482
- tools: summarizeTools(options.tools)
24483
- } : {},
24484
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
24485
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
24486
- };
24487
- }
24488
- function getOptionObject(value) {
24489
- return isObject(value) ? value : void 0;
24490
- }
24491
- function summarizeTools(tools) {
24492
- return tools.flatMap((tool) => {
24493
- if (!isObject(tool)) {
24494
- return [];
24495
- }
24496
- const name = typeof tool.name === "string" ? tool.name : void 0;
24497
- if (!name) {
24498
- return [];
24499
- }
24500
- return [
24501
- {
24502
- function: {
24503
- description: typeof tool.description === "string" ? tool.description : void 0,
24504
- name,
24505
- parameters: tool.parameters
24506
- },
24507
- type: "function"
24508
- }
24509
- ];
24510
- });
24175
+ function operationOutput(event) {
24176
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
24177
+ return llmResultFromOperationResult(event.result);
24178
+ }
24179
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
24511
24180
  }
24512
- function extractPromptResponseMetadata(result) {
24513
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
24514
- return modelId ? {
24515
- model: modelId,
24516
- "flue.model": modelId
24517
- } : {};
24181
+ function llmResultFromOperationResult(result) {
24182
+ if (!isObjectLike(result)) {
24183
+ return result;
24184
+ }
24185
+ const text = Reflect.get(result, "text");
24186
+ return text === void 0 ? result : text;
24518
24187
  }
24519
- function extractOperationOutput(result) {
24520
- if (!result) {
24188
+ function usageFromOperationResult(result) {
24189
+ if (!isObjectLike(result)) {
24521
24190
  return void 0;
24522
24191
  }
24523
- if ("data" in result) {
24524
- return result.data;
24525
- }
24526
- if ("text" in result) {
24527
- return result.text;
24528
- }
24529
- return result;
24192
+ return Reflect.get(result, "usage");
24530
24193
  }
24531
24194
  function metricsFromUsage(usage) {
24195
+ if (!isObjectLike(usage)) {
24196
+ return {};
24197
+ }
24198
+ const cacheRead = Reflect.get(usage, "cacheRead");
24199
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
24200
+ const cost = Reflect.get(usage, "cost");
24201
+ const input = Reflect.get(usage, "input");
24202
+ const output = Reflect.get(usage, "output");
24203
+ const totalTokens = Reflect.get(usage, "totalTokens");
24204
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
24532
24205
  return {
24533
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
24534
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
24535
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
24536
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
24537
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
24538
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
24539
- };
24540
- }
24541
- function buildDurationMetrics3(startTime) {
24542
- return {
24543
- duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
24206
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
24207
+ ...typeof output === "number" ? { completion_tokens: output } : {},
24208
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
24209
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
24210
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
24211
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
24544
24212
  };
24545
24213
  }
24546
- function durationMsMetrics(durationMs) {
24214
+ function durationMetrics2(durationMs) {
24547
24215
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
24548
24216
  }
24549
- function scopeKey(event) {
24550
- if (event.operationId) {
24551
- return `operation:${event.operationId}`;
24552
- }
24553
- if (event.taskId) {
24554
- return `task:${event.taskId}`;
24555
- }
24556
- if (event.session) {
24557
- return `session:${event.session}`;
24217
+ function eventTime(value) {
24218
+ if (typeof value !== "string") {
24219
+ return void 0;
24558
24220
  }
24559
- return "flue:unknown";
24221
+ const timestamp = Date.parse(value);
24222
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
24223
+ }
24224
+ function turnKey(event) {
24225
+ return event.turnId;
24560
24226
  }
24561
24227
  function toolKey(event) {
24562
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24228
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
24563
24229
  }
24564
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24230
+ function compactionKey(event) {
24565
24231
  return [
24566
- {
24567
- finish_reason: finishReason ?? "stop",
24568
- index: 0,
24569
- message: {
24570
- content: text,
24571
- ...reasoning ? { reasoning } : {},
24572
- role: "assistant",
24573
- ...toolCalls?.length ? {
24574
- tool_calls: toolCalls.map((toolCall) => ({
24575
- function: {
24576
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
24577
- name: toolCall.toolName ?? "unknown"
24578
- },
24579
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
24580
- type: "function"
24581
- }))
24582
- } : {}
24583
- }
24584
- }
24585
- ];
24232
+ event.instanceId ?? "",
24233
+ event.runId ?? "",
24234
+ event.session ?? "",
24235
+ event.operationId ?? "",
24236
+ event.taskId ?? ""
24237
+ ].join(":");
24238
+ }
24239
+ function stateMatchesOperation(state, operationId) {
24240
+ return state.metadata["flue.operation_id"] === operationId;
24241
+ }
24242
+ function stateMatchesRun(state, runId) {
24243
+ return state.metadata["flue.run_id"] === runId;
24586
24244
  }
24587
24245
  function startFlueSpan(parent, args) {
24588
24246
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -24594,6 +24252,13 @@ function safeLog3(span, event) {
24594
24252
  logInstrumentationError3("Flue span log", error);
24595
24253
  }
24596
24254
  }
24255
+ function safeEnd(span, endTime) {
24256
+ try {
24257
+ span.end(endTime === void 0 ? void 0 : { endTime });
24258
+ } catch (error) {
24259
+ logInstrumentationError3("Flue span end", error);
24260
+ }
24261
+ }
24597
24262
  function errorToString(error) {
24598
24263
  if (error instanceof Error) {
24599
24264
  return error.message;
@@ -25087,7 +24752,7 @@ var BraintrustPlugin = class extends BasePlugin {
25087
24752
  this.config = config;
25088
24753
  }
25089
24754
  onEnable() {
25090
- const integrations = this.config.integrations || {};
24755
+ const integrations = this.config.integrations ?? {};
25091
24756
  if (integrations.openai !== false) {
25092
24757
  this.openaiPlugin = new OpenAIPlugin();
25093
24758
  this.openaiPlugin.enable();
@@ -25152,7 +24817,7 @@ var BraintrustPlugin = class extends BasePlugin {
25152
24817
  this.genkitPlugin = new GenkitPlugin();
25153
24818
  this.genkitPlugin.enable();
25154
24819
  }
25155
- if (getIntegrationConfig(integrations, "gitHubCopilot") !== false) {
24820
+ if (integrations.gitHubCopilot !== false) {
25156
24821
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25157
24822
  this.gitHubCopilotPlugin.enable();
25158
24823
  }
@@ -25265,6 +24930,7 @@ var envIntegrationAliases = {
25265
24930
  cursorsdk: "cursorSDK",
25266
24931
  flue: "flue",
25267
24932
  "flue-runtime": "flue",
24933
+ mastra: "mastra",
25268
24934
  "openai-agents": "openAIAgents",
25269
24935
  openaiagents: "openAIAgents",
25270
24936
  "openai-agents-core": "openAIAgents",
@@ -25307,6 +24973,7 @@ function getDefaultInstrumentationIntegrations() {
25307
24973
  cursor: true,
25308
24974
  cursorSDK: true,
25309
24975
  flue: true,
24976
+ mastra: true,
25310
24977
  openAIAgents: true,
25311
24978
  openrouter: true,
25312
24979
  openrouterAgent: true,
@@ -25331,6 +24998,9 @@ function readDisabledInstrumentationEnvConfig(disabledList) {
25331
24998
  }
25332
24999
  return { integrations };
25333
25000
  }
25001
+ function isInstrumentationIntegrationDisabled(integrations, ...names) {
25002
+ return names.some((name) => integrations?.[name] === false);
25003
+ }
25334
25004
 
25335
25005
  // src/instrumentation/registry.ts
25336
25006
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
@@ -25424,6 +25094,263 @@ var PluginRegistry = class {
25424
25094
  };
25425
25095
  var registry = new PluginRegistry();
25426
25096
 
25097
+ // src/auto-instrumentations/loader/mastra-observability-patch.ts
25098
+ var MASTRA_EXPORTER_FACTORY_GLOBAL = "__braintrustMastraExporterFactory";
25099
+ function installMastraExporterFactory(factory) {
25100
+ const globals = globalThis;
25101
+ globals[MASTRA_EXPORTER_FACTORY_GLOBAL] ??= factory;
25102
+ }
25103
+ var EXPORTER_FACTORY_KEY = JSON.stringify(MASTRA_EXPORTER_FACTORY_GLOBAL);
25104
+ var OBSERVABILITY_APPEND_BODY = `
25105
+ ;(function __braintrustWrapObservability() {
25106
+ // Top-level so we can both read and reassign the var binding the original
25107
+ // entry declared.
25108
+ if (typeof Observability === "undefined") return;
25109
+ if (Observability.__braintrustWrapped) return;
25110
+ function __braintrustEnsureExporter(rawConfig) {
25111
+ try {
25112
+ var factory = globalThis[${EXPORTER_FACTORY_KEY}];
25113
+ if (typeof factory !== "function") return rawConfig;
25114
+ var config = rawConfig && typeof rawConfig === "object" ? rawConfig : {};
25115
+ var configsIn = config.configs && typeof config.configs === "object" ? config.configs : null;
25116
+ var configsOut = {};
25117
+ var hadEntries = false;
25118
+ if (configsIn) {
25119
+ for (var name in configsIn) {
25120
+ if (!Object.prototype.hasOwnProperty.call(configsIn, name)) continue;
25121
+ hadEntries = true;
25122
+ var inst = configsIn[name] || {};
25123
+ var existing = Array.isArray(inst.exporters) ? inst.exporters : [];
25124
+ var hasOurs = existing.some(function (e) { return e && e.name === "braintrust"; });
25125
+ configsOut[name] = Object.assign({}, inst, {
25126
+ exporters: hasOurs ? existing : existing.concat([factory()]),
25127
+ });
25128
+ }
25129
+ }
25130
+ if (!hadEntries) {
25131
+ configsOut.default = {
25132
+ serviceName: "mastra",
25133
+ exporters: [factory()],
25134
+ };
25135
+ }
25136
+ return Object.assign({}, config, { configs: configsOut });
25137
+ } catch (e) {
25138
+ return rawConfig;
25139
+ }
25140
+ }
25141
+ var __OriginalObservability = Observability;
25142
+ Observability = new Proxy(__OriginalObservability, {
25143
+ construct: function (target, args, newTarget) {
25144
+ var nextArgs = args.slice();
25145
+ nextArgs[0] = __braintrustEnsureExporter(nextArgs[0]);
25146
+ return Reflect.construct(target, nextArgs, newTarget);
25147
+ },
25148
+ });
25149
+ Observability.__braintrustWrapped = true;
25150
+ if (typeof exports !== "undefined" && exports && typeof exports === "object") {
25151
+ try {
25152
+ Object.defineProperty(exports, "Observability", {
25153
+ enumerable: true,
25154
+ configurable: true,
25155
+ get: function () { return Observability; },
25156
+ });
25157
+ } catch (e) {}
25158
+ }
25159
+ })();
25160
+ `;
25161
+
25162
+ // src/wrappers/mastra.ts
25163
+ var MASTRA_BRAINTRUST_EXPORTER_NAME = "braintrust";
25164
+ var SPAN_TYPE_MAP = {
25165
+ agent_run: "task" /* TASK */,
25166
+ model_generation: "llm" /* LLM */,
25167
+ model_step: "llm" /* LLM */,
25168
+ model_chunk: "llm" /* LLM */,
25169
+ tool_call: "tool" /* TOOL */,
25170
+ mcp_tool_call: "tool" /* TOOL */,
25171
+ workflow_run: "task" /* TASK */,
25172
+ workflow_step: "function" /* FUNCTION */,
25173
+ workflow_conditional: "function" /* FUNCTION */,
25174
+ workflow_conditional_eval: "function" /* FUNCTION */,
25175
+ workflow_parallel: "function" /* FUNCTION */,
25176
+ workflow_loop: "function" /* FUNCTION */,
25177
+ workflow_sleep: "function" /* FUNCTION */,
25178
+ workflow_wait_event: "function" /* FUNCTION */,
25179
+ memory_operation: "function" /* FUNCTION */,
25180
+ workspace_action: "function" /* FUNCTION */,
25181
+ rag_ingestion: "task" /* TASK */,
25182
+ rag_embedding: "llm" /* LLM */,
25183
+ rag_vector_operation: "function" /* FUNCTION */,
25184
+ rag_action: "function" /* FUNCTION */,
25185
+ graph_action: "function" /* FUNCTION */,
25186
+ scorer_run: "score" /* SCORE */,
25187
+ scorer_step: "score" /* SCORE */,
25188
+ processor_run: "function" /* FUNCTION */,
25189
+ generic: "function" /* FUNCTION */
25190
+ };
25191
+ function spanTypeFor(mastraType) {
25192
+ return SPAN_TYPE_MAP[mastraType] ?? "function" /* FUNCTION */;
25193
+ }
25194
+ function epochSeconds(value) {
25195
+ if (value === void 0) return void 0;
25196
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
25197
+ return Number.isFinite(ms) ? ms / 1e3 : void 0;
25198
+ }
25199
+ function modelMetrics(attributes) {
25200
+ if (!isObject(attributes)) return void 0;
25201
+ const usage = isObject(attributes.usage) ? attributes.usage : void 0;
25202
+ if (!usage) return void 0;
25203
+ const out = {};
25204
+ if (typeof usage.inputTokens === "number")
25205
+ out.prompt_tokens = usage.inputTokens;
25206
+ if (typeof usage.outputTokens === "number")
25207
+ out.completion_tokens = usage.outputTokens;
25208
+ if (typeof usage.inputTokens === "number" && typeof usage.outputTokens === "number") {
25209
+ out.tokens = usage.inputTokens + usage.outputTokens;
25210
+ }
25211
+ const inputDetails = isObject(usage.inputDetails) ? usage.inputDetails : void 0;
25212
+ const outputDetails = isObject(usage.outputDetails) ? usage.outputDetails : void 0;
25213
+ if (inputDetails && typeof inputDetails.cacheRead === "number") {
25214
+ out.prompt_cached_tokens = inputDetails.cacheRead;
25215
+ }
25216
+ if (inputDetails && typeof inputDetails.cacheWrite === "number") {
25217
+ out.prompt_cache_creation_tokens = inputDetails.cacheWrite;
25218
+ }
25219
+ if (outputDetails && typeof outputDetails.reasoning === "number") {
25220
+ out.completion_reasoning_tokens = outputDetails.reasoning;
25221
+ }
25222
+ return Object.keys(out).length > 0 ? out : void 0;
25223
+ }
25224
+ function buildMetadata(exported) {
25225
+ const out = {};
25226
+ if (exported.entityId !== void 0) out.entity_id = exported.entityId;
25227
+ if (exported.entityName !== void 0) out.entity_name = exported.entityName;
25228
+ if (exported.entityType !== void 0) out.entity_type = exported.entityType;
25229
+ if (exported.metadata && isObject(exported.metadata)) {
25230
+ Object.assign(out, exported.metadata);
25231
+ }
25232
+ if (exported.attributes && isObject(exported.attributes)) {
25233
+ for (const [key, value] of Object.entries(exported.attributes)) {
25234
+ if (key === "usage") continue;
25235
+ if (value !== void 0) out[key] = value;
25236
+ }
25237
+ }
25238
+ if (exported.tags && exported.tags.length > 0) {
25239
+ out.tags = exported.tags;
25240
+ }
25241
+ if (exported.requestContext && isObject(exported.requestContext)) {
25242
+ out.request_context = exported.requestContext;
25243
+ }
25244
+ return out;
25245
+ }
25246
+ var BraintrustObservabilityExporter = class {
25247
+ name = MASTRA_BRAINTRUST_EXPORTER_NAME;
25248
+ spans = /* @__PURE__ */ new Map();
25249
+ // Captured at the first SPAN_STARTED event. Mastra's observability bus may
25250
+ // dispatch later events outside the user's AsyncLocalStorage context, where
25251
+ // `currentSpan()` returns NOOP_SPAN — which would make our `startSpan()`
25252
+ // calls go to a no-op logger and silently drop. Anchoring on the parent
25253
+ // we observe while still in-context keeps the whole Mastra subtree under
25254
+ // the user's traced scenario.
25255
+ capturedParent;
25256
+ constructor() {
25257
+ _internalSetInitialState();
25258
+ }
25259
+ async exportTracingEvent(event) {
25260
+ const exported = event.exportedSpan;
25261
+ if (exported.isInternal === true) return;
25262
+ try {
25263
+ switch (event.type) {
25264
+ case "span_started":
25265
+ this.onStart(exported);
25266
+ break;
25267
+ case "span_updated":
25268
+ this.onUpdate(exported);
25269
+ break;
25270
+ case "span_ended":
25271
+ this.onEnd(exported);
25272
+ break;
25273
+ }
25274
+ } catch (err) {
25275
+ logExporterError(err);
25276
+ }
25277
+ }
25278
+ async flush() {
25279
+ const state = _internalGetGlobalState();
25280
+ if (state) {
25281
+ await state.bgLogger().flush();
25282
+ }
25283
+ }
25284
+ async shutdown() {
25285
+ await this.flush();
25286
+ this.spans.clear();
25287
+ }
25288
+ onStart(exported) {
25289
+ if (this.spans.has(exported.id)) return;
25290
+ const args = {
25291
+ name: exported.name,
25292
+ spanAttributes: { type: spanTypeFor(exported.type) },
25293
+ startTime: epochSeconds(exported.startTime)
25294
+ };
25295
+ const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
25296
+ if (!this.capturedParent) {
25297
+ const probe = currentSpan();
25298
+ if (probe && probe.spanId) {
25299
+ this.capturedParent = probe;
25300
+ }
25301
+ }
25302
+ const span = parentRecord ? parentRecord.span.startSpan(args) : this.capturedParent ? this.capturedParent.startSpan(args) : startSpan(args);
25303
+ const record = { span, hasLoggedInput: false };
25304
+ this.logPayload(record, exported);
25305
+ this.spans.set(exported.id, record);
25306
+ if (exported.isEvent === true) {
25307
+ span.end({ endTime: args.startTime });
25308
+ this.spans.delete(exported.id);
25309
+ }
25310
+ }
25311
+ onUpdate(exported) {
25312
+ const record = this.spans.get(exported.id);
25313
+ if (!record) return;
25314
+ this.logPayload(record, exported);
25315
+ }
25316
+ onEnd(exported) {
25317
+ const record = this.spans.get(exported.id);
25318
+ if (!record) return;
25319
+ this.logPayload(record, exported);
25320
+ if (exported.errorInfo) {
25321
+ record.span.log({
25322
+ error: exported.errorInfo.message || exported.errorInfo.name || "Unknown Mastra error"
25323
+ });
25324
+ }
25325
+ record.span.end({ endTime: epochSeconds(exported.endTime) });
25326
+ this.spans.delete(exported.id);
25327
+ }
25328
+ logPayload(record, exported) {
25329
+ const event = {};
25330
+ if (exported.input !== void 0) {
25331
+ event.input = exported.input;
25332
+ record.hasLoggedInput = true;
25333
+ }
25334
+ if (exported.output !== void 0) {
25335
+ event.output = exported.output;
25336
+ }
25337
+ const metadata = buildMetadata(exported);
25338
+ if (Object.keys(metadata).length > 0) {
25339
+ event.metadata = metadata;
25340
+ }
25341
+ const metrics = modelMetrics(exported.attributes);
25342
+ if (metrics) {
25343
+ event.metrics = metrics;
25344
+ }
25345
+ if (Object.keys(event).length > 0) {
25346
+ record.span.log(event);
25347
+ }
25348
+ }
25349
+ };
25350
+ function logExporterError(err) {
25351
+ debugLogger.warn("Mastra exporter failure:", err);
25352
+ }
25353
+
25427
25354
  // src/node/config.ts
25428
25355
  var BRAINTRUST_ENV_SEARCH_PARENT_LIMIT = 64;
25429
25356
  function configureNode() {
@@ -25509,6 +25436,12 @@ function configureNode() {
25509
25436
  isomorph_default.gunzip = promisify(zlib.gunzip);
25510
25437
  isomorph_default.hash = (data) => crypto.createHash("sha256").update(data).digest("hex");
25511
25438
  _internalSetInitialState();
25439
+ const disabled = readDisabledInstrumentationEnvConfig(
25440
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
25441
+ ).integrations;
25442
+ if (!isInstrumentationIntegrationDisabled(disabled, "mastra")) {
25443
+ installMastraExporterFactory(() => new BraintrustObservabilityExporter());
25444
+ }
25512
25445
  registry.enable();
25513
25446
  }
25514
25447