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
package/dist/index.mjs CHANGED
@@ -14,6 +14,8 @@ import {
14
14
  googleGenAIChannels,
15
15
  groqChannels,
16
16
  huggingFaceChannels,
17
+ installMastraExporterFactory,
18
+ isInstrumentationIntegrationDisabled,
17
19
  isomorph_default,
18
20
  langChainChannels,
19
21
  mistralChannels,
@@ -24,7 +26,7 @@ import {
24
26
  openRouterChannels,
25
27
  patchTracingChannel,
26
28
  readDisabledInstrumentationEnvConfig
27
- } from "./chunk-75IQCUB2.mjs";
29
+ } from "./chunk-O4ZIWXO3.mjs";
28
30
 
29
31
  // src/node/config.ts
30
32
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -4085,6 +4087,76 @@ var LRUCache = class {
4085
4087
  }
4086
4088
  };
4087
4089
 
4090
+ // src/prompt-cache/cache-config.ts
4091
+ var CACHE_LOCATION_ENV_VAR = "BRAINTRUST_CACHE_LOCATION";
4092
+ var DEFAULT_CACHE_MEMORY_MAX = 1 << 10;
4093
+ var DEFAULT_CACHE_DISK_MAX = 1 << 20;
4094
+ var warnedInvalidCacheModeEnvValue = false;
4095
+ var warnedUnavailableDiskCacheMode = false;
4096
+ function warnInvalidCacheMode(value) {
4097
+ if (warnedInvalidCacheModeEnvValue) {
4098
+ return;
4099
+ }
4100
+ warnedInvalidCacheModeEnvValue = true;
4101
+ debugLogger.warn(
4102
+ `Invalid ${CACHE_LOCATION_ENV_VAR} value "${value}". Expected "mixed", "memory", "disk", or "none". Falling back to "mixed".`
4103
+ );
4104
+ }
4105
+ function warnUnavailableDiskCache() {
4106
+ if (warnedUnavailableDiskCacheMode) {
4107
+ return;
4108
+ }
4109
+ warnedUnavailableDiskCacheMode = true;
4110
+ debugLogger.warn(
4111
+ `Disk cache is not supported on this platform, so ${CACHE_LOCATION_ENV_VAR}="disk" disables prompt and parameters caching.`
4112
+ );
4113
+ }
4114
+ function parseCacheMode() {
4115
+ const value = isomorph_default.getEnv(CACHE_LOCATION_ENV_VAR);
4116
+ const normalized = value?.trim().toLowerCase();
4117
+ if (!normalized) {
4118
+ return "mixed";
4119
+ }
4120
+ if (normalized === "mixed" || normalized === "memory" || normalized === "disk" || normalized === "none") {
4121
+ return normalized;
4122
+ }
4123
+ warnInvalidCacheMode(value ?? "");
4124
+ return "mixed";
4125
+ }
4126
+ function parsePositiveIntegerEnv(envVar, defaultValue) {
4127
+ const value = Number(isomorph_default.getEnv(envVar));
4128
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
4129
+ }
4130
+ function createCacheLayers({
4131
+ memoryMaxEnvVar,
4132
+ diskCacheDirEnvVar,
4133
+ diskMaxEnvVar,
4134
+ getDefaultDiskCacheDir
4135
+ }) {
4136
+ const mode = parseCacheMode();
4137
+ const memoryCache = mode === "mixed" || mode === "memory" ? new LRUCache({
4138
+ max: parsePositiveIntegerEnv(
4139
+ memoryMaxEnvVar,
4140
+ DEFAULT_CACHE_MEMORY_MAX
4141
+ )
4142
+ }) : void 0;
4143
+ let diskCache;
4144
+ if (mode === "mixed" || mode === "disk") {
4145
+ if (canUseDiskCache()) {
4146
+ diskCache = new DiskCache({
4147
+ cacheDir: isomorph_default.getEnv(diskCacheDirEnvVar) ?? getDefaultDiskCacheDir(),
4148
+ max: parsePositiveIntegerEnv(diskMaxEnvVar, DEFAULT_CACHE_DISK_MAX)
4149
+ });
4150
+ } else if (mode === "disk") {
4151
+ warnUnavailableDiskCache();
4152
+ }
4153
+ }
4154
+ if (diskCache) {
4155
+ return { memoryCache, diskCache };
4156
+ }
4157
+ return { memoryCache };
4158
+ }
4159
+
4088
4160
  // src/prompt-cache/prompt-cache.ts
