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