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/browser.mjs CHANGED
@@ -3938,6 +3938,76 @@ var LRUCache = class {
3938
3938
  }
3939
3939
  };
3940
3940
 
3941
+ // src/prompt-cache/cache-config.ts
3942
+ var CACHE_LOCATION_ENV_VAR = "BRAINTRUST_CACHE_LOCATION";
3943
+ var DEFAULT_CACHE_MEMORY_MAX = 1 << 10;
3944
+ var DEFAULT_CACHE_DISK_MAX = 1 << 20;
3945
+ var warnedInvalidCacheModeEnvValue = false;
3946
+ var warnedUnavailableDiskCacheMode = false;
3947
+ function warnInvalidCacheMode(value) {
3948
+ if (warnedInvalidCacheModeEnvValue) {
3949
+ return;
3950
+ }
3951
+ warnedInvalidCacheModeEnvValue = true;
3952
+ debugLogger.warn(
3953
+ `Invalid ${CACHE_LOCATION_ENV_VAR} value "${value}". Expected "mixed", "memory", "disk", or "none". Falling back to "mixed".`
3954
+ );
3955
+ }
3956
+ function warnUnavailableDiskCache() {
3957
+ if (warnedUnavailableDiskCacheMode) {
3958
+ return;
3959
+ }
3960
+ warnedUnavailableDiskCacheMode = true;
3961
+ debugLogger.warn(
3962
+ `Disk cache is not supported on this platform, so ${CACHE_LOCATION_ENV_VAR}="disk" disables prompt and parameters caching.`
3963
+ );
3964
+ }
3965
+ function parseCacheMode() {
3966
+ const value = isomorph_default.getEnv(CACHE_LOCATION_ENV_VAR);
3967
+ const normalized = value?.trim().toLowerCase();
3968
+ if (!normalized) {
3969
+ return "mixed";
3970
+ }
3971
+ if (normalized === "mixed" || normalized === "memory" || normalized === "disk" || normalized === "none") {
3972
+ return normalized;
3973
+ }
3974
+ warnInvalidCacheMode(value ?? "");
3975
+ return "mixed";
3976
+ }
3977
+ function parsePositiveIntegerEnv(envVar, defaultValue) {
3978
+ const value = Number(isomorph_default.getEnv(envVar));
3979
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
3980
+ }
3981
+ function createCacheLayers({
3982
+ memoryMaxEnvVar,
3983
+ diskCacheDirEnvVar,
3984
+ diskMaxEnvVar,
3985
+ getDefaultDiskCacheDir
3986
+ }) {
3987
+ const mode = parseCacheMode();
3988
+ const memoryCache = mode === "mixed" || mode === "memory" ? new LRUCache({
3989
+ max: parsePositiveIntegerEnv(
3990
+ memoryMaxEnvVar,
3991
+ DEFAULT_CACHE_MEMORY_MAX
3992
+ )
3993
+ }) : void 0;
3994
+ let diskCache;
3995
+ if (mode === "mixed" || mode === "disk") {
3996
+ if (canUseDiskCache()) {
3997
+ diskCache = new DiskCache({
3998
+ cacheDir: isomorph_default.getEnv(diskCacheDirEnvVar) ?? getDefaultDiskCacheDir(),
3999
+ max: parsePositiveIntegerEnv(diskMaxEnvVar, DEFAULT_CACHE_DISK_MAX)
4000
+ });
4001
+ } else if (mode === "disk") {
4002
+ warnUnavailableDiskCache();
4003
+ }
4004
+ }
4005
+ if (diskCache) {
4006
+ return { memoryCache, diskCache };
4007
+ }
4008
+ return { memoryCache };
4009
+ }
4010
+
3941
4011
  // src/prompt-cache/prompt-cache.ts
