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