braintrust 3.14.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 (42) hide show
  1. package/dev/dist/index.js +616 -1026
  2. package/dev/dist/index.mjs +577 -987
  3. package/dist/apply-auto-instrumentation.js +176 -186
  4. package/dist/apply-auto-instrumentation.mjs +6 -16
  5. package/dist/auto-instrumentations/bundler/esbuild.cjs +5 -39
  6. package/dist/auto-instrumentations/bundler/esbuild.mjs +1 -1
  7. package/dist/auto-instrumentations/bundler/next.cjs +5 -39
  8. package/dist/auto-instrumentations/bundler/next.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/rollup.cjs +5 -39
  10. package/dist/auto-instrumentations/bundler/rollup.mjs +1 -1
  11. package/dist/auto-instrumentations/bundler/vite.cjs +5 -39
  12. package/dist/auto-instrumentations/bundler/vite.mjs +1 -1
  13. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +5 -39
  14. package/dist/auto-instrumentations/bundler/webpack.cjs +5 -39
  15. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  16. package/dist/auto-instrumentations/{chunk-OTUQ7KH5.mjs → chunk-CNQ7BUKN.mjs} +1 -1
  17. package/dist/auto-instrumentations/{chunk-XKAAVWT6.mjs → chunk-VXJONZVX.mjs} +5 -39
  18. package/dist/auto-instrumentations/hook.mjs +5 -39
  19. package/dist/browser.d.mts +13 -17
  20. package/dist/browser.d.ts +13 -17
  21. package/dist/browser.js +581 -1015
  22. package/dist/browser.mjs +581 -1015
  23. package/dist/{chunk-NU2GSPHX.mjs → chunk-O4ZIWXO3.mjs} +0 -24
  24. package/dist/{chunk-NKD77KGB.js → chunk-VMBQETG3.js} +0 -24
  25. package/dist/cli.js +578 -988
  26. package/dist/edge-light.d.mts +1 -1
  27. package/dist/edge-light.d.ts +1 -1
  28. package/dist/edge-light.js +581 -1015
  29. package/dist/edge-light.mjs +581 -1015
  30. package/dist/index.d.mts +13 -17
  31. package/dist/index.d.ts +13 -17
  32. package/dist/index.js +967 -1377
  33. package/dist/index.mjs +582 -992
  34. package/dist/instrumentation/index.d.mts +11 -1
  35. package/dist/instrumentation/index.d.ts +11 -1
  36. package/dist/instrumentation/index.js +611 -1015
  37. package/dist/instrumentation/index.mjs +610 -1015
  38. package/dist/workerd.d.mts +1 -1
  39. package/dist/workerd.d.ts +1 -1
  40. package/dist/workerd.js +581 -1015
  41. package/dist/workerd.mjs +581 -1015
  42. package/package.json +1 -1
package/dist/browser.mjs CHANGED
@@ -23919,608 +23919,210 @@ var flueChannels = defineChannels("@flue/runtime", {
23919
23919
  createContext: channel({
23920
23920
  channelName: "createFlueContext",
23921
23921
  kind: "sync-stream"
23922
- }),
23923
- openSession: channel({
23924
- channelName: "Harness.openSession",
23925
- kind: "async"
23926
- }),
23927
- contextEvent: channel({
23928
- channelName: "context.event",
23929
- kind: "sync-stream"
23930
- }),
23931
- prompt: channel({
23932
- channelName: "session.prompt",
23933
- kind: "async"
23934
- }),
23935
- skill: channel({
23936
- channelName: "session.skill",
23937
- kind: "async"
23938
- }),
23939
- task: channel({
23940
- channelName: "session.task",
23941
- kind: "async"
23942
- }),
23943
- compact: channel({
23944
- channelName: "session.compact",
23945
- kind: "async"
23946
23922
  })
23947
23923
  });
23948
23924
 
23949
- // src/wrappers/flue.ts
23950
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23951
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23952
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23953
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23954
- "braintrust.flue.subscribed-context-events"
23955
- );
23956
- function wrapFlueContext(ctx) {
23957
- if (!isPlausibleFlueContext(ctx)) {
23958
- console.warn("Unsupported Flue context. Not wrapping.");
23959
- 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());
23960
23934
  }
23961
- const context = ctx;
23962
- subscribeFlueContextEvents(context, { captureTurnSpans: true });
23963
- return patchFlueContextInPlace(context);
23964
- }
23965
- function patchFlueContextInPlace(ctx) {
23966
- const context = ctx;
23967
- if (context[WRAPPED_FLUE_CONTEXT]) {
23968
- return ctx;
23935
+ onDisable() {
23936
+ for (const unsubscribe of this.unsubscribers) {
23937
+ unsubscribe();
23938
+ }
23939
+ this.unsubscribers = [];
23969
23940
  }
23970
- const originalInit = context.init.bind(context);
23971
- try {
23972
- Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23973
- configurable: false,
23974
- enumerable: false,
23975
- value: true
23976
- });
23977
- Object.defineProperty(context, "init", {
23978
- configurable: true,
23979
- value: async function wrappedFlueInit(options) {
23980
- const harness = await originalInit(options);
23981
- return wrapFlueHarness(harness);
23982
- },
23983
- writable: true
23984
- });
23985
- } 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;
23986
23955
  }
23987
- return ctx;
23956
+ let released = false;
23957
+ return () => {
23958
+ if (released) {
23959
+ return;
23960
+ }
23961
+ released = true;
23962
+ releaseAutoState(state);
23963
+ };
23988
23964
  }
23989
- function wrapFlueSession(session) {
23990
- if (!isPlausibleFlueSession(session)) {
23991
- console.warn("Unsupported Flue session. Not wrapping.");
23992
- return session;
23965
+ function getAutoState() {
23966
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
23967
+ if (isAutoState(existing)) {
23968
+ return existing;
23993
23969
  }
23994
- 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;
23995
23976
  }
23996
- function subscribeFlueContextEvents(ctx, options = {}) {
23997
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23998
- return void 0;
23999
- }
24000
- const context = ctx;
24001
- const captureTurnSpans = options.captureTurnSpans ?? true;
24002
- const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
24003
- if (existingSubscription) {
24004
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
24005
- return void 0;
24006
- }
24007
- try {
24008
- existingSubscription.unsubscribe();
24009
- } catch {
24010
- }
24011
- }
24012
- try {
24013
- const unsubscribe = ctx.subscribeEvent((event) => {
24014
- flueChannels.contextEvent.traceSync(() => void 0, {
24015
- arguments: [event],
24016
- captureTurnSpans,
24017
- context: ctx
24018
- });
24019
- });
24020
- if (existingSubscription) {
24021
- existingSubscription.captureTurnSpans = captureTurnSpans;
24022
- existingSubscription.unsubscribe = unsubscribe;
24023
- } else {
24024
- Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
24025
- configurable: false,
24026
- enumerable: false,
24027
- value: {
24028
- captureTurnSpans,
24029
- unsubscribe
24030
- }
24031
- });
24032
- }
24033
- return unsubscribe;
24034
- } catch {
24035
- return void 0;
23977
+ function getObserveBridge() {
23978
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
23979
+ if (isFlueObserveBridge(existing)) {
23980
+ return existing;
24036
23981
  }
23982
+ const bridge = new FlueObserveBridge();
23983
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
23984
+ return bridge;
24037
23985
  }
24038
- function wrapFlueHarness(harness) {
24039
- if (!isPlausibleFlueHarness(harness)) {
24040
- return harness;
24041
- }
24042
- const target = harness;
24043
- if (target[WRAPPED_FLUE_HARNESS]) {
24044
- return harness;
24045
- }
24046
- const originalSession = target.session.bind(target);
24047
- try {
24048
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
24049
- configurable: false,
24050
- enumerable: false,
24051
- value: true
24052
- });
24053
- Object.defineProperty(target, "session", {
24054
- configurable: true,
24055
- value: async function wrappedFlueHarnessSession(name, options) {
24056
- const session = await originalSession(name, options);
24057
- return patchFlueSessionInPlace(session);
24058
- },
24059
- writable: true
24060
- });
24061
- const sessions = target.sessions;
24062
- if (sessions && typeof sessions === "object") {
24063
- patchFlueSessionFactory(sessions, "get");
24064
- patchFlueSessionFactory(sessions, "create");
24065
- }
24066
- } catch {
24067
- }
24068
- return harness;
23986
+ function isFlueObserveBridge(value) {
23987
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
24069
23988
  }
24070
- function patchFlueSessionInPlace(session) {
24071
- if (session[WRAPPED_FLUE_SESSION]) {
24072
- return session;
24073
- }
24074
- try {
24075
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
24076
- configurable: false,
24077
- enumerable: false,
24078
- value: true
24079
- });
24080
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
24081
- patchCallHandleMethod(session, "skill", flueChannels.skill);
24082
- patchCallHandleMethod(session, "task", flueChannels.task);
24083
- patchCompact(session);
24084
- } catch {
24085
- }
24086
- return session;
23989
+ function isAutoState(value) {
23990
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
24087
23991
  }
24088
- function patchFlueSessionFactory(sessions, method) {
24089
- const original = sessions[method];
24090
- if (typeof original !== "function") {
23992
+ function releaseAutoState(state) {
23993
+ state.refCount -= 1;
23994
+ if (state.refCount > 0) {
24091
23995
  return;
24092
23996
  }
24093
- const bound = original.bind(sessions);
24094
- Object.defineProperty(sessions, method, {
24095
- configurable: true,
24096
- value: async function wrappedFlueSessionFactory(name, options) {
24097
- const session = await bound(name, options);
24098
- return patchFlueSessionInPlace(session);
24099
- },
24100
- writable: true
24101
- });
24102
- }
24103
- function patchCallHandleMethod(session, method, channel2) {
24104
- const original = session[method];
24105
- if (typeof original !== "function") {
24106
- 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);
24107
24003
  }
24108
- const bound = original.bind(session);
24109
- Object.defineProperty(session, method, {
24110
- configurable: true,
24111
- value(input, options) {
24112
- const args = [input, options];
24113
- const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
24114
- context: {
24115
- arguments: args,
24116
- operation: method,
24117
- session
24118
- },
24119
- run: () => bound(input, options)
24120
- });
24121
- return preserveCallHandle(originalResult, traced2);
24122
- },
24123
- writable: true
24124
- });
24125
24004
  }
24126
- function patchCompact(session) {
24127
- const original = session.compact;
24128
- if (typeof original !== "function") {
24005
+ function subscribeToFlueContext(value, state) {
24006
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
24129
24007
  return;
24130
24008
  }
24131
- const bound = original.bind(session);
24132
- Object.defineProperty(session, "compact", {
24133
- configurable: true,
24134
- value() {
24135
- const context = {
24136
- arguments: [],
24137
- operation: "compact",
24138
- session
24139
- };
24140
- return flueChannels.compact.tracePromise(() => bound(), context);
24141
- },
24142
- writable: true
24143
- });
24144
- }
24145
- function traceFlueOperation(channel2, args) {
24146
- const tracingChannel2 = channel2.tracingChannel();
24147
- const context = args.context;
24148
- let originalResult;
24149
- let traced2;
24150
- 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;
24151
24017
  try {
24152
- originalResult = args.run();
24153
- tracingChannel2.end?.publish(context);
24018
+ unsubscribe?.();
24154
24019
  } catch (error) {
24155
- context.error = normalizeError3(error);
24156
- tracingChannel2.error?.publish(context);
24157
- tracingChannel2.end?.publish(context);
24158
- throw error;
24020
+ logInstrumentationError3("Flue context unsubscribe", error);
24159
24021
  }
24160
- traced2 = Promise.resolve(originalResult).then(
24161
- (result) => {
24162
- context.result = result;
24163
- tracingChannel2.asyncStart?.publish(context);
24164
- tracingChannel2.asyncEnd?.publish(context);
24165
- return result;
24166
- },
24167
- (error) => {
24168
- context.error = normalizeError3(error);
24169
- tracingChannel2.error?.publish(context);
24170
- tracingChannel2.asyncStart?.publish(context);
24171
- tracingChannel2.asyncEnd?.publish(context);
24172
- throw error;
24173
- }
24174
- );
24175
24022
  };
24176
- if (tracingChannel2.start?.runStores) {
24177
- tracingChannel2.start.runStores(context, run);
24178
- } else {
24179
- tracingChannel2.start?.publish(context);
24180
- 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);
24181
24037
  }
24182
- return { originalResult, traced: traced2 };
24183
24038
  }
24184
- function normalizeError3(error) {
24185
- return error instanceof Error ? error : new Error(String(error));
24186
- }
24187
- function preserveCallHandle(originalHandle, traced2) {
24188
- if (!isFlueCallHandle(originalHandle)) {
24189
- return traced2;
24039
+ function isAutoContextTerminalEvent(event, ctx) {
24040
+ if (!isObjectLike(event)) {
24041
+ return false;
24190
24042
  }
24191
- const handle = originalHandle;
24192
- const wrapped = {
24193
- get signal() {
24194
- return handle.signal;
24195
- },
24196
- abort(reason) {
24197
- return handle.abort(reason);
24198
- },
24199
- then(onfulfilled, onrejected) {
24200
- return traced2.then(onfulfilled, onrejected);
24201
- }
24202
- };
24203
- 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";
24204
24051
  }
24205
- function isPlausibleFlueContext(value) {
24206
- return !!value && typeof value === "object" && typeof value.init === "function";
24052
+ function isObservableFlueContext(value) {
24053
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
24207
24054
  }
24208
- function isPlausibleFlueHarness(value) {
24209
- 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";
24210
24058
  }
24211
- function isPlausibleFlueSession(value) {
24212
- 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
+ };
24213
24069
  }
24214
- function isFlueCallHandle(value) {
24215
- 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);
24216
24072
  }
24217
-
24218
- // src/instrumentation/plugins/flue-plugin.ts
24219
- var FluePlugin = class extends BasePlugin {
24220
- activeOperationsById = /* @__PURE__ */ new Map();
24221
- activeOperationsByScope = /* @__PURE__ */ new Map();
24222
- compactionsByScope = /* @__PURE__ */ new Map();
24223
- 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();
24224
24078
  tasksById = /* @__PURE__ */ new Map();
24225
- toolsById = /* @__PURE__ */ new Map();
24226
- turnsByScope = /* @__PURE__ */ new Map();
24227
- onEnable() {
24228
- this.subscribeToContextCreation();
24229
- this.subscribeToSessionCreation();
24230
- this.subscribeToContextEvents();
24231
- this.subscribeToSessionOperations();
24232
- }
24233
- onDisable() {
24234
- for (const unsubscribe of this.unsubscribers) {
24235
- unsubscribe();
24236
- }
24237
- this.unsubscribers = [];
24238
- this.activeOperationsById.clear();
24239
- this.activeOperationsByScope.clear();
24240
- this.compactionsByScope.clear();
24241
- this.pendingOperationsByKey.clear();
24242
- this.tasksById.clear();
24243
- this.toolsById.clear();
24244
- this.turnsByScope.clear();
24245
- }
24246
- subscribeToContextCreation() {
24247
- const channel2 = flueChannels.createContext.tracingChannel();
24248
- const handlers = {
24249
- end: (event) => {
24250
- const ctx = event.result;
24251
- if (!ctx) {
24252
- return;
24253
- }
24254
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
24255
- patchFlueContextInPlace(ctx);
24256
- },
24257
- error: () => {
24258
- }
24259
- };
24260
- channel2.subscribe(handlers);
24261
- this.unsubscribers.push(() => {
24262
- channel2.unsubscribe(handlers);
24263
- });
24264
- }
24265
- subscribeToSessionCreation() {
24266
- const channel2 = flueChannels.openSession.tracingChannel();
24267
- const handlers = {
24268
- asyncEnd: (event) => {
24269
- if (event.result) {
24270
- patchFlueSessionInPlace(
24271
- event.result
24272
- );
24273
- }
24274
- if (event.harness) {
24275
- wrapFlueHarness(event.harness);
24276
- }
24277
- },
24278
- error: () => {
24279
- }
24280
- };
24281
- channel2.subscribe(handlers);
24282
- this.unsubscribers.push(() => {
24283
- channel2.unsubscribe(handlers);
24284
- });
24285
- }
24286
- subscribeToSessionOperations() {
24287
- this.subscribeToSessionOperation(flueChannels.prompt);
24288
- this.subscribeToSessionOperation(flueChannels.skill);
24289
- this.subscribeToSessionOperation(flueChannels.task);
24290
- this.subscribeToCompact();
24291
- }
24292
- subscribeToSessionOperation(channel2) {
24293
- const tracingChannel2 = channel2.tracingChannel();
24294
- const states = /* @__PURE__ */ new WeakMap();
24295
- const ensureState2 = (event) => {
24296
- const existing = states.get(event);
24297
- if (existing) {
24298
- return existing;
24299
- }
24300
- const state = this.startOperationState({
24301
- args: event.arguments,
24302
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24303
- operation: event.operation,
24304
- session: event.session
24305
- });
24306
- states.set(event, state);
24307
- return state;
24308
- };
24309
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24310
- tracingChannel2,
24311
- ensureState2
24312
- );
24313
- const handlers = {
24314
- start: (event) => {
24315
- ensureState2(event);
24316
- },
24317
- asyncEnd: (event) => {
24318
- this.endOperationState(states.get(event), event.result);
24319
- states.delete(event);
24320
- },
24321
- error: (event) => {
24322
- const state = states.get(event);
24323
- if (state && event.error) {
24324
- safeLog3(state.span, { error: errorToString(event.error) });
24325
- this.finishOperationState(state);
24326
- }
24327
- states.delete(event);
24328
- }
24329
- };
24330
- tracingChannel2.subscribe(handlers);
24331
- this.unsubscribers.push(() => {
24332
- unbindCurrentSpanStore?.();
24333
- tracingChannel2.unsubscribe(handlers);
24334
- });
24335
- }
24336
- subscribeToCompact() {
24337
- const tracingChannel2 = flueChannels.compact.tracingChannel();
24338
- const states = /* @__PURE__ */ new WeakMap();
24339
- const ensureState2 = (event) => {
24340
- const existing = states.get(event);
24341
- if (existing) {
24342
- return existing;
24343
- }
24344
- const state = this.startOperationState({
24345
- args: [],
24346
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24347
- operation: event.operation,
24348
- session: event.session
24349
- });
24350
- states.set(event, state);
24351
- return state;
24352
- };
24353
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24354
- tracingChannel2,
24355
- ensureState2
24356
- );
24357
- const handlers = {
24358
- start: (event) => {
24359
- ensureState2(event);
24360
- },
24361
- asyncEnd: (event) => {
24362
- this.endOperationState(states.get(event), void 0);
24363
- states.delete(event);
24364
- },
24365
- error: (event) => {
24366
- const state = states.get(event);
24367
- if (state && event.error) {
24368
- safeLog3(state.span, { error: errorToString(event.error) });
24369
- this.finishOperationState(state);
24370
- }
24371
- states.delete(event);
24372
- }
24373
- };
24374
- tracingChannel2.subscribe(handlers);
24375
- this.unsubscribers.push(() => {
24376
- unbindCurrentSpanStore?.();
24377
- tracingChannel2.unsubscribe(handlers);
24378
- });
24379
- }
24380
- subscribeToContextEvents() {
24381
- const channel2 = flueChannels.contextEvent.tracingChannel();
24382
- const handlers = {
24383
- start: (event) => {
24384
- const flueEvent = event.arguments[0];
24385
- if (!flueEvent) {
24386
- return;
24387
- }
24388
- try {
24389
- this.handleFlueEvent(flueEvent, {
24390
- captureTurnSpans: event.captureTurnSpans !== false
24391
- });
24392
- } catch (error) {
24393
- logInstrumentationError3("Flue event", error);
24394
- }
24395
- },
24396
- error: () => {
24397
- }
24398
- };
24399
- channel2.subscribe(handlers);
24400
- this.unsubscribers.push(() => {
24401
- channel2.unsubscribe(handlers);
24402
- });
24403
- }
24404
- bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
24405
- const state = _internalGetGlobalState();
24406
- const startChannel = tracingChannel2.start;
24407
- const contextManager = state?.contextManager;
24408
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
24409
- if (!currentSpanStore || !startChannel) {
24410
- return void 0;
24079
+ toolsByKey = /* @__PURE__ */ new Map();
24080
+ turnsByKey = /* @__PURE__ */ new Map();
24081
+ handle(event, ctx) {
24082
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
24083
+ return;
24411
24084
  }
24412
- startChannel.bindStore(currentSpanStore, (event) => {
24413
- const operationState = ensureState2(event);
24414
- return contextManager.wrapSpanForStore(operationState.span);
24415
- });
24416
- return () => {
24417
- startChannel.unbindStore(currentSpanStore);
24418
- };
24419
- }
24420
- startOperationState(args) {
24421
- const sessionName = getSessionName(args.session);
24422
- const metadata = {
24423
- ...extractOperationInputMetadata(args.operation, args.args),
24424
- ...extractSessionMetadata(args.session),
24425
- "flue.operation": args.operation,
24426
- provider: "flue",
24427
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24428
- };
24429
- const span = startSpan({
24430
- name: `flue.session.${args.operation}`,
24431
- spanAttributes: { type: "task" /* TASK */ }
24432
- });
24433
- const state = {
24434
- metadata,
24435
- operation: args.operation,
24436
- sessionName,
24437
- span,
24438
- startTime: getCurrentUnixTimestamp()
24439
- };
24440
- safeLog3(span, {
24441
- input: extractOperationInput(args.operation, args.args),
24442
- metadata
24443
- });
24444
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24445
- state
24446
- );
24447
- addOperationToScope(
24448
- this.activeOperationsByScope,
24449
- sessionName ?? "unknown",
24450
- state
24451
- );
24452
- return state;
24453
- }
24454
- endOperationState(state, result) {
24455
- if (!state) {
24085
+ if (this.seenEvents.has(event)) {
24456
24086
  return;
24457
24087
  }
24458
- const metadata = {
24459
- ...state.metadata,
24460
- ...extractPromptResponseMetadata(result)
24461
- };
24462
- const metrics = {
24463
- ...buildDurationMetrics3(state.startTime),
24464
- ...metricsFromUsage(result?.usage)
24465
- };
24466
- safeLog3(state.span, {
24467
- metadata,
24468
- metrics,
24469
- output: extractOperationOutput(result)
24470
- });
24471
- this.finishCompactionsForOperation(state);
24472
- this.finishOperationState(state);
24473
- }
24474
- finishOperationState(state) {
24475
- removePendingOperation(this.pendingOperationsByKey, state);
24476
- if (state.operationId) {
24477
- this.activeOperationsById.delete(state.operationId);
24088
+ this.seenEvents.add(event);
24089
+ try {
24090
+ this.handleEvent(event, flueContextFromUnknown(ctx));
24091
+ } catch (error) {
24092
+ logInstrumentationError3("Flue observe", error);
24478
24093
  }
24479
- removeScopedOperation(this.activeOperationsByScope, state);
24480
- state.span.end();
24481
24094
  }
24482
- handleFlueEvent(event, options) {
24095
+ reset() {
24096
+ this.compactionsByKey.clear();
24097
+ this.operationsById.clear();
24098
+ this.runsById.clear();
24099
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
24100
+ this.tasksById.clear();
24101
+ this.toolsByKey.clear();
24102
+ this.turnsByKey.clear();
24103
+ }
24104
+ handleEvent(event, ctx) {
24483
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;
24484
24112
  case "operation_start":
24485
24113
  this.handleOperationStart(event);
24486
24114
  return;
24487
24115
  case "operation":
24488
24116
  this.handleOperation(event);
24489
24117
  return;
24490
- case "text_delta":
24491
- if (!options.captureTurnSpans) {
24492
- return;
24493
- }
24494
- this.ensureTurnState(event).text.push(
24495
- typeof event.text === "string" ? event.text : ""
24496
- );
24497
- return;
24498
- case "thinking_start":
24499
- if (!options.captureTurnSpans) {
24500
- return;
24501
- }
24502
- this.handleThinkingStart(event);
24503
- return;
24504
- case "thinking_delta":
24505
- if (!options.captureTurnSpans) {
24506
- return;
24507
- }
24508
- this.handleThinkingDelta(event);
24509
- return;
24510
- case "thinking_end":
24511
- if (!options.captureTurnSpans) {
24512
- return;
24513
- }
24514
- this.handleThinkingEnd(event);
24118
+ case "turn_request":
24119
+ this.handleTurnRequest(event);
24515
24120
  return;
24516
24121
  case "turn":
24517
- if (!options.captureTurnSpans) {
24518
- return;
24519
- }
24520
24122
  this.handleTurn(event);
24521
24123
  return;
24522
24124
  case "tool_start":
24523
- this.handleToolStart(event, options);
24125
+ this.handleToolStart(event);
24524
24126
  return;
24525
24127
  case "tool_call":
24526
24128
  this.handleToolCall(event);
@@ -24541,203 +24143,216 @@ var FluePlugin = class extends BasePlugin {
24541
24143
  return;
24542
24144
  }
24543
24145
  }
24544
- handleOperationStart(event) {
24545
- if (!isInstrumentedOperation(event.operationKind)) {
24146
+ handleRunStart(event, ctx) {
24147
+ if (!event.runId) {
24546
24148
  return;
24547
24149
  }
24548
- const state = this.takePendingOperationForEvent(event);
24549
- if (!state) {
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"
24156
+ };
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
+ }
24165
+ });
24166
+ this.runsById.set(event.runId, { metadata, span });
24167
+ }
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
24181
+ });
24182
+ safeEnd(state.span, eventTime(event.timestamp));
24183
+ this.runsById.delete(event.runId);
24184
+ }
24185
+ void flush().catch((error) => {
24186
+ logInstrumentationError3("Flue flush", error);
24187
+ });
24188
+ }
24189
+ handleOperationStart(event) {
24190
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
24550
24191
  return;
24551
24192
  }
24552
- state.operationId = event.operationId;
24553
- this.activeOperationsById.set(event.operationId, state);
24554
- addScopedOperation(this.activeOperationsByScope, event, state);
24555
- state.metadata = {
24556
- ...state.metadata,
24193
+ const metadata = {
24557
24194
  ...extractEventMetadata(event),
24558
- "flue.operation_id": event.operationId
24195
+ "flue.operation": event.operationKind,
24196
+ provider: "flue"
24559
24197
  };
24560
- 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 });
24561
24206
  }
24562
24207
  handleOperation(event) {
24563
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24564
- if (!state) {
24208
+ if (!isInstrumentedOperation(event.operationKind)) {
24565
24209
  return;
24566
24210
  }
24211
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
24212
+ const output = operationOutput(event);
24567
24213
  const metadata = {
24568
24214
  ...state.metadata,
24569
24215
  ...extractEventMetadata(event),
24570
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24571
- ...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 } : {}
24572
24218
  };
24573
- const metrics = metricsFromUsage(event.usage);
24219
+ this.finishPendingChildrenForOperation(event, output);
24574
24220
  safeLog3(state.span, {
24575
- ...event.error ? { error: errorToString(event.error) } : {},
24221
+ ...event.isError ? { error: errorToString(event.error) } : {},
24576
24222
  metadata,
24577
- ...Object.keys(metrics).length ? { metrics } : {}
24223
+ metrics: durationMetrics2(event.durationMs),
24224
+ output
24578
24225
  });
24226
+ safeEnd(state.span, eventTime(event.timestamp));
24227
+ this.operationsById.delete(event.operationId);
24579
24228
  }
24580
- ensureTurnState(event) {
24581
- const scope = scopeKey(event);
24582
- const existing = this.turnsByScope.get(scope);
24583
- if (existing) {
24584
- return existing;
24229
+ handleTurnRequest(event) {
24230
+ const key = turnKey(event);
24231
+ if (!key) {
24232
+ return;
24585
24233
  }
24586
- const parent = this.parentSpanForEvent(event);
24587
24234
  const metadata = {
24588
24235
  ...extractEventMetadata(event),
24589
- 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 } : {}
24590
24244
  };
24245
+ const parent = this.parentSpanForTurn(event);
24591
24246
  const span = startFlueSpan(parent, {
24592
- name: "flue.turn",
24593
- 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
+ }
24594
24254
  });
24595
- const state = {
24596
- metadata,
24597
- span,
24598
- hasThinking: false,
24599
- startTime: getCurrentUnixTimestamp(),
24600
- text: [],
24601
- thinking: [],
24602
- toolCalls: []
24603
- };
24604
- safeLog3(span, { metadata });
24605
- this.turnsByScope.set(scope, state);
24606
- return state;
24255
+ this.logOperationInput(
24256
+ event.operationId,
24257
+ event.input?.messages ?? event.input
24258
+ );
24259
+ this.turnsByKey.set(key, { metadata, span });
24607
24260
  }
24608
24261
  handleTurn(event) {
24609
- const scope = scopeKey(event);
24610
- const state = this.ensureTurnState(event);
24611
- const text = state.text.join("");
24612
- const reasoning = state.finalThinking ?? state.thinking.join("");
24613
- 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);
24614
24267
  const metadata = {
24615
24268
  ...state.metadata,
24616
24269
  ...extractEventMetadata(event),
24270
+ ...event.api ? { "flue.api": event.api } : {},
24617
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 } : {},
24618
24275
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24619
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24620
- provider: "flue"
24276
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24621
24277
  };
24622
24278
  safeLog3(state.span, {
24623
- ...event.error ? { error: errorToString(event.error) } : {},
24279
+ ...event.isError ? { error: errorToString(event.error) } : {},
24624
24280
  metadata,
24625
24281
  metrics: {
24626
- ...durationMsMetrics(event.durationMs),
24627
- ...metricsFromUsage(event.usage)
24628
- },
24629
- output: toAssistantOutput(
24630
- text,
24631
- event.stopReason,
24632
- outputReasoning,
24633
- state.toolCalls
24634
- )
24635
- });
24636
- state.span.end();
24637
- this.turnsByScope.delete(scope);
24638
- }
24639
- handleThinkingDelta(event) {
24640
- const delta = event.delta;
24641
- if (typeof delta !== "string" || !delta) {
24642
- return;
24643
- }
24644
- const state = this.ensureTurnState(event);
24645
- state.hasThinking = true;
24646
- state.metadata["flue.thinking"] = true;
24647
- state.thinking.push(delta);
24648
- }
24649
- handleThinkingStart(event) {
24650
- const state = this.ensureTurnState(event);
24651
- state.hasThinking = true;
24652
- state.metadata["flue.thinking"] = true;
24653
- }
24654
- handleThinkingEnd(event) {
24655
- const state = this.ensureTurnState(event);
24656
- state.hasThinking = true;
24657
- state.metadata["flue.thinking"] = true;
24658
- if (typeof event.content === "string" && event.content) {
24659
- state.finalThinking = event.content;
24660
- }
24282
+ ...durationMetrics2(event.durationMs),
24283
+ ...metricsFromUsage(event.usage)
24284
+ },
24285
+ output: event.output
24286
+ });
24287
+ safeEnd(state.span, eventTime(event.timestamp));
24288
+ this.turnsByKey.delete(key);
24661
24289
  }
24662
- handleToolStart(event, options) {
24663
- const toolCallId = event.toolCallId;
24664
- if (!toolCallId) {
24290
+ handleToolStart(event) {
24291
+ if (!event.toolCallId) {
24665
24292
  return;
24666
24293
  }
24667
- const parent = this.parentSpanForEvent(event);
24668
- const scope = scopeKey(event);
24669
- let turnState = this.turnsByScope.get(scope);
24670
- if (!turnState && parent && options.captureTurnSpans) {
24671
- turnState = this.ensureTurnState(event);
24672
- }
24673
24294
  const metadata = {
24674
24295
  ...extractEventMetadata(event),
24675
24296
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24676
- "flue.tool_call_id": toolCallId,
24297
+ "flue.tool_call_id": event.toolCallId,
24677
24298
  provider: "flue"
24678
24299
  };
24300
+ const parent = this.parentSpanForTool(event);
24679
24301
  const span = startFlueSpan(parent, {
24680
- name: `tool: ${event.toolName ?? "unknown"}`,
24681
- spanAttributes: { type: "tool" /* TOOL */ }
24682
- });
24683
- if (turnState) {
24684
- turnState.toolCalls.push({
24685
- args: event.args,
24686
- toolCallId,
24687
- toolName: event.toolName
24688
- });
24689
- }
24690
- safeLog3(span, {
24691
- input: event.args,
24692
- metadata
24693
- });
24694
- this.toolsById.set(toolKey(event), {
24695
- metadata,
24696
- span,
24697
- 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
+ }
24698
24309
  });
24310
+ this.toolsByKey.set(toolKey(event), { metadata, span });
24699
24311
  }
24700
24312
  handleToolCall(event) {
24313
+ if (!event.toolCallId) {
24314
+ return;
24315
+ }
24701
24316
  const key = toolKey(event);
24702
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24317
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
24703
24318
  const metadata = {
24704
24319
  ...state.metadata,
24705
24320
  ...extractEventMetadata(event),
24706
24321
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24707
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24322
+ "flue.tool_call_id": event.toolCallId,
24708
24323
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24709
24324
  };
24710
24325
  safeLog3(state.span, {
24711
24326
  ...event.isError ? { error: errorToString(event.result) } : {},
24712
24327
  metadata,
24713
- metrics: durationMsMetrics(event.durationMs),
24328
+ metrics: durationMetrics2(event.durationMs),
24714
24329
  output: event.result
24715
24330
  });
24716
- state.span.end();
24717
- this.toolsById.delete(key);
24331
+ safeEnd(state.span, eventTime(event.timestamp));
24332
+ this.toolsByKey.delete(key);
24718
24333
  }
24719
24334
  handleTaskStart(event) {
24720
- const parent = this.parentSpanForEvent(event);
24335
+ if (!event.taskId) {
24336
+ return;
24337
+ }
24721
24338
  const metadata = {
24722
24339
  ...extractEventMetadata(event),
24723
- ...event.role ? { "flue.role": event.role } : {},
24340
+ ...event.agent ? { "flue.agent": event.agent } : {},
24724
24341
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
24725
24342
  "flue.task_id": event.taskId,
24726
24343
  provider: "flue"
24727
24344
  };
24345
+ const parent = this.parentSpanForEvent(event);
24728
24346
  const span = startFlueSpan(parent, {
24729
- name: "flue.task",
24730
- spanAttributes: { type: "task" /* TASK */ }
24731
- });
24732
- safeLog3(span, {
24733
- input: event.prompt,
24734
- metadata
24735
- });
24736
- this.tasksById.set(event.taskId, {
24737
- metadata,
24738
- span,
24739
- 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
+ }
24740
24354
  });
24355
+ this.tasksById.set(event.taskId, { metadata, span });
24741
24356
  }
24742
24357
  handleTask(event) {
24743
24358
  const state = this.tasksById.get(event.taskId);
@@ -24749,426 +24364,372 @@ var FluePlugin = class extends BasePlugin {
24749
24364
  metadata: {
24750
24365
  ...state.metadata,
24751
24366
  ...extractEventMetadata(event),
24367
+ ...event.agent ? { "flue.agent": event.agent } : {},
24752
24368
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24753
24369
  },
24754
- metrics: durationMsMetrics(event.durationMs),
24370
+ metrics: durationMetrics2(event.durationMs),
24755
24371
  output: event.result
24756
24372
  });
24757
- state.span.end();
24373
+ safeEnd(state.span, eventTime(event.timestamp));
24758
24374
  this.tasksById.delete(event.taskId);
24759
24375
  }
24760
24376
  handleCompactionStart(event) {
24761
- const operationState = this.operationStateForEvent(event);
24762
- 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
+ };
24763
24382
  const metadata = {
24764
24383
  ...extractEventMetadata(event),
24765
24384
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24766
24385
  provider: "flue"
24767
24386
  };
24768
- const input = {
24769
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24770
- ...event.reason ? { reason: event.reason } : {}
24771
- };
24387
+ const parent = this.parentSpanForEvent(event);
24772
24388
  const span = startFlueSpan(parent, {
24773
- name: "flue.compaction",
24774
- spanAttributes: { type: "task" /* TASK */ }
24775
- });
24776
- safeLog3(span, {
24777
- input,
24778
- metadata
24779
- });
24780
- this.compactionsByScope.set(scopeKey(event), {
24781
- input,
24782
- metadata,
24783
- operationState,
24784
- span,
24785
- 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
+ }
24786
24396
  });
24397
+ this.logOperationInput(event.operationId, input);
24398
+ this.compactionsByKey.set(key, { metadata, span });
24787
24399
  }
24788
24400
  handleCompaction(event) {
24789
- const key = scopeKey(event);
24790
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24791
- if (!state) {
24792
- return;
24793
- }
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
+ };
24794
24408
  safeLog3(state.span, {
24795
- metadata: {
24796
- ...state.metadata,
24797
- ...extractEventMetadata(event),
24798
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24799
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24800
- },
24409
+ metadata,
24801
24410
  metrics: {
24802
- ...durationMsMetrics(event.durationMs),
24803
- ...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 } : {}
24804
24414
  },
24805
24415
  output: {
24806
24416
  messagesAfter: event.messagesAfter,
24807
24417
  messagesBefore: event.messagesBefore
24808
24418
  }
24809
24419
  });
24810
- state.span.end();
24811
- this.deleteCompactionState(state);
24420
+ safeEnd(state.span, eventTime(event.timestamp));
24421
+ this.compactionsByKey.delete(key);
24812
24422
  }
24813
- findCompactionState(event) {
24814
- const operationState = this.operationStateForEvent(event);
24815
- for (const state of this.compactionsByScope.values()) {
24816
- if (operationState && state.operationState === operationState) {
24817
- 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;
24818
24428
  }
24819
24429
  }
24820
- return void 0;
24430
+ return this.parentSpanForEvent(event);
24821
24431
  }
24822
- finishCompactionsForOperation(operationState) {
24823
- for (const state of [...this.compactionsByScope.values()]) {
24824
- if (state.operationState !== operationState) {
24825
- 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;
24826
24438
  }
24827
- safeLog3(state.span, {
24828
- input: state.input,
24829
- metadata: state.metadata,
24830
- metrics: {
24831
- ...buildDurationMetrics3(state.startTime)
24832
- },
24833
- output: { completed: true }
24834
- });
24835
- state.span.end();
24836
- this.deleteCompactionState(state);
24837
24439
  }
24838
- }
24839
- deleteCompactionState(state) {
24840
- for (const [key, candidate] of this.compactionsByScope) {
24841
- if (candidate !== state) {
24842
- continue;
24440
+ if (event.taskId) {
24441
+ const task = this.tasksById.get(event.taskId);
24442
+ if (task) {
24443
+ return task.span;
24843
24444
  }
24844
- this.compactionsByScope.delete(key);
24845
- return;
24846
24445
  }
24847
- }
24848
- startSyntheticToolState(event, toolName) {
24849
- const parent = this.parentSpanForEvent(event);
24850
- const metadata = {
24851
- ...extractEventMetadata(event),
24852
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24853
- "flue.tool_name": toolName,
24854
- provider: "flue"
24855
- };
24856
- const span = startFlueSpan(parent, {
24857
- name: `tool: ${toolName}`,
24858
- spanAttributes: { type: "tool" /* TOOL */ }
24859
- });
24860
- safeLog3(span, { metadata });
24861
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
24862
- }
24863
- operationStateForEvent(event) {
24864
24446
  if (event.operationId) {
24865
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24447
+ const operation = this.operationsById.get(event.operationId);
24866
24448
  if (operation) {
24867
- return operation;
24449
+ return operation.span;
24868
24450
  }
24869
24451
  }
24870
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24452
+ if (event.runId) {
24453
+ return this.runsById.get(event.runId)?.span;
24454
+ }
24455
+ return void 0;
24871
24456
  }
24872
- 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
+ }
24873
24464
  if (event.operationId) {
24874
- const operation = this.operationStateForEvent(event);
24465
+ const operation = this.operationsById.get(event.operationId);
24875
24466
  if (operation) {
24876
24467
  return operation.span;
24877
24468
  }
24878
24469
  }
24879
- if (event.taskId) {
24880
- return this.tasksById.get(event.taskId)?.span;
24470
+ if (event.runId) {
24471
+ return this.runsById.get(event.runId)?.span;
24881
24472
  }
24882
- return this.operationStateForEvent(event)?.span;
24473
+ return void 0;
24883
24474
  }
24884
- promotePendingOperationForEvent(event) {
24885
- if (!event.operationId) {
24886
- 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);
24887
24567
  }
24888
- const scopePrefixes = operationScopePrefixes(event);
24889
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24890
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24568
+ for (const [key, state] of this.tasksById) {
24569
+ if (!stateMatchesOperation(state, event.operationId)) {
24891
24570
  continue;
24892
24571
  }
24893
- const state = candidateQueue.shift();
24894
- if (!state) {
24895
- 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;
24896
24578
  }
24897
- state.operationId = event.operationId;
24898
- this.activeOperationsById.set(event.operationId, state);
24899
- addScopedOperation(this.activeOperationsByScope, event, state);
24900
- state.metadata = {
24901
- ...state.metadata,
24902
- ...extractEventMetadata(event),
24903
- "flue.operation_id": event.operationId
24904
- };
24905
- safeLog3(state.span, { metadata: state.metadata });
24906
- 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);
24907
24586
  }
24908
- return void 0;
24909
24587
  }
24910
- activeOperationForEventScope(event) {
24911
- for (const scope of operationScopeNames(event)) {
24912
- const operations = this.activeOperationsByScope.get(scope);
24913
- if (operations?.length) {
24914
- 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;
24915
24593
  }
24594
+ safeEnd(state.span, endTime);
24595
+ this.toolsByKey.delete(key);
24916
24596
  }
24917
- return void 0;
24918
- }
24919
- pendingOperationForEventScope(event) {
24920
- const scopePrefixes = operationScopePrefixes(event);
24921
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24922
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24597
+ for (const [key, state] of this.turnsByKey) {
24598
+ if (!stateMatchesRun(state, event.runId)) {
24923
24599
  continue;
24924
24600
  }
24925
- return candidateQueue[0];
24601
+ safeEnd(state.span, endTime);
24602
+ this.turnsByKey.delete(key);
24926
24603
  }
24927
- return void 0;
24928
- }
24929
- takePendingOperationForEvent(event) {
24930
- const key = operationKey(event.session, event.operationKind);
24931
- const queue2 = this.pendingOperationsByKey.get(key);
24932
- if (queue2?.length) {
24933
- 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);
24934
24610
  }
24935
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24936
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24937
- return candidateQueue.shift();
24611
+ for (const [key, state] of this.compactionsByKey) {
24612
+ if (!stateMatchesRun(state, event.runId)) {
24613
+ continue;
24938
24614
  }
24615
+ safeLog3(state.span, {
24616
+ metadata: state.metadata,
24617
+ output: { completed: true }
24618
+ });
24619
+ safeEnd(state.span, endTime);
24620
+ this.compactionsByKey.delete(key);
24939
24621
  }
24940
- return void 0;
24941
- }
24942
- pendingOperationQueue(key) {
24943
- const existing = this.pendingOperationsByKey.get(key);
24944
- if (existing) {
24945
- 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);
24946
24632
  }
24947
- const queue2 = [];
24948
- this.pendingOperationsByKey.set(key, queue2);
24949
- return queue2;
24950
24633
  }
24951
24634
  };
24952
24635
  function isInstrumentedOperation(operation) {
24953
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24954
- }
24955
- function getSessionName(session) {
24956
- return typeof session?.name === "string" ? session.name : void 0;
24957
- }
24958
- function operationKey(sessionName, operation) {
24959
- return `${sessionName ?? "unknown"}::${operation}`;
24960
- }
24961
- function operationScopePrefixes(event) {
24962
- const scopes = /* @__PURE__ */ new Set();
24963
- for (const scope of operationScopeNames(event)) {
24964
- scopes.add(`${scope}::`);
24965
- }
24966
- return scopes;
24967
- }
24968
- function operationKeyMatchesScopes(key, scopes) {
24969
- for (const scope of scopes) {
24970
- if (key.startsWith(scope)) {
24971
- return true;
24972
- }
24973
- }
24974
- return false;
24975
- }
24976
- function operationScopeNames(event) {
24977
- const scopes = /* @__PURE__ */ new Set();
24978
- if (event.session) {
24979
- scopes.add(event.session);
24980
- }
24981
- if (event.parentSession) {
24982
- scopes.add(event.parentSession);
24983
- }
24984
- if (!scopes.size) {
24985
- scopes.add("unknown");
24986
- }
24987
- return scopes;
24988
- }
24989
- function addScopedOperation(operationsByScope, event, state) {
24990
- for (const scope of operationScopeNames(event)) {
24991
- addOperationToScope(operationsByScope, scope, state);
24992
- }
24993
- }
24994
- function addOperationToScope(operationsByScope, scope, state) {
24995
- const operations = operationsByScope.get(scope);
24996
- if (operations) {
24997
- if (!operations.includes(state)) {
24998
- operations.push(state);
24999
- }
25000
- } else {
25001
- operationsByScope.set(scope, [state]);
25002
- }
25003
- }
25004
- function removeScopedOperation(operationsByScope, state) {
25005
- for (const [scope, operations] of operationsByScope) {
25006
- const index = operations.indexOf(state);
25007
- if (index === -1) {
25008
- continue;
25009
- }
25010
- operations.splice(index, 1);
25011
- if (operations.length === 0) {
25012
- operationsByScope.delete(scope);
25013
- }
25014
- }
25015
- }
25016
- function removePendingOperation(pendingOperationsByKey, state) {
25017
- for (const [key, queue2] of pendingOperationsByKey) {
25018
- const index = queue2.indexOf(state);
25019
- if (index === -1) {
25020
- continue;
25021
- }
25022
- queue2.splice(index, 1);
25023
- if (queue2.length === 0) {
25024
- pendingOperationsByKey.delete(key);
25025
- }
25026
- return;
25027
- }
25028
- }
25029
- function extractSessionMetadata(session) {
25030
- const sessionName = getSessionName(session);
25031
- return sessionName ? { "flue.session": sessionName } : {};
24636
+ return operation === "prompt" || operation === "skill" || operation === "compact";
25032
24637
  }
25033
- function extractEventMetadata(event) {
24638
+ function extractEventMetadata(event, ctx) {
25034
24639
  return {
25035
24640
  ...event.runId ? { "flue.run_id": event.runId } : {},
24641
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
24642
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
25036
24643
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
25037
24644
  ...event.session ? { "flue.session": event.session } : {},
25038
24645
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
25039
24646
  ...event.harness ? { "flue.harness": event.harness } : {},
25040
24647
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
25041
- ...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 } : {}
25042
24652
  };
25043
24653
  }
25044
- function extractOperationInput(operation, args) {
25045
- switch (operation) {
25046
- case "prompt":
25047
- case "task":
25048
- return args[0];
25049
- case "skill":
25050
- return {
25051
- args: getOptionObject(args[1])?.args,
25052
- name: args[0]
25053
- };
25054
- case "compact":
25055
- return void 0;
24654
+ function extractPayloadMetadata(payload) {
24655
+ if (!isObjectLike(payload)) {
24656
+ return {};
25056
24657
  }
24658
+ const metadata = Reflect.get(payload, "metadata");
24659
+ if (!isObjectLike(metadata)) {
24660
+ return {};
24661
+ }
24662
+ return Object.fromEntries(Object.entries(metadata));
25057
24663
  }
25058
- function extractOperationInputMetadata(operation, args) {
25059
- const options = getOptionObject(args[1]);
25060
- return {
25061
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
25062
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
25063
- ...options?.role ? { "flue.role": options.role } : {},
25064
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
25065
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
25066
- ...Array.isArray(options?.tools) ? {
25067
- "flue.tools_count": options.tools.length,
25068
- tools: summarizeTools(options.tools)
25069
- } : {},
25070
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
25071
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
25072
- };
25073
- }
25074
- function getOptionObject(value) {
25075
- return isObject(value) ? value : void 0;
25076
- }
25077
- function summarizeTools(tools) {
25078
- return tools.flatMap((tool) => {
25079
- if (!isObject(tool)) {
25080
- return [];
25081
- }
25082
- const name = typeof tool.name === "string" ? tool.name : void 0;
25083
- if (!name) {
25084
- return [];
25085
- }
25086
- return [
25087
- {
25088
- function: {
25089
- description: typeof tool.description === "string" ? tool.description : void 0,
25090
- name,
25091
- parameters: tool.parameters
25092
- },
25093
- type: "function"
25094
- }
25095
- ];
25096
- });
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);
25097
24669
  }
25098
- function extractPromptResponseMetadata(result) {
25099
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
25100
- return modelId ? {
25101
- model: modelId,
25102
- "flue.model": modelId
25103
- } : {};
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;
25104
24676
  }
25105
- function extractOperationOutput(result) {
25106
- if (!result) {
24677
+ function usageFromOperationResult(result) {
24678
+ if (!isObjectLike(result)) {
25107
24679
  return void 0;
25108
24680
  }
25109
- if ("data" in result) {
25110
- return result.data;
25111
- }
25112
- if ("text" in result) {
25113
- return result.text;
25114
- }
25115
- return result;
24681
+ return Reflect.get(result, "usage");
25116
24682
  }
25117
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;
25118
24694
  return {
25119
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
25120
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
25121
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
25122
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
25123
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
25124
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
25125
- };
25126
- }
25127
- function buildDurationMetrics3(startTime) {
25128
- return {
25129
- 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 } : {}
25130
24701
  };
25131
24702
  }
25132
- function durationMsMetrics(durationMs) {
24703
+ function durationMetrics2(durationMs) {
25133
24704
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
25134
24705
  }
25135
- function scopeKey(event) {
25136
- if (event.operationId) {
25137
- return `operation:${event.operationId}`;
25138
- }
25139
- if (event.taskId) {
25140
- return `task:${event.taskId}`;
25141
- }
25142
- if (event.session) {
25143
- return `session:${event.session}`;
24706
+ function eventTime(value) {
24707
+ if (typeof value !== "string") {
24708
+ return void 0;
25144
24709
  }
25145
- 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;
25146
24715
  }
25147
24716
  function toolKey(event) {
25148
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24717
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
25149
24718
  }
25150
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24719
+ function compactionKey(event) {
25151
24720
  return [
25152
- {
25153
- finish_reason: finishReason ?? "stop",
25154
- index: 0,
25155
- message: {
25156
- content: text,
25157
- ...reasoning ? { reasoning } : {},
25158
- role: "assistant",
25159
- ...toolCalls?.length ? {
25160
- tool_calls: toolCalls.map((toolCall) => ({
25161
- function: {
25162
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
25163
- name: toolCall.toolName ?? "unknown"
25164
- },
25165
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
25166
- type: "function"
25167
- }))
25168
- } : {}
25169
- }
25170
- }
25171
- ];
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;
25172
24733
  }
25173
24734
  function startFlueSpan(parent, args) {
25174
24735
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -25180,6 +24741,13 @@ function safeLog3(span, event) {
25180
24741
  logInstrumentationError3("Flue span log", error);
25181
24742
  }
25182
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
+ }
25183
24751
  function errorToString(error) {
25184
24752
  if (error instanceof Error) {
25185
24753
  return error.message;
@@ -26199,6 +25767,7 @@ __export(exports_exports, {
26199
25767
  _internalIso: () => isomorph_default,
26200
25768
  _internalSetInitialState: () => _internalSetInitialState,
26201
25769
  addAzureBlobHeaders: () => addAzureBlobHeaders,
25770
+ braintrustFlueObserver: () => braintrustFlueObserver,
26202
25771
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
26203
25772
  buildLocalSummary: () => buildLocalSummary,
26204
25773
  configureInstrumentation: () => configureInstrumentation,
@@ -26278,8 +25847,6 @@ __export(exports_exports, {
26278
25847
  wrapCohere: () => wrapCohere,
26279
25848
  wrapCopilotClient: () => wrapCopilotClient,
26280
25849
  wrapCursorSDK: () => wrapCursorSDK,
26281
- wrapFlueContext: () => wrapFlueContext,
26282
- wrapFlueSession: () => wrapFlueSession,
26283
25850
  wrapGenkit: () => wrapGenkit,
26284
25851
  wrapGoogleADK: () => wrapGoogleADK,
26285
25852
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -33504,6 +33071,7 @@ export {
33504
33071
  isomorph_default as _internalIso,
33505
33072
  _internalSetInitialState,
33506
33073
  addAzureBlobHeaders,
33074
+ braintrustFlueObserver,
33507
33075
  braintrustStreamChunkSchema,
33508
33076
  buildLocalSummary,
33509
33077
  configureInstrumentation,
@@ -33584,8 +33152,6 @@ export {
33584
33152
  wrapCohere,
33585
33153
  wrapCopilotClient,
33586
33154
  wrapCursorSDK,
33587
- wrapFlueContext,
33588
- wrapFlueSession,
33589
33155
  wrapGenkit,
33590
33156
  wrapGoogleADK,
33591
33157
  wrapGoogleGenAI,