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
@@ -24039,608 +24039,210 @@ var flueChannels = defineChannels("@flue/runtime", {
24039
24039
  createContext: channel({
24040
24040
  channelName: "createFlueContext",
24041
24041
  kind: "sync-stream"
24042
- }),
24043
- openSession: channel({
24044
- channelName: "Harness.openSession",
24045
- kind: "async"
24046
- }),
24047
- contextEvent: channel({
24048
- channelName: "context.event",
24049
- kind: "sync-stream"
24050
- }),
24051
- prompt: channel({
24052
- channelName: "session.prompt",
24053
- kind: "async"
24054
- }),
24055
- skill: channel({
24056
- channelName: "session.skill",
24057
- kind: "async"
24058
- }),
24059
- task: channel({
24060
- channelName: "session.task",
24061
- kind: "async"
24062
- }),
24063
- compact: channel({
24064
- channelName: "session.compact",
24065
- kind: "async"
24066
24042
  })
24067
24043
  });
24068
24044
 
24069
- // src/wrappers/flue.ts
24070
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
24071
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
24072
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
24073
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
24074
- "braintrust.flue.subscribed-context-events"
24075
- );
24076
- function wrapFlueContext(ctx) {
24077
- if (!isPlausibleFlueContext(ctx)) {
24078
- console.warn("Unsupported Flue context. Not wrapping.");
24079
- return ctx;
24045
+ // src/instrumentation/plugins/flue-plugin.ts
24046
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
24047
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
24048
+ var braintrustFlueObserver = (event, ctx) => {
24049
+ getObserveBridge().handle(event, ctx);
24050
+ };
24051
+ var FluePlugin = class extends BasePlugin {
24052
+ onEnable() {
24053
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
24080
24054
  }
24081
- const context = ctx;
24082
- subscribeFlueContextEvents(context, { captureTurnSpans: true });
24083
- return patchFlueContextInPlace(context);
24084
- }
24085
- function patchFlueContextInPlace(ctx) {
24086
- const context = ctx;
24087
- if (context[WRAPPED_FLUE_CONTEXT]) {
24088
- return ctx;
24055
+ onDisable() {
24056
+ for (const unsubscribe of this.unsubscribers) {
24057
+ unsubscribe();
24058
+ }
24059
+ this.unsubscribers = [];
24089
24060
  }
24090
- const originalInit = context.init.bind(context);
24091
- try {
24092
- Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
24093
- configurable: false,
24094
- enumerable: false,
24095
- value: true
24096
- });
24097
- Object.defineProperty(context, "init", {
24098
- configurable: true,
24099
- value: async function wrappedFlueInit(options) {
24100
- const harness = await originalInit(options);
24101
- return wrapFlueHarness(harness);
24102
- },
24103
- writable: true
24104
- });
24105
- } catch {
24061
+ };
24062
+ function enableFlueAutoInstrumentation() {
24063
+ const state = getAutoState();
24064
+ state.refCount += 1;
24065
+ if (!state.handlers) {
24066
+ const channel2 = flueChannels.createContext.tracingChannel();
24067
+ const handlers = {
24068
+ end: (event) => {
24069
+ subscribeToFlueContext(event.result, state);
24070
+ }
24071
+ };
24072
+ channel2.subscribe(handlers);
24073
+ state.channel = channel2;
24074
+ state.handlers = handlers;
24106
24075
  }
24107
- return ctx;
24076
+ let released = false;
24077
+ return () => {
24078
+ if (released) {
24079
+ return;
24080
+ }
24081
+ released = true;
24082
+ releaseAutoState(state);
24083
+ };
24108
24084
  }
24109
- function wrapFlueSession(session) {
24110
- if (!isPlausibleFlueSession(session)) {
24111
- console.warn("Unsupported Flue session. Not wrapping.");
24112
- return session;
24085
+ function getAutoState() {
24086
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
24087
+ if (isAutoState(existing)) {
24088
+ return existing;
24113
24089
  }
24114
- return patchFlueSessionInPlace(session);
24090
+ const state = {
24091
+ contexts: /* @__PURE__ */ new WeakSet(),
24092
+ refCount: 0
24093
+ };
24094
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
24095
+ return state;
24115
24096
  }
24116
- function subscribeFlueContextEvents(ctx, options = {}) {
24117
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
24118
- return void 0;
24119
- }
24120
- const context = ctx;
24121
- const captureTurnSpans = options.captureTurnSpans ?? true;
24122
- const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
24123
- if (existingSubscription) {
24124
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
24125
- return void 0;
24126
- }
24127
- try {
24128
- existingSubscription.unsubscribe();
24129
- } catch {
24130
- }
24131
- }
24132
- try {
24133
- const unsubscribe = ctx.subscribeEvent((event) => {
24134
- flueChannels.contextEvent.traceSync(() => void 0, {
24135
- arguments: [event],
24136
- captureTurnSpans,
24137
- context: ctx
24138
- });
24139
- });
24140
- if (existingSubscription) {
24141
- existingSubscription.captureTurnSpans = captureTurnSpans;
24142
- existingSubscription.unsubscribe = unsubscribe;
24143
- } else {
24144
- Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
24145
- configurable: false,
24146
- enumerable: false,
24147
- value: {
24148
- captureTurnSpans,
24149
- unsubscribe
24150
- }
24151
- });
24152
- }
24153
- return unsubscribe;
24154
- } catch {
24155
- return void 0;
24097
+ function getObserveBridge() {
24098
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
24099
+ if (isFlueObserveBridge(existing)) {
24100
+ return existing;
24156
24101
  }
24102
+ const bridge = new FlueObserveBridge();
24103
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
24104
+ return bridge;
24157
24105
  }
24158
- function wrapFlueHarness(harness) {
24159
- if (!isPlausibleFlueHarness(harness)) {
24160
- return harness;
24161
- }
24162
- const target = harness;
24163
- if (target[WRAPPED_FLUE_HARNESS]) {
24164
- return harness;
24165
- }
24166
- const originalSession = target.session.bind(target);
24167
- try {
24168
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
24169
- configurable: false,
24170
- enumerable: false,
24171
- value: true
24172
- });
24173
- Object.defineProperty(target, "session", {
24174
- configurable: true,
24175
- value: async function wrappedFlueHarnessSession(name, options) {
24176
- const session = await originalSession(name, options);
24177
- return patchFlueSessionInPlace(session);
24178
- },
24179
- writable: true
24180
- });
24181
- const sessions = target.sessions;
24182
- if (sessions && typeof sessions === "object") {
24183
- patchFlueSessionFactory(sessions, "get");
24184
- patchFlueSessionFactory(sessions, "create");
24185
- }
24186
- } catch {
24187
- }
24188
- return harness;
24106
+ function isFlueObserveBridge(value) {
24107
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
24189
24108
  }
24190
- function patchFlueSessionInPlace(session) {
24191
- if (session[WRAPPED_FLUE_SESSION]) {
24192
- return session;
24193
- }
24194
- try {
24195
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
24196
- configurable: false,
24197
- enumerable: false,
24198
- value: true
24199
- });
24200
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
24201
- patchCallHandleMethod(session, "skill", flueChannels.skill);
24202
- patchCallHandleMethod(session, "task", flueChannels.task);
24203
- patchCompact(session);
24204
- } catch {
24205
- }
24206
- return session;
24109
+ function isAutoState(value) {
24110
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
24207
24111
  }