4089
4161
  function createCacheKey(key) {
4090
4162
  if (key.id) {
@@ -4112,16 +4184,18 @@ var PromptCache = class {
4112
4184
  */
4113
4185
  async get(key) {
4114
4186
  const cacheKey = createCacheKey(key);
4115
- const memoryPrompt = this.memoryCache.get(cacheKey);
4116
- if (memoryPrompt !== void 0) {
4117
- return memoryPrompt;
4187
+ if (this.memoryCache) {
4188
+ const memoryPrompt = this.memoryCache.get(cacheKey);
4189
+ if (memoryPrompt !== void 0) {
4190
+ return memoryPrompt;
4191
+ }
4118
4192
  }
4119
4193
  if (this.diskCache) {
4120
4194
  const diskPrompt = await this.diskCache.get(cacheKey);
4121
4195
  if (!diskPrompt) {
4122
4196
  return void 0;
4123
4197
  }
4124
- this.memoryCache.set(cacheKey, diskPrompt);
4198
+ this.memoryCache?.set(cacheKey, diskPrompt);
4125
4199
  return diskPrompt;
4126
4200
  }
4127
4201
  return void 0;
@@ -4136,7 +4210,7 @@ var PromptCache = class {
4136
4210
  */
4137
4211
  async set(key, value) {
4138
4212
  const cacheKey = createCacheKey(key);
4139
- this.memoryCache.set(cacheKey, value);
4213
+ this.memoryCache?.set(cacheKey, value);
4140
4214
  if (this.diskCache) {
4141
4215
  await this.diskCache.set(cacheKey, value);
4142
4216
  }
@@ -4166,23 +4240,25 @@ var ParametersCache = class {
4166
4240
  }
4167
4241
  async get(key) {
4168
4242
  const cacheKey = createCacheKey2(key);
4169
- const memoryParams = this.memoryCache.get(cacheKey);
4170
- if (memoryParams !== void 0) {
4171
- return memoryParams;
4243
+ if (this.memoryCache) {
4244
+ const memoryParams = this.memoryCache.get(cacheKey);
4245
+ if (memoryParams !== void 0) {
4246
+ return memoryParams;
4247
+ }
4172
4248
  }
4173
4249
  if (this.diskCache) {
4174
4250
  const diskParams = await this.diskCache.get(cacheKey);
4175
4251
  if (!diskParams) {
4176
4252
  return void 0;
4177
4253
  }
4178
- this.memoryCache.set(cacheKey, diskParams);
4254
+ this.memoryCache?.set(cacheKey, diskParams);
4179
4255
  return diskParams;
4180
4256
  }
4181
4257
  return void 0;
4182
4258
  }
4183
4259
  async set(key, value) {
4184
4260
  const cacheKey = createCacheKey2(key);
4185
- this.memoryCache.set(cacheKey, value);
4261
+ this.memoryCache?.set(cacheKey, value);
4186
4262
  if (this.diskCache) {
4187
4263
  await this.diskCache.set(cacheKey, value);
4188
4264
  }
@@ -4714,21 +4790,22 @@ var BraintrustState = class _BraintrustState {
4714
4790
  setGlobalDebugLogLevel(void 0);
4715
4791
  }
4716
4792
  this.resetLoginInfo();
4717
- const memoryCache = new LRUCache({
4718
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
4793
+ const { memoryCache, diskCache } = createCacheLayers({
4794
+ memoryMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_MEMORY_MAX",
4795
+ diskCacheDirEnvVar: "BRAINTRUST_PROMPT_CACHE_DIR",
4796
+ diskMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_DISK_MAX",
4797
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`
4719
4798
  });
4720
- const diskCache = canUseDiskCache() ? new DiskCache({
4721
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`,
4722
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DISK_MAX")) ?? 1 << 20
4723
- }) : void 0;
4724
4799
  this.promptCache = new PromptCache({ memoryCache, diskCache });
4725
- const parametersMemoryCache = new LRUCache({
4726
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX")) ?? 1 << 10
4800
+ const {
4801
+ memoryCache: parametersMemoryCache,
4802
+ diskCache: parametersDiskCache
4803
+ } = createCacheLayers({
4804
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
4805
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
4806
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
4807
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
4727
4808
  });
4728
- const parametersDiskCache = canUseDiskCache() ? new DiskCache({
4729
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`,
4730
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DISK_MAX")) ?? 1 << 20
4731
- }) : void 0;
4732
4809
  this.parametersCache = new ParametersCache({
4733
4810
  memoryCache: parametersMemoryCache,
4734
4811
  diskCache: parametersDiskCache
@@ -23521,798 +23598,437 @@ var GitHubCopilotPlugin = class extends BasePlugin {
23521
23598
  }
23522
23599
  };
23523
23600
 
23524
- // src/wrappers/flue.ts
23525
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23526
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23527
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23528
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23529
- "braintrust.flue.subscribed-context-events"
23530
- );
23531
- function wrapFlueContext(ctx) {
23532
- if (!isPlausibleFlueContext(ctx)) {
23533
- console.warn("Unsupported Flue context. Not wrapping.");
23534
- return ctx;
23601
+ // src/instrumentation/plugins/flue-plugin.ts
23602
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
23603
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
23604
+ var braintrustFlueObserver = (event, ctx) => {
23605
+ getObserveBridge().handle(event, ctx);
23606
+ };
23607
+ var FluePlugin = class extends BasePlugin {
23608
+ onEnable() {
23609
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
23535
23610
  }
23536
- const context = ctx;
23537
- subscribeFlueContextEvents(context, { captureTurnSpans: true });
23538
- return patchFlueContextInPlace(context);
23539
- }
23540
- function patchFlueContextInPlace(ctx) {
23541
- const context = ctx;
23542
- if (context[WRAPPED_FLUE_CONTEXT]) {
23543
- return ctx;
23611
+ onDisable() {
23612
+ for (const unsubscribe of this.unsubscribers) {
23613
+ unsubscribe();
23614
+ }
23615
+ this.unsubscribers = [];
23544
23616
  }
23545
- const originalInit = context.init.bind(context);
23546
- try {
23547
- Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23548
- configurable: false,
23549
- enumerable: false,
23550
- value: true
23551
- });
23552
- Object.defineProperty(context, "init", {
23553
- configurable: true,
23554
- value: async function wrappedFlueInit(options) {
23555
- const harness = await originalInit(options);
23556
- return wrapFlueHarness(harness);
23557
- },
23558
- writable: true
23559
- });
23560
- } catch {
23617
+ };
23618
+ function enableFlueAutoInstrumentation() {
23619
+ const state = getAutoState();
23620
+ state.refCount += 1;
23621
+ if (!state.handlers) {
23622
+ const channel = flueChannels.createContext.tracingChannel();
23623
+ const handlers = {
23624
+ end: (event) => {
23625
+ subscribeToFlueContext(event.result, state);
23626
+ }
23627
+ };
23628
+ channel.subscribe(handlers);
23629
+ state.channel = channel;
23630
+ state.handlers = handlers;
23561
23631
  }
23562
- return ctx;
23632
+ let released = false;
23633
+ return () => {
23634
+ if (released) {
23635
+ return;
23636
+ }
23637
+ released = true;
23638
+ releaseAutoState(state);
23639
+ };
23563
23640
  }
23564
- function wrapFlueSession(session) {
23565
- if (!isPlausibleFlueSession(session)) {
23566
- console.warn("Unsupported Flue session. Not wrapping.");
23567
- return session;
23641
+ function getAutoState() {
23642
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
23643
+ if (isAutoState(existing)) {
23644
+ return existing;
23568
23645
  }
23569
- return patchFlueSessionInPlace(session);
23646
+ const state = {
23647
+ contexts: /* @__PURE__ */ new WeakSet(),
23648
+ refCount: 0
23649
+ };
23650
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
23651
+ return state;
23570
23652
  }
23571
- function subscribeFlueContextEvents(ctx, options = {}) {
23572
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23573
- return void 0;
23574
- }
23575
- const context = ctx;
23576
- const captureTurnSpans = options.captureTurnSpans ?? true;
23577
- const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
23578
- if (existingSubscription) {
23579
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
23580
- return void 0;
23581
- }
23582
- try {
23583
- existingSubscription.unsubscribe();
23584
- } catch {
23585
- }
23586
- }
23587
- try {
23588
- const unsubscribe = ctx.subscribeEvent((event) => {
23589
- flueChannels.contextEvent.traceSync(() => void 0, {
23590
- arguments: [event],
23591
- captureTurnSpans,
23592
- context: ctx
23593
- });
23594
- });
23595
- if (existingSubscription) {
23596
- existingSubscription.captureTurnSpans = captureTurnSpans;
23597
- existingSubscription.unsubscribe = unsubscribe;
23598
- } else {
23599
- Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
23600
- configurable: false,
23601
- enumerable: false,
23602
- value: {
23603
- captureTurnSpans,
23604
- unsubscribe
23605
- }
23606
- });
23607
- }
23608
- return unsubscribe;
23609
- } catch {
23610
- return void 0;
23653
+ function getObserveBridge() {
23654
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
23655
+ if (isFlueObserveBridge(existing)) {
23656
+ return existing;
23611
23657
  }
23658
+ const bridge = new FlueObserveBridge();
23659
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
23660
+ return bridge;
23612
23661
  }
23613
- function wrapFlueHarness(harness) {
23614
- if (!isPlausibleFlueHarness(harness)) {
23615
- return harness;
23616
- }
23617
- const target = harness;
23618
- if (target[WRAPPED_FLUE_HARNESS]) {
23619
- return harness;
23620
- }
23621
- const originalSession = target.session.bind(target);
23622
- try {
23623
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
23624
- configurable: false,
23625
- enumerable: false,
23626
- value: true
23627
- });
23628
- Object.defineProperty(target, "session", {
23629
- configurable: true,
23630
- value: async function wrappedFlueHarnessSession(name, options) {
23631
- const session = await originalSession(name, options);
23632
- return patchFlueSessionInPlace(session);
23633
- },
23634
- writable: true
23635
- });
23636
- const sessions = target.sessions;
23637
- if (sessions && typeof sessions === "object") {
23638
- patchFlueSessionFactory(sessions, "get");
23639
- patchFlueSessionFactory(sessions, "create");
23640
- }
23641
- } catch {
23642
- }
23643
- return harness;
23662
+ function isFlueObserveBridge(value) {
23663
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
23644
23664
  }
23645
- function patchFlueSessionInPlace(session) {
23646
- if (session[WRAPPED_FLUE_SESSION]) {
23647
- return session;
23648
- }
23649
- try {
23650
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
23651
- configurable: false,
23652
- enumerable: false,
23653
- value: true
23654
- });
23655
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
23656
- patchCallHandleMethod(session, "skill", flueChannels.skill);
23657
- patchCallHandleMethod(session, "task", flueChannels.task);
23658
- patchCompact(session);
23659
- } catch {
23660
- }
23661
- return session;
23665
+ function isAutoState(value) {
23666
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
23662
23667
  }
23663
- function patchFlueSessionFactory(sessions, method) {
23664
- const original = sessions[method];
23665
- if (typeof original !== "function") {
23668
+ function releaseAutoState(state) {
23669
+ state.refCount -= 1;
23670
+ if (state.refCount > 0) {
23666
23671
  return;
23667
23672
  }
23668
- const bound = original.bind(sessions);
23669
- Object.defineProperty(sessions, method, {
23670
- configurable: true,
23671
- value: async function wrappedFlueSessionFactory(name, options) {
23672
- const session = await bound(name, options);
23673
- return patchFlueSessionInPlace(session);
23674
- },
23675
- writable: true
23676
- });
23677
- }
23678
- function patchCallHandleMethod(session, method, channel) {
23679
- const original = session[method];
23680
- if (typeof original !== "function") {
23681
- return;
23673
+ try {
23674
+ if (state.channel && state.handlers) {
23675
+ state.channel.unsubscribe(state.handlers);
23676
+ }
23677
+ } finally {
23678
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
23682
23679
  }
23683
- const bound = original.bind(session);
23684
- Object.defineProperty(session, method, {
23685
- configurable: true,
23686
- value(input, options) {
23687
- const args = [input, options];
23688
- const { originalResult, traced: traced2 } = traceFlueOperation(channel, {
23689
- context: {
23690
- arguments: args,
23691
- operation: method,
23692
- session
23693
- },
23694
- run: () => bound(input, options)
23695
- });
23696
- return preserveCallHandle(originalResult, traced2);
23697
- },
23698
- writable: true
23699
- });
23700
23680
  }
23701
- function patchCompact(session) {
23702
- const original = session.compact;
23703
- if (typeof original !== "function") {
23681
+ function subscribeToFlueContext(value, state) {
23682
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
23704
23683
  return;
23705
23684
  }
23706
- const bound = original.bind(session);
23707
- Object.defineProperty(session, "compact", {
23708
- configurable: true,
23709
- value() {
23710
- const context = {
23711
- arguments: [],
23712
- operation: "compact",
23713
- session
23714
- };
23715
- return flueChannels.compact.tracePromise(() => bound(), context);
23716
- },
23717
- writable: true
23718
- });
23719
- }
23720
- function traceFlueOperation(channel, args) {
23721
- const tracingChannel2 = channel.tracingChannel();
23722
- const context = args.context;
23723
- let originalResult;
23724
- let traced2;
23725
- const run = () => {
23685
+ const ctx = flueContextFromUnknown(value);
23686
+ let released = false;
23687
+ let unsubscribe;
23688
+ const release = () => {
23689
+ if (released) {
23690
+ return;
23691
+ }
23692
+ released = true;
23726
23693
  try {
23727
- originalResult = args.run();
23728
- tracingChannel2.end?.publish(context);
23694
+ unsubscribe?.();
23729
23695
  } catch (error) {
23730
- context.error = normalizeError3(error);
23731
- tracingChannel2.error?.publish(context);
23732
- tracingChannel2.end?.publish(context);
23733
- throw error;
23696
+ logInstrumentationError3("Flue context unsubscribe", error);
23734
23697
  }
23735
- traced2 = Promise.resolve(originalResult).then(
23736
- (result) => {
23737
- context.result = result;
23738
- tracingChannel2.asyncStart?.publish(context);
23739
- tracingChannel2.asyncEnd?.publish(context);
23740
- return result;
23741
- },
23742
- (error) => {
23743
- context.error = normalizeError3(error);
23744
- tracingChannel2.error?.publish(context);
23745
- tracingChannel2.asyncStart?.publish(context);
23746
- tracingChannel2.asyncEnd?.publish(context);
23747
- throw error;
23748
- }
23749
- );
23750
23698
  };
23751
- if (tracingChannel2.start?.runStores) {
23752
- tracingChannel2.start.runStores(context, run);
23753
- } else {
23754
- tracingChannel2.start?.publish(context);
23755
- run();
23699
+ try {
23700
+ unsubscribe = value.subscribeEvent((event) => {
23701
+ if (state.refCount <= 0) {
23702
+ release();
23703
+ return;
23704
+ }
23705
+ braintrustFlueObserver(event, ctx);
23706
+ if (isAutoContextTerminalEvent(event, ctx)) {
23707
+ release();
23708
+ }
23709
+ });
23710
+ state.contexts.add(value);
23711
+ } catch (error) {
23712
+ logInstrumentationError3("Flue context subscription", error);
23756
23713
  }
23757
- return { originalResult, traced: traced2 };
23758
- }
23759
- function normalizeError3(error) {
23760
- return error instanceof Error ? error : new Error(String(error));
23761
23714
  }
23762
- function preserveCallHandle(originalHandle, traced2) {
23763
- if (!isFlueCallHandle(originalHandle)) {
23764
- return traced2;
23715
+ function isAutoContextTerminalEvent(event, ctx) {
23716
+ if (!isObjectLike(event)) {
23717
+ return false;
23765
23718
  }
23766
- const handle = originalHandle;
23767
- const wrapped = {
23768
- get signal() {
23769
- return handle.signal;
23770
- },
23771
- abort(reason) {
23772
- return handle.abort(reason);
23773
- },
23774
- then(onfulfilled, onrejected) {
23775
- return traced2.then(onfulfilled, onrejected);
23776
- }
23777
- };
23778
- return wrapped;
23719
+ const type = Reflect.get(event, "type");
23720
+ if (type === "run_end") {
23721
+ return true;
23722
+ }
23723
+ if (type !== "operation") {
23724
+ return false;
23725
+ }
23726
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
23779
23727
  }
23780
- function isPlausibleFlueContext(value) {
23781
- return !!value && typeof value === "object" && typeof value.init === "function";
23728
+ function isObservableFlueContext(value) {
23729
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
23782
23730
  }
23783
- function isPlausibleFlueHarness(value) {
23784
- return !!value && typeof value === "object" && typeof value.session === "function";
23731
+ function isFlueEvent(event) {
23732
+ const type = Reflect.get(event, "type");
23733
+ 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";
23785
23734
  }
23786
- function isPlausibleFlueSession(value) {
23787
- return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
23735
+ function flueContextFromUnknown(ctx) {
23736
+ if (!isObjectLike(ctx)) {
23737
+ return void 0;
23738
+ }
23739
+ const id = Reflect.get(ctx, "id");
23740
+ const runId = Reflect.get(ctx, "runId");
23741
+ return {
23742
+ ...typeof id === "string" ? { id } : {},
23743
+ ...typeof runId === "string" ? { runId } : {}
23744
+ };
23788
23745
  }
23789
- function isFlueCallHandle(value) {
23790
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
23746
+ function isObjectLike(value) {
23747
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23791
23748
  }
23792
-
23793
- // src/instrumentation/plugins/flue-plugin.ts
23794
- var FluePlugin = class extends BasePlugin {
23795
- activeOperationsById = /* @__PURE__ */ new Map();
23796
- activeOperationsByScope = /* @__PURE__ */ new Map();
23797
- compactionsByScope = /* @__PURE__ */ new Map();
23798
- pendingOperationsByKey = /* @__PURE__ */ new Map();
23749
+ var FlueObserveBridge = class {
23750
+ compactionsByKey = /* @__PURE__ */ new Map();
23751
+ operationsById = /* @__PURE__ */ new Map();
23752
+ runsById = /* @__PURE__ */ new Map();
23753
+ seenEvents = /* @__PURE__ */ new WeakSet();
23799
23754
  tasksById = /* @__PURE__ */ new Map();
23800
- toolsById = /* @__PURE__ */ new Map();
23801
- turnsByScope = /* @__PURE__ */ new Map();
23802
- onEnable() {
23803
- this.subscribeToContextCreation();
23804
- this.subscribeToSessionCreation();
23805
- this.subscribeToContextEvents();
23806
- this.subscribeToSessionOperations();
23807
- }
23808
- onDisable() {
23809
- for (const unsubscribe of this.unsubscribers) {
23810
- unsubscribe();
23755
+ toolsByKey = /* @__PURE__ */ new Map();
23756
+ turnsByKey = /* @__PURE__ */ new Map();
23757
+ handle(event, ctx) {
23758
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
23759
+ return;
23811
23760
  }
23812
- this.unsubscribers = [];
23813
- this.activeOperationsById.clear();
23814
- this.activeOperationsByScope.clear();
23815
- this.compactionsByScope.clear();
23816
- this.pendingOperationsByKey.clear();
23761
+ if (this.seenEvents.has(event)) {
23762
+ return;
23763
+ }
23764
+ this.seenEvents.add(event);
23765
+ try {
23766
+ this.handleEvent(event, flueContextFromUnknown(ctx));
23767
+ } catch (error) {
23768
+ logInstrumentationError3("Flue observe", error);
23769
+ }
23770
+ }
23771
+ reset() {
23772
+ this.compactionsByKey.clear();
23773
+ this.operationsById.clear();
23774
+ this.runsById.clear();
23775
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
23817
23776
  this.tasksById.clear();
23818
- this.toolsById.clear();
23819
- this.turnsByScope.clear();
23777
+ this.toolsByKey.clear();
23778
+ this.turnsByKey.clear();
23820
23779
  }
23821
- subscribeToContextCreation() {
23822
- const channel = flueChannels.createContext.tracingChannel();
23823
- const handlers = {
23824
- end: (event) => {
23825
- const ctx = event.result;
23826
- if (!ctx) {
23827
- return;
23828
- }
23829
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
23830
- patchFlueContextInPlace(ctx);
23831
- },
23832
- error: () => {
23833
- }
23780
+ handleEvent(event, ctx) {
23781
+ switch (event.type) {
23782
+ case "run_start":
23783
+ this.handleRunStart(event, ctx);
23784
+ return;
23785
+ case "run_end":
23786
+ this.handleRunEnd(event);
23787
+ return;
23788
+ case "operation_start":
23789
+ this.handleOperationStart(event);
23790
+ return;
23791
+ case "operation":
23792
+ this.handleOperation(event);
23793
+ return;
23794
+ case "turn_request":
23795
+ this.handleTurnRequest(event);
23796
+ return;
23797
+ case "turn":
23798
+ this.handleTurn(event);
23799
+ return;
23800
+ case "tool_start":
23801
+ this.handleToolStart(event);
23802
+ return;
23803
+ case "tool_call":
23804
+ this.handleToolCall(event);
23805
+ return;
23806
+ case "task_start":
23807
+ this.handleTaskStart(event);
23808
+ return;
23809
+ case "task":
23810
+ this.handleTask(event);
23811
+ return;
23812
+ case "compaction_start":
23813
+ this.handleCompactionStart(event);
23814
+ return;
23815
+ case "compaction":
23816
+ this.handleCompaction(event);
23817
+ return;
23818
+ default:
23819
+ return;
23820
+ }
23821
+ }
23822
+ handleRunStart(event, ctx) {
23823
+ if (!event.runId) {
23824
+ return;
23825
+ }
23826
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
23827
+ const metadata = {
23828
+ ...extractPayloadMetadata(event.payload),
23829
+ ...extractEventMetadata(event, ctx),
23830
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
23831
+ provider: "flue"
23834
23832
  };
23835
- channel.subscribe(handlers);
23836
- this.unsubscribers.push(() => {
23837
- channel.unsubscribe(handlers);
23833
+ const span = startSpan({
23834
+ name: `workflow:${workflowName}`,
23835
+ spanAttributes: { type: "task" /* TASK */ },
23836
+ startTime: eventTime(event.startedAt ?? event.timestamp),
23837
+ event: {
23838
+ input: event.payload,
23839
+ metadata
23840
+ }
23838
23841
  });
23842
+ this.runsById.set(event.runId, { metadata, span });
23839
23843
  }
23840
- subscribeToSessionCreation() {
23841
- const channel = flueChannels.openSession.tracingChannel();
23842
- const handlers = {
23843
- asyncEnd: (event) => {
23844
- if (event.result) {
23845
- patchFlueSessionInPlace(
23846
- event.result
23847
- );
23848
- }
23849
- if (event.harness) {
23850
- wrapFlueHarness(event.harness);
23851
- }
23852
- },
23853
- error: () => {
23854
- }
23855
- };
23856
- channel.subscribe(handlers);
23857
- this.unsubscribers.push(() => {
23858
- channel.unsubscribe(handlers);
23844
+ handleRunEnd(event) {
23845
+ const state = this.runsById.get(event.runId);
23846
+ this.finishPendingSpansForRun(event);
23847
+ if (state) {
23848
+ safeLog3(state.span, {
23849
+ ...event.isError ? { error: errorToString(event.error) } : {},
23850
+ metadata: {
23851
+ ...state.metadata,
23852
+ ...extractEventMetadata(event),
23853
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
23854
+ },
23855
+ metrics: durationMetrics2(event.durationMs),
23856
+ output: event.result
23857
+ });
23858
+ safeEnd(state.span, eventTime(event.timestamp));
23859
+ this.runsById.delete(event.runId);
23860
+ }
23861
+ void flush().catch((error) => {
23862
+ logInstrumentationError3("Flue flush", error);
23859
23863
  });
23860
23864
  }
23861
- subscribeToSessionOperations() {
23862
- this.subscribeToSessionOperation(flueChannels.prompt);
23863
- this.subscribeToSessionOperation(flueChannels.skill);
23864
- this.subscribeToSessionOperation(flueChannels.task);
23865
- this.subscribeToCompact();
23866
- }
23867
- subscribeToSessionOperation(channel) {
23868
- const tracingChannel2 = channel.tracingChannel();
23869
- const states = /* @__PURE__ */ new WeakMap();
23870
- const ensureState2 = (event) => {
23871
- const existing = states.get(event);
23872
- if (existing) {
23873
- return existing;
23874
- }
23875
- const state = this.startOperationState({
23876
- args: event.arguments,
23877
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23878
- operation: event.operation,
23879
- session: event.session
23880
- });
23881
- states.set(event, state);
23882
- return state;
23883
- };
23884
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23885
- tracingChannel2,
23886
- ensureState2
23887
- );
23888
- const handlers = {
23889
- start: (event) => {
23890
- ensureState2(event);
23891
- },
23892
- asyncEnd: (event) => {
23893
- this.endOperationState(states.get(event), event.result);
23894
- states.delete(event);
23895
- },
23896
- error: (event) => {
23897
- const state = states.get(event);
23898
- if (state && event.error) {
23899
- safeLog3(state.span, { error: errorToString(event.error) });
23900
- this.finishOperationState(state);
23901
- }
23902
- states.delete(event);
23903
- }
23904
- };
23905
- tracingChannel2.subscribe(handlers);
23906
- this.unsubscribers.push(() => {
23907
- unbindCurrentSpanStore?.();
23908
- tracingChannel2.unsubscribe(handlers);
23909
- });
23910
- }
23911
- subscribeToCompact() {
23912
- const tracingChannel2 = flueChannels.compact.tracingChannel();
23913
- const states = /* @__PURE__ */ new WeakMap();
23914
- const ensureState2 = (event) => {
23915
- const existing = states.get(event);
23916
- if (existing) {
23917
- return existing;
23918
- }
23919
- const state = this.startOperationState({
23920
- args: [],
23921
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23922
- operation: event.operation,
23923
- session: event.session
23924
- });
23925
- states.set(event, state);
23926
- return state;
23927
- };
23928
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23929
- tracingChannel2,
23930
- ensureState2
23931
- );
23932
- const handlers = {
23933
- start: (event) => {
23934
- ensureState2(event);
23935
- },
23936
- asyncEnd: (event) => {
23937
- this.endOperationState(states.get(event), void 0);
23938
- states.delete(event);
23939
- },
23940
- error: (event) => {
23941
- const state = states.get(event);
23942
- if (state && event.error) {
23943
- safeLog3(state.span, { error: errorToString(event.error) });
23944
- this.finishOperationState(state);
23945
- }
23946
- states.delete(event);
23947
- }
23948
- };
23949
- tracingChannel2.subscribe(handlers);
23950
- this.unsubscribers.push(() => {
23951
- unbindCurrentSpanStore?.();
23952
- tracingChannel2.unsubscribe(handlers);
23953
- });
23954
- }
23955
- subscribeToContextEvents() {
23956
- const channel = flueChannels.contextEvent.tracingChannel();
23957
- const handlers = {
23958
- start: (event) => {
23959
- const flueEvent = event.arguments[0];
23960
- if (!flueEvent) {
23961
- return;
23962
- }
23963
- try {
23964
- this.handleFlueEvent(flueEvent, {
23965
- captureTurnSpans: event.captureTurnSpans !== false
23966
- });
23967
- } catch (error) {
23968
- logInstrumentationError3("Flue event", error);
23969
- }
23970
- },
23971
- error: () => {
23972
- }
23973
- };
23974
- channel.subscribe(handlers);
23975
- this.unsubscribers.push(() => {
23976
- channel.unsubscribe(handlers);
23977
- });
23978
- }
23979
- bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
23980
- const state = _internalGetGlobalState();
23981
- const startChannel = tracingChannel2.start;
23982
- const contextManager = state?.contextManager;
23983
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
23984
- if (!currentSpanStore || !startChannel) {
23985
- return void 0;
23986
- }
23987
- startChannel.bindStore(currentSpanStore, (event) => {
23988
- const operationState = ensureState2(event);
23989
- return contextManager.wrapSpanForStore(operationState.span);
23990
- });
23991
- return () => {
23992
- startChannel.unbindStore(currentSpanStore);
23993
- };
23994
- }
23995
- startOperationState(args) {
23996
- const sessionName = getSessionName(args.session);
23997
- const metadata = {
23998
- ...extractOperationInputMetadata(args.operation, args.args),
23999
- ...extractSessionMetadata(args.session),
24000
- "flue.operation": args.operation,
24001
- provider: "flue",
24002
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24003
- };
24004
- const span = startSpan({
24005
- name: `flue.session.${args.operation}`,
24006
- spanAttributes: { type: "task" /* TASK */ }
24007
- });
24008
- const state = {
24009
- metadata,
24010
- operation: args.operation,
24011
- sessionName,
24012
- span,
24013
- startTime: getCurrentUnixTimestamp()
24014
- };
24015
- safeLog3(span, {
24016
- input: extractOperationInput(args.operation, args.args),
24017
- metadata
24018
- });
24019
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24020
- state
24021
- );
24022
- addOperationToScope(
24023
- this.activeOperationsByScope,
24024
- sessionName ?? "unknown",
24025
- state
24026
- );
24027
- return state;
24028
- }
24029
- endOperationState(state, result) {
24030
- if (!state) {
24031
- return;
24032
- }
24033
- const metadata = {
24034
- ...state.metadata,
24035
- ...extractPromptResponseMetadata(result)
24036
- };
24037
- const metrics = {
24038
- ...buildDurationMetrics3(state.startTime),
24039
- ...metricsFromUsage(result?.usage)
24040
- };
24041
- safeLog3(state.span, {
24042
- metadata,
24043
- metrics,
24044
- output: extractOperationOutput(result)
24045
- });
24046
- this.finishCompactionsForOperation(state);
24047
- this.finishOperationState(state);
24048
- }
24049
- finishOperationState(state) {
24050
- removePendingOperation(this.pendingOperationsByKey, state);
24051
- if (state.operationId) {
24052
- this.activeOperationsById.delete(state.operationId);
24053
- }
24054
- removeScopedOperation(this.activeOperationsByScope, state);
24055
- state.span.end();
24056
- }
24057
- handleFlueEvent(event, options) {
24058
- switch (event.type) {
24059
- case "operation_start":
24060
- this.handleOperationStart(event);
24061
- return;
24062
- case "operation":
24063
- this.handleOperation(event);
24064
- return;
24065
- case "text_delta":
24066
- if (!options.captureTurnSpans) {
24067
- return;
24068
- }
24069
- this.ensureTurnState(event).text.push(
24070
- typeof event.text === "string" ? event.text : ""
24071
- );
24072
- return;
24073
- case "thinking_start":
24074
- if (!options.captureTurnSpans) {
24075
- return;
24076
- }
24077
- this.handleThinkingStart(event);
24078
- return;
24079
- case "thinking_delta":
24080
- if (!options.captureTurnSpans) {
24081
- return;
24082
- }
24083
- this.handleThinkingDelta(event);
24084
- return;
24085
- case "thinking_end":
24086
- if (!options.captureTurnSpans) {
24087
- return;
24088
- }
24089
- this.handleThinkingEnd(event);
24090
- return;
24091
- case "turn":
24092
- if (!options.captureTurnSpans) {
24093
- return;
24094
- }
24095
- this.handleTurn(event);
24096
- return;
24097
- case "tool_start":
24098
- this.handleToolStart(event, options);
24099
- return;
24100
- case "tool_call":
24101
- this.handleToolCall(event);
24102
- return;
24103
- case "task_start":
24104
- this.handleTaskStart(event);
24105
- return;
24106
- case "task":
24107
- this.handleTask(event);
24108
- return;
24109
- case "compaction_start":
24110
- this.handleCompactionStart(event);
24111
- return;
24112
- case "compaction":
24113
- this.handleCompaction(event);
24114
- return;
24115
- default:
24116
- return;
24117
- }
24118
- }
24119
- handleOperationStart(event) {
24120
- if (!isInstrumentedOperation(event.operationKind)) {
24121
- return;
24122
- }
24123
- const state = this.takePendingOperationForEvent(event);
24124
- if (!state) {
24125
- return;
24126
- }
24127
- state.operationId = event.operationId;
24128
- this.activeOperationsById.set(event.operationId, state);
24129
- addScopedOperation(this.activeOperationsByScope, event, state);
24130
- state.metadata = {
24131
- ...state.metadata,
24132
- ...extractEventMetadata(event),
24133
- "flue.operation_id": event.operationId
24134
- };
24135
- safeLog3(state.span, { metadata: state.metadata });
23865
+ handleOperationStart(event) {
23866
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
23867
+ return;
23868
+ }
23869
+ const metadata = {
23870
+ ...extractEventMetadata(event),
23871
+ "flue.operation": event.operationKind,
23872
+ provider: "flue"
23873
+ };
23874
+ const parent = this.parentSpanForEvent(event);
23875
+ const span = startFlueSpan(parent, {
23876
+ name: `flue.${event.operationKind}`,
23877
+ spanAttributes: { type: "task" /* TASK */ },
23878
+ startTime: eventTime(event.timestamp),
23879
+ event: { metadata }
23880
+ });
23881
+ this.operationsById.set(event.operationId, { metadata, span });
24136
23882
  }
24137
23883
  handleOperation(event) {
24138
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24139
- if (!state) {
23884
+ if (!isInstrumentedOperation(event.operationKind)) {
24140
23885
  return;
24141
23886
  }
23887
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
23888
+ const output = operationOutput(event);
24142
23889
  const metadata = {
24143
23890
  ...state.metadata,
24144
23891
  ...extractEventMetadata(event),
24145
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24146
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
23892
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
23893
+ ...event.usage ? { "flue.usage": event.usage } : {}
24147
23894
  };
24148
- const metrics = metricsFromUsage(event.usage);
23895
+ this.finishPendingChildrenForOperation(event, output);
24149
23896
  safeLog3(state.span, {
24150
- ...event.error ? { error: errorToString(event.error) } : {},
23897
+ ...event.isError ? { error: errorToString(event.error) } : {},
24151
23898
  metadata,
24152
- ...Object.keys(metrics).length ? { metrics } : {}
23899
+ metrics: durationMetrics2(event.durationMs),
23900
+ output
24153
23901
  });
23902
+ safeEnd(state.span, eventTime(event.timestamp));
23903
+ this.operationsById.delete(event.operationId);
24154
23904
  }
24155
- ensureTurnState(event) {
24156
- const scope = scopeKey(event);
24157
- const existing = this.turnsByScope.get(scope);
24158
- if (existing) {
24159
- return existing;
23905
+ handleTurnRequest(event) {
23906
+ const key = turnKey(event);
23907
+ if (!key) {
23908
+ return;
24160
23909
  }
24161
- const parent = this.parentSpanForEvent(event);
24162
23910
  const metadata = {
24163
23911
  ...extractEventMetadata(event),
24164
- provider: "flue"
23912
+ ...event.api ? { "flue.api": event.api } : {},
23913
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
23914
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
23915
+ ...event.provider ? { "flue.provider": event.provider } : {},
23916
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
23917
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
23918
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
23919
+ ...event.input?.tools ? { tools: event.input.tools } : {}
24165
23920
  };
23921
+ const parent = this.parentSpanForTurn(event);
24166
23922
  const span = startFlueSpan(parent, {
24167
- name: "flue.turn",
24168
- spanAttributes: { type: "llm" /* LLM */ }
23923
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
23924
+ spanAttributes: { type: "llm" /* LLM */ },
23925
+ startTime: eventTime(event.timestamp),
23926
+ event: {
23927
+ input: event.input?.messages,
23928
+ metadata
23929
+ }
24169
23930
  });
24170
- const state = {
24171
- metadata,
24172
- span,
24173
- hasThinking: false,
24174
- startTime: getCurrentUnixTimestamp(),
24175
- text: [],
24176
- thinking: [],
24177
- toolCalls: []
24178
- };
24179
- safeLog3(span, { metadata });
24180
- this.turnsByScope.set(scope, state);
24181
- return state;
23931
+ this.logOperationInput(
23932
+ event.operationId,
23933
+ event.input?.messages ?? event.input
23934
+ );
23935
+ this.turnsByKey.set(key, { metadata, span });
24182
23936
  }
24183
23937
  handleTurn(event) {
24184
- const scope = scopeKey(event);
24185
- const state = this.ensureTurnState(event);
24186
- const text = state.text.join("");
24187
- const reasoning = state.finalThinking ?? state.thinking.join("");
24188
- const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
23938
+ const key = turnKey(event);
23939
+ if (!key) {
23940
+ return;
23941
+ }
23942
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
24189
23943
  const metadata = {
24190
23944
  ...state.metadata,
24191
23945
  ...extractEventMetadata(event),
23946
+ ...event.api ? { "flue.api": event.api } : {},
24192
23947
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
23948
+ ...event.provider ? { provider: event.provider } : {},
23949
+ ...event.provider ? { "flue.provider": event.provider } : {},
23950
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24193
23951
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24194
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24195
- provider: "flue"
23952
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24196
23953
  };
24197
23954
  safeLog3(state.span, {
24198
- ...event.error ? { error: errorToString(event.error) } : {},
23955
+ ...event.isError ? { error: errorToString(event.error) } : {},
24199
23956
  metadata,
24200
23957
  metrics: {
24201
- ...durationMsMetrics(event.durationMs),
23958
+ ...durationMetrics2(event.durationMs),
24202
23959
  ...metricsFromUsage(event.usage)
24203
23960
  },
24204
- output: toAssistantOutput(
24205
- text,
24206
- event.stopReason,
24207
- outputReasoning,
24208
- state.toolCalls
24209
- )
23961
+ output: event.output
24210
23962
  });
24211
- state.span.end();
24212
- this.turnsByScope.delete(scope);
23963
+ safeEnd(state.span, eventTime(event.timestamp));
23964
+ this.turnsByKey.delete(key);
24213
23965
  }
24214
- handleThinkingDelta(event) {
24215
- const delta = event.delta;
24216
- if (typeof delta !== "string" || !delta) {
23966
+ handleToolStart(event) {
23967
+ if (!event.toolCallId) {
24217
23968
  return;
24218
23969
  }
24219
- const state = this.ensureTurnState(event);
24220
- state.hasThinking = true;
24221
- state.metadata["flue.thinking"] = true;
24222
- state.thinking.push(delta);
24223
- }
24224
- handleThinkingStart(event) {
24225
- const state = this.ensureTurnState(event);
24226
- state.hasThinking = true;
24227
- state.metadata["flue.thinking"] = true;
24228
- }
24229
- handleThinkingEnd(event) {
24230
- const state = this.ensureTurnState(event);
24231
- state.hasThinking = true;
24232
- state.metadata["flue.thinking"] = true;
24233
- if (typeof event.content === "string" && event.content) {
24234
- state.finalThinking = event.content;
24235
- }
24236
- }
24237
- handleToolStart(event, options) {
24238
- const toolCallId = event.toolCallId;
24239
- if (!toolCallId) {
24240
- return;
24241
- }
24242
- const parent = this.parentSpanForEvent(event);
24243
- const scope = scopeKey(event);
24244
- let turnState = this.turnsByScope.get(scope);
24245
- if (!turnState && parent && options.captureTurnSpans) {
24246
- turnState = this.ensureTurnState(event);
24247
- }
24248
23970
  const metadata = {
24249
23971
  ...extractEventMetadata(event),
24250
23972
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24251
- "flue.tool_call_id": toolCallId,
23973
+ "flue.tool_call_id": event.toolCallId,
24252
23974
  provider: "flue"
24253
23975
  };
23976
+ const parent = this.parentSpanForTool(event);
24254
23977
  const span = startFlueSpan(parent, {
24255
- name: `tool: ${event.toolName ?? "unknown"}`,
24256
- spanAttributes: { type: "tool" /* TOOL */ }
24257
- });
24258
- if (turnState) {
24259
- turnState.toolCalls.push({
24260
- args: event.args,
24261
- toolCallId,
24262
- toolName: event.toolName
24263
- });
24264
- }
24265
- safeLog3(span, {
24266
- input: event.args,
24267
- metadata
24268
- });
24269
- this.toolsById.set(toolKey(event), {
24270
- metadata,
24271
- span,
24272
- startTime: getCurrentUnixTimestamp()
23978
+ name: `tool:${event.toolName ?? "unknown"}`,
23979
+ spanAttributes: { type: "tool" /* TOOL */ },
23980
+ startTime: eventTime(event.timestamp),
23981
+ event: {
23982
+ input: event.args,
23983
+ metadata
23984
+ }
24273
23985
  });
23986
+ this.toolsByKey.set(toolKey(event), { metadata, span });
24274
23987
  }
24275
23988
  handleToolCall(event) {
23989
+ if (!event.toolCallId) {
23990
+ return;
23991
+ }
24276
23992
  const key = toolKey(event);
24277
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
23993
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
24278
23994
  const metadata = {
24279
23995
  ...state.metadata,
24280
23996
  ...extractEventMetadata(event),
24281
23997
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24282
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
23998
+ "flue.tool_call_id": event.toolCallId,
24283
23999
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24284
24000
  };
24285
24001
  safeLog3(state.span, {
24286
24002
  ...event.isError ? { error: errorToString(event.result) } : {},
24287
24003
  metadata,
24288
- metrics: durationMsMetrics(event.durationMs),
24004
+ metrics: durationMetrics2(event.durationMs),
24289
24005
  output: event.result
24290
24006
  });
24291
- state.span.end();
24292
- this.toolsById.delete(key);
24007
+ safeEnd(state.span, eventTime(event.timestamp));
24008
+ this.toolsByKey.delete(key);
24293
24009
  }
24294
24010
  handleTaskStart(event) {
24295
- const parent = this.parentSpanForEvent(event);
24011
+ if (!event.taskId) {
24012
+ return;
24013
+ }
24296
24014
  const metadata = {
24297
24015
  ...extractEventMetadata(event),
24298
- ...event.role ? { "flue.role": event.role } : {},
24016
+ ...event.agent ? { "flue.agent": event.agent } : {},
24299
24017
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
24300
24018
  "flue.task_id": event.taskId,
24301
24019
  provider: "flue"
24302
24020
  };
24021
+ const parent = this.parentSpanForEvent(event);
24303
24022
  const span = startFlueSpan(parent, {
24304
- name: "flue.task",
24305
- spanAttributes: { type: "task" /* TASK */ }
24306
- });
24307
- safeLog3(span, {
24308
- input: event.prompt,
24309
- metadata
24310
- });
24311
- this.tasksById.set(event.taskId, {
24312
- metadata,
24313
- span,
24314
- startTime: getCurrentUnixTimestamp()
24023
+ name: event.agent ? `task:${event.agent}` : "flue.task",
24024
+ spanAttributes: { type: "task" /* TASK */ },
24025
+ startTime: eventTime(event.timestamp),
24026
+ event: {
24027
+ input: event.prompt,
24028
+ metadata
24029
+ }
24315
24030
  });
24031
+ this.tasksById.set(event.taskId, { metadata, span });
24316
24032
  }
24317
24033
  handleTask(event) {
24318
24034
  const state = this.tasksById.get(event.taskId);
@@ -24324,426 +24040,372 @@ var FluePlugin = class extends BasePlugin {
24324
24040
  metadata: {
24325
24041
  ...state.metadata,
24326
24042
  ...extractEventMetadata(event),
24043
+ ...event.agent ? { "flue.agent": event.agent } : {},
24327
24044
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24328
24045
  },
24329
- metrics: durationMsMetrics(event.durationMs),
24046
+ metrics: durationMetrics2(event.durationMs),
24330
24047
  output: event.result
24331
24048
  });
24332
- state.span.end();
24049
+ safeEnd(state.span, eventTime(event.timestamp));
24333
24050
  this.tasksById.delete(event.taskId);
24334
24051
  }
24335
24052
  handleCompactionStart(event) {
24336
- const operationState = this.operationStateForEvent(event);
24337
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
24053
+ const key = compactionKey(event);
24054
+ const input = {
24055
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
24056
+ ...event.reason ? { reason: event.reason } : {}
24057
+ };
24338
24058
  const metadata = {
24339
24059
  ...extractEventMetadata(event),
24340
24060
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24341
24061
  provider: "flue"
24342
24062
  };
24343
- const input = {
24344
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24345
- ...event.reason ? { reason: event.reason } : {}
24346
- };
24063
+ const parent = this.parentSpanForEvent(event);
24347
24064
  const span = startFlueSpan(parent, {
24348
- name: "flue.compaction",
24349
- spanAttributes: { type: "task" /* TASK */ }
24350
- });
24351
- safeLog3(span, {
24352
- input,
24353
- metadata
24354
- });
24355
- this.compactionsByScope.set(scopeKey(event), {
24356
- input,
24357
- metadata,
24358
- operationState,
24359
- span,
24360
- startTime: getCurrentUnixTimestamp()
24065
+ name: `compaction:${event.reason ?? "unknown"}`,
24066
+ spanAttributes: { type: "task" /* TASK */ },
24067
+ startTime: eventTime(event.timestamp),
24068
+ event: {
24069
+ input,
24070
+ metadata
24071
+ }
24361
24072
  });
24073
+ this.logOperationInput(event.operationId, input);
24074
+ this.compactionsByKey.set(key, { metadata, span });
24362
24075
  }
24363
24076
  handleCompaction(event) {
24364
- const key = scopeKey(event);
24365
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24366
- if (!state) {
24367
- return;
24368
- }
24077
+ const key = compactionKey(event);
24078
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
24079
+ const metadata = {
24080
+ ...state.metadata,
24081
+ ...extractEventMetadata(event),
24082
+ ...event.usage ? { "flue.usage": event.usage } : {}
24083
+ };
24369
24084
  safeLog3(state.span, {
24370
- metadata: {
24371
- ...state.metadata,
24372
- ...extractEventMetadata(event),
24373
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24374
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24375
- },
24085
+ metadata,
24376
24086
  metrics: {
24377
- ...durationMsMetrics(event.durationMs),
24378
- ...metricsFromUsage(event.usage)
24087
+ ...durationMetrics2(event.durationMs),
24088
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
24089
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
24379
24090
  },
24380
24091
  output: {
24381
24092
  messagesAfter: event.messagesAfter,
24382
24093
  messagesBefore: event.messagesBefore
24383
24094
  }
24384
24095
  });
24385
- state.span.end();
24386
- this.deleteCompactionState(state);
24096
+ safeEnd(state.span, eventTime(event.timestamp));
24097
+ this.compactionsByKey.delete(key);
24387
24098
  }
24388
- findCompactionState(event) {
24389
- const operationState = this.operationStateForEvent(event);
24390
- for (const state of this.compactionsByScope.values()) {
24391
- if (operationState && state.operationState === operationState) {
24392
- return state;
24099
+ parentSpanForTurn(event) {
24100
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
24101
+ const compaction = this.compactionsByKey.get(compactionKey(event));
24102
+ if (compaction) {
24103
+ return compaction.span;
24393
24104
  }
24394
24105
  }
24395
- return void 0;
24106
+ return this.parentSpanForEvent(event);
24396
24107
  }
24397
- finishCompactionsForOperation(operationState) {
24398
- for (const state of [...this.compactionsByScope.values()]) {
24399
- if (state.operationState !== operationState) {
24400
- continue;
24108
+ parentSpanForEvent(event) {
24109
+ const turn = turnKey(event);
24110
+ if (turn) {
24111
+ const turnState = this.turnsByKey.get(turn);
24112
+ if (turnState) {
24113
+ return turnState.span;
24401
24114
  }
24402
- safeLog3(state.span, {
24403
- input: state.input,
24404
- metadata: state.metadata,
24405
- metrics: {
24406
- ...buildDurationMetrics3(state.startTime)
24407
- },
24408
- output: { completed: true }
24409
- });
24410
- state.span.end();
24411
- this.deleteCompactionState(state);
24412
24115
  }
24413
- }
24414
- deleteCompactionState(state) {
24415
- for (const [key, candidate] of this.compactionsByScope) {
24416
- if (candidate !== state) {
24417
- continue;
24116
+ if (event.taskId) {
24117
+ const task = this.tasksById.get(event.taskId);
24118
+ if (task) {
24119
+ return task.span;
24418
24120
  }
24419
- this.compactionsByScope.delete(key);
24420
- return;
24421
24121
  }
24422
- }
24423
- startSyntheticToolState(event, toolName) {
24424
- const parent = this.parentSpanForEvent(event);
24425
- const metadata = {
24426
- ...extractEventMetadata(event),
24427
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24428
- "flue.tool_name": toolName,
24429
- provider: "flue"
24430
- };
24431
- const span = startFlueSpan(parent, {
24432
- name: `tool: ${toolName}`,
24433
- spanAttributes: { type: "tool" /* TOOL */ }
24434
- });
24435
- safeLog3(span, { metadata });
24436
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
24437
- }
24438
- operationStateForEvent(event) {
24439
24122
  if (event.operationId) {
24440
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24123
+ const operation = this.operationsById.get(event.operationId);
24441
24124
  if (operation) {
24442
- return operation;
24125
+ return operation.span;
24443
24126
  }
24444
24127
  }
24445
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24128
+ if (event.runId) {
24129
+ return this.runsById.get(event.runId)?.span;
24130
+ }
24131
+ return void 0;
24446
24132
  }
24447
- parentSpanForEvent(event) {
24133
+ parentSpanForTool(event) {
24134
+ if (event.taskId) {
24135
+ const task = this.tasksById.get(event.taskId);
24136
+ if (task) {
24137
+ return task.span;
24138
+ }
24139
+ }
24448
24140
  if (event.operationId) {
24449
- const operation = this.operationStateForEvent(event);
24141
+ const operation = this.operationsById.get(event.operationId);
24450
24142
  if (operation) {
24451
24143
  return operation.span;
24452
24144
  }
24453
24145
  }
24454
- if (event.taskId) {
24455
- return this.tasksById.get(event.taskId)?.span;
24146
+ if (event.runId) {
24147
+ return this.runsById.get(event.runId)?.span;
24148
+ }
24149
+ return void 0;
24150
+ }
24151
+ logOperationInput(operationId, input) {
24152
+ if (!operationId || input === void 0) {
24153
+ return;
24154
+ }
24155
+ const operation = this.operationsById.get(operationId);
24156
+ if (!operation || operation.loggedInput) {
24157
+ return;
24456
24158
  }
24457
- return this.operationStateForEvent(event)?.span;
24159
+ safeLog3(operation.span, { input });
24160
+ operation.loggedInput = true;
24458
24161
  }
24459
- promotePendingOperationForEvent(event) {
24460
- if (!event.operationId) {
24461
- return void 0;
24162
+ startSyntheticOperation(event) {
24163
+ const metadata = {
24164
+ ...extractEventMetadata(event),
24165
+ "flue.operation": event.operationKind,
24166
+ provider: "flue"
24167
+ };
24168
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24169
+ name: `flue.${event.operationKind}`,
24170
+ spanAttributes: { type: "task" /* TASK */ },
24171
+ startTime: eventTime(event.timestamp),
24172
+ event: { metadata }
24173
+ });
24174
+ return { metadata, span };
24175
+ }
24176
+ startSyntheticTurn(event) {
24177
+ const metadata = {
24178
+ ...extractEventMetadata(event),
24179
+ ...event.api ? { "flue.api": event.api } : {},
24180
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24181
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24182
+ ...event.provider ? { "flue.provider": event.provider } : {},
24183
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
24184
+ };
24185
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24186
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24187
+ spanAttributes: { type: "llm" /* LLM */ },
24188
+ startTime: eventTime(event.timestamp),
24189
+ event: { metadata }
24190
+ });
24191
+ return { metadata, span };
24192
+ }
24193
+ startSyntheticTool(event) {
24194
+ const metadata = {
24195
+ ...extractEventMetadata(event),
24196
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24197
+ "flue.tool_call_id": event.toolCallId,
24198
+ provider: "flue"
24199
+ };
24200
+ const span = startFlueSpan(this.parentSpanForTool(event), {
24201
+ name: `tool:${event.toolName ?? "unknown"}`,
24202
+ spanAttributes: { type: "tool" /* TOOL */ },
24203
+ startTime: eventTime(event.timestamp),
24204
+ event: { metadata }
24205
+ });
24206
+ return { metadata, span };
24207
+ }
24208
+ startSyntheticCompaction(event) {
24209
+ const metadata = {
24210
+ ...extractEventMetadata(event),
24211
+ provider: "flue"
24212
+ };
24213
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24214
+ name: "compaction:unknown",
24215
+ spanAttributes: { type: "task" /* TASK */ },
24216
+ startTime: eventTime(event.timestamp),
24217
+ event: { metadata }
24218
+ });
24219
+ return { metadata, span };
24220
+ }
24221
+ finishPendingChildrenForOperation(event, operationOutput2) {
24222
+ const endTime = eventTime(event.timestamp);
24223
+ const usage = event.usage ?? usageFromOperationResult(event.result);
24224
+ const turnEntries = [...this.turnsByKey].filter(
24225
+ ([, state]) => stateMatchesOperation(state, event.operationId)
24226
+ );
24227
+ turnEntries.forEach(([key, state], index) => {
24228
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
24229
+ safeLog3(state.span, {
24230
+ metadata: state.metadata,
24231
+ metrics: metricsFromUsage(usage),
24232
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
24233
+ });
24234
+ safeEnd(state.span, endTime);
24235
+ this.turnsByKey.delete(key);
24236
+ });
24237
+ for (const [key, state] of this.toolsByKey) {
24238
+ if (!stateMatchesOperation(state, event.operationId)) {
24239
+ continue;
24240
+ }
24241
+ safeEnd(state.span, endTime);
24242
+ this.toolsByKey.delete(key);
24462
24243
  }
24463
- const scopePrefixes = operationScopePrefixes(event);
24464
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24465
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24244
+ for (const [key, state] of this.tasksById) {
24245
+ if (!stateMatchesOperation(state, event.operationId)) {
24466
24246
  continue;
24467
24247
  }
24468
- const state = candidateQueue.shift();
24469
- if (!state) {
24470
- return void 0;
24248
+ safeEnd(state.span, endTime);
24249
+ this.tasksById.delete(key);
24250
+ }
24251
+ for (const [key, state] of this.compactionsByKey) {
24252
+ if (!stateMatchesOperation(state, event.operationId)) {
24253
+ continue;
24471
24254
  }
24472
- state.operationId = event.operationId;
24473
- this.activeOperationsById.set(event.operationId, state);
24474
- addScopedOperation(this.activeOperationsByScope, event, state);
24475
- state.metadata = {
24476
- ...state.metadata,
24477
- ...extractEventMetadata(event),
24478
- "flue.operation_id": event.operationId
24479
- };
24480
- safeLog3(state.span, { metadata: state.metadata });
24481
- return state;
24255
+ safeLog3(state.span, {
24256
+ metadata: state.metadata,
24257
+ metrics: durationMetrics2(event.durationMs),
24258
+ output: { completed: true }
24259
+ });
24260
+ safeEnd(state.span, eventTime(event.timestamp));
24261
+ this.compactionsByKey.delete(key);
24482
24262
  }
24483
- return void 0;
24484
24263
  }
24485
- activeOperationForEventScope(event) {
24486
- for (const scope of operationScopeNames(event)) {
24487
- const operations = this.activeOperationsByScope.get(scope);
24488
- if (operations?.length) {
24489
- return operations[operations.length - 1];
24264
+ finishPendingSpansForRun(event) {
24265
+ const endTime = eventTime(event.timestamp);
24266
+ for (const [key, state] of this.toolsByKey) {
24267
+ if (!stateMatchesRun(state, event.runId)) {
24268
+ continue;
24490
24269
  }
24270
+ safeEnd(state.span, endTime);
24271
+ this.toolsByKey.delete(key);
24491
24272
  }
24492
- return void 0;
24493
- }
24494
- pendingOperationForEventScope(event) {
24495
- const scopePrefixes = operationScopePrefixes(event);
24496
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24497
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24273
+ for (const [key, state] of this.turnsByKey) {
24274
+ if (!stateMatchesRun(state, event.runId)) {
24498
24275
  continue;
24499
24276
  }
24500
- return candidateQueue[0];
24277
+ safeEnd(state.span, endTime);
24278
+ this.turnsByKey.delete(key);
24501
24279
  }
24502
- return void 0;
24503
- }
24504
- takePendingOperationForEvent(event) {
24505
- const key = operationKey(event.session, event.operationKind);
24506
- const queue2 = this.pendingOperationsByKey.get(key);
24507
- if (queue2?.length) {
24508
- return queue2.shift();
24280
+ for (const [key, state] of this.tasksById) {
24281
+ if (!stateMatchesRun(state, event.runId)) {
24282
+ continue;
24283
+ }
24284
+ safeEnd(state.span, endTime);
24285
+ this.tasksById.delete(key);
24509
24286
  }
24510
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24511
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24512
- return candidateQueue.shift();
24287
+ for (const [key, state] of this.compactionsByKey) {
24288
+ if (!stateMatchesRun(state, event.runId)) {
24289
+ continue;
24513
24290
  }
24291
+ safeLog3(state.span, {
24292
+ metadata: state.metadata,
24293
+ output: { completed: true }
24294
+ });
24295
+ safeEnd(state.span, endTime);
24296
+ this.compactionsByKey.delete(key);
24514
24297
  }
24515
- return void 0;
24516
- }
24517
- pendingOperationQueue(key) {
24518
- const existing = this.pendingOperationsByKey.get(key);
24519
- if (existing) {
24520
- return existing;
24298
+ for (const [key, state] of this.operationsById) {
24299
+ if (!stateMatchesRun(state, event.runId)) {
24300
+ continue;
24301
+ }
24302
+ safeLog3(state.span, {
24303
+ metadata: state.metadata,
24304
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
24305
+ });
24306
+ safeEnd(state.span, endTime);
24307
+ this.operationsById.delete(key);
24521
24308
  }
24522
- const queue2 = [];
24523
- this.pendingOperationsByKey.set(key, queue2);
24524
- return queue2;
24525
24309
  }
24526
24310
  };
24527
24311
  function isInstrumentedOperation(operation) {
24528
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24529
- }
24530
- function getSessionName(session) {
24531
- return typeof session?.name === "string" ? session.name : void 0;
24532
- }
24533
- function operationKey(sessionName, operation) {
24534
- return `${sessionName ?? "unknown"}::${operation}`;
24312
+ return operation === "prompt" || operation === "skill" || operation === "compact";
24535
24313
  }
24536
- function operationScopePrefixes(event) {
24537
- const scopes = /* @__PURE__ */ new Set();
24538
- for (const scope of operationScopeNames(event)) {
24539
- scopes.add(`${scope}::`);
24540
- }
24541
- return scopes;
24542
- }
24543
- function operationKeyMatchesScopes(key, scopes) {
24544
- for (const scope of scopes) {
24545
- if (key.startsWith(scope)) {
24546
- return true;
24547
- }
24548
- }
24549
- return false;
24550
- }
24551
- function operationScopeNames(event) {
24552
- const scopes = /* @__PURE__ */ new Set();
24553
- if (event.session) {
24554
- scopes.add(event.session);
24555
- }
24556
- if (event.parentSession) {
24557
- scopes.add(event.parentSession);
24558
- }
24559
- if (!scopes.size) {
24560
- scopes.add("unknown");
24561
- }
24562
- return scopes;
24563
- }
24564
- function addScopedOperation(operationsByScope, event, state) {
24565
- for (const scope of operationScopeNames(event)) {
24566
- addOperationToScope(operationsByScope, scope, state);
24567
- }
24568
- }
24569
- function addOperationToScope(operationsByScope, scope, state) {
24570
- const operations = operationsByScope.get(scope);
24571
- if (operations) {
24572
- if (!operations.includes(state)) {
24573
- operations.push(state);
24574
- }
24575
- } else {
24576
- operationsByScope.set(scope, [state]);
24577
- }
24578
- }
24579
- function removeScopedOperation(operationsByScope, state) {
24580
- for (const [scope, operations] of operationsByScope) {
24581
- const index = operations.indexOf(state);
24582
- if (index === -1) {
24583
- continue;
24584
- }
24585
- operations.splice(index, 1);
24586
- if (operations.length === 0) {
24587
- operationsByScope.delete(scope);
24588
- }
24589
- }
24590
- }
24591
- function removePendingOperation(pendingOperationsByKey, state) {
24592
- for (const [key, queue2] of pendingOperationsByKey) {
24593
- const index = queue2.indexOf(state);
24594
- if (index === -1) {
24595
- continue;
24596
- }
24597
- queue2.splice(index, 1);
24598
- if (queue2.length === 0) {
24599
- pendingOperationsByKey.delete(key);
24600
- }
24601
- return;
24602
- }
24603
- }
24604
- function extractSessionMetadata(session) {
24605
- const sessionName = getSessionName(session);
24606
- return sessionName ? { "flue.session": sessionName } : {};
24607
- }
24608
- function extractEventMetadata(event) {
24314
+ function extractEventMetadata(event, ctx) {
24609
24315
  return {
24610
24316
  ...event.runId ? { "flue.run_id": event.runId } : {},
24317
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
24318
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
24611
24319
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
24612
24320
  ...event.session ? { "flue.session": event.session } : {},
24613
24321
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
24614
24322
  ...event.harness ? { "flue.harness": event.harness } : {},
24615
24323
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
24616
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24324
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
24325
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
24326
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
24327
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
24617
24328
  };
24618
24329
  }
24619
- function extractOperationInput(operation, args) {
24620
- switch (operation) {
24621
- case "prompt":
24622
- case "task":
24623
- return args[0];
24624
- case "skill":
24625
- return {
24626
- args: getOptionObject(args[1])?.args,
24627
- name: args[0]
24628
- };
24629
- case "compact":
24630
- return void 0;
24330
+ function extractPayloadMetadata(payload) {
24331
+ if (!isObjectLike(payload)) {
24332
+ return {};
24631
24333
  }
24334
+ const metadata = Reflect.get(payload, "metadata");
24335
+ if (!isObjectLike(metadata)) {
24336
+ return {};
24337
+ }
24338
+ return Object.fromEntries(Object.entries(metadata));
24632
24339
  }
24633
- function extractOperationInputMetadata(operation, args) {
24634
- const options = getOptionObject(args[1]);
24635
- return {
24636
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
24637
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
24638
- ...options?.role ? { "flue.role": options.role } : {},
24639
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
24640
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
24641
- ...Array.isArray(options?.tools) ? {
24642
- "flue.tools_count": options.tools.length,
24643
- tools: summarizeTools(options.tools)
24644
- } : {},
24645
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
24646
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
24647
- };
24648
- }
24649
- function getOptionObject(value) {
24650
- return isObject(value) ? value : void 0;
24651
- }
24652
- function summarizeTools(tools) {
24653
- return tools.flatMap((tool) => {
24654
- if (!isObject(tool)) {
24655
- return [];
24656
- }
24657
- const name = typeof tool.name === "string" ? tool.name : void 0;
24658
- if (!name) {
24659
- return [];
24660
- }
24661
- return [
24662
- {
24663
- function: {
24664
- description: typeof tool.description === "string" ? tool.description : void 0,
24665
- name,
24666
- parameters: tool.parameters
24667
- },
24668
- type: "function"
24669
- }
24670
- ];
24671
- });
24340
+ function operationOutput(event) {
24341
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
24342
+ return llmResultFromOperationResult(event.result);
24343
+ }
24344
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
24672
24345
  }
24673
- function extractPromptResponseMetadata(result) {
24674
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
24675
- return modelId ? {
24676
- model: modelId,
24677
- "flue.model": modelId
24678
- } : {};
24346
+ function llmResultFromOperationResult(result) {
24347
+ if (!isObjectLike(result)) {
24348
+ return result;
24349
+ }
24350
+ const text = Reflect.get(result, "text");
24351
+ return text === void 0 ? result : text;
24679
24352
  }
24680
- function extractOperationOutput(result) {
24681
- if (!result) {
24353
+ function usageFromOperationResult(result) {
24354
+ if (!isObjectLike(result)) {
24682
24355
  return void 0;
24683
24356
  }
24684
- if ("data" in result) {
24685
- return result.data;
24686
- }
24687
- if ("text" in result) {
24688
- return result.text;
24689
- }
24690
- return result;
24357
+ return Reflect.get(result, "usage");
24691
24358
  }
24692
24359
  function metricsFromUsage(usage) {
24360
+ if (!isObjectLike(usage)) {
24361
+ return {};
24362
+ }
24363
+ const cacheRead = Reflect.get(usage, "cacheRead");
24364
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
24365
+ const cost = Reflect.get(usage, "cost");
24366
+ const input = Reflect.get(usage, "input");
24367
+ const output = Reflect.get(usage, "output");
24368
+ const totalTokens = Reflect.get(usage, "totalTokens");
24369
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
24693
24370
  return {
24694
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
24695
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
24696
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
24697
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
24698
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
24699
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
24700
- };
24701
- }
24702
- function buildDurationMetrics3(startTime) {
24703
- return {
24704
- duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
24371
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
24372
+ ...typeof output === "number" ? { completion_tokens: output } : {},
24373
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
24374
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
24375
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
24376
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
24705
24377
  };
24706
24378
  }
24707
- function durationMsMetrics(durationMs) {
24379
+ function durationMetrics2(durationMs) {
24708
24380
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
24709
24381
  }
24710
- function scopeKey(event) {
24711
- if (event.operationId) {
24712
- return `operation:${event.operationId}`;
24713
- }
24714
- if (event.taskId) {
24715
- return `task:${event.taskId}`;
24716
- }
24717
- if (event.session) {
24718
- return `session:${event.session}`;
24382
+ function eventTime(value) {
24383
+ if (typeof value !== "string") {
24384
+ return void 0;
24719
24385
  }
24720
- return "flue:unknown";
24386
+ const timestamp = Date.parse(value);
24387
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
24388
+ }
24389
+ function turnKey(event) {
24390
+ return event.turnId;
24721
24391
  }
24722
24392
  function toolKey(event) {
24723
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24393
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
24724
24394
  }
24725
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24395
+ function compactionKey(event) {
24726
24396
  return [
24727
- {
24728
- finish_reason: finishReason ?? "stop",
24729
- index: 0,
24730
- message: {
24731
- content: text,
24732
- ...reasoning ? { reasoning } : {},
24733
- role: "assistant",
24734
- ...toolCalls?.length ? {
24735
- tool_calls: toolCalls.map((toolCall) => ({
24736
- function: {
24737
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
24738
- name: toolCall.toolName ?? "unknown"
24739
- },
24740
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
24741
- type: "function"
24742
- }))
24743
- } : {}
24744
- }
24745
- }
24746
- ];
24397
+ event.instanceId ?? "",
24398
+ event.runId ?? "",
24399
+ event.session ?? "",
24400
+ event.operationId ?? "",
24401
+ event.taskId ?? ""
24402
+ ].join(":");
24403
+ }
24404
+ function stateMatchesOperation(state, operationId) {
24405
+ return state.metadata["flue.operation_id"] === operationId;
24406
+ }
24407
+ function stateMatchesRun(state, runId) {
24408
+ return state.metadata["flue.run_id"] === runId;
24747
24409
  }
24748
24410
  function startFlueSpan(parent, args) {
24749
24411
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -24755,6 +24417,13 @@ function safeLog3(span, event) {
24755
24417
  logInstrumentationError3("Flue span log", error);
24756
24418
  }
24757
24419
  }
24420
+ function safeEnd(span, endTime) {
24421
+ try {
24422
+ span.end(endTime === void 0 ? void 0 : { endTime });
24423
+ } catch (error) {
24424
+ logInstrumentationError3("Flue span end", error);
24425
+ }
24426
+ }
24758
24427
  function errorToString(error) {
24759
24428
  if (error instanceof Error) {
24760
24429
  return error.message;
@@ -25236,7 +24905,7 @@ var BraintrustPlugin = class extends BasePlugin {
25236
24905
  this.config = config;
25237
24906
  }
25238
24907
  onEnable() {
25239
- const integrations = this.config.integrations || {};
24908
+ const integrations = this.config.integrations ?? {};
25240
24909
  if (integrations.openai !== false) {
25241
24910
  this.openaiPlugin = new OpenAIPlugin();
25242
24911
  this.openaiPlugin.enable();
@@ -25301,7 +24970,7 @@ var BraintrustPlugin = class extends BasePlugin {
25301
24970
  this.genkitPlugin = new GenkitPlugin();
25302
24971
  this.genkitPlugin.enable();
25303
24972
  }
25304
- if (getIntegrationConfig(integrations, "gitHubCopilot") !== false) {
24973
+ if (integrations.gitHubCopilot !== false) {
25305
24974
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25306
24975
  this.gitHubCopilotPlugin.enable();
25307
24976
  }
@@ -25489,6 +25158,201 @@ function configureInstrumentation(config) {
25489
25158
  registry.configure(config);
25490
25159
  }
25491
25160
 
25161
+ // src/wrappers/mastra.ts
25162
+ var MASTRA_BRAINTRUST_EXPORTER_NAME = "braintrust";
25163
+ var SPAN_TYPE_MAP = {
25164
+ agent_run: "task" /* TASK */,
25165
+ model_generation: "llm" /* LLM */,
25166
+ model_step: "llm" /* LLM */,
25167
+ model_chunk: "llm" /* LLM */,
25168
+ tool_call: "tool" /* TOOL */,
25169
+ mcp_tool_call: "tool" /* TOOL */,
25170
+ workflow_run: "task" /* TASK */,
25171
+ workflow_step: "function" /* FUNCTION */,
25172
+ workflow_conditional: "function" /* FUNCTION */,
25173
+ workflow_conditional_eval: "function" /* FUNCTION */,
25174
+ workflow_parallel: "function" /* FUNCTION */,
25175
+ workflow_loop: "function" /* FUNCTION */,
25176
+ workflow_sleep: "function" /* FUNCTION */,
25177
+ workflow_wait_event: "function" /* FUNCTION */,
25178
+ memory_operation: "function" /* FUNCTION */,
25179
+ workspace_action: "function" /* FUNCTION */,
25180
+ rag_ingestion: "task" /* TASK */,
25181
+ rag_embedding: "llm" /* LLM */,
25182
+ rag_vector_operation: "function" /* FUNCTION */,
25183
+ rag_action: "function" /* FUNCTION */,
25184
+ graph_action: "function" /* FUNCTION */,
25185
+ scorer_run: "score" /* SCORE */,
25186
+ scorer_step: "score" /* SCORE */,
25187
+ processor_run: "function" /* FUNCTION */,
25188
+ generic: "function" /* FUNCTION */
25189
+ };
25190
+ function spanTypeFor(mastraType) {
25191
+ return SPAN_TYPE_MAP[mastraType] ?? "function" /* FUNCTION */;
25192
+ }
25193
+ function epochSeconds(value) {
25194
+ if (value === void 0) return void 0;
25195
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
25196
+ return Number.isFinite(ms) ? ms / 1e3 : void 0;
25197
+ }
25198
+ function modelMetrics(attributes) {
25199
+ if (!isObject(attributes)) return void 0;
25200
+ const usage = isObject(attributes.usage) ? attributes.usage : void 0;
25201
+ if (!usage) return void 0;
25202
+ const out = {};
25203
+ if (typeof usage.inputTokens === "number")
25204
+ out.prompt_tokens = usage.inputTokens;
25205
+ if (typeof usage.outputTokens === "number")
25206
+ out.completion_tokens = usage.outputTokens;
25207
+ if (typeof usage.inputTokens === "number" && typeof usage.outputTokens === "number") {
25208
+ out.tokens = usage.inputTokens + usage.outputTokens;
25209
+ }
25210
+ const inputDetails = isObject(usage.inputDetails) ? usage.inputDetails : void 0;
25211
+ const outputDetails = isObject(usage.outputDetails) ? usage.outputDetails : void 0;
25212
+ if (inputDetails && typeof inputDetails.cacheRead === "number") {
25213
+ out.prompt_cached_tokens = inputDetails.cacheRead;
25214
+ }
25215
+ if (inputDetails && typeof inputDetails.cacheWrite === "number") {
25216
+ out.prompt_cache_creation_tokens = inputDetails.cacheWrite;
25217
+ }
25218
+ if (outputDetails && typeof outputDetails.reasoning === "number") {
25219
+ out.completion_reasoning_tokens = outputDetails.reasoning;
25220
+ }
25221
+ return Object.keys(out).length > 0 ? out : void 0;
25222
+ }
25223
+ function buildMetadata(exported) {
25224
+ const out = {};
25225
+ if (exported.entityId !== void 0) out.entity_id = exported.entityId;
25226
+ if (exported.entityName !== void 0) out.entity_name = exported.entityName;
25227
+ if (exported.entityType !== void 0) out.entity_type = exported.entityType;
25228
+ if (exported.metadata && isObject(exported.metadata)) {
25229
+ Object.assign(out, exported.metadata);
25230
+ }
25231
+ if (exported.attributes && isObject(exported.attributes)) {
25232
+ for (const [key, value] of Object.entries(exported.attributes)) {
25233
+ if (key === "usage") continue;
25234
+ if (value !== void 0) out[key] = value;
25235
+ }
25236
+ }
25237
+ if (exported.tags && exported.tags.length > 0) {
25238
+ out.tags = exported.tags;
25239
+ }
25240
+ if (exported.requestContext && isObject(exported.requestContext)) {
25241
+ out.request_context = exported.requestContext;
25242
+ }
25243
+ return out;
25244
+ }
25245
+ var BraintrustObservabilityExporter = class {
25246
+ name = MASTRA_BRAINTRUST_EXPORTER_NAME;
25247
+ spans = /* @__PURE__ */ new Map();
25248
+ // Captured at the first SPAN_STARTED event. Mastra's observability bus may
25249
+ // dispatch later events outside the user's AsyncLocalStorage context, where
25250
+ // `currentSpan()` returns NOOP_SPAN — which would make our `startSpan()`
25251
+ // calls go to a no-op logger and silently drop. Anchoring on the parent
25252
+ // we observe while still in-context keeps the whole Mastra subtree under
25253
+ // the user's traced scenario.
25254
+ capturedParent;
25255
+ constructor() {
25256
+ _internalSetInitialState();
25257
+ }
25258
+ async exportTracingEvent(event) {
25259
+ const exported = event.exportedSpan;
25260
+ if (exported.isInternal === true) return;
25261
+ try {
25262
+ switch (event.type) {
25263
+ case "span_started":
25264
+ this.onStart(exported);
25265
+ break;
25266
+ case "span_updated":
25267
+ this.onUpdate(exported);
25268
+ break;
25269
+ case "span_ended":
25270
+ this.onEnd(exported);
25271
+ break;
25272
+ }
25273
+ } catch (err) {
25274
+ logExporterError(err);
25275
+ }
25276
+ }
25277
+ async flush() {
25278
+ const state = _internalGetGlobalState();
25279
+ if (state) {
25280
+ await state.bgLogger().flush();
25281
+ }
25282
+ }
25283
+ async shutdown() {
25284
+ await this.flush();
25285
+ this.spans.clear();
25286
+ }
25287
+ onStart(exported) {
25288
+ if (this.spans.has(exported.id)) return;
25289
+ const args = {
25290
+ name: exported.name,
25291
+ spanAttributes: { type: spanTypeFor(exported.type) },
25292
+ startTime: epochSeconds(exported.startTime)
25293
+ };
25294
+ const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
25295
+ if (!this.capturedParent) {
25296
+ const probe = currentSpan();
25297
+ if (probe && probe.spanId) {
25298
+ this.capturedParent = probe;
25299
+ }
25300
+ }
25301
+ const span = parentRecord ? parentRecord.span.startSpan(args) : this.capturedParent ? this.capturedParent.startSpan(args) : startSpan(args);
25302
+ const record = { span, hasLoggedInput: false };
25303
+ this.logPayload(record, exported);
25304
+ this.spans.set(exported.id, record);
25305
+ if (exported.isEvent === true) {
25306
+ span.end({ endTime: args.startTime });
25307
+ this.spans.delete(exported.id);
25308
+ }
25309
+ }
25310
+ onUpdate(exported) {
25311
+ const record = this.spans.get(exported.id);
25312
+ if (!record) return;
25313
+ this.logPayload(record, exported);
25314
+ }
25315
+ onEnd(exported) {
25316
+ const record = this.spans.get(exported.id);
25317
+ if (!record) return;
25318
+ this.logPayload(record, exported);
25319
+ if (exported.errorInfo) {
25320
+ record.span.log({
25321
+ error: exported.errorInfo.message || exported.errorInfo.name || "Unknown Mastra error"
25322
+ });
25323
+ }
25324
+ record.span.end({ endTime: epochSeconds(exported.endTime) });
25325
+ this.spans.delete(exported.id);
25326
+ }
25327
+ logPayload(record, exported) {
25328
+ const event = {};
25329
+ if (exported.input !== void 0) {
25330
+ event.input = exported.input;
25331
+ record.hasLoggedInput = true;
25332
+ }
25333
+ if (exported.output !== void 0) {
25334
+ event.output = exported.output;
25335
+ }
25336
+ const metadata = buildMetadata(exported);
25337
+ if (Object.keys(metadata).length > 0) {
25338
+ event.metadata = metadata;
25339
+ }
25340
+ const metrics = modelMetrics(exported.attributes);
25341
+ if (metrics) {
25342
+ event.metrics = metrics;
25343
+ }
25344
+ if (Object.keys(event).length > 0) {
25345
+ record.span.log(event);
25346
+ }
25347
+ }
25348
+ };
25349
+ function logExporterError(err) {
25350
+ debugLogger.warn("Mastra exporter failure:", err);
25351
+ }
25352
+ function wrapMastraAgent(agent, _options) {
25353
+ return agent;
25354
+ }
25355
+
25492
25356
  // src/node/config.ts
25493
25357
  var BRAINTRUST_ENV_SEARCH_PARENT_LIMIT = 64;
25494
25358
  function configureNode() {
@@ -25574,6 +25438,12 @@ function configureNode() {
25574
25438
  isomorph_default.gunzip = promisify(zlib.gunzip);
25575
25439
  isomorph_default.hash = (data) => crypto.createHash("sha256").update(data).digest("hex");
25576
25440
  _internalSetInitialState();
25441
+ const disabled = readDisabledInstrumentationEnvConfig(
25442
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
25443
+ ).integrations;
25444
+ if (!isInstrumentationIntegrationDisabled(disabled, "mastra")) {
25445
+ installMastraExporterFactory(() => new BraintrustObservabilityExporter());
25446
+ }
25577
25447
  registry.enable();
25578
25448
  }
25579
25449
 
@@ -25588,6 +25458,7 @@ __export(exports_exports, {
25588
25458
  BaseExperiment: () => BaseExperiment,
25589
25459
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
25590
25460
  BraintrustMiddleware: () => BraintrustMiddleware,
25461
+ BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
25591
25462
  BraintrustState: () => BraintrustState,
25592
25463
  BraintrustStream: () => BraintrustStream,
25593
25464
  CachedSpanFetcher: () => CachedSpanFetcher,
@@ -25634,6 +25505,7 @@ __export(exports_exports, {
25634
25505
  _internalIso: () => isomorph_default,
25635
25506
  _internalSetInitialState: () => _internalSetInitialState,
25636
25507
  addAzureBlobHeaders: () => addAzureBlobHeaders,
25508
+ braintrustFlueObserver: () => braintrustFlueObserver,
25637
25509
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
25638
25510
  buildLocalSummary: () => buildLocalSummary,
25639
25511
  configureInstrumentation: () => configureInstrumentation,
@@ -25713,8 +25585,6 @@ __export(exports_exports, {
25713
25585
  wrapCohere: () => wrapCohere,
25714
25586
  wrapCopilotClient: () => wrapCopilotClient,
25715
25587
  wrapCursorSDK: () => wrapCursorSDK,
25716
- wrapFlueContext: () => wrapFlueContext,
25717
- wrapFlueSession: () => wrapFlueSession,
25718
25588
  wrapGenkit: () => wrapGenkit,
25719
25589
  wrapGoogleADK: () => wrapGoogleADK,
25720
25590
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -27203,11 +27073,6 @@ function toolRunnerProxy(toolRunner, anthropic, channel) {
27203
27073
  });
27204
27074
  }
27205
27075
 
27206
- // src/wrappers/mastra.ts
27207
- function wrapMastraAgent(agent, _options) {
27208
- return agent;
27209
- }
27210
-
27211
27076
  // src/wrappers/claude-agent-sdk/claude-agent-sdk.ts
27212
27077
  function wrapClaudeAgentSDK(sdk) {
27213
27078
  const s = sdk;
@@ -32702,6 +32567,7 @@ export {
32702
32567
  BaseExperiment,
32703
32568
  BraintrustLangChainCallbackHandler,
32704
32569
  BraintrustMiddleware,
32570
+ BraintrustObservabilityExporter,
32705
32571
  BraintrustState,
32706
32572
  BraintrustStream,
32707
32573
  CachedSpanFetcher,
@@ -32748,6 +32614,7 @@ export {
32748
32614
  isomorph_default as _internalIso,
32749
32615
  _internalSetInitialState,
32750
32616
  addAzureBlobHeaders,
32617
+ braintrustFlueObserver,
32751
32618
  braintrustStreamChunkSchema,
32752
32619
  buildLocalSummary,
32753
32620
  configureInstrumentation,
@@ -32828,8 +32695,6 @@ export {
32828
32695
  wrapCohere,
32829
32696
  wrapCopilotClient,
32830
32697
  wrapCursorSDK,
32831
- wrapFlueContext,
32832
- wrapFlueSession,
32833
32698
  wrapGenkit,
32834
32699
  wrapGoogleADK,
32835
32700
  wrapGoogleGenAI,