3942
4012
  function createCacheKey(key) {
3943
4013
  if (key.id) {
@@ -3965,16 +4035,18 @@ var PromptCache = class {
3965
4035
  */
3966
4036
  async get(key) {
3967
4037
  const cacheKey = createCacheKey(key);
3968
- const memoryPrompt = this.memoryCache.get(cacheKey);
3969
- if (memoryPrompt !== void 0) {
3970
- return memoryPrompt;
4038
+ if (this.memoryCache) {
4039
+ const memoryPrompt = this.memoryCache.get(cacheKey);
4040
+ if (memoryPrompt !== void 0) {
4041
+ return memoryPrompt;
4042
+ }
3971
4043
  }
3972
4044
  if (this.diskCache) {
3973
4045
  const diskPrompt = await this.diskCache.get(cacheKey);
3974
4046
  if (!diskPrompt) {
3975
4047
  return void 0;
3976
4048
  }
3977
- this.memoryCache.set(cacheKey, diskPrompt);
4049
+ this.memoryCache?.set(cacheKey, diskPrompt);
3978
4050
  return diskPrompt;
3979
4051
  }
3980
4052
  return void 0;
@@ -3989,7 +4061,7 @@ var PromptCache = class {
3989
4061
  */
3990
4062
  async set(key, value) {
3991
4063
  const cacheKey = createCacheKey(key);
3992
- this.memoryCache.set(cacheKey, value);
4064
+ this.memoryCache?.set(cacheKey, value);
3993
4065
  if (this.diskCache) {
3994
4066
  await this.diskCache.set(cacheKey, value);
3995
4067
  }
@@ -4019,23 +4091,25 @@ var ParametersCache = class {
4019
4091
  }
4020
4092
  async get(key) {
4021
4093
  const cacheKey = createCacheKey2(key);
4022
- const memoryParams = this.memoryCache.get(cacheKey);
4023
- if (memoryParams !== void 0) {
4024
- return memoryParams;
4094
+ if (this.memoryCache) {
4095
+ const memoryParams = this.memoryCache.get(cacheKey);
4096
+ if (memoryParams !== void 0) {
4097
+ return memoryParams;
4098
+ }
4025
4099
  }
4026
4100
  if (this.diskCache) {
4027
4101
  const diskParams = await this.diskCache.get(cacheKey);
4028
4102
  if (!diskParams) {
4029
4103
  return void 0;
4030
4104
  }
4031
- this.memoryCache.set(cacheKey, diskParams);
4105
+ this.memoryCache?.set(cacheKey, diskParams);
4032
4106
  return diskParams;
4033
4107
  }
4034
4108
  return void 0;
4035
4109
  }
4036
4110
  async set(key, value) {
4037
4111
  const cacheKey = createCacheKey2(key);
4038
- this.memoryCache.set(cacheKey, value);
4112
+ this.memoryCache?.set(cacheKey, value);
4039
4113
  if (this.diskCache) {
4040
4114
  await this.diskCache.set(cacheKey, value);
4041
4115
  }
@@ -4567,21 +4641,22 @@ var BraintrustState = class _BraintrustState {
4567
4641
  setGlobalDebugLogLevel(void 0);
4568
4642
  }
4569
4643
  this.resetLoginInfo();
4570
- const memoryCache = new LRUCache({
4571
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
4644
+ const { memoryCache, diskCache } = createCacheLayers({
4645
+ memoryMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_MEMORY_MAX",
4646
+ diskCacheDirEnvVar: "BRAINTRUST_PROMPT_CACHE_DIR",
4647
+ diskMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_DISK_MAX",
4648
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`
4572
4649
  });
4573
- const diskCache = canUseDiskCache() ? new DiskCache({
4574
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`,
4575
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DISK_MAX")) ?? 1 << 20
4576
- }) : void 0;
4577
4650
  this.promptCache = new PromptCache({ memoryCache, diskCache });
4578
- const parametersMemoryCache = new LRUCache({
4579
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX")) ?? 1 << 10
4651
+ const {
4652
+ memoryCache: parametersMemoryCache,
4653
+ diskCache: parametersDiskCache
4654
+ } = createCacheLayers({
4655
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
4656
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
4657
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
4658
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
4580
4659
  });
4581
- const parametersDiskCache = canUseDiskCache() ? new DiskCache({
4582
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`,
4583
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DISK_MAX")) ?? 1 << 20
4584
- }) : void 0;
4585
4660
  this.parametersCache = new ParametersCache({
4586
4661
  memoryCache: parametersMemoryCache,
4587
4662
  diskCache: parametersDiskCache
@@ -23844,825 +23919,440 @@ var flueChannels = defineChannels("@flue/runtime", {
23844
23919
  createContext: channel({
23845
23920
  channelName: "createFlueContext",
23846
23921
  kind: "sync-stream"
23847
- }),
23848
- openSession: channel({
23849
- channelName: "Harness.openSession",
23850
- kind: "async"
23851
- }),
23852
- contextEvent: channel({
23853
- channelName: "context.event",
23854
- kind: "sync-stream"
23855
- }),
23856
- prompt: channel({
23857
- channelName: "session.prompt",
23858
- kind: "async"
23859
- }),
23860
- skill: channel({
23861
- channelName: "session.skill",
23862
- kind: "async"
23863
- }),
23864
- task: channel({
23865
- channelName: "session.task",
23866
- kind: "async"
23867
- }),
23868
- compact: channel({
23869
- channelName: "session.compact",
23870
- kind: "async"
23871
23922
  })
23872
23923
  });
23873
23924
 
23874
- // src/wrappers/flue.ts
23875
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23876
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23877
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23878
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23879
- "braintrust.flue.subscribed-context-events"
23880
- );
23881
- function wrapFlueContext(ctx) {
23882
- if (!isPlausibleFlueContext(ctx)) {
23883
- console.warn("Unsupported Flue context. Not wrapping.");
23884
- return ctx;
23925
+ // src/instrumentation/plugins/flue-plugin.ts
23926
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
23927
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
23928
+ var braintrustFlueObserver = (event, ctx) => {
23929
+ getObserveBridge().handle(event, ctx);
23930
+ };
23931
+ var FluePlugin = class extends BasePlugin {
23932
+ onEnable() {
23933
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
23885
23934
  }
23886
- const context = ctx;
23887
- subscribeFlueContextEvents(context, { captureTurnSpans: true });
23888
- return patchFlueContextInPlace(context);
23889
- }
23890
- function patchFlueContextInPlace(ctx) {
23891
- const context = ctx;
23892
- if (context[WRAPPED_FLUE_CONTEXT]) {
23893
- return ctx;
23935
+ onDisable() {
23936
+ for (const unsubscribe of this.unsubscribers) {
23937
+ unsubscribe();
23938
+ }
23939
+ this.unsubscribers = [];
23894
23940
  }
23895
- const originalInit = context.init.bind(context);
23896
- try {
23897
- Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23898
- configurable: false,
23899
- enumerable: false,
23900
- value: true
23901
- });
23902
- Object.defineProperty(context, "init", {
23903
- configurable: true,
23904
- value: async function wrappedFlueInit(options) {
23905
- const harness = await originalInit(options);
23906
- return wrapFlueHarness(harness);
23907
- },
23908
- writable: true
23909
- });
23910
- } catch {
23941
+ };
23942
+ function enableFlueAutoInstrumentation() {
23943
+ const state = getAutoState();
23944
+ state.refCount += 1;
23945
+ if (!state.handlers) {
23946
+ const channel2 = flueChannels.createContext.tracingChannel();
23947
+ const handlers = {
23948
+ end: (event) => {
23949
+ subscribeToFlueContext(event.result, state);
23950
+ }
23951
+ };
23952
+ channel2.subscribe(handlers);
23953
+ state.channel = channel2;
23954
+ state.handlers = handlers;
23911
23955
  }
23912
- return ctx;
23956
+ let released = false;
23957
+ return () => {
23958
+ if (released) {
23959
+ return;
23960
+ }
23961
+ released = true;
23962
+ releaseAutoState(state);
23963
+ };
23913
23964
  }
23914
- function wrapFlueSession(session) {
23915
- if (!isPlausibleFlueSession(session)) {
23916
- console.warn("Unsupported Flue session. Not wrapping.");
23917
- return session;
23965
+ function getAutoState() {
23966
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
23967
+ if (isAutoState(existing)) {
23968
+ return existing;
23918
23969
  }
23919
- return patchFlueSessionInPlace(session);
23970
+ const state = {
23971
+ contexts: /* @__PURE__ */ new WeakSet(),
23972
+ refCount: 0
23973
+ };
23974
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
23975
+ return state;
23920
23976
  }
23921
- function subscribeFlueContextEvents(ctx, options = {}) {
23922
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23923
- return void 0;
23924
- }
23925
- const context = ctx;
23926
- const captureTurnSpans = options.captureTurnSpans ?? true;
23927
- const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
23928
- if (existingSubscription) {
23929
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
23930
- return void 0;
23931
- }
23932
- try {
23933
- existingSubscription.unsubscribe();
23934
- } catch {
23935
- }
23936
- }
23937
- try {
23938
- const unsubscribe = ctx.subscribeEvent((event) => {
23939
- flueChannels.contextEvent.traceSync(() => void 0, {
23940
- arguments: [event],
23941
- captureTurnSpans,
23942
- context: ctx
23943
- });
23944
- });
23945
- if (existingSubscription) {
23946
- existingSubscription.captureTurnSpans = captureTurnSpans;
23947
- existingSubscription.unsubscribe = unsubscribe;
23948
- } else {
23949
- Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
23950
- configurable: false,
23951
- enumerable: false,
23952
- value: {
23953
- captureTurnSpans,
23954
- unsubscribe
23955
- }
23956
- });
23957
- }
23958
- return unsubscribe;
23959
- } catch {
23960
- return void 0;
23977
+ function getObserveBridge() {
23978
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
23979
+ if (isFlueObserveBridge(existing)) {
23980
+ return existing;
23961
23981
  }
23982
+ const bridge = new FlueObserveBridge();
23983
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
23984
+ return bridge;
23962
23985
  }
23963
- function wrapFlueHarness(harness) {
23964
- if (!isPlausibleFlueHarness(harness)) {
23965
- return harness;
23966
- }
23967
- const target = harness;
23968
- if (target[WRAPPED_FLUE_HARNESS]) {
23969
- return harness;
23970
- }
23971
- const originalSession = target.session.bind(target);
23972
- try {
23973
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
23974
- configurable: false,
23975
- enumerable: false,
23976
- value: true
23977
- });
23978
- Object.defineProperty(target, "session", {
23979
- configurable: true,
23980
- value: async function wrappedFlueHarnessSession(name, options) {
23981
- const session = await originalSession(name, options);
23982
- return patchFlueSessionInPlace(session);
23983
- },
23984
- writable: true
23985
- });
23986
- const sessions = target.sessions;
23987
- if (sessions && typeof sessions === "object") {
23988
- patchFlueSessionFactory(sessions, "get");
23989
- patchFlueSessionFactory(sessions, "create");
23990
- }
23991
- } catch {
23992
- }
23993
- return harness;
23986
+ function isFlueObserveBridge(value) {
23987
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
23994
23988
  }
23995
- function patchFlueSessionInPlace(session) {
23996
- if (session[WRAPPED_FLUE_SESSION]) {
23997
- return session;
23998
- }
23999
- try {
24000
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
24001
- configurable: false,
24002
- enumerable: false,
24003
- value: true
24004
- });
24005
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
24006
- patchCallHandleMethod(session, "skill", flueChannels.skill);
24007
- patchCallHandleMethod(session, "task", flueChannels.task);
24008
- patchCompact(session);
24009
- } catch {
24010
- }
24011
- return session;
23989
+ function isAutoState(value) {
23990
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
24012
23991
  }
24013
- function patchFlueSessionFactory(sessions, method) {
24014
- const original = sessions[method];
24015
- if (typeof original !== "function") {
23992
+ function releaseAutoState(state) {
23993
+ state.refCount -= 1;
23994
+ if (state.refCount > 0) {
24016
23995
  return;
24017
23996
  }
24018
- const bound = original.bind(sessions);
24019
- Object.defineProperty(sessions, method, {
24020
- configurable: true,
24021
- value: async function wrappedFlueSessionFactory(name, options) {
24022
- const session = await bound(name, options);
24023
- return patchFlueSessionInPlace(session);
24024
- },
24025
- writable: true
24026
- });
24027
- }
24028
- function patchCallHandleMethod(session, method, channel2) {
24029
- const original = session[method];
24030
- if (typeof original !== "function") {
24031
- return;
23997
+ try {
23998
+ if (state.channel && state.handlers) {
23999
+ state.channel.unsubscribe(state.handlers);
24000
+ }
24001
+ } finally {
24002
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
24032
24003
  }
24033
- const bound = original.bind(session);
24034
- Object.defineProperty(session, method, {
24035
- configurable: true,
24036
- value(input, options) {
24037
- const args = [input, options];
24038
- const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
24039
- context: {
24040
- arguments: args,
24041
- operation: method,
24042
- session
24043
- },
24044
- run: () => bound(input, options)
24045
- });
24046
- return preserveCallHandle(originalResult, traced2);
24047
- },
24048
- writable: true
24049
- });
24050
24004
  }
24051
- function patchCompact(session) {
24052
- const original = session.compact;
24053
- if (typeof original !== "function") {
24005
+ function subscribeToFlueContext(value, state) {
24006
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
24054
24007
  return;
24055
24008
  }
24056
- const bound = original.bind(session);
24057
- Object.defineProperty(session, "compact", {
24058
- configurable: true,
24059
- value() {
24060
- const context = {
24061
- arguments: [],
24062
- operation: "compact",
24063
- session
24064
- };
24065
- return flueChannels.compact.tracePromise(() => bound(), context);
24066
- },
24067
- writable: true
24068
- });
24069
- }
24070
- function traceFlueOperation(channel2, args) {
24071
- const tracingChannel2 = channel2.tracingChannel();
24072
- const context = args.context;
24073
- let originalResult;
24074
- let traced2;
24075
- const run = () => {
24009
+ const ctx = flueContextFromUnknown(value);
24010
+ let released = false;
24011
+ let unsubscribe;
24012
+ const release = () => {
24013
+ if (released) {
24014
+ return;
24015
+ }
24016
+ released = true;
24076
24017
  try {
24077
- originalResult = args.run();
24078
- tracingChannel2.end?.publish(context);
24018
+ unsubscribe?.();
24079
24019
  } catch (error) {
24080
- context.error = normalizeError3(error);
24081
- tracingChannel2.error?.publish(context);
24082
- tracingChannel2.end?.publish(context);
24083
- throw error;
24020
+ logInstrumentationError3("Flue context unsubscribe", error);
24084
24021
  }
24085
- traced2 = Promise.resolve(originalResult).then(
24086
- (result) => {
24087
- context.result = result;
24088
- tracingChannel2.asyncStart?.publish(context);
24089
- tracingChannel2.asyncEnd?.publish(context);
24090
- return result;
24091
- },
24092
- (error) => {
24093
- context.error = normalizeError3(error);
24094
- tracingChannel2.error?.publish(context);
24095
- tracingChannel2.asyncStart?.publish(context);
24096
- tracingChannel2.asyncEnd?.publish(context);
24097
- throw error;
24098
- }
24099
- );
24100
24022
  };
24101
- if (tracingChannel2.start?.runStores) {
24102
- tracingChannel2.start.runStores(context, run);
24103
- } else {
24104
- tracingChannel2.start?.publish(context);
24105
- run();
24023
+ try {
24024
+ unsubscribe = value.subscribeEvent((event) => {
24025
+ if (state.refCount <= 0) {
24026
+ release();
24027
+ return;
24028
+ }
24029
+ braintrustFlueObserver(event, ctx);
24030
+ if (isAutoContextTerminalEvent(event, ctx)) {
24031
+ release();
24032
+ }
24033
+ });
24034
+ state.contexts.add(value);
24035
+ } catch (error) {
24036
+ logInstrumentationError3("Flue context subscription", error);
24106
24037
  }
24107
- return { originalResult, traced: traced2 };
24108
- }
24109
- function normalizeError3(error) {
24110
- return error instanceof Error ? error : new Error(String(error));
24111
24038
  }
24112
- function preserveCallHandle(originalHandle, traced2) {
24113
- if (!isFlueCallHandle(originalHandle)) {
24114
- return traced2;
24039
+ function isAutoContextTerminalEvent(event, ctx) {
24040
+ if (!isObjectLike(event)) {
24041
+ return false;
24115
24042
  }
24116
- const handle = originalHandle;
24117
- const wrapped = {
24118
- get signal() {
24119
- return handle.signal;
24120
- },
24121
- abort(reason) {
24122
- return handle.abort(reason);
24123
- },
24124
- then(onfulfilled, onrejected) {
24125
- return traced2.then(onfulfilled, onrejected);
24126
- }
24127
- };
24128
- return wrapped;
24043
+ const type = Reflect.get(event, "type");
24044
+ if (type === "run_end") {
24045
+ return true;
24046
+ }
24047
+ if (type !== "operation") {
24048
+ return false;
24049
+ }
24050
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
24129
24051
  }
24130
- function isPlausibleFlueContext(value) {
24131
- return !!value && typeof value === "object" && typeof value.init === "function";
24052
+ function isObservableFlueContext(value) {
24053
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
24132
24054
  }
24133
- function isPlausibleFlueHarness(value) {
24134
- return !!value && typeof value === "object" && typeof value.session === "function";
24055
+ function isFlueEvent(event) {
24056
+ const type = Reflect.get(event, "type");
24057
+ 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";
24135
24058
  }
24136
- function isPlausibleFlueSession(value) {
24137
- return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
24059
+ function flueContextFromUnknown(ctx) {
24060
+ if (!isObjectLike(ctx)) {
24061
+ return void 0;
24062
+ }
24063
+ const id = Reflect.get(ctx, "id");
24064
+ const runId = Reflect.get(ctx, "runId");
24065
+ return {
24066
+ ...typeof id === "string" ? { id } : {},
24067
+ ...typeof runId === "string" ? { runId } : {}
24068
+ };
24138
24069
  }
24139
- function isFlueCallHandle(value) {
24140
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
24070
+ function isObjectLike(value) {
24071
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24141
24072
  }
24142
-
24143
- // src/instrumentation/plugins/flue-plugin.ts
24144
- var FluePlugin = class extends BasePlugin {
24145
- activeOperationsById = /* @__PURE__ */ new Map();
24146
- activeOperationsByScope = /* @__PURE__ */ new Map();
24147
- compactionsByScope = /* @__PURE__ */ new Map();
24148
- pendingOperationsByKey = /* @__PURE__ */ new Map();
24073
+ var FlueObserveBridge = class {
24074
+ compactionsByKey = /* @__PURE__ */ new Map();
24075
+ operationsById = /* @__PURE__ */ new Map();
24076
+ runsById = /* @__PURE__ */ new Map();
24077
+ seenEvents = /* @__PURE__ */ new WeakSet();
24149
24078
  tasksById = /* @__PURE__ */ new Map();
24150
- toolsById = /* @__PURE__ */ new Map();
24151
- turnsByScope = /* @__PURE__ */ new Map();
24152
- onEnable() {
24153
- this.subscribeToContextCreation();
24154
- this.subscribeToSessionCreation();
24155
- this.subscribeToContextEvents();
24156
- this.subscribeToSessionOperations();
24157
- }
24158
- onDisable() {
24159
- for (const unsubscribe of this.unsubscribers) {
24160
- unsubscribe();
24079
+ toolsByKey = /* @__PURE__ */ new Map();
24080
+ turnsByKey = /* @__PURE__ */ new Map();
24081
+ handle(event, ctx) {
24082
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
24083
+ return;
24161
24084
  }
24162
- this.unsubscribers = [];
24163
- this.activeOperationsById.clear();
24164
- this.activeOperationsByScope.clear();
24165
- this.compactionsByScope.clear();
24166
- this.pendingOperationsByKey.clear();
24085
+ if (this.seenEvents.has(event)) {
24086
+ return;
24087
+ }
24088
+ this.seenEvents.add(event);
24089
+ try {
24090
+ this.handleEvent(event, flueContextFromUnknown(ctx));
24091
+ } catch (error) {
24092
+ logInstrumentationError3("Flue observe", error);
24093
+ }
24094
+ }
24095
+ reset() {
24096
+ this.compactionsByKey.clear();
24097
+ this.operationsById.clear();
24098
+ this.runsById.clear();
24099
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
24167
24100
  this.tasksById.clear();
24168
- this.toolsById.clear();
24169
- this.turnsByScope.clear();
24101
+ this.toolsByKey.clear();
24102
+ this.turnsByKey.clear();
24170
24103
  }
24171
- subscribeToContextCreation() {
24172
- const channel2 = flueChannels.createContext.tracingChannel();
24173
- const handlers = {
24174
- end: (event) => {
24175
- const ctx = event.result;
24176
- if (!ctx) {
24177
- return;
24178
- }
24179
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
24180
- patchFlueContextInPlace(ctx);
24181
- },
24182
- error: () => {
24183
- }
24184
- };
24185
- channel2.subscribe(handlers);
24186
- this.unsubscribers.push(() => {
24187
- channel2.unsubscribe(handlers);
24188
- });
24104
+ handleEvent(event, ctx) {
24105
+ switch (event.type) {
24106
+ case "run_start":
24107
+ this.handleRunStart(event, ctx);
24108
+ return;
24109
+ case "run_end":
24110
+ this.handleRunEnd(event);
24111
+ return;
24112
+ case "operation_start":
24113
+ this.handleOperationStart(event);
24114
+ return;
24115
+ case "operation":
24116
+ this.handleOperation(event);
24117
+ return;
24118
+ case "turn_request":
24119
+ this.handleTurnRequest(event);
24120
+ return;
24121
+ case "turn":
24122
+ this.handleTurn(event);
24123
+ return;
24124
+ case "tool_start":
24125
+ this.handleToolStart(event);
24126
+ return;
24127
+ case "tool_call":
24128
+ this.handleToolCall(event);
24129
+ return;
24130
+ case "task_start":
24131
+ this.handleTaskStart(event);
24132
+ return;
24133
+ case "task":
24134
+ this.handleTask(event);
24135
+ return;
24136
+ case "compaction_start":
24137
+ this.handleCompactionStart(event);
24138
+ return;
24139
+ case "compaction":
24140
+ this.handleCompaction(event);
24141
+ return;
24142
+ default:
24143
+ return;
24144
+ }
24189
24145
  }
24190
- subscribeToSessionCreation() {
24191
- const channel2 = flueChannels.openSession.tracingChannel();
24192
- const handlers = {
24193
- asyncEnd: (event) => {
24194
- if (event.result) {
24195
- patchFlueSessionInPlace(
24196
- event.result
24197
- );
24198
- }
24199
- if (event.harness) {
24200
- wrapFlueHarness(event.harness);
24201
- }
24202
- },
24203
- error: () => {
24204
- }
24146
+ handleRunStart(event, ctx) {
24147
+ if (!event.runId) {
24148
+ return;
24149
+ }
24150
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
24151
+ const metadata = {
24152
+ ...extractPayloadMetadata(event.payload),
24153
+ ...extractEventMetadata(event, ctx),
24154
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
24155
+ provider: "flue"
24205
24156
  };
24206
- channel2.subscribe(handlers);
24207
- this.unsubscribers.push(() => {
24208
- channel2.unsubscribe(handlers);
24157
+ const span = startSpan({
24158
+ name: `workflow:${workflowName}`,
24159
+ spanAttributes: { type: "task" /* TASK */ },
24160
+ startTime: eventTime(event.startedAt ?? event.timestamp),
24161
+ event: {
24162
+ input: event.payload,
24163
+ metadata
24164
+ }
24209
24165
  });
24166
+ this.runsById.set(event.runId, { metadata, span });
24210
24167
  }
24211
- subscribeToSessionOperations() {
24212
- this.subscribeToSessionOperation(flueChannels.prompt);
24213
- this.subscribeToSessionOperation(flueChannels.skill);
24214
- this.subscribeToSessionOperation(flueChannels.task);
24215
- this.subscribeToCompact();
24216
- }
24217
- subscribeToSessionOperation(channel2) {
24218
- const tracingChannel2 = channel2.tracingChannel();
24219
- const states = /* @__PURE__ */ new WeakMap();
24220
- const ensureState2 = (event) => {
24221
- const existing = states.get(event);
24222
- if (existing) {
24223
- return existing;
24224
- }
24225
- const state = this.startOperationState({
24226
- args: event.arguments,
24227
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24228
- operation: event.operation,
24229
- session: event.session
24230
- });
24231
- states.set(event, state);
24232
- return state;
24233
- };
24234
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24235
- tracingChannel2,
24236
- ensureState2
24237
- );
24238
- const handlers = {
24239
- start: (event) => {
24240
- ensureState2(event);
24241
- },
24242
- asyncEnd: (event) => {
24243
- this.endOperationState(states.get(event), event.result);
24244
- states.delete(event);
24245
- },
24246
- error: (event) => {
24247
- const state = states.get(event);
24248
- if (state && event.error) {
24249
- safeLog3(state.span, { error: errorToString(event.error) });
24250
- this.finishOperationState(state);
24251
- }
24252
- states.delete(event);
24253
- }
24254
- };
24255
- tracingChannel2.subscribe(handlers);
24256
- this.unsubscribers.push(() => {
24257
- unbindCurrentSpanStore?.();
24258
- tracingChannel2.unsubscribe(handlers);
24259
- });
24260
- }
24261
- subscribeToCompact() {
24262
- const tracingChannel2 = flueChannels.compact.tracingChannel();
24263
- const states = /* @__PURE__ */ new WeakMap();
24264
- const ensureState2 = (event) => {
24265
- const existing = states.get(event);
24266
- if (existing) {
24267
- return existing;
24268
- }
24269
- const state = this.startOperationState({
24270
- args: [],
24271
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24272
- operation: event.operation,
24273
- session: event.session
24168
+ handleRunEnd(event) {
24169
+ const state = this.runsById.get(event.runId);
24170
+ this.finishPendingSpansForRun(event);
24171
+ if (state) {
24172
+ safeLog3(state.span, {
24173
+ ...event.isError ? { error: errorToString(event.error) } : {},
24174
+ metadata: {
24175
+ ...state.metadata,
24176
+ ...extractEventMetadata(event),
24177
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24178
+ },
24179
+ metrics: durationMetrics2(event.durationMs),
24180
+ output: event.result
24274
24181
  });
24275
- states.set(event, state);
24276
- return state;
24277
- };
24278
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24279
- tracingChannel2,
24280
- ensureState2
24281
- );
24282
- const handlers = {
24283
- start: (event) => {
24284
- ensureState2(event);
24285
- },
24286
- asyncEnd: (event) => {
24287
- this.endOperationState(states.get(event), void 0);
24288
- states.delete(event);
24289
- },
24290
- error: (event) => {
24291
- const state = states.get(event);
24292
- if (state && event.error) {
24293
- safeLog3(state.span, { error: errorToString(event.error) });
24294
- this.finishOperationState(state);
24295
- }
24296
- states.delete(event);
24297
- }
24298
- };
24299
- tracingChannel2.subscribe(handlers);
24300
- this.unsubscribers.push(() => {
24301
- unbindCurrentSpanStore?.();
24302
- tracingChannel2.unsubscribe(handlers);
24303
- });
24304
- }
24305
- subscribeToContextEvents() {
24306
- const channel2 = flueChannels.contextEvent.tracingChannel();
24307
- const handlers = {
24308
- start: (event) => {
24309
- const flueEvent = event.arguments[0];
24310
- if (!flueEvent) {
24311
- return;
24312
- }
24313
- try {
24314
- this.handleFlueEvent(flueEvent, {
24315
- captureTurnSpans: event.captureTurnSpans !== false
24316
- });
24317
- } catch (error) {
24318
- logInstrumentationError3("Flue event", error);
24319
- }
24320
- },
24321
- error: () => {
24322
- }
24323
- };
24324
- channel2.subscribe(handlers);
24325
- this.unsubscribers.push(() => {
24326
- channel2.unsubscribe(handlers);
24327
- });
24328
- }
24329
- bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
24330
- const state = _internalGetGlobalState();
24331
- const startChannel = tracingChannel2.start;
24332
- const contextManager = state?.contextManager;
24333
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
24334
- if (!currentSpanStore || !startChannel) {
24335
- return void 0;
24182
+ safeEnd(state.span, eventTime(event.timestamp));
24183
+ this.runsById.delete(event.runId);
24336
24184
  }
24337
- startChannel.bindStore(currentSpanStore, (event) => {
24338
- const operationState = ensureState2(event);
24339
- return contextManager.wrapSpanForStore(operationState.span);
24185
+ void flush().catch((error) => {
24186
+ logInstrumentationError3("Flue flush", error);
24340
24187
  });
24341
- return () => {
24342
- startChannel.unbindStore(currentSpanStore);
24343
- };
24344
- }
24345
- startOperationState(args) {
24346
- const sessionName = getSessionName(args.session);
24347
- const metadata = {
24348
- ...extractOperationInputMetadata(args.operation, args.args),
24349
- ...extractSessionMetadata(args.session),
24350
- "flue.operation": args.operation,
24351
- provider: "flue",
24352
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24353
- };
24354
- const span = startSpan({
24355
- name: `flue.session.${args.operation}`,
24356
- spanAttributes: { type: "task" /* TASK */ }
24357
- });
24358
- const state = {
24359
- metadata,
24360
- operation: args.operation,
24361
- sessionName,
24362
- span,
24363
- startTime: getCurrentUnixTimestamp()
24364
- };
24365
- safeLog3(span, {
24366
- input: extractOperationInput(args.operation, args.args),
24367
- metadata
24368
- });
24369
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24370
- state
24371
- );
24372
- addOperationToScope(
24373
- this.activeOperationsByScope,
24374
- sessionName ?? "unknown",
24375
- state
24376
- );
24377
- return state;
24378
- }
24379
- endOperationState(state, result) {
24380
- if (!state) {
24381
- return;
24382
- }
24383
- const metadata = {
24384
- ...state.metadata,
24385
- ...extractPromptResponseMetadata(result)
24386
- };
24387
- const metrics = {
24388
- ...buildDurationMetrics3(state.startTime),
24389
- ...metricsFromUsage(result?.usage)
24390
- };
24391
- safeLog3(state.span, {
24392
- metadata,
24393
- metrics,
24394
- output: extractOperationOutput(result)
24395
- });
24396
- this.finishCompactionsForOperation(state);
24397
- this.finishOperationState(state);
24398
- }
24399
- finishOperationState(state) {
24400
- removePendingOperation(this.pendingOperationsByKey, state);
24401
- if (state.operationId) {
24402
- this.activeOperationsById.delete(state.operationId);
24403
- }
24404
- removeScopedOperation(this.activeOperationsByScope, state);
24405
- state.span.end();
24406
- }
24407
- handleFlueEvent(event, options) {
24408
- switch (event.type) {
24409
- case "operation_start":
24410
- this.handleOperationStart(event);
24411
- return;
24412
- case "operation":
24413
- this.handleOperation(event);
24414
- return;
24415
- case "text_delta":
24416
- if (!options.captureTurnSpans) {
24417
- return;
24418
- }
24419
- this.ensureTurnState(event).text.push(
24420
- typeof event.text === "string" ? event.text : ""
24421
- );
24422
- return;
24423
- case "thinking_start":
24424
- if (!options.captureTurnSpans) {
24425
- return;
24426
- }
24427
- this.handleThinkingStart(event);
24428
- return;
24429
- case "thinking_delta":
24430
- if (!options.captureTurnSpans) {
24431
- return;
24432
- }
24433
- this.handleThinkingDelta(event);
24434
- return;
24435
- case "thinking_end":
24436
- if (!options.captureTurnSpans) {
24437
- return;
24438
- }
24439
- this.handleThinkingEnd(event);
24440
- return;
24441
- case "turn":
24442
- if (!options.captureTurnSpans) {
24443
- return;
24444
- }
24445
- this.handleTurn(event);
24446
- return;
24447
- case "tool_start":
24448
- this.handleToolStart(event, options);
24449
- return;
24450
- case "tool_call":
24451
- this.handleToolCall(event);
24452
- return;
24453
- case "task_start":
24454
- this.handleTaskStart(event);
24455
- return;
24456
- case "task":
24457
- this.handleTask(event);
24458
- return;
24459
- case "compaction_start":
24460
- this.handleCompactionStart(event);
24461
- return;
24462
- case "compaction":
24463
- this.handleCompaction(event);
24464
- return;
24465
- default:
24466
- return;
24467
- }
24468
24188
  }
24469
24189
  handleOperationStart(event) {
24470
- if (!isInstrumentedOperation(event.operationKind)) {
24190
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
24471
24191
  return;
24472
24192
  }
24473
- const state = this.takePendingOperationForEvent(event);
24474
- if (!state) {
24475
- return;
24476
- }
24477
- state.operationId = event.operationId;
24478
- this.activeOperationsById.set(event.operationId, state);
24479
- addScopedOperation(this.activeOperationsByScope, event, state);
24480
- state.metadata = {
24481
- ...state.metadata,
24193
+ const metadata = {
24482
24194
  ...extractEventMetadata(event),
24483
- "flue.operation_id": event.operationId
24195
+ "flue.operation": event.operationKind,
24196
+ provider: "flue"
24484
24197
  };
24485
- safeLog3(state.span, { metadata: state.metadata });
24198
+ const parent = this.parentSpanForEvent(event);
24199
+ const span = startFlueSpan(parent, {
24200
+ name: `flue.${event.operationKind}`,
24201
+ spanAttributes: { type: "task" /* TASK */ },
24202
+ startTime: eventTime(event.timestamp),
24203
+ event: { metadata }
24204
+ });
24205
+ this.operationsById.set(event.operationId, { metadata, span });
24486
24206
  }
24487
24207
  handleOperation(event) {
24488
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24489
- if (!state) {
24208
+ if (!isInstrumentedOperation(event.operationKind)) {
24490
24209
  return;
24491
24210
  }
24211
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
24212
+ const output = operationOutput(event);
24492
24213
  const metadata = {
24493
24214
  ...state.metadata,
24494
24215
  ...extractEventMetadata(event),
24495
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24496
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24216
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24217
+ ...event.usage ? { "flue.usage": event.usage } : {}
24497
24218
  };
24498
- const metrics = metricsFromUsage(event.usage);
24219
+ this.finishPendingChildrenForOperation(event, output);
24499
24220
  safeLog3(state.span, {
24500
- ...event.error ? { error: errorToString(event.error) } : {},
24221
+ ...event.isError ? { error: errorToString(event.error) } : {},
24501
24222
  metadata,
24502
- ...Object.keys(metrics).length ? { metrics } : {}
24223
+ metrics: durationMetrics2(event.durationMs),
24224
+ output
24503
24225
  });
24226
+ safeEnd(state.span, eventTime(event.timestamp));
24227
+ this.operationsById.delete(event.operationId);
24504
24228
  }
24505
- ensureTurnState(event) {
24506
- const scope = scopeKey(event);
24507
- const existing = this.turnsByScope.get(scope);
24508
- if (existing) {
24509
- return existing;
24229
+ handleTurnRequest(event) {
24230
+ const key = turnKey(event);
24231
+ if (!key) {
24232
+ return;
24510
24233
  }
24511
- const parent = this.parentSpanForEvent(event);
24512
24234
  const metadata = {
24513
24235
  ...extractEventMetadata(event),
24514
- provider: "flue"
24236
+ ...event.api ? { "flue.api": event.api } : {},
24237
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24238
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24239
+ ...event.provider ? { "flue.provider": event.provider } : {},
24240
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24241
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
24242
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
24243
+ ...event.input?.tools ? { tools: event.input.tools } : {}
24515
24244
  };
24245
+ const parent = this.parentSpanForTurn(event);
24516
24246
  const span = startFlueSpan(parent, {
24517
- name: "flue.turn",
24518
- spanAttributes: { type: "llm" /* LLM */ }
24247
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24248
+ spanAttributes: { type: "llm" /* LLM */ },
24249
+ startTime: eventTime(event.timestamp),
24250
+ event: {
24251
+ input: event.input?.messages,
24252
+ metadata
24253
+ }
24519
24254
  });
24520
- const state = {
24521
- metadata,
24522
- span,
24523
- hasThinking: false,
24524
- startTime: getCurrentUnixTimestamp(),
24525
- text: [],
24526
- thinking: [],
24527
- toolCalls: []
24528
- };
24529
- safeLog3(span, { metadata });
24530
- this.turnsByScope.set(scope, state);
24531
- return state;
24255
+ this.logOperationInput(
24256
+ event.operationId,
24257
+ event.input?.messages ?? event.input
24258
+ );
24259
+ this.turnsByKey.set(key, { metadata, span });
24532
24260
  }
24533
24261
  handleTurn(event) {
24534
- const scope = scopeKey(event);
24535
- const state = this.ensureTurnState(event);
24536
- const text = state.text.join("");
24537
- const reasoning = state.finalThinking ?? state.thinking.join("");
24538
- const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
24262
+ const key = turnKey(event);
24263
+ if (!key) {
24264
+ return;
24265
+ }
24266
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
24539
24267
  const metadata = {
24540
24268
  ...state.metadata,
24541
24269
  ...extractEventMetadata(event),
24270
+ ...event.api ? { "flue.api": event.api } : {},
24542
24271
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
24272
+ ...event.provider ? { provider: event.provider } : {},
24273
+ ...event.provider ? { "flue.provider": event.provider } : {},
24274
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24543
24275
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24544
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24545
- provider: "flue"
24276
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24546
24277
  };
24547
24278
  safeLog3(state.span, {
24548
- ...event.error ? { error: errorToString(event.error) } : {},
24279
+ ...event.isError ? { error: errorToString(event.error) } : {},
24549
24280
  metadata,
24550
24281
  metrics: {
24551
- ...durationMsMetrics(event.durationMs),
24282
+ ...durationMetrics2(event.durationMs),
24552
24283
  ...metricsFromUsage(event.usage)
24553
24284
  },
24554
- output: toAssistantOutput(
24555
- text,
24556
- event.stopReason,
24557
- outputReasoning,
24558
- state.toolCalls
24559
- )
24285
+ output: event.output
24560
24286
  });
24561
- state.span.end();
24562
- this.turnsByScope.delete(scope);
24563
- }
24564
- handleThinkingDelta(event) {
24565
- const delta = event.delta;
24566
- if (typeof delta !== "string" || !delta) {
24567
- return;
24568
- }
24569
- const state = this.ensureTurnState(event);
24570
- state.hasThinking = true;
24571
- state.metadata["flue.thinking"] = true;
24572
- state.thinking.push(delta);
24573
- }
24574
- handleThinkingStart(event) {
24575
- const state = this.ensureTurnState(event);
24576
- state.hasThinking = true;
24577
- state.metadata["flue.thinking"] = true;
24578
- }
24579
- handleThinkingEnd(event) {
24580
- const state = this.ensureTurnState(event);
24581
- state.hasThinking = true;
24582
- state.metadata["flue.thinking"] = true;
24583
- if (typeof event.content === "string" && event.content) {
24584
- state.finalThinking = event.content;
24585
- }
24287
+ safeEnd(state.span, eventTime(event.timestamp));
24288
+ this.turnsByKey.delete(key);
24586
24289
  }
24587
- handleToolStart(event, options) {
24588
- const toolCallId = event.toolCallId;
24589
- if (!toolCallId) {
24290
+ handleToolStart(event) {
24291
+ if (!event.toolCallId) {
24590
24292
  return;
24591
24293
  }
24592
- const parent = this.parentSpanForEvent(event);
24593
- const scope = scopeKey(event);
24594
- let turnState = this.turnsByScope.get(scope);
24595
- if (!turnState && parent && options.captureTurnSpans) {
24596
- turnState = this.ensureTurnState(event);
24597
- }
24598
24294
  const metadata = {
24599
24295
  ...extractEventMetadata(event),
24600
24296
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24601
- "flue.tool_call_id": toolCallId,
24297
+ "flue.tool_call_id": event.toolCallId,
24602
24298
  provider: "flue"
24603
24299
  };
24300
+ const parent = this.parentSpanForTool(event);
24604
24301
  const span = startFlueSpan(parent, {
24605
- name: `tool: ${event.toolName ?? "unknown"}`,
24606
- spanAttributes: { type: "tool" /* TOOL */ }
24607
- });
24608
- if (turnState) {
24609
- turnState.toolCalls.push({
24610
- args: event.args,
24611
- toolCallId,
24612
- toolName: event.toolName
24613
- });
24614
- }
24615
- safeLog3(span, {
24616
- input: event.args,
24617
- metadata
24618
- });
24619
- this.toolsById.set(toolKey(event), {
24620
- metadata,
24621
- span,
24622
- startTime: getCurrentUnixTimestamp()
24302
+ name: `tool:${event.toolName ?? "unknown"}`,
24303
+ spanAttributes: { type: "tool" /* TOOL */ },
24304
+ startTime: eventTime(event.timestamp),
24305
+ event: {
24306
+ input: event.args,
24307
+ metadata
24308
+ }
24623
24309
  });
24310
+ this.toolsByKey.set(toolKey(event), { metadata, span });
24624
24311
  }
24625
24312
  handleToolCall(event) {
24313
+ if (!event.toolCallId) {
24314
+ return;
24315
+ }
24626
24316
  const key = toolKey(event);
24627
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24317
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
24628
24318
  const metadata = {
24629
24319
  ...state.metadata,
24630
24320
  ...extractEventMetadata(event),
24631
24321
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24632
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24322
+ "flue.tool_call_id": event.toolCallId,
24633
24323
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24634
24324
  };
24635
24325
  safeLog3(state.span, {
24636
24326
  ...event.isError ? { error: errorToString(event.result) } : {},
24637
24327
  metadata,
24638
- metrics: durationMsMetrics(event.durationMs),
24328
+ metrics: durationMetrics2(event.durationMs),
24639
24329
  output: event.result
24640
24330
  });
24641
- state.span.end();
24642
- this.toolsById.delete(key);
24331
+ safeEnd(state.span, eventTime(event.timestamp));
24332
+ this.toolsByKey.delete(key);
24643
24333
  }
24644
24334
  handleTaskStart(event) {
24645
- const parent = this.parentSpanForEvent(event);
24335
+ if (!event.taskId) {
24336
+ return;
24337
+ }
24646
24338
  const metadata = {
24647
24339
  ...extractEventMetadata(event),
24648
- ...event.role ? { "flue.role": event.role } : {},
24340
+ ...event.agent ? { "flue.agent": event.agent } : {},
24649
24341
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
24650
24342
  "flue.task_id": event.taskId,
24651
24343
  provider: "flue"
24652
24344
  };
24345
+ const parent = this.parentSpanForEvent(event);
24653
24346
  const span = startFlueSpan(parent, {
24654
- name: "flue.task",
24655
- spanAttributes: { type: "task" /* TASK */ }
24656
- });
24657
- safeLog3(span, {
24658
- input: event.prompt,
24659
- metadata
24660
- });
24661
- this.tasksById.set(event.taskId, {
24662
- metadata,
24663
- span,
24664
- startTime: getCurrentUnixTimestamp()
24347
+ name: event.agent ? `task:${event.agent}` : "flue.task",
24348
+ spanAttributes: { type: "task" /* TASK */ },
24349
+ startTime: eventTime(event.timestamp),
24350
+ event: {
24351
+ input: event.prompt,
24352
+ metadata
24353
+ }
24665
24354
  });
24355
+ this.tasksById.set(event.taskId, { metadata, span });
24666
24356
  }
24667
24357
  handleTask(event) {
24668
24358
  const state = this.tasksById.get(event.taskId);
@@ -24674,426 +24364,372 @@ var FluePlugin = class extends BasePlugin {
24674
24364
  metadata: {
24675
24365
  ...state.metadata,
24676
24366
  ...extractEventMetadata(event),
24367
+ ...event.agent ? { "flue.agent": event.agent } : {},
24677
24368
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24678
24369
  },
24679
- metrics: durationMsMetrics(event.durationMs),
24370
+ metrics: durationMetrics2(event.durationMs),
24680
24371
  output: event.result
24681
24372
  });
24682
- state.span.end();
24373
+ safeEnd(state.span, eventTime(event.timestamp));
24683
24374
  this.tasksById.delete(event.taskId);
24684
24375
  }
24685
24376
  handleCompactionStart(event) {
24686
- const operationState = this.operationStateForEvent(event);
24687
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
24377
+ const key = compactionKey(event);
24378
+ const input = {
24379
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
24380
+ ...event.reason ? { reason: event.reason } : {}
24381
+ };
24688
24382
  const metadata = {
24689
24383
  ...extractEventMetadata(event),
24690
24384
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24691
24385
  provider: "flue"
24692
24386
  };
24693
- const input = {
24694
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24695
- ...event.reason ? { reason: event.reason } : {}
24696
- };
24387
+ const parent = this.parentSpanForEvent(event);
24697
24388
  const span = startFlueSpan(parent, {
24698
- name: "flue.compaction",
24699
- spanAttributes: { type: "task" /* TASK */ }
24700
- });
24701
- safeLog3(span, {
24702
- input,
24703
- metadata
24704
- });
24705
- this.compactionsByScope.set(scopeKey(event), {
24706
- input,
24707
- metadata,
24708
- operationState,
24709
- span,
24710
- startTime: getCurrentUnixTimestamp()
24389
+ name: `compaction:${event.reason ?? "unknown"}`,
24390
+ spanAttributes: { type: "task" /* TASK */ },
24391
+ startTime: eventTime(event.timestamp),
24392
+ event: {
24393
+ input,
24394
+ metadata
24395
+ }
24711
24396
  });
24397
+ this.logOperationInput(event.operationId, input);
24398
+ this.compactionsByKey.set(key, { metadata, span });
24712
24399
  }
24713
24400
  handleCompaction(event) {
24714
- const key = scopeKey(event);
24715
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24716
- if (!state) {
24717
- return;
24718
- }
24401
+ const key = compactionKey(event);
24402
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
24403
+ const metadata = {
24404
+ ...state.metadata,
24405
+ ...extractEventMetadata(event),
24406
+ ...event.usage ? { "flue.usage": event.usage } : {}
24407
+ };
24719
24408
  safeLog3(state.span, {
24720
- metadata: {
24721
- ...state.metadata,
24722
- ...extractEventMetadata(event),
24723
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24724
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24725
- },
24409
+ metadata,
24726
24410
  metrics: {
24727
- ...durationMsMetrics(event.durationMs),
24728
- ...metricsFromUsage(event.usage)
24411
+ ...durationMetrics2(event.durationMs),
24412
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
24413
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
24729
24414
  },
24730
24415
  output: {
24731
24416
  messagesAfter: event.messagesAfter,
24732
24417
  messagesBefore: event.messagesBefore
24733
24418
  }
24734
24419
  });
24735
- state.span.end();
24736
- this.deleteCompactionState(state);
24420
+ safeEnd(state.span, eventTime(event.timestamp));
24421
+ this.compactionsByKey.delete(key);
24737
24422
  }
24738
- findCompactionState(event) {
24739
- const operationState = this.operationStateForEvent(event);
24740
- for (const state of this.compactionsByScope.values()) {
24741
- if (operationState && state.operationState === operationState) {
24742
- return state;
24423
+ parentSpanForTurn(event) {
24424
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
24425
+ const compaction = this.compactionsByKey.get(compactionKey(event));
24426
+ if (compaction) {
24427
+ return compaction.span;
24743
24428
  }
24744
24429
  }
24745
- return void 0;
24430
+ return this.parentSpanForEvent(event);
24746
24431
  }
24747
- finishCompactionsForOperation(operationState) {
24748
- for (const state of [...this.compactionsByScope.values()]) {
24749
- if (state.operationState !== operationState) {
24750
- continue;
24432
+ parentSpanForEvent(event) {
24433
+ const turn = turnKey(event);
24434
+ if (turn) {
24435
+ const turnState = this.turnsByKey.get(turn);
24436
+ if (turnState) {
24437
+ return turnState.span;
24751
24438
  }
24752
- safeLog3(state.span, {
24753
- input: state.input,
24754
- metadata: state.metadata,
24755
- metrics: {
24756
- ...buildDurationMetrics3(state.startTime)
24757
- },
24758
- output: { completed: true }
24759
- });
24760
- state.span.end();
24761
- this.deleteCompactionState(state);
24762
24439
  }
24763
- }
24764
- deleteCompactionState(state) {
24765
- for (const [key, candidate] of this.compactionsByScope) {
24766
- if (candidate !== state) {
24767
- continue;
24440
+ if (event.taskId) {
24441
+ const task = this.tasksById.get(event.taskId);
24442
+ if (task) {
24443
+ return task.span;
24768
24444
  }
24769
- this.compactionsByScope.delete(key);
24770
- return;
24771
24445
  }
24772
- }
24773
- startSyntheticToolState(event, toolName) {
24774
- const parent = this.parentSpanForEvent(event);
24775
- const metadata = {
24776
- ...extractEventMetadata(event),
24777
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24778
- "flue.tool_name": toolName,
24779
- provider: "flue"
24780
- };
24781
- const span = startFlueSpan(parent, {
24782
- name: `tool: ${toolName}`,
24783
- spanAttributes: { type: "tool" /* TOOL */ }
24784
- });
24785
- safeLog3(span, { metadata });
24786
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
24787
- }
24788
- operationStateForEvent(event) {
24789
24446
  if (event.operationId) {
24790
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24447
+ const operation = this.operationsById.get(event.operationId);
24791
24448
  if (operation) {
24792
- return operation;
24449
+ return operation.span;
24793
24450
  }
24794
24451
  }
24795
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24452
+ if (event.runId) {
24453
+ return this.runsById.get(event.runId)?.span;
24454
+ }
24455
+ return void 0;
24796
24456
  }
24797
- parentSpanForEvent(event) {
24457
+ parentSpanForTool(event) {
24458
+ if (event.taskId) {
24459
+ const task = this.tasksById.get(event.taskId);
24460
+ if (task) {
24461
+ return task.span;
24462
+ }
24463
+ }
24798
24464
  if (event.operationId) {
24799
- const operation = this.operationStateForEvent(event);
24465
+ const operation = this.operationsById.get(event.operationId);
24800
24466
  if (operation) {
24801
24467
  return operation.span;
24802
24468
  }
24803
24469
  }
24804
- if (event.taskId) {
24805
- return this.tasksById.get(event.taskId)?.span;
24470
+ if (event.runId) {
24471
+ return this.runsById.get(event.runId)?.span;
24806
24472
  }
24807
- return this.operationStateForEvent(event)?.span;
24473
+ return void 0;
24808
24474
  }
24809
- promotePendingOperationForEvent(event) {
24810
- if (!event.operationId) {
24811
- return void 0;
24475
+ logOperationInput(operationId, input) {
24476
+ if (!operationId || input === void 0) {
24477
+ return;
24478
+ }
24479
+ const operation = this.operationsById.get(operationId);
24480
+ if (!operation || operation.loggedInput) {
24481
+ return;
24482
+ }
24483
+ safeLog3(operation.span, { input });
24484
+ operation.loggedInput = true;
24485
+ }
24486
+ startSyntheticOperation(event) {
24487
+ const metadata = {
24488
+ ...extractEventMetadata(event),
24489
+ "flue.operation": event.operationKind,
24490
+ provider: "flue"
24491
+ };
24492
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24493
+ name: `flue.${event.operationKind}`,
24494
+ spanAttributes: { type: "task" /* TASK */ },
24495
+ startTime: eventTime(event.timestamp),
24496
+ event: { metadata }
24497
+ });
24498
+ return { metadata, span };
24499
+ }
24500
+ startSyntheticTurn(event) {
24501
+ const metadata = {
24502
+ ...extractEventMetadata(event),
24503
+ ...event.api ? { "flue.api": event.api } : {},
24504
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24505
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24506
+ ...event.provider ? { "flue.provider": event.provider } : {},
24507
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
24508
+ };
24509
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24510
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24511
+ spanAttributes: { type: "llm" /* LLM */ },
24512
+ startTime: eventTime(event.timestamp),
24513
+ event: { metadata }
24514
+ });
24515
+ return { metadata, span };
24516
+ }
24517
+ startSyntheticTool(event) {
24518
+ const metadata = {
24519
+ ...extractEventMetadata(event),
24520
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24521
+ "flue.tool_call_id": event.toolCallId,
24522
+ provider: "flue"
24523
+ };
24524
+ const span = startFlueSpan(this.parentSpanForTool(event), {
24525
+ name: `tool:${event.toolName ?? "unknown"}`,
24526
+ spanAttributes: { type: "tool" /* TOOL */ },
24527
+ startTime: eventTime(event.timestamp),
24528
+ event: { metadata }
24529
+ });
24530
+ return { metadata, span };
24531
+ }
24532
+ startSyntheticCompaction(event) {
24533
+ const metadata = {
24534
+ ...extractEventMetadata(event),
24535
+ provider: "flue"
24536
+ };
24537
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24538
+ name: "compaction:unknown",
24539
+ spanAttributes: { type: "task" /* TASK */ },
24540
+ startTime: eventTime(event.timestamp),
24541
+ event: { metadata }
24542
+ });
24543
+ return { metadata, span };
24544
+ }
24545
+ finishPendingChildrenForOperation(event, operationOutput2) {
24546
+ const endTime = eventTime(event.timestamp);
24547
+ const usage = event.usage ?? usageFromOperationResult(event.result);
24548
+ const turnEntries = [...this.turnsByKey].filter(
24549
+ ([, state]) => stateMatchesOperation(state, event.operationId)
24550
+ );
24551
+ turnEntries.forEach(([key, state], index) => {
24552
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
24553
+ safeLog3(state.span, {
24554
+ metadata: state.metadata,
24555
+ metrics: metricsFromUsage(usage),
24556
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
24557
+ });
24558
+ safeEnd(state.span, endTime);
24559
+ this.turnsByKey.delete(key);
24560
+ });
24561
+ for (const [key, state] of this.toolsByKey) {
24562
+ if (!stateMatchesOperation(state, event.operationId)) {
24563
+ continue;
24564
+ }
24565
+ safeEnd(state.span, endTime);
24566
+ this.toolsByKey.delete(key);
24812
24567
  }
24813
- const scopePrefixes = operationScopePrefixes(event);
24814
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24815
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24568
+ for (const [key, state] of this.tasksById) {
24569
+ if (!stateMatchesOperation(state, event.operationId)) {
24816
24570
  continue;
24817
24571
  }
24818
- const state = candidateQueue.shift();
24819
- if (!state) {
24820
- return void 0;
24572
+ safeEnd(state.span, endTime);
24573
+ this.tasksById.delete(key);
24574
+ }
24575
+ for (const [key, state] of this.compactionsByKey) {
24576
+ if (!stateMatchesOperation(state, event.operationId)) {
24577
+ continue;
24821
24578
  }
24822
- state.operationId = event.operationId;
24823
- this.activeOperationsById.set(event.operationId, state);
24824
- addScopedOperation(this.activeOperationsByScope, event, state);
24825
- state.metadata = {
24826
- ...state.metadata,
24827
- ...extractEventMetadata(event),
24828
- "flue.operation_id": event.operationId
24829
- };
24830
- safeLog3(state.span, { metadata: state.metadata });
24831
- return state;
24579
+ safeLog3(state.span, {
24580
+ metadata: state.metadata,
24581
+ metrics: durationMetrics2(event.durationMs),
24582
+ output: { completed: true }
24583
+ });
24584
+ safeEnd(state.span, eventTime(event.timestamp));
24585
+ this.compactionsByKey.delete(key);
24832
24586
  }
24833
- return void 0;
24834
24587
  }
24835
- activeOperationForEventScope(event) {
24836
- for (const scope of operationScopeNames(event)) {
24837
- const operations = this.activeOperationsByScope.get(scope);
24838
- if (operations?.length) {
24839
- return operations[operations.length - 1];
24588
+ finishPendingSpansForRun(event) {
24589
+ const endTime = eventTime(event.timestamp);
24590
+ for (const [key, state] of this.toolsByKey) {
24591
+ if (!stateMatchesRun(state, event.runId)) {
24592
+ continue;
24840
24593
  }
24594
+ safeEnd(state.span, endTime);
24595
+ this.toolsByKey.delete(key);
24841
24596
  }
24842
- return void 0;
24843
- }
24844
- pendingOperationForEventScope(event) {
24845
- const scopePrefixes = operationScopePrefixes(event);
24846
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24847
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24597
+ for (const [key, state] of this.turnsByKey) {
24598
+ if (!stateMatchesRun(state, event.runId)) {
24848
24599
  continue;
24849
24600
  }
24850
- return candidateQueue[0];
24601
+ safeEnd(state.span, endTime);
24602
+ this.turnsByKey.delete(key);
24851
24603
  }
24852
- return void 0;
24853
- }
24854
- takePendingOperationForEvent(event) {
24855
- const key = operationKey(event.session, event.operationKind);
24856
- const queue2 = this.pendingOperationsByKey.get(key);
24857
- if (queue2?.length) {
24858
- return queue2.shift();
24604
+ for (const [key, state] of this.tasksById) {
24605
+ if (!stateMatchesRun(state, event.runId)) {
24606
+ continue;
24607
+ }
24608
+ safeEnd(state.span, endTime);
24609
+ this.tasksById.delete(key);
24859
24610
  }
24860
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24861
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24862
- return candidateQueue.shift();
24611
+ for (const [key, state] of this.compactionsByKey) {
24612
+ if (!stateMatchesRun(state, event.runId)) {
24613
+ continue;
24863
24614
  }
24615
+ safeLog3(state.span, {
24616
+ metadata: state.metadata,
24617
+ output: { completed: true }
24618
+ });
24619
+ safeEnd(state.span, endTime);
24620
+ this.compactionsByKey.delete(key);
24864
24621
  }
24865
- return void 0;
24866
- }
24867
- pendingOperationQueue(key) {
24868
- const existing = this.pendingOperationsByKey.get(key);
24869
- if (existing) {
24870
- return existing;
24622
+ for (const [key, state] of this.operationsById) {
24623
+ if (!stateMatchesRun(state, event.runId)) {
24624
+ continue;
24625
+ }
24626
+ safeLog3(state.span, {
24627
+ metadata: state.metadata,
24628
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
24629
+ });
24630
+ safeEnd(state.span, endTime);
24631
+ this.operationsById.delete(key);
24871
24632
  }
24872
- const queue2 = [];
24873
- this.pendingOperationsByKey.set(key, queue2);
24874
- return queue2;
24875
24633
  }
24876
24634
  };
24877
24635
  function isInstrumentedOperation(operation) {
24878
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24879
- }
24880
- function getSessionName(session) {
24881
- return typeof session?.name === "string" ? session.name : void 0;
24882
- }
24883
- function operationKey(sessionName, operation) {
24884
- return `${sessionName ?? "unknown"}::${operation}`;
24885
- }
24886
- function operationScopePrefixes(event) {
24887
- const scopes = /* @__PURE__ */ new Set();
24888
- for (const scope of operationScopeNames(event)) {
24889
- scopes.add(`${scope}::`);
24890
- }
24891
- return scopes;
24892
- }
24893
- function operationKeyMatchesScopes(key, scopes) {
24894
- for (const scope of scopes) {
24895
- if (key.startsWith(scope)) {
24896
- return true;
24897
- }
24898
- }
24899
- return false;
24636
+ return operation === "prompt" || operation === "skill" || operation === "compact";
24900
24637
  }
24901
- function operationScopeNames(event) {
24902
- const scopes = /* @__PURE__ */ new Set();
24903
- if (event.session) {
24904
- scopes.add(event.session);
24905
- }
24906
- if (event.parentSession) {
24907
- scopes.add(event.parentSession);
24908
- }
24909
- if (!scopes.size) {
24910
- scopes.add("unknown");
24911
- }
24912
- return scopes;
24913
- }
24914
- function addScopedOperation(operationsByScope, event, state) {
24915
- for (const scope of operationScopeNames(event)) {
24916
- addOperationToScope(operationsByScope, scope, state);
24917
- }
24918
- }
24919
- function addOperationToScope(operationsByScope, scope, state) {
24920
- const operations = operationsByScope.get(scope);
24921
- if (operations) {
24922
- if (!operations.includes(state)) {
24923
- operations.push(state);
24924
- }
24925
- } else {
24926
- operationsByScope.set(scope, [state]);
24927
- }
24928
- }
24929
- function removeScopedOperation(operationsByScope, state) {
24930
- for (const [scope, operations] of operationsByScope) {
24931
- const index = operations.indexOf(state);
24932
- if (index === -1) {
24933
- continue;
24934
- }
24935
- operations.splice(index, 1);
24936
- if (operations.length === 0) {
24937
- operationsByScope.delete(scope);
24938
- }
24939
- }
24940
- }
24941
- function removePendingOperation(pendingOperationsByKey, state) {
24942
- for (const [key, queue2] of pendingOperationsByKey) {
24943
- const index = queue2.indexOf(state);
24944
- if (index === -1) {
24945
- continue;
24946
- }
24947
- queue2.splice(index, 1);
24948
- if (queue2.length === 0) {
24949
- pendingOperationsByKey.delete(key);
24950
- }
24951
- return;
24952
- }
24953
- }
24954
- function extractSessionMetadata(session) {
24955
- const sessionName = getSessionName(session);
24956
- return sessionName ? { "flue.session": sessionName } : {};
24957
- }
24958
- function extractEventMetadata(event) {
24638
+ function extractEventMetadata(event, ctx) {
24959
24639
  return {
24960
24640
  ...event.runId ? { "flue.run_id": event.runId } : {},
24641
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
24642
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
24961
24643
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
24962
24644
  ...event.session ? { "flue.session": event.session } : {},
24963
24645
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
24964
24646
  ...event.harness ? { "flue.harness": event.harness } : {},
24965
24647
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
24966
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24648
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
24649
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
24650
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
24651
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
24967
24652
  };
24968
24653
  }
24969
- function extractOperationInput(operation, args) {
24970
- switch (operation) {
24971
- case "prompt":
24972
- case "task":
24973
- return args[0];
24974
- case "skill":
24975
- return {
24976
- args: getOptionObject(args[1])?.args,
24977
- name: args[0]
24978
- };
24979
- case "compact":
24980
- return void 0;
24654
+ function extractPayloadMetadata(payload) {
24655
+ if (!isObjectLike(payload)) {
24656
+ return {};
24981
24657
  }
24658
+ const metadata = Reflect.get(payload, "metadata");
24659
+ if (!isObjectLike(metadata)) {
24660
+ return {};
24661
+ }
24662
+ return Object.fromEntries(Object.entries(metadata));
24982
24663
  }
24983
- function extractOperationInputMetadata(operation, args) {
24984
- const options = getOptionObject(args[1]);
24985
- return {
24986
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
24987
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
24988
- ...options?.role ? { "flue.role": options.role } : {},
24989
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
24990
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
24991
- ...Array.isArray(options?.tools) ? {
24992
- "flue.tools_count": options.tools.length,
24993
- tools: summarizeTools(options.tools)
24994
- } : {},
24995
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
24996
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
24997
- };
24998
- }
24999
- function getOptionObject(value) {
25000
- return isObject(value) ? value : void 0;
25001
- }
25002
- function summarizeTools(tools) {
25003
- return tools.flatMap((tool) => {
25004
- if (!isObject(tool)) {
25005
- return [];
25006
- }
25007
- const name = typeof tool.name === "string" ? tool.name : void 0;
25008
- if (!name) {
25009
- return [];
25010
- }
25011
- return [
25012
- {
25013
- function: {
25014
- description: typeof tool.description === "string" ? tool.description : void 0,
25015
- name,
25016
- parameters: tool.parameters
25017
- },
25018
- type: "function"
25019
- }
25020
- ];
25021
- });
24664
+ function operationOutput(event) {
24665
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
24666
+ return llmResultFromOperationResult(event.result);
24667
+ }
24668
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
25022
24669
  }
25023
- function extractPromptResponseMetadata(result) {
25024
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
25025
- return modelId ? {
25026
- model: modelId,
25027
- "flue.model": modelId
25028
- } : {};
24670
+ function llmResultFromOperationResult(result) {
24671
+ if (!isObjectLike(result)) {
24672
+ return result;
24673
+ }
24674
+ const text = Reflect.get(result, "text");
24675
+ return text === void 0 ? result : text;
25029
24676
  }
25030
- function extractOperationOutput(result) {
25031
- if (!result) {
24677
+ function usageFromOperationResult(result) {
24678
+ if (!isObjectLike(result)) {
25032
24679
  return void 0;
25033
24680
  }
25034
- if ("data" in result) {
25035
- return result.data;
25036
- }
25037
- if ("text" in result) {
25038
- return result.text;
25039
- }
25040
- return result;
24681
+ return Reflect.get(result, "usage");
25041
24682
  }
25042
24683
  function metricsFromUsage(usage) {
24684
+ if (!isObjectLike(usage)) {
24685
+ return {};
24686
+ }
24687
+ const cacheRead = Reflect.get(usage, "cacheRead");
24688
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
24689
+ const cost = Reflect.get(usage, "cost");
24690
+ const input = Reflect.get(usage, "input");
24691
+ const output = Reflect.get(usage, "output");
24692
+ const totalTokens = Reflect.get(usage, "totalTokens");
24693
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
25043
24694
  return {
25044
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
25045
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
25046
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
25047
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
25048
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
25049
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
25050
- };
25051
- }
25052
- function buildDurationMetrics3(startTime) {
25053
- return {
25054
- duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
24695
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
24696
+ ...typeof output === "number" ? { completion_tokens: output } : {},
24697
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
24698
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
24699
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
24700
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
25055
24701
  };
25056
24702
  }
25057
- function durationMsMetrics(durationMs) {
24703
+ function durationMetrics2(durationMs) {
25058
24704
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
25059
24705
  }
25060
- function scopeKey(event) {
25061
- if (event.operationId) {
25062
- return `operation:${event.operationId}`;
25063
- }
25064
- if (event.taskId) {
25065
- return `task:${event.taskId}`;
25066
- }
25067
- if (event.session) {
25068
- return `session:${event.session}`;
24706
+ function eventTime(value) {
24707
+ if (typeof value !== "string") {
24708
+ return void 0;
25069
24709
  }
25070
- return "flue:unknown";
24710
+ const timestamp = Date.parse(value);
24711
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
24712
+ }
24713
+ function turnKey(event) {
24714
+ return event.turnId;
25071
24715
  }
25072
24716
  function toolKey(event) {
25073
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24717
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
25074
24718
  }
25075
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24719
+ function compactionKey(event) {
25076
24720
  return [
25077
- {
25078
- finish_reason: finishReason ?? "stop",
25079
- index: 0,
25080
- message: {
25081
- content: text,
25082
- ...reasoning ? { reasoning } : {},
25083
- role: "assistant",
25084
- ...toolCalls?.length ? {
25085
- tool_calls: toolCalls.map((toolCall) => ({
25086
- function: {
25087
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
25088
- name: toolCall.toolName ?? "unknown"
25089
- },
25090
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
25091
- type: "function"
25092
- }))
25093
- } : {}
25094
- }
25095
- }
25096
- ];
24721
+ event.instanceId ?? "",
24722
+ event.runId ?? "",
24723
+ event.session ?? "",
24724
+ event.operationId ?? "",
24725
+ event.taskId ?? ""
24726
+ ].join(":");
24727
+ }
24728
+ function stateMatchesOperation(state, operationId) {
24729
+ return state.metadata["flue.operation_id"] === operationId;
24730
+ }
24731
+ function stateMatchesRun(state, runId) {
24732
+ return state.metadata["flue.run_id"] === runId;
25097
24733
  }
25098
24734
  function startFlueSpan(parent, args) {
25099
24735
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -25105,6 +24741,13 @@ function safeLog3(span, event) {
25105
24741
  logInstrumentationError3("Flue span log", error);
25106
24742
  }
25107
24743
  }
24744
+ function safeEnd(span, endTime) {
24745
+ try {
24746
+ span.end(endTime === void 0 ? void 0 : { endTime });
24747
+ } catch (error) {
24748
+ logInstrumentationError3("Flue span end", error);
24749
+ }
24750
+ }
25108
24751
  function errorToString(error) {
25109
24752
  if (error instanceof Error) {
25110
24753
  return error.message;
@@ -25598,7 +25241,7 @@ var BraintrustPlugin = class extends BasePlugin {
25598
25241
  this.config = config;
25599
25242
  }
25600
25243
  onEnable() {
25601
- const integrations = this.config.integrations || {};
25244
+ const integrations = this.config.integrations ?? {};
25602
25245
  if (integrations.openai !== false) {
25603
25246
  this.openaiPlugin = new OpenAIPlugin();
25604
25247
  this.openaiPlugin.enable();
@@ -25663,7 +25306,7 @@ var BraintrustPlugin = class extends BasePlugin {
25663
25306
  this.genkitPlugin = new GenkitPlugin();
25664
25307
  this.genkitPlugin.enable();
25665
25308
  }
25666
- if (getIntegrationConfig(integrations, "gitHubCopilot") !== false) {
25309
+ if (integrations.gitHubCopilot !== false) {
25667
25310
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25668
25311
  this.gitHubCopilotPlugin.enable();
25669
25312
  }
@@ -25776,6 +25419,7 @@ var envIntegrationAliases = {
25776
25419
  cursorsdk: "cursorSDK",
25777
25420
  flue: "flue",
25778
25421
  "flue-runtime": "flue",
25422
+ mastra: "mastra",
25779
25423
  "openai-agents": "openAIAgents",
25780
25424
  openaiagents: "openAIAgents",
25781
25425
  "openai-agents-core": "openAIAgents",
@@ -25818,6 +25462,7 @@ function getDefaultInstrumentationIntegrations() {
25818
25462
  cursor: true,
25819
25463
  cursorSDK: true,
25820
25464
  flue: true,
25465
+ mastra: true,
25821
25466
  openAIAgents: true,
25822
25467
  openrouter: true,
25823
25468
  openrouterAgent: true,
@@ -26075,6 +25720,7 @@ __export(exports_exports, {
26075
25720
  BaseExperiment: () => BaseExperiment,
26076
25721
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
26077
25722
  BraintrustMiddleware: () => BraintrustMiddleware,
25723
+ BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
26078
25724
  BraintrustState: () => BraintrustState,
26079
25725
  BraintrustStream: () => BraintrustStream,
26080
25726
  CachedSpanFetcher: () => CachedSpanFetcher,
@@ -26121,6 +25767,7 @@ __export(exports_exports, {
26121
25767
  _internalIso: () => isomorph_default,
26122
25768
  _internalSetInitialState: () => _internalSetInitialState,
26123
25769
  addAzureBlobHeaders: () => addAzureBlobHeaders,
25770
+ braintrustFlueObserver: () => braintrustFlueObserver,
26124
25771
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
26125
25772
  buildLocalSummary: () => buildLocalSummary,
26126
25773
  configureInstrumentation: () => configureInstrumentation,
@@ -26200,8 +25847,6 @@ __export(exports_exports, {
26200
25847
  wrapCohere: () => wrapCohere,
26201
25848
  wrapCopilotClient: () => wrapCopilotClient,
26202
25849
  wrapCursorSDK: () => wrapCursorSDK,
26203
- wrapFlueContext: () => wrapFlueContext,
26204
- wrapFlueSession: () => wrapFlueSession,
26205
25850
  wrapGenkit: () => wrapGenkit,
26206
25851
  wrapGoogleADK: () => wrapGoogleADK,
26207
25852
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -27691,6 +27336,196 @@ function toolRunnerProxy(toolRunner, anthropic, channel2) {
27691
27336
  }
27692
27337
 
27693
27338
  // src/wrappers/mastra.ts
27339
+ var MASTRA_BRAINTRUST_EXPORTER_NAME = "braintrust";
27340
+ var SPAN_TYPE_MAP = {
27341
+ agent_run: "task" /* TASK */,
27342
+ model_generation: "llm" /* LLM */,
27343
+ model_step: "llm" /* LLM */,
27344
+ model_chunk: "llm" /* LLM */,
27345
+ tool_call: "tool" /* TOOL */,
27346
+ mcp_tool_call: "tool" /* TOOL */,
27347
+ workflow_run: "task" /* TASK */,
27348
+ workflow_step: "function" /* FUNCTION */,
27349
+ workflow_conditional: "function" /* FUNCTION */,
27350
+ workflow_conditional_eval: "function" /* FUNCTION */,
27351
+ workflow_parallel: "function" /* FUNCTION */,
27352
+ workflow_loop: "function" /* FUNCTION */,
27353
+ workflow_sleep: "function" /* FUNCTION */,
27354
+ workflow_wait_event: "function" /* FUNCTION */,
27355
+ memory_operation: "function" /* FUNCTION */,
27356
+ workspace_action: "function" /* FUNCTION */,
27357
+ rag_ingestion: "task" /* TASK */,
27358
+ rag_embedding: "llm" /* LLM */,
27359
+ rag_vector_operation: "function" /* FUNCTION */,
27360
+ rag_action: "function" /* FUNCTION */,
27361
+ graph_action: "function" /* FUNCTION */,
27362
+ scorer_run: "score" /* SCORE */,
27363
+ scorer_step: "score" /* SCORE */,
27364
+ processor_run: "function" /* FUNCTION */,
27365
+ generic: "function" /* FUNCTION */
27366
+ };
27367
+ function spanTypeFor(mastraType) {
27368
+ return SPAN_TYPE_MAP[mastraType] ?? "function" /* FUNCTION */;
27369
+ }
27370
+ function epochSeconds(value) {
27371
+ if (value === void 0) return void 0;
27372
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
27373
+ return Number.isFinite(ms) ? ms / 1e3 : void 0;
27374
+ }
27375
+ function modelMetrics(attributes) {
27376
+ if (!isObject(attributes)) return void 0;
27377
+ const usage = isObject(attributes.usage) ? attributes.usage : void 0;
27378
+ if (!usage) return void 0;
27379
+ const out = {};
27380
+ if (typeof usage.inputTokens === "number")
27381
+ out.prompt_tokens = usage.inputTokens;
27382
+ if (typeof usage.outputTokens === "number")
27383
+ out.completion_tokens = usage.outputTokens;
27384
+ if (typeof usage.inputTokens === "number" && typeof usage.outputTokens === "number") {
27385
+ out.tokens = usage.inputTokens + usage.outputTokens;
27386
+ }
27387
+ const inputDetails = isObject(usage.inputDetails) ? usage.inputDetails : void 0;
27388
+ const outputDetails = isObject(usage.outputDetails) ? usage.outputDetails : void 0;
27389
+ if (inputDetails && typeof inputDetails.cacheRead === "number") {
27390
+ out.prompt_cached_tokens = inputDetails.cacheRead;
27391
+ }
27392
+ if (inputDetails && typeof inputDetails.cacheWrite === "number") {
27393
+ out.prompt_cache_creation_tokens = inputDetails.cacheWrite;
27394
+ }
27395
+ if (outputDetails && typeof outputDetails.reasoning === "number") {
27396
+ out.completion_reasoning_tokens = outputDetails.reasoning;
27397
+ }
27398
+ return Object.keys(out).length > 0 ? out : void 0;
27399
+ }
27400
+ function buildMetadata(exported) {
27401
+ const out = {};
27402
+ if (exported.entityId !== void 0) out.entity_id = exported.entityId;
27403
+ if (exported.entityName !== void 0) out.entity_name = exported.entityName;
27404
+ if (exported.entityType !== void 0) out.entity_type = exported.entityType;
27405
+ if (exported.metadata && isObject(exported.metadata)) {
27406
+ Object.assign(out, exported.metadata);
27407
+ }
27408
+ if (exported.attributes && isObject(exported.attributes)) {
27409
+ for (const [key, value] of Object.entries(exported.attributes)) {
27410
+ if (key === "usage") continue;
27411
+ if (value !== void 0) out[key] = value;
27412
+ }
27413
+ }
27414
+ if (exported.tags && exported.tags.length > 0) {
27415
+ out.tags = exported.tags;
27416
+ }
27417
+ if (exported.requestContext && isObject(exported.requestContext)) {
27418
+ out.request_context = exported.requestContext;
27419
+ }
27420
+ return out;
27421
+ }
27422
+ var BraintrustObservabilityExporter = class {
27423
+ name = MASTRA_BRAINTRUST_EXPORTER_NAME;
27424
+ spans = /* @__PURE__ */ new Map();
27425
+ // Captured at the first SPAN_STARTED event. Mastra's observability bus may
27426
+ // dispatch later events outside the user's AsyncLocalStorage context, where
27427
+ // `currentSpan()` returns NOOP_SPAN — which would make our `startSpan()`
27428
+ // calls go to a no-op logger and silently drop. Anchoring on the parent
27429
+ // we observe while still in-context keeps the whole Mastra subtree under
27430
+ // the user's traced scenario.
27431
+ capturedParent;
27432
+ constructor() {
27433
+ _internalSetInitialState();
27434
+ }
27435
+ async exportTracingEvent(event) {
27436
+ const exported = event.exportedSpan;
27437
+ if (exported.isInternal === true) return;
27438
+ try {
27439
+ switch (event.type) {
27440
+ case "span_started":
27441
+ this.onStart(exported);
27442
+ break;
27443
+ case "span_updated":
27444
+ this.onUpdate(exported);
27445
+ break;
27446
+ case "span_ended":
27447
+ this.onEnd(exported);
27448
+ break;
27449
+ }
27450
+ } catch (err) {
27451
+ logExporterError(err);
27452
+ }
27453
+ }
27454
+ async flush() {
27455
+ const state = _internalGetGlobalState();
27456
+ if (state) {
27457
+ await state.bgLogger().flush();
27458
+ }
27459
+ }
27460
+ async shutdown() {
27461
+ await this.flush();
27462
+ this.spans.clear();
27463
+ }
27464
+ onStart(exported) {
27465
+ if (this.spans.has(exported.id)) return;
27466
+ const args = {
27467
+ name: exported.name,
27468
+ spanAttributes: { type: spanTypeFor(exported.type) },
27469
+ startTime: epochSeconds(exported.startTime)
27470
+ };
27471
+ const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
27472
+ if (!this.capturedParent) {
27473
+ const probe = currentSpan();
27474
+ if (probe && probe.spanId) {
27475
+ this.capturedParent = probe;
27476
+ }
27477
+ }
27478
+ const span = parentRecord ? parentRecord.span.startSpan(args) : this.capturedParent ? this.capturedParent.startSpan(args) : startSpan(args);
27479
+ const record = { span, hasLoggedInput: false };
27480
+ this.logPayload(record, exported);
27481
+ this.spans.set(exported.id, record);
27482
+ if (exported.isEvent === true) {
27483
+ span.end({ endTime: args.startTime });
27484
+ this.spans.delete(exported.id);
27485
+ }
27486
+ }
27487
+ onUpdate(exported) {
27488
+ const record = this.spans.get(exported.id);
27489
+ if (!record) return;
27490
+ this.logPayload(record, exported);
27491
+ }
27492
+ onEnd(exported) {
27493
+ const record = this.spans.get(exported.id);
27494
+ if (!record) return;
27495
+ this.logPayload(record, exported);
27496
+ if (exported.errorInfo) {
27497
+ record.span.log({
27498
+ error: exported.errorInfo.message || exported.errorInfo.name || "Unknown Mastra error"
27499
+ });
27500
+ }
27501
+ record.span.end({ endTime: epochSeconds(exported.endTime) });
27502
+ this.spans.delete(exported.id);
27503
+ }
27504
+ logPayload(record, exported) {
27505
+ const event = {};
27506
+ if (exported.input !== void 0) {
27507
+ event.input = exported.input;
27508
+ record.hasLoggedInput = true;
27509
+ }
27510
+ if (exported.output !== void 0) {
27511
+ event.output = exported.output;
27512
+ }
27513
+ const metadata = buildMetadata(exported);
27514
+ if (Object.keys(metadata).length > 0) {
27515
+ event.metadata = metadata;
27516
+ }
27517
+ const metrics = modelMetrics(exported.attributes);
27518
+ if (metrics) {
27519
+ event.metrics = metrics;
27520
+ }
27521
+ if (Object.keys(event).length > 0) {
27522
+ record.span.log(event);
27523
+ }
27524
+ }
27525
+ };
27526
+ function logExporterError(err) {
27527
+ debugLogger.warn("Mastra exporter failure:", err);
27528
+ }
27694
27529
  function wrapMastraAgent(agent, _options) {
27695
27530
  return agent;
27696
27531
  }
@@ -33189,6 +33024,7 @@ export {
33189
33024
  BaseExperiment,
33190
33025
  BraintrustLangChainCallbackHandler,
33191
33026
  BraintrustMiddleware,
33027
+ BraintrustObservabilityExporter,
33192
33028
  BraintrustState,
33193
33029
  BraintrustStream,
33194
33030
  CachedSpanFetcher,
@@ -33235,6 +33071,7 @@ export {
33235
33071
  isomorph_default as _internalIso,
33236
33072
  _internalSetInitialState,
33237
33073
  addAzureBlobHeaders,
33074
+ braintrustFlueObserver,
33238
33075
  braintrustStreamChunkSchema,
33239
33076
  buildLocalSummary,
33240
33077
  configureInstrumentation,
@@ -33315,8 +33152,6 @@ export {
33315
33152
  wrapCohere,
33316
33153
  wrapCopilotClient,
33317
33154
  wrapCursorSDK,
33318
- wrapFlueContext,
33319
- wrapFlueSession,
33320
33155
  wrapGenkit,
33321
33156
  wrapGoogleADK,
33322
33157
  wrapGoogleGenAI,