24208
- function patchFlueSessionFactory(sessions, method) {
24209
- const original = sessions[method];
24210
- if (typeof original !== "function") {
24112
+ function releaseAutoState(state) {
24113
+ state.refCount -= 1;
24114
+ if (state.refCount > 0) {
24211
24115
  return;
24212
24116
  }
24213
- const bound = original.bind(sessions);
24214
- Object.defineProperty(sessions, method, {
24215
- configurable: true,
24216
- value: async function wrappedFlueSessionFactory(name, options) {
24217
- const session = await bound(name, options);
24218
- return patchFlueSessionInPlace(session);
24219
- },
24220
- writable: true
24221
- });
24222
- }
24223
- function patchCallHandleMethod(session, method, channel2) {
24224
- const original = session[method];
24225
- if (typeof original !== "function") {
24226
- return;
24117
+ try {
24118
+ if (state.channel && state.handlers) {
24119
+ state.channel.unsubscribe(state.handlers);
24120
+ }
24121
+ } finally {
24122
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
24227
24123
  }
24228
- const bound = original.bind(session);
24229
- Object.defineProperty(session, method, {
24230
- configurable: true,
24231
- value(input, options) {
24232
- const args = [input, options];
24233
- const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
24234
- context: {
24235
- arguments: args,
24236
- operation: method,
24237
- session
24238
- },
24239
- run: () => bound(input, options)
24240
- });
24241
- return preserveCallHandle(originalResult, traced2);
24242
- },
24243
- writable: true
24244
- });
24245
24124
  }
24246
- function patchCompact(session) {
24247
- const original = session.compact;
24248
- if (typeof original !== "function") {
24125
+ function subscribeToFlueContext(value, state) {
24126
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
24249
24127
  return;
24250
24128
  }
24251
- const bound = original.bind(session);
24252
- Object.defineProperty(session, "compact", {
24253
- configurable: true,
24254
- value() {
24255
- const context = {
24256
- arguments: [],
24257
- operation: "compact",
24258
- session
24259
- };
24260
- return flueChannels.compact.tracePromise(() => bound(), context);
24261
- },
24262
- writable: true
24263
- });
24264
- }
24265
- function traceFlueOperation(channel2, args) {
24266
- const tracingChannel2 = channel2.tracingChannel();
24267
- const context = args.context;
24268
- let originalResult;
24269
- let traced2;
24270
- const run = () => {
24129
+ const ctx = flueContextFromUnknown(value);
24130
+ let released = false;
24131
+ let unsubscribe;
24132
+ const release = () => {
24133
+ if (released) {
24134
+ return;
24135
+ }
24136
+ released = true;
24271
24137
  try {
24272
- originalResult = args.run();
24273
- tracingChannel2.end?.publish(context);
24138
+ unsubscribe?.();
24274
24139
  } catch (error) {
24275
- context.error = normalizeError3(error);
24276
- tracingChannel2.error?.publish(context);
24277
- tracingChannel2.end?.publish(context);
24278
- throw error;
24140
+ logInstrumentationError3("Flue context unsubscribe", error);
24279
24141
  }
24280
- traced2 = Promise.resolve(originalResult).then(
24281
- (result) => {
24282
- context.result = result;
24283
- tracingChannel2.asyncStart?.publish(context);
24284
- tracingChannel2.asyncEnd?.publish(context);
24285
- return result;
24286
- },
24287
- (error) => {
24288
- context.error = normalizeError3(error);
24289
- tracingChannel2.error?.publish(context);
24290
- tracingChannel2.asyncStart?.publish(context);
24291
- tracingChannel2.asyncEnd?.publish(context);
24292
- throw error;
24293
- }
24294
- );
24295
24142
  };
24296
- if (tracingChannel2.start?.runStores) {
24297
- tracingChannel2.start.runStores(context, run);
24298
- } else {
24299
- tracingChannel2.start?.publish(context);
24300
- run();
24143
+ try {
24144
+ unsubscribe = value.subscribeEvent((event) => {
24145
+ if (state.refCount <= 0) {
24146
+ release();
24147
+ return;
24148
+ }
24149
+ braintrustFlueObserver(event, ctx);
24150
+ if (isAutoContextTerminalEvent(event, ctx)) {
24151
+ release();
24152
+ }
24153
+ });
24154
+ state.contexts.add(value);
24155
+ } catch (error) {
24156
+ logInstrumentationError3("Flue context subscription", error);
24301
24157
  }
24302
- return { originalResult, traced: traced2 };
24303
24158
  }
24304
- function normalizeError3(error) {
24305
- return error instanceof Error ? error : new Error(String(error));
24306
- }
24307
- function preserveCallHandle(originalHandle, traced2) {
24308
- if (!isFlueCallHandle(originalHandle)) {
24309
- return traced2;
24159
+ function isAutoContextTerminalEvent(event, ctx) {
24160
+ if (!isObjectLike(event)) {
24161
+ return false;
24310
24162
  }
24311
- const handle = originalHandle;
24312
- const wrapped = {
24313
- get signal() {
24314
- return handle.signal;
24315
- },
24316
- abort(reason) {
24317
- return handle.abort(reason);
24318
- },
24319
- then(onfulfilled, onrejected) {
24320
- return traced2.then(onfulfilled, onrejected);
24321
- }
24322
- };
24323
- return wrapped;
24163
+ const type = Reflect.get(event, "type");
24164
+ if (type === "run_end") {
24165
+ return true;
24166
+ }
24167
+ if (type !== "operation") {
24168
+ return false;
24169
+ }
24170
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
24324
24171
  }
24325
- function isPlausibleFlueContext(value) {
24326
- return !!value && typeof value === "object" && typeof value.init === "function";
24172
+ function isObservableFlueContext(value) {
24173
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
24327
24174
  }
24328
- function isPlausibleFlueHarness(value) {
24329
- return !!value && typeof value === "object" && typeof value.session === "function";
24175
+ function isFlueEvent(event) {
24176
+ const type = Reflect.get(event, "type");
24177
+ 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";
24330
24178
  }
24331
- function isPlausibleFlueSession(value) {
24332
- return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
24179
+ function flueContextFromUnknown(ctx) {
24180
+ if (!isObjectLike(ctx)) {
24181
+ return void 0;
24182
+ }
24183
+ const id = Reflect.get(ctx, "id");
24184
+ const runId = Reflect.get(ctx, "runId");
24185
+ return {
24186
+ ...typeof id === "string" ? { id } : {},
24187
+ ...typeof runId === "string" ? { runId } : {}
24188
+ };
24333
24189
  }
24334
- function isFlueCallHandle(value) {
24335
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
24190
+ function isObjectLike(value) {
24191
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24336
24192
  }
24337
-
24338
- // src/instrumentation/plugins/flue-plugin.ts
24339
- var FluePlugin = class extends BasePlugin {
24340
- activeOperationsById = /* @__PURE__ */ new Map();
24341
- activeOperationsByScope = /* @__PURE__ */ new Map();
24342
- compactionsByScope = /* @__PURE__ */ new Map();
24343
- pendingOperationsByKey = /* @__PURE__ */ new Map();
24193
+ var FlueObserveBridge = class {
24194
+ compactionsByKey = /* @__PURE__ */ new Map();
24195
+ operationsById = /* @__PURE__ */ new Map();
24196
+ runsById = /* @__PURE__ */ new Map();
24197
+ seenEvents = /* @__PURE__ */ new WeakSet();
24344
24198
  tasksById = /* @__PURE__ */ new Map();
24345
- toolsById = /* @__PURE__ */ new Map();
24346
- turnsByScope = /* @__PURE__ */ new Map();
24347
- onEnable() {
24348
- this.subscribeToContextCreation();
24349
- this.subscribeToSessionCreation();
24350
- this.subscribeToContextEvents();
24351
- this.subscribeToSessionOperations();
24352
- }
24353
- onDisable() {
24354
- for (const unsubscribe of this.unsubscribers) {
24355
- unsubscribe();
24356
- }
24357
- this.unsubscribers = [];
24358
- this.activeOperationsById.clear();
24359
- this.activeOperationsByScope.clear();
24360
- this.compactionsByScope.clear();
24361
- this.pendingOperationsByKey.clear();
24362
- this.tasksById.clear();
24363
- this.toolsById.clear();
24364
- this.turnsByScope.clear();
24365
- }
24366
- subscribeToContextCreation() {
24367
- const channel2 = flueChannels.createContext.tracingChannel();
24368
- const handlers = {
24369
- end: (event) => {
24370
- const ctx = event.result;
24371
- if (!ctx) {
24372
- return;
24373
- }
24374
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
24375
- patchFlueContextInPlace(ctx);
24376
- },
24377
- error: () => {
24378
- }
24379
- };
24380
- channel2.subscribe(handlers);
24381
- this.unsubscribers.push(() => {
24382
- channel2.unsubscribe(handlers);
24383
- });
24384
- }
24385
- subscribeToSessionCreation() {
24386
- const channel2 = flueChannels.openSession.tracingChannel();
24387
- const handlers = {
24388
- asyncEnd: (event) => {
24389
- if (event.result) {
24390
- patchFlueSessionInPlace(
24391
- event.result
24392
- );
24393
- }
24394
- if (event.harness) {
24395
- wrapFlueHarness(event.harness);
24396
- }
24397
- },
24398
- error: () => {
24399
- }
24400
- };
24401
- channel2.subscribe(handlers);
24402
- this.unsubscribers.push(() => {
24403
- channel2.unsubscribe(handlers);
24404
- });
24405
- }
24406
- subscribeToSessionOperations() {
24407
- this.subscribeToSessionOperation(flueChannels.prompt);
24408
- this.subscribeToSessionOperation(flueChannels.skill);
24409
- this.subscribeToSessionOperation(flueChannels.task);
24410
- this.subscribeToCompact();
24411
- }
24412
- subscribeToSessionOperation(channel2) {
24413
- const tracingChannel2 = channel2.tracingChannel();
24414
- const states = /* @__PURE__ */ new WeakMap();
24415
- const ensureState2 = (event) => {
24416
- const existing = states.get(event);
24417
- if (existing) {
24418
- return existing;
24419
- }
24420
- const state = this.startOperationState({
24421
- args: event.arguments,
24422
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24423
- operation: event.operation,
24424
- session: event.session
24425
- });
24426
- states.set(event, state);
24427
- return state;
24428
- };
24429
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24430
- tracingChannel2,
24431
- ensureState2
24432
- );
24433
- const handlers = {
24434
- start: (event) => {
24435
- ensureState2(event);
24436
- },
24437
- asyncEnd: (event) => {
24438
- this.endOperationState(states.get(event), event.result);
24439
- states.delete(event);
24440
- },
24441
- error: (event) => {
24442
- const state = states.get(event);
24443
- if (state && event.error) {
24444
- safeLog3(state.span, { error: errorToString(event.error) });
24445
- this.finishOperationState(state);
24446
- }
24447
- states.delete(event);
24448
- }
24449
- };
24450
- tracingChannel2.subscribe(handlers);
24451
- this.unsubscribers.push(() => {
24452
- unbindCurrentSpanStore?.();
24453
- tracingChannel2.unsubscribe(handlers);
24454
- });
24455
- }
24456
- subscribeToCompact() {
24457
- const tracingChannel2 = flueChannels.compact.tracingChannel();
24458
- const states = /* @__PURE__ */ new WeakMap();
24459
- const ensureState2 = (event) => {
24460
- const existing = states.get(event);
24461
- if (existing) {
24462
- return existing;
24463
- }
24464
- const state = this.startOperationState({
24465
- args: [],
24466
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24467
- operation: event.operation,
24468
- session: event.session
24469
- });
24470
- states.set(event, state);
24471
- return state;
24472
- };
24473
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24474
- tracingChannel2,
24475
- ensureState2
24476
- );
24477
- const handlers = {
24478
- start: (event) => {
24479
- ensureState2(event);
24480
- },
24481
- asyncEnd: (event) => {
24482
- this.endOperationState(states.get(event), void 0);
24483
- states.delete(event);
24484
- },
24485
- error: (event) => {
24486
- const state = states.get(event);
24487
- if (state && event.error) {
24488
- safeLog3(state.span, { error: errorToString(event.error) });
24489
- this.finishOperationState(state);
24490
- }
24491
- states.delete(event);
24492
- }
24493
- };
24494
- tracingChannel2.subscribe(handlers);
24495
- this.unsubscribers.push(() => {
24496
- unbindCurrentSpanStore?.();
24497
- tracingChannel2.unsubscribe(handlers);
24498
- });
24499
- }
24500
- subscribeToContextEvents() {
24501
- const channel2 = flueChannels.contextEvent.tracingChannel();
24502
- const handlers = {
24503
- start: (event) => {
24504
- const flueEvent = event.arguments[0];
24505
- if (!flueEvent) {
24506
- return;
24507
- }
24508
- try {
24509
- this.handleFlueEvent(flueEvent, {
24510
- captureTurnSpans: event.captureTurnSpans !== false
24511
- });
24512
- } catch (error) {
24513
- logInstrumentationError3("Flue event", error);
24514
- }
24515
- },
24516
- error: () => {
24517
- }
24518
- };
24519
- channel2.subscribe(handlers);
24520
- this.unsubscribers.push(() => {
24521
- channel2.unsubscribe(handlers);
24522
- });
24523
- }
24524
- bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
24525
- const state = _internalGetGlobalState();
24526
- const startChannel = tracingChannel2.start;
24527
- const contextManager = state?.contextManager;
24528
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
24529
- if (!currentSpanStore || !startChannel) {
24530
- return void 0;
24199
+ toolsByKey = /* @__PURE__ */ new Map();
24200
+ turnsByKey = /* @__PURE__ */ new Map();
24201
+ handle(event, ctx) {
24202
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
24203
+ return;
24531
24204
  }
24532
- startChannel.bindStore(currentSpanStore, (event) => {
24533
- const operationState = ensureState2(event);
24534
- return contextManager.wrapSpanForStore(operationState.span);
24535
- });
24536
- return () => {
24537
- startChannel.unbindStore(currentSpanStore);
24538
- };
24539
- }
24540
- startOperationState(args) {
24541
- const sessionName = getSessionName(args.session);
24542
- const metadata = {
24543
- ...extractOperationInputMetadata(args.operation, args.args),
24544
- ...extractSessionMetadata(args.session),
24545
- "flue.operation": args.operation,
24546
- provider: "flue",
24547
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24548
- };
24549
- const span = startSpan({
24550
- name: `flue.session.${args.operation}`,
24551
- spanAttributes: { type: "task" /* TASK */ }
24552
- });
24553
- const state = {
24554
- metadata,
24555
- operation: args.operation,
24556
- sessionName,
24557
- span,
24558
- startTime: getCurrentUnixTimestamp()
24559
- };
24560
- safeLog3(span, {
24561
- input: extractOperationInput(args.operation, args.args),
24562
- metadata
24563
- });
24564
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24565
- state
24566
- );
24567
- addOperationToScope(
24568
- this.activeOperationsByScope,
24569
- sessionName ?? "unknown",
24570
- state
24571
- );
24572
- return state;
24573
- }
24574
- endOperationState(state, result) {
24575
- if (!state) {
24205
+ if (this.seenEvents.has(event)) {
24576
24206
  return;
24577
24207
  }
24578
- const metadata = {
24579
- ...state.metadata,
24580
- ...extractPromptResponseMetadata(result)
24581
- };
24582
- const metrics = {
24583
- ...buildDurationMetrics3(state.startTime),
24584
- ...metricsFromUsage(result?.usage)
24585
- };
24586
- safeLog3(state.span, {
24587
- metadata,
24588
- metrics,
24589
- output: extractOperationOutput(result)
24590
- });
24591
- this.finishCompactionsForOperation(state);
24592
- this.finishOperationState(state);
24593
- }
24594
- finishOperationState(state) {
24595
- removePendingOperation(this.pendingOperationsByKey, state);
24596
- if (state.operationId) {
24597
- this.activeOperationsById.delete(state.operationId);
24208
+ this.seenEvents.add(event);
24209
+ try {
24210
+ this.handleEvent(event, flueContextFromUnknown(ctx));
24211
+ } catch (error) {
24212
+ logInstrumentationError3("Flue observe", error);
24598
24213
  }
24599
- removeScopedOperation(this.activeOperationsByScope, state);
24600
- state.span.end();
24601
24214
  }
24602
- handleFlueEvent(event, options) {
24215
+ reset() {
24216
+ this.compactionsByKey.clear();
24217
+ this.operationsById.clear();
24218
+ this.runsById.clear();
24219
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
24220
+ this.tasksById.clear();
24221
+ this.toolsByKey.clear();
24222
+ this.turnsByKey.clear();
24223
+ }
24224
+ handleEvent(event, ctx) {
24603
24225
  switch (event.type) {
24226
+ case "run_start":
24227
+ this.handleRunStart(event, ctx);
24228
+ return;
24229
+ case "run_end":
24230
+ this.handleRunEnd(event);
24231
+ return;
24604
24232
  case "operation_start":
24605
24233
  this.handleOperationStart(event);
24606
24234
  return;
24607
24235
  case "operation":
24608
24236
  this.handleOperation(event);
24609
24237
  return;
24610
- case "text_delta":
24611
- if (!options.captureTurnSpans) {
24612
- return;
24613
- }
24614
- this.ensureTurnState(event).text.push(
24615
- typeof event.text === "string" ? event.text : ""
24616
- );
24617
- return;
24618
- case "thinking_start":
24619
- if (!options.captureTurnSpans) {
24620
- return;
24621
- }
24622
- this.handleThinkingStart(event);
24623
- return;
24624
- case "thinking_delta":
24625
- if (!options.captureTurnSpans) {
24626
- return;
24627
- }
24628
- this.handleThinkingDelta(event);
24629
- return;
24630
- case "thinking_end":
24631
- if (!options.captureTurnSpans) {
24632
- return;
24633
- }
24634
- this.handleThinkingEnd(event);
24238
+ case "turn_request":
24239
+ this.handleTurnRequest(event);
24635
24240
  return;
24636
24241
  case "turn":
24637
- if (!options.captureTurnSpans) {
24638
- return;
24639
- }
24640
24242
  this.handleTurn(event);
24641
24243
  return;
24642
24244
  case "tool_start":
24643
- this.handleToolStart(event, options);
24245
+ this.handleToolStart(event);
24644
24246
  return;
24645
24247
  case "tool_call":
24646
24248
  this.handleToolCall(event);
@@ -24661,203 +24263,216 @@ var FluePlugin = class extends BasePlugin {
24661
24263
  return;
24662
24264
  }
24663
24265
  }
24664
- handleOperationStart(event) {
24665
- if (!isInstrumentedOperation(event.operationKind)) {
24266
+ handleRunStart(event, ctx) {
24267
+ if (!event.runId) {
24666
24268
  return;
24667
24269
  }
24668
- const state = this.takePendingOperationForEvent(event);
24669
- if (!state) {
24270
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
24271
+ const metadata = {
24272
+ ...extractPayloadMetadata(event.payload),
24273
+ ...extractEventMetadata(event, ctx),
24274
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
24275
+ provider: "flue"
24276
+ };
24277
+ const span = startSpan({
24278
+ name: `workflow:${workflowName}`,
24279
+ spanAttributes: { type: "task" /* TASK */ },
24280
+ startTime: eventTime(event.startedAt ?? event.timestamp),
24281
+ event: {
24282
+ input: event.payload,
24283
+ metadata
24284
+ }
24285
+ });
24286
+ this.runsById.set(event.runId, { metadata, span });
24287
+ }
24288
+ handleRunEnd(event) {
24289
+ const state = this.runsById.get(event.runId);
24290
+ this.finishPendingSpansForRun(event);
24291
+ if (state) {
24292
+ safeLog3(state.span, {
24293
+ ...event.isError ? { error: errorToString(event.error) } : {},
24294
+ metadata: {
24295
+ ...state.metadata,
24296
+ ...extractEventMetadata(event),
24297
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24298
+ },
24299
+ metrics: durationMetrics2(event.durationMs),
24300
+ output: event.result
24301
+ });
24302
+ safeEnd(state.span, eventTime(event.timestamp));
24303
+ this.runsById.delete(event.runId);
24304
+ }
24305
+ void flush().catch((error) => {
24306
+ logInstrumentationError3("Flue flush", error);
24307
+ });
24308
+ }
24309
+ handleOperationStart(event) {
24310
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
24670
24311
  return;
24671
24312
  }
24672
- state.operationId = event.operationId;
24673
- this.activeOperationsById.set(event.operationId, state);
24674
- addScopedOperation(this.activeOperationsByScope, event, state);
24675
- state.metadata = {
24676
- ...state.metadata,
24313
+ const metadata = {
24677
24314
  ...extractEventMetadata(event),
24678
- "flue.operation_id": event.operationId
24315
+ "flue.operation": event.operationKind,
24316
+ provider: "flue"
24679
24317
  };
24680
- safeLog3(state.span, { metadata: state.metadata });
24318
+ const parent = this.parentSpanForEvent(event);
24319
+ const span = startFlueSpan(parent, {
24320
+ name: `flue.${event.operationKind}`,
24321
+ spanAttributes: { type: "task" /* TASK */ },
24322
+ startTime: eventTime(event.timestamp),
24323
+ event: { metadata }
24324
+ });
24325
+ this.operationsById.set(event.operationId, { metadata, span });
24681
24326
  }
24682
24327
  handleOperation(event) {
24683
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24684
- if (!state) {
24328
+ if (!isInstrumentedOperation(event.operationKind)) {
24685
24329
  return;
24686
24330
  }
24331
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
24332
+ const output = operationOutput(event);
24687
24333
  const metadata = {
24688
24334
  ...state.metadata,
24689
24335
  ...extractEventMetadata(event),
24690
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24691
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24336
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24337
+ ...event.usage ? { "flue.usage": event.usage } : {}
24692
24338
  };
24693
- const metrics = metricsFromUsage(event.usage);
24339
+ this.finishPendingChildrenForOperation(event, output);
24694
24340
  safeLog3(state.span, {
24695
- ...event.error ? { error: errorToString(event.error) } : {},
24341
+ ...event.isError ? { error: errorToString(event.error) } : {},
24696
24342
  metadata,
24697
- ...Object.keys(metrics).length ? { metrics } : {}
24343
+ metrics: durationMetrics2(event.durationMs),
24344
+ output
24698
24345
  });
24346
+ safeEnd(state.span, eventTime(event.timestamp));
24347
+ this.operationsById.delete(event.operationId);
24699
24348
  }
24700
- ensureTurnState(event) {
24701
- const scope = scopeKey(event);
24702
- const existing = this.turnsByScope.get(scope);
24703
- if (existing) {
24704
- return existing;
24349
+ handleTurnRequest(event) {
24350
+ const key = turnKey(event);
24351
+ if (!key) {
24352
+ return;
24705
24353
  }
24706
- const parent = this.parentSpanForEvent(event);
24707
24354
  const metadata = {
24708
24355
  ...extractEventMetadata(event),
24709
- provider: "flue"
24356
+ ...event.api ? { "flue.api": event.api } : {},
24357
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24358
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24359
+ ...event.provider ? { "flue.provider": event.provider } : {},
24360
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24361
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
24362
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
24363
+ ...event.input?.tools ? { tools: event.input.tools } : {}
24710
24364
  };
24365
+ const parent = this.parentSpanForTurn(event);
24711
24366
  const span = startFlueSpan(parent, {
24712
- name: "flue.turn",
24713
- spanAttributes: { type: "llm" /* LLM */ }
24367
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24368
+ spanAttributes: { type: "llm" /* LLM */ },
24369
+ startTime: eventTime(event.timestamp),
24370
+ event: {
24371
+ input: event.input?.messages,
24372
+ metadata
24373
+ }
24714
24374
  });
24715
- const state = {
24716
- metadata,
24717
- span,
24718
- hasThinking: false,
24719
- startTime: getCurrentUnixTimestamp(),
24720
- text: [],
24721
- thinking: [],
24722
- toolCalls: []
24723
- };
24724
- safeLog3(span, { metadata });
24725
- this.turnsByScope.set(scope, state);
24726
- return state;
24375
+ this.logOperationInput(
24376
+ event.operationId,
24377
+ event.input?.messages ?? event.input
24378
+ );
24379
+ this.turnsByKey.set(key, { metadata, span });
24727
24380
  }
24728
24381
  handleTurn(event) {
24729
- const scope = scopeKey(event);
24730
- const state = this.ensureTurnState(event);
24731
- const text = state.text.join("");
24732
- const reasoning = state.finalThinking ?? state.thinking.join("");
24733
- const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
24382
+ const key = turnKey(event);
24383
+ if (!key) {
24384
+ return;
24385
+ }
24386
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
24734
24387
  const metadata = {
24735
24388
  ...state.metadata,
24736
24389
  ...extractEventMetadata(event),
24390
+ ...event.api ? { "flue.api": event.api } : {},
24737
24391
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
24392
+ ...event.provider ? { provider: event.provider } : {},
24393
+ ...event.provider ? { "flue.provider": event.provider } : {},
24394
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24738
24395
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24739
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24740
- provider: "flue"
24396
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24741
24397
  };
24742
24398
  safeLog3(state.span, {
24743
- ...event.error ? { error: errorToString(event.error) } : {},
24399
+ ...event.isError ? { error: errorToString(event.error) } : {},
24744
24400
  metadata,
24745
24401
  metrics: {
24746
- ...durationMsMetrics(event.durationMs),
24747
- ...metricsFromUsage(event.usage)
24748
- },
24749
- output: toAssistantOutput(
24750
- text,
24751
- event.stopReason,
24752
- outputReasoning,
24753
- state.toolCalls
24754
- )
24755
- });
24756
- state.span.end();
24757
- this.turnsByScope.delete(scope);
24758
- }
24759
- handleThinkingDelta(event) {
24760
- const delta = event.delta;
24761
- if (typeof delta !== "string" || !delta) {
24762
- return;
24763
- }
24764
- const state = this.ensureTurnState(event);
24765
- state.hasThinking = true;
24766
- state.metadata["flue.thinking"] = true;
24767
- state.thinking.push(delta);
24768
- }
24769
- handleThinkingStart(event) {
24770
- const state = this.ensureTurnState(event);
24771
- state.hasThinking = true;
24772
- state.metadata["flue.thinking"] = true;
24773
- }
24774
- handleThinkingEnd(event) {
24775
- const state = this.ensureTurnState(event);
24776
- state.hasThinking = true;
24777
- state.metadata["flue.thinking"] = true;
24778
- if (typeof event.content === "string" && event.content) {
24779
- state.finalThinking = event.content;
24780
- }
24402
+ ...durationMetrics2(event.durationMs),
24403
+ ...metricsFromUsage(event.usage)
24404
+ },
24405
+ output: event.output
24406
+ });
24407
+ safeEnd(state.span, eventTime(event.timestamp));
24408
+ this.turnsByKey.delete(key);
24781
24409
  }
24782
- handleToolStart(event, options) {
24783
- const toolCallId = event.toolCallId;
24784
- if (!toolCallId) {
24410
+ handleToolStart(event) {
24411
+ if (!event.toolCallId) {
24785
24412
  return;
24786
24413
  }
24787
- const parent = this.parentSpanForEvent(event);
24788
- const scope = scopeKey(event);
24789
- let turnState = this.turnsByScope.get(scope);
24790
- if (!turnState && parent && options.captureTurnSpans) {
24791
- turnState = this.ensureTurnState(event);
24792
- }
24793
24414
  const metadata = {
24794
24415
  ...extractEventMetadata(event),
24795
24416
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24796
- "flue.tool_call_id": toolCallId,
24417
+ "flue.tool_call_id": event.toolCallId,
24797
24418
  provider: "flue"
24798
24419
  };
24420
+ const parent = this.parentSpanForTool(event);
24799
24421
  const span = startFlueSpan(parent, {
24800
- name: `tool: ${event.toolName ?? "unknown"}`,
24801
- spanAttributes: { type: "tool" /* TOOL */ }
24802
- });
24803
- if (turnState) {
24804
- turnState.toolCalls.push({
24805
- args: event.args,
24806
- toolCallId,
24807
- toolName: event.toolName
24808
- });
24809
- }
24810
- safeLog3(span, {
24811
- input: event.args,
24812
- metadata
24813
- });
24814
- this.toolsById.set(toolKey(event), {
24815
- metadata,
24816
- span,
24817
- startTime: getCurrentUnixTimestamp()
24422
+ name: `tool:${event.toolName ?? "unknown"}`,
24423
+ spanAttributes: { type: "tool" /* TOOL */ },
24424
+ startTime: eventTime(event.timestamp),
24425
+ event: {
24426
+ input: event.args,
24427
+ metadata
24428
+ }
24818
24429
  });
24430
+ this.toolsByKey.set(toolKey(event), { metadata, span });
24819
24431
  }
24820
24432
  handleToolCall(event) {
24433
+ if (!event.toolCallId) {
24434
+ return;
24435
+ }
24821
24436
  const key = toolKey(event);
24822
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24437
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
24823
24438
  const metadata = {
24824
24439
  ...state.metadata,
24825
24440
  ...extractEventMetadata(event),
24826
24441
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24827
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24442
+ "flue.tool_call_id": event.toolCallId,
24828
24443
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24829
24444
  };
24830
24445
  safeLog3(state.span, {
24831
24446
  ...event.isError ? { error: errorToString(event.result) } : {},
24832
24447
  metadata,
24833
- metrics: durationMsMetrics(event.durationMs),
24448
+ metrics: durationMetrics2(event.durationMs),
24834
24449
  output: event.result
24835
24450
  });
24836
- state.span.end();
24837
- this.toolsById.delete(key);
24451
+ safeEnd(state.span, eventTime(event.timestamp));
24452
+ this.toolsByKey.delete(key);
24838
24453
  }
24839
24454
  handleTaskStart(event) {
24840
- const parent = this.parentSpanForEvent(event);
24455
+ if (!event.taskId) {
24456
+ return;
24457
+ }
24841
24458
  const metadata = {
24842
24459
  ...extractEventMetadata(event),
24843
- ...event.role ? { "flue.role": event.role } : {},
24460
+ ...event.agent ? { "flue.agent": event.agent } : {},
24844
24461
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
24845
24462
  "flue.task_id": event.taskId,
24846
24463
  provider: "flue"
24847
24464
  };
24465
+ const parent = this.parentSpanForEvent(event);
24848
24466
  const span = startFlueSpan(parent, {
24849
- name: "flue.task",
24850
- spanAttributes: { type: "task" /* TASK */ }
24851
- });
24852
- safeLog3(span, {
24853
- input: event.prompt,
24854
- metadata
24855
- });
24856
- this.tasksById.set(event.taskId, {
24857
- metadata,
24858
- span,
24859
- startTime: getCurrentUnixTimestamp()
24467
+ name: event.agent ? `task:${event.agent}` : "flue.task",
24468
+ spanAttributes: { type: "task" /* TASK */ },
24469
+ startTime: eventTime(event.timestamp),
24470
+ event: {
24471
+ input: event.prompt,
24472
+ metadata
24473
+ }
24860
24474
  });
24475
+ this.tasksById.set(event.taskId, { metadata, span });
24861
24476
  }
24862
24477
  handleTask(event) {
24863
24478
  const state = this.tasksById.get(event.taskId);
@@ -24869,426 +24484,372 @@ var FluePlugin = class extends BasePlugin {
24869
24484
  metadata: {
24870
24485
  ...state.metadata,
24871
24486
  ...extractEventMetadata(event),
24487
+ ...event.agent ? { "flue.agent": event.agent } : {},
24872
24488
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24873
24489
  },
24874
- metrics: durationMsMetrics(event.durationMs),
24490
+ metrics: durationMetrics2(event.durationMs),
24875
24491
  output: event.result
24876
24492
  });
24877
- state.span.end();
24493
+ safeEnd(state.span, eventTime(event.timestamp));
24878
24494
  this.tasksById.delete(event.taskId);
24879
24495
  }
24880
24496
  handleCompactionStart(event) {
24881
- const operationState = this.operationStateForEvent(event);
24882
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
24497
+ const key = compactionKey(event);
24498
+ const input = {
24499
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
24500
+ ...event.reason ? { reason: event.reason } : {}
24501
+ };
24883
24502
  const metadata = {
24884
24503
  ...extractEventMetadata(event),
24885
24504
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24886
24505
  provider: "flue"
24887
24506
  };
24888
- const input = {
24889
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24890
- ...event.reason ? { reason: event.reason } : {}
24891
- };
24507
+ const parent = this.parentSpanForEvent(event);
24892
24508
  const span = startFlueSpan(parent, {
24893
- name: "flue.compaction",
24894
- spanAttributes: { type: "task" /* TASK */ }
24895
- });
24896
- safeLog3(span, {
24897
- input,
24898
- metadata
24899
- });
24900
- this.compactionsByScope.set(scopeKey(event), {
24901
- input,
24902
- metadata,
24903
- operationState,
24904
- span,
24905
- startTime: getCurrentUnixTimestamp()
24509
+ name: `compaction:${event.reason ?? "unknown"}`,
24510
+ spanAttributes: { type: "task" /* TASK */ },
24511
+ startTime: eventTime(event.timestamp),
24512
+ event: {
24513
+ input,
24514
+ metadata
24515
+ }
24906
24516
  });
24517
+ this.logOperationInput(event.operationId, input);
24518
+ this.compactionsByKey.set(key, { metadata, span });
24907
24519
  }
24908
24520
  handleCompaction(event) {
24909
- const key = scopeKey(event);
24910
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24911
- if (!state) {
24912
- return;
24913
- }
24521
+ const key = compactionKey(event);
24522
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
24523
+ const metadata = {
24524
+ ...state.metadata,
24525
+ ...extractEventMetadata(event),
24526
+ ...event.usage ? { "flue.usage": event.usage } : {}
24527
+ };
24914
24528
  safeLog3(state.span, {
24915
- metadata: {
24916
- ...state.metadata,
24917
- ...extractEventMetadata(event),
24918
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24919
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24920
- },
24529
+ metadata,
24921
24530
  metrics: {
24922
- ...durationMsMetrics(event.durationMs),
24923
- ...metricsFromUsage(event.usage)
24531
+ ...durationMetrics2(event.durationMs),
24532
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
24533
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
24924
24534
  },
24925
24535
  output: {
24926
24536
  messagesAfter: event.messagesAfter,
24927
24537
  messagesBefore: event.messagesBefore
24928
24538
  }
24929
24539
  });
24930
- state.span.end();
24931
- this.deleteCompactionState(state);
24540
+ safeEnd(state.span, eventTime(event.timestamp));
24541
+ this.compactionsByKey.delete(key);
24932
24542
  }
24933
- findCompactionState(event) {
24934
- const operationState = this.operationStateForEvent(event);
24935
- for (const state of this.compactionsByScope.values()) {
24936
- if (operationState && state.operationState === operationState) {
24937
- return state;
24543
+ parentSpanForTurn(event) {
24544
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
24545
+ const compaction = this.compactionsByKey.get(compactionKey(event));
24546
+ if (compaction) {
24547
+ return compaction.span;
24938
24548
  }
24939
24549
  }
24940
- return void 0;
24550
+ return this.parentSpanForEvent(event);
24941
24551
  }
24942
- finishCompactionsForOperation(operationState) {
24943
- for (const state of [...this.compactionsByScope.values()]) {
24944
- if (state.operationState !== operationState) {
24945
- continue;
24552
+ parentSpanForEvent(event) {
24553
+ const turn = turnKey(event);
24554
+ if (turn) {
24555
+ const turnState = this.turnsByKey.get(turn);
24556
+ if (turnState) {
24557
+ return turnState.span;
24946
24558
  }
24947
- safeLog3(state.span, {
24948
- input: state.input,
24949
- metadata: state.metadata,
24950
- metrics: {
24951
- ...buildDurationMetrics3(state.startTime)
24952
- },
24953
- output: { completed: true }
24954
- });
24955
- state.span.end();
24956
- this.deleteCompactionState(state);
24957
24559
  }
24958
- }
24959
- deleteCompactionState(state) {
24960
- for (const [key, candidate] of this.compactionsByScope) {
24961
- if (candidate !== state) {
24962
- continue;
24560
+ if (event.taskId) {
24561
+ const task = this.tasksById.get(event.taskId);
24562
+ if (task) {
24563
+ return task.span;
24963
24564
  }
24964
- this.compactionsByScope.delete(key);
24965
- return;
24966
24565
  }
24967
- }
24968
- startSyntheticToolState(event, toolName) {
24969
- const parent = this.parentSpanForEvent(event);
24970
- const metadata = {
24971
- ...extractEventMetadata(event),
24972
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24973
- "flue.tool_name": toolName,
24974
- provider: "flue"
24975
- };
24976
- const span = startFlueSpan(parent, {
24977
- name: `tool: ${toolName}`,
24978
- spanAttributes: { type: "tool" /* TOOL */ }
24979
- });
24980
- safeLog3(span, { metadata });
24981
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
24982
- }
24983
- operationStateForEvent(event) {
24984
24566
  if (event.operationId) {
24985
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24567
+ const operation = this.operationsById.get(event.operationId);
24986
24568
  if (operation) {
24987
- return operation;
24569
+ return operation.span;
24988
24570
  }
24989
24571
  }
24990
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24572
+ if (event.runId) {
24573
+ return this.runsById.get(event.runId)?.span;
24574
+ }
24575
+ return void 0;
24991
24576
  }
24992
- parentSpanForEvent(event) {
24577
+ parentSpanForTool(event) {
24578
+ if (event.taskId) {
24579
+ const task = this.tasksById.get(event.taskId);
24580
+ if (task) {
24581
+ return task.span;
24582
+ }
24583
+ }
24993
24584
  if (event.operationId) {
24994
- const operation = this.operationStateForEvent(event);
24585
+ const operation = this.operationsById.get(event.operationId);
24995
24586
  if (operation) {
24996
24587
  return operation.span;
24997
24588
  }
24998
24589
  }
24999
- if (event.taskId) {
25000
- return this.tasksById.get(event.taskId)?.span;
24590
+ if (event.runId) {
24591
+ return this.runsById.get(event.runId)?.span;
25001
24592
  }
25002
- return this.operationStateForEvent(event)?.span;
24593
+ return void 0;
25003
24594
  }
25004
- promotePendingOperationForEvent(event) {
25005
- if (!event.operationId) {
25006
- return void 0;
24595
+ logOperationInput(operationId, input) {
24596
+ if (!operationId || input === void 0) {
24597
+ return;
24598
+ }
24599
+ const operation = this.operationsById.get(operationId);
24600
+ if (!operation || operation.loggedInput) {
24601
+ return;
24602
+ }
24603
+ safeLog3(operation.span, { input });
24604
+ operation.loggedInput = true;
24605
+ }
24606
+ startSyntheticOperation(event) {
24607
+ const metadata = {
24608
+ ...extractEventMetadata(event),
24609
+ "flue.operation": event.operationKind,
24610
+ provider: "flue"
24611
+ };
24612
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24613
+ name: `flue.${event.operationKind}`,
24614
+ spanAttributes: { type: "task" /* TASK */ },
24615
+ startTime: eventTime(event.timestamp),
24616
+ event: { metadata }
24617
+ });
24618
+ return { metadata, span };
24619
+ }
24620
+ startSyntheticTurn(event) {
24621
+ const metadata = {
24622
+ ...extractEventMetadata(event),
24623
+ ...event.api ? { "flue.api": event.api } : {},
24624
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24625
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24626
+ ...event.provider ? { "flue.provider": event.provider } : {},
24627
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
24628
+ };
24629
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24630
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24631
+ spanAttributes: { type: "llm" /* LLM */ },
24632
+ startTime: eventTime(event.timestamp),
24633
+ event: { metadata }
24634
+ });
24635
+ return { metadata, span };
24636
+ }
24637
+ startSyntheticTool(event) {
24638
+ const metadata = {
24639
+ ...extractEventMetadata(event),
24640
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24641
+ "flue.tool_call_id": event.toolCallId,
24642
+ provider: "flue"
24643
+ };
24644
+ const span = startFlueSpan(this.parentSpanForTool(event), {
24645
+ name: `tool:${event.toolName ?? "unknown"}`,
24646
+ spanAttributes: { type: "tool" /* TOOL */ },
24647
+ startTime: eventTime(event.timestamp),
24648
+ event: { metadata }
24649
+ });
24650
+ return { metadata, span };
24651
+ }
24652
+ startSyntheticCompaction(event) {
24653
+ const metadata = {
24654
+ ...extractEventMetadata(event),
24655
+ provider: "flue"
24656
+ };
24657
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24658
+ name: "compaction:unknown",
24659
+ spanAttributes: { type: "task" /* TASK */ },
24660
+ startTime: eventTime(event.timestamp),
24661
+ event: { metadata }
24662
+ });
24663
+ return { metadata, span };
24664
+ }
24665
+ finishPendingChildrenForOperation(event, operationOutput2) {
24666
+ const endTime = eventTime(event.timestamp);
24667
+ const usage = event.usage ?? usageFromOperationResult(event.result);
24668
+ const turnEntries = [...this.turnsByKey].filter(
24669
+ ([, state]) => stateMatchesOperation(state, event.operationId)
24670
+ );
24671
+ turnEntries.forEach(([key, state], index) => {
24672
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
24673
+ safeLog3(state.span, {
24674
+ metadata: state.metadata,
24675
+ metrics: metricsFromUsage(usage),
24676
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
24677
+ });
24678
+ safeEnd(state.span, endTime);
24679
+ this.turnsByKey.delete(key);
24680
+ });
24681
+ for (const [key, state] of this.toolsByKey) {
24682
+ if (!stateMatchesOperation(state, event.operationId)) {
24683
+ continue;
24684
+ }
24685
+ safeEnd(state.span, endTime);
24686
+ this.toolsByKey.delete(key);
25007
24687
  }
25008
- const scopePrefixes = operationScopePrefixes(event);
25009
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25010
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24688
+ for (const [key, state] of this.tasksById) {
24689
+ if (!stateMatchesOperation(state, event.operationId)) {
25011
24690
  continue;
25012
24691
  }
25013
- const state = candidateQueue.shift();
25014
- if (!state) {
25015
- return void 0;
24692
+ safeEnd(state.span, endTime);
24693
+ this.tasksById.delete(key);
24694
+ }
24695
+ for (const [key, state] of this.compactionsByKey) {
24696
+ if (!stateMatchesOperation(state, event.operationId)) {
24697
+ continue;
25016
24698
  }
25017
- state.operationId = event.operationId;
25018
- this.activeOperationsById.set(event.operationId, state);
25019
- addScopedOperation(this.activeOperationsByScope, event, state);
25020
- state.metadata = {
25021
- ...state.metadata,
25022
- ...extractEventMetadata(event),
25023
- "flue.operation_id": event.operationId
25024
- };
25025
- safeLog3(state.span, { metadata: state.metadata });
25026
- return state;
24699
+ safeLog3(state.span, {
24700
+ metadata: state.metadata,
24701
+ metrics: durationMetrics2(event.durationMs),
24702
+ output: { completed: true }
24703
+ });
24704
+ safeEnd(state.span, eventTime(event.timestamp));
24705
+ this.compactionsByKey.delete(key);
25027
24706
  }
25028
- return void 0;
25029
24707
  }
25030
- activeOperationForEventScope(event) {
25031
- for (const scope of operationScopeNames(event)) {
25032
- const operations = this.activeOperationsByScope.get(scope);
25033
- if (operations?.length) {
25034
- return operations[operations.length - 1];
24708
+ finishPendingSpansForRun(event) {
24709
+ const endTime = eventTime(event.timestamp);
24710
+ for (const [key, state] of this.toolsByKey) {
24711
+ if (!stateMatchesRun(state, event.runId)) {
24712
+ continue;
25035
24713
  }
24714
+ safeEnd(state.span, endTime);
24715
+ this.toolsByKey.delete(key);
25036
24716
  }
25037
- return void 0;
25038
- }
25039
- pendingOperationForEventScope(event) {
25040
- const scopePrefixes = operationScopePrefixes(event);
25041
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25042
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24717
+ for (const [key, state] of this.turnsByKey) {
24718
+ if (!stateMatchesRun(state, event.runId)) {
25043
24719
  continue;
25044
24720
  }
25045
- return candidateQueue[0];
24721
+ safeEnd(state.span, endTime);
24722
+ this.turnsByKey.delete(key);
25046
24723
  }
25047
- return void 0;
25048
- }
25049
- takePendingOperationForEvent(event) {
25050
- const key = operationKey(event.session, event.operationKind);
25051
- const queue2 = this.pendingOperationsByKey.get(key);
25052
- if (queue2?.length) {
25053
- return queue2.shift();
24724
+ for (const [key, state] of this.tasksById) {
24725
+ if (!stateMatchesRun(state, event.runId)) {
24726
+ continue;
24727
+ }
24728
+ safeEnd(state.span, endTime);
24729
+ this.tasksById.delete(key);
25054
24730
  }
25055
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25056
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
25057
- return candidateQueue.shift();
24731
+ for (const [key, state] of this.compactionsByKey) {
24732
+ if (!stateMatchesRun(state, event.runId)) {
24733
+ continue;
25058
24734
  }
24735
+ safeLog3(state.span, {
24736
+ metadata: state.metadata,
24737
+ output: { completed: true }
24738
+ });
24739
+ safeEnd(state.span, endTime);
24740
+ this.compactionsByKey.delete(key);
25059
24741
  }
25060
- return void 0;
25061
- }
25062
- pendingOperationQueue(key) {
25063
- const existing = this.pendingOperationsByKey.get(key);
25064
- if (existing) {
25065
- return existing;
24742
+ for (const [key, state] of this.operationsById) {
24743
+ if (!stateMatchesRun(state, event.runId)) {
24744
+ continue;
24745
+ }
24746
+ safeLog3(state.span, {
24747
+ metadata: state.metadata,
24748
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
24749
+ });
24750
+ safeEnd(state.span, endTime);
24751
+ this.operationsById.delete(key);
25066
24752
  }
25067
- const queue2 = [];
25068
- this.pendingOperationsByKey.set(key, queue2);
25069
- return queue2;
25070
24753
  }
25071
24754
  };
25072
24755
  function isInstrumentedOperation(operation) {
25073
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
25074
- }
25075
- function getSessionName(session) {
25076
- return typeof session?.name === "string" ? session.name : void 0;
25077
- }
25078
- function operationKey(sessionName, operation) {
25079
- return `${sessionName ?? "unknown"}::${operation}`;
25080
- }
25081
- function operationScopePrefixes(event) {
25082
- const scopes = /* @__PURE__ */ new Set();
25083
- for (const scope of operationScopeNames(event)) {
25084
- scopes.add(`${scope}::`);
25085
- }
25086
- return scopes;
25087
- }
25088
- function operationKeyMatchesScopes(key, scopes) {
25089
- for (const scope of scopes) {
25090
- if (key.startsWith(scope)) {
25091
- return true;
25092
- }
25093
- }
25094
- return false;
25095
- }
25096
- function operationScopeNames(event) {
25097
- const scopes = /* @__PURE__ */ new Set();
25098
- if (event.session) {
25099
- scopes.add(event.session);
25100
- }
25101
- if (event.parentSession) {
25102
- scopes.add(event.parentSession);
25103
- }
25104
- if (!scopes.size) {
25105
- scopes.add("unknown");
25106
- }
25107
- return scopes;
25108
- }
25109
- function addScopedOperation(operationsByScope, event, state) {
25110
- for (const scope of operationScopeNames(event)) {
25111
- addOperationToScope(operationsByScope, scope, state);
25112
- }
25113
- }
25114
- function addOperationToScope(operationsByScope, scope, state) {
25115
- const operations = operationsByScope.get(scope);
25116
- if (operations) {
25117
- if (!operations.includes(state)) {
25118
- operations.push(state);
25119
- }
25120
- } else {
25121
- operationsByScope.set(scope, [state]);
25122
- }
25123
- }
25124
- function removeScopedOperation(operationsByScope, state) {
25125
- for (const [scope, operations] of operationsByScope) {
25126
- const index = operations.indexOf(state);
25127
- if (index === -1) {
25128
- continue;
25129
- }
25130
- operations.splice(index, 1);
25131
- if (operations.length === 0) {
25132
- operationsByScope.delete(scope);
25133
- }
25134
- }
25135
- }
25136
- function removePendingOperation(pendingOperationsByKey, state) {
25137
- for (const [key, queue2] of pendingOperationsByKey) {
25138
- const index = queue2.indexOf(state);
25139
- if (index === -1) {
25140
- continue;
25141
- }
25142
- queue2.splice(index, 1);
25143
- if (queue2.length === 0) {
25144
- pendingOperationsByKey.delete(key);
25145
- }
25146
- return;
25147
- }
25148
- }
25149
- function extractSessionMetadata(session) {
25150
- const sessionName = getSessionName(session);
25151
- return sessionName ? { "flue.session": sessionName } : {};
24756
+ return operation === "prompt" || operation === "skill" || operation === "compact";
25152
24757
  }
25153
- function extractEventMetadata(event) {
24758
+ function extractEventMetadata(event, ctx) {
25154
24759
  return {
25155
24760
  ...event.runId ? { "flue.run_id": event.runId } : {},
24761
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
24762
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
25156
24763
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
25157
24764
  ...event.session ? { "flue.session": event.session } : {},
25158
24765
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
25159
24766
  ...event.harness ? { "flue.harness": event.harness } : {},
25160
24767
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
25161
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24768
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
24769
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
24770
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
24771
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
25162
24772
  };
25163
24773
  }
25164
- function extractOperationInput(operation, args) {
25165
- switch (operation) {
25166
- case "prompt":
25167
- case "task":
25168
- return args[0];
25169
- case "skill":
25170
- return {
25171
- args: getOptionObject(args[1])?.args,
25172
- name: args[0]
25173
- };
25174
- case "compact":
25175
- return void 0;
24774
+ function extractPayloadMetadata(payload) {
24775
+ if (!isObjectLike(payload)) {
24776
+ return {};
25176
24777
  }
24778
+ const metadata = Reflect.get(payload, "metadata");
24779
+ if (!isObjectLike(metadata)) {
24780
+ return {};
24781
+ }
24782
+ return Object.fromEntries(Object.entries(metadata));
25177
24783
  }
25178
- function extractOperationInputMetadata(operation, args) {
25179
- const options = getOptionObject(args[1]);
25180
- return {
25181
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
25182
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
25183
- ...options?.role ? { "flue.role": options.role } : {},
25184
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
25185
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
25186
- ...Array.isArray(options?.tools) ? {
25187
- "flue.tools_count": options.tools.length,
25188
- tools: summarizeTools(options.tools)
25189
- } : {},
25190
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
25191
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
25192
- };
25193
- }
25194
- function getOptionObject(value) {
25195
- return isObject(value) ? value : void 0;
25196
- }
25197
- function summarizeTools(tools) {
25198
- return tools.flatMap((tool) => {
25199
- if (!isObject(tool)) {
25200
- return [];
25201
- }
25202
- const name = typeof tool.name === "string" ? tool.name : void 0;
25203
- if (!name) {
25204
- return [];
25205
- }
25206
- return [
25207
- {
25208
- function: {
25209
- description: typeof tool.description === "string" ? tool.description : void 0,
25210
- name,
25211
- parameters: tool.parameters
25212
- },
25213
- type: "function"
25214
- }
25215
- ];
25216
- });
24784
+ function operationOutput(event) {
24785
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
24786
+ return llmResultFromOperationResult(event.result);
24787
+ }
24788
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
25217
24789
  }
25218
- function extractPromptResponseMetadata(result) {
25219
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
25220
- return modelId ? {
25221
- model: modelId,
25222
- "flue.model": modelId
25223
- } : {};
24790
+ function llmResultFromOperationResult(result) {
24791
+ if (!isObjectLike(result)) {
24792
+ return result;
24793
+ }
24794
+ const text = Reflect.get(result, "text");
24795
+ return text === void 0 ? result : text;
25224
24796
  }
25225
- function extractOperationOutput(result) {
25226
- if (!result) {
24797
+ function usageFromOperationResult(result) {
24798
+ if (!isObjectLike(result)) {
25227
24799
  return void 0;
25228
24800
  }
25229
- if ("data" in result) {
25230
- return result.data;
25231
- }
25232
- if ("text" in result) {
25233
- return result.text;
25234
- }
25235
- return result;
24801
+ return Reflect.get(result, "usage");
25236
24802
  }
25237
24803
  function metricsFromUsage(usage) {
24804
+ if (!isObjectLike(usage)) {
24805
+ return {};
24806
+ }
24807
+ const cacheRead = Reflect.get(usage, "cacheRead");
24808
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
24809
+ const cost = Reflect.get(usage, "cost");
24810
+ const input = Reflect.get(usage, "input");
24811
+ const output = Reflect.get(usage, "output");
24812
+ const totalTokens = Reflect.get(usage, "totalTokens");
24813
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
25238
24814
  return {
25239
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
25240
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
25241
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
25242
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
25243
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
25244
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
25245
- };
25246
- }
25247
- function buildDurationMetrics3(startTime) {
25248
- return {
25249
- duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
24815
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
24816
+ ...typeof output === "number" ? { completion_tokens: output } : {},
24817
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
24818
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
24819
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
24820
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
25250
24821
  };
25251
24822
  }
25252
- function durationMsMetrics(durationMs) {
24823
+ function durationMetrics2(durationMs) {
25253
24824
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
25254
24825
  }
25255
- function scopeKey(event) {
25256
- if (event.operationId) {
25257
- return `operation:${event.operationId}`;
25258
- }
25259
- if (event.taskId) {
25260
- return `task:${event.taskId}`;
25261
- }
25262
- if (event.session) {
25263
- return `session:${event.session}`;
24826
+ function eventTime(value) {
24827
+ if (typeof value !== "string") {
24828
+ return void 0;
25264
24829
  }
25265
- return "flue:unknown";
24830
+ const timestamp = Date.parse(value);
24831
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
24832
+ }
24833
+ function turnKey(event) {
24834
+ return event.turnId;
25266
24835
  }
25267
24836
  function toolKey(event) {
25268
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24837
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
25269
24838
  }
25270
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24839
+ function compactionKey(event) {
25271
24840
  return [
25272
- {
25273
- finish_reason: finishReason ?? "stop",
25274
- index: 0,
25275
- message: {
25276
- content: text,
25277
- ...reasoning ? { reasoning } : {},
25278
- role: "assistant",
25279
- ...toolCalls?.length ? {
25280
- tool_calls: toolCalls.map((toolCall) => ({
25281
- function: {
25282
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
25283
- name: toolCall.toolName ?? "unknown"
25284
- },
25285
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
25286
- type: "function"
25287
- }))
25288
- } : {}
25289
- }
25290
- }
25291
- ];
24841
+ event.instanceId ?? "",
24842
+ event.runId ?? "",
24843
+ event.session ?? "",
24844
+ event.operationId ?? "",
24845
+ event.taskId ?? ""
24846
+ ].join(":");
24847
+ }
24848
+ function stateMatchesOperation(state, operationId) {
24849
+ return state.metadata["flue.operation_id"] === operationId;
24850
+ }
24851
+ function stateMatchesRun(state, runId) {
24852
+ return state.metadata["flue.run_id"] === runId;
25292
24853
  }
25293
24854
  function startFlueSpan(parent, args) {
25294
24855
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -25300,6 +24861,13 @@ function safeLog3(span, event) {
25300
24861
  logInstrumentationError3("Flue span log", error);
25301
24862
  }
25302
24863
  }
24864
+ function safeEnd(span, endTime) {
24865
+ try {
24866
+ span.end(endTime === void 0 ? void 0 : { endTime });
24867
+ } catch (error) {
24868
+ logInstrumentationError3("Flue span end", error);
24869
+ }
24870
+ }
25303
24871
  function errorToString(error) {
25304
24872
  if (error instanceof Error) {
25305
24873
  return error.message;
@@ -26234,6 +25802,7 @@ __export(exports_exports, {
26234
25802
  _internalIso: () => isomorph_default,
26235
25803
  _internalSetInitialState: () => _internalSetInitialState,
26236
25804
  addAzureBlobHeaders: () => addAzureBlobHeaders,
25805
+ braintrustFlueObserver: () => braintrustFlueObserver,
26237
25806
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
26238
25807
  buildLocalSummary: () => buildLocalSummary,
26239
25808
  configureInstrumentation: () => configureInstrumentation,
@@ -26313,8 +25882,6 @@ __export(exports_exports, {
26313
25882
  wrapCohere: () => wrapCohere,
26314
25883
  wrapCopilotClient: () => wrapCopilotClient,
26315
25884
  wrapCursorSDK: () => wrapCursorSDK,
26316
- wrapFlueContext: () => wrapFlueContext,
26317
- wrapFlueSession: () => wrapFlueSession,
26318
25885
  wrapGenkit: () => wrapGenkit,
26319
25886
  wrapGoogleADK: () => wrapGoogleADK,
26320
25887
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -33539,6 +33106,7 @@ export {
33539
33106
  isomorph_default as _internalIso,
33540
33107
  _internalSetInitialState,
33541
33108
  addAzureBlobHeaders,
33109
+ braintrustFlueObserver,
33542
33110
  braintrustStreamChunkSchema,
33543
33111
  buildLocalSummary,
33544
33112
  configureInstrumentation,
@@ -33619,8 +33187,6 @@ export {
33619
33187
  wrapCohere,
33620
33188
  wrapCopilotClient,
33621
33189
  wrapCursorSDK,
33622
- wrapFlueContext,
33623
- wrapFlueSession,
33624
33190
  wrapGenkit,
33625
33191
  wrapGoogleADK,
33626
33192
  wrapGoogleGenAI,