braintrust 3.14.0 → 3.16.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 +655 -1059
  2. package/dev/dist/index.mjs +613 -1017
  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 +10 -40
  19. package/dist/browser.d.mts +75 -18
  20. package/dist/browser.d.ts +75 -18
  21. package/dist/browser.js +616 -1042
  22. package/dist/browser.mjs +616 -1042
  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 +614 -1018
  26. package/dist/edge-light.d.mts +1 -1
  27. package/dist/edge-light.d.ts +1 -1
  28. package/dist/edge-light.js +616 -1042
  29. package/dist/edge-light.mjs +616 -1042
  30. package/dist/index.d.mts +75 -18
  31. package/dist/index.d.ts +75 -18
  32. package/dist/index.js +1007 -1409
  33. package/dist/index.mjs +620 -1022
  34. package/dist/instrumentation/index.d.mts +11 -1
  35. package/dist/instrumentation/index.d.ts +11 -1
  36. package/dist/instrumentation/index.js +616 -1016
  37. package/dist/instrumentation/index.mjs +615 -1016
  38. package/dist/workerd.d.mts +1 -1
  39. package/dist/workerd.d.ts +1 -1
  40. package/dist/workerd.js +616 -1042
  41. package/dist/workerd.mjs +616 -1042
  42. package/package.json +1 -1
@@ -60,6 +60,7 @@ __export(edge_light_exports, {
60
60
  LEGACY_CACHED_HEADER: () => LEGACY_CACHED_HEADER,
61
61
  LOGS3_OVERFLOW_REFERENCE_TYPE: () => LOGS3_OVERFLOW_REFERENCE_TYPE,
62
62
  LazyValue: () => LazyValue,
63
+ LocalTrace: () => LocalTrace,
63
64
  Logger: () => Logger,
64
65
  LoginInvalidOrgError: () => LoginInvalidOrgError,
65
66
  NOOP_SPAN: () => NOOP_SPAN,
@@ -85,6 +86,7 @@ __export(edge_light_exports, {
85
86
  _internalIso: () => isomorph_default,
86
87
  _internalSetInitialState: () => _internalSetInitialState,
87
88
  addAzureBlobHeaders: () => addAzureBlobHeaders,
89
+ braintrustFlueObserver: () => braintrustFlueObserver,
88
90
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
89
91
  buildLocalSummary: () => buildLocalSummary,
90
92
  configureInstrumentation: () => configureInstrumentation,
@@ -165,8 +167,6 @@ __export(edge_light_exports, {
165
167
  wrapCohere: () => wrapCohere,
166
168
  wrapCopilotClient: () => wrapCopilotClient,
167
169
  wrapCursorSDK: () => wrapCursorSDK,
168
- wrapFlueContext: () => wrapFlueContext,
169
- wrapFlueSession: () => wrapFlueSession,
170
170
  wrapGenkit: () => wrapGenkit,
171
171
  wrapGoogleADK: () => wrapGoogleADK,
172
172
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -3880,7 +3880,7 @@ function btStreamParser() {
3880
3880
  },
3881
3881
  async transform(chunk, controller) {
3882
3882
  if (chunk instanceof Uint8Array) {
3883
- parser.feed(decoder.decode(chunk));
3883
+ parser.feed(decoder.decode(chunk, { stream: true }));
3884
3884
  } else if (typeof chunk === "string") {
3885
3885
  parser.feed(chunk);
3886
3886
  } else {
@@ -3888,6 +3888,10 @@ function btStreamParser() {
3888
3888
  }
3889
3889
  },
3890
3890
  async flush(controller) {
3891
+ const tail = decoder.decode();
3892
+ if (tail) {
3893
+ parser.feed(tail);
3894
+ }
3891
3895
  controller.terminate();
3892
3896
  }
3893
3897
  });
@@ -24217,825 +24221,440 @@ var flueChannels = defineChannels("@flue/runtime", {
24217
24221
  createContext: channel({
24218
24222
  channelName: "createFlueContext",
24219
24223
  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
24224
  })
24245
24225
  });
24246
24226
 
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;
24227
+ // src/instrumentation/plugins/flue-plugin.ts
24228
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
24229
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
24230
+ var braintrustFlueObserver = (event, ctx) => {
24231
+ getObserveBridge().handle(event, ctx);
24232
+ };
24233
+ var FluePlugin = class extends BasePlugin {
24234
+ onEnable() {
24235
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
24258
24236
  }
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;
24237
+ onDisable() {
24238
+ for (const unsubscribe of this.unsubscribers) {
24239
+ unsubscribe();
24240
+ }
24241
+ this.unsubscribers = [];
24267
24242
  }
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 {
24243
+ };
24244
+ function enableFlueAutoInstrumentation() {
24245
+ const state = getAutoState();
24246
+ state.refCount += 1;
24247
+ if (!state.handlers) {
24248
+ const channel2 = flueChannels.createContext.tracingChannel();
24249
+ const handlers = {
24250
+ end: (event) => {
24251
+ subscribeToFlueContext(event.result, state);
24252
+ }
24253
+ };
24254
+ channel2.subscribe(handlers);
24255
+ state.channel = channel2;
24256
+ state.handlers = handlers;
24284
24257
  }
24285
- return ctx;
24258
+ let released = false;
24259
+ return () => {
24260
+ if (released) {
24261
+ return;
24262
+ }
24263
+ released = true;
24264
+ releaseAutoState(state);
24265
+ };
24286
24266
  }
24287
- function wrapFlueSession(session) {
24288
- if (!isPlausibleFlueSession(session)) {
24289
- console.warn("Unsupported Flue session. Not wrapping.");
24290
- return session;
24267
+ function getAutoState() {
24268
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
24269
+ if (isAutoState(existing)) {
24270
+ return existing;
24291
24271
  }
24292
- return patchFlueSessionInPlace(session);
24272
+ const state = {
24273
+ contexts: /* @__PURE__ */ new WeakSet(),
24274
+ refCount: 0
24275
+ };
24276
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
24277
+ return state;
24293
24278
  }
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;
24279
+ function getObserveBridge() {
24280
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
24281
+ if (isFlueObserveBridge(existing)) {
24282
+ return existing;
24334
24283
  }
24284
+ const bridge = new FlueObserveBridge();
24285
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
24286
+ return bridge;
24335
24287
  }
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;
24288
+ function isFlueObserveBridge(value) {
24289
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
24367
24290
  }
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;
24291
+ function isAutoState(value) {
24292
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
24385
24293
  }
24386
- function patchFlueSessionFactory(sessions, method) {
24387
- const original = sessions[method];
24388
- if (typeof original !== "function") {
24294
+ function releaseAutoState(state) {
24295
+ state.refCount -= 1;
24296
+ if (state.refCount > 0) {
24389
24297
  return;
24390
24298
  }
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;
24299
+ try {
24300
+ if (state.channel && state.handlers) {
24301
+ state.channel.unsubscribe(state.handlers);
24302
+ }
24303
+ } finally {
24304
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
24405
24305
  }
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
24306
  }
24424
- function patchCompact(session) {
24425
- const original = session.compact;
24426
- if (typeof original !== "function") {
24307
+ function subscribeToFlueContext(value, state) {
24308
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
24427
24309
  return;
24428
24310
  }
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 = () => {
24311
+ const ctx = flueContextFromUnknown(value);
24312
+ let released = false;
24313
+ let unsubscribe;
24314
+ const release = () => {
24315
+ if (released) {
24316
+ return;
24317
+ }
24318
+ released = true;
24449
24319
  try {
24450
- originalResult = args.run();
24451
- tracingChannel2.end?.publish(context);
24320
+ unsubscribe?.();
24452
24321
  } catch (error) {
24453
- context.error = normalizeError3(error);
24454
- tracingChannel2.error?.publish(context);
24455
- tracingChannel2.end?.publish(context);
24456
- throw error;
24322
+ logInstrumentationError3("Flue context unsubscribe", error);
24457
24323
  }
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
24324
  };
24474
- if (tracingChannel2.start?.runStores) {
24475
- tracingChannel2.start.runStores(context, run);
24476
- } else {
24477
- tracingChannel2.start?.publish(context);
24478
- run();
24325
+ try {
24326
+ unsubscribe = value.subscribeEvent((event) => {
24327
+ if (state.refCount <= 0) {
24328
+ release();
24329
+ return;
24330
+ }
24331
+ braintrustFlueObserver(event, ctx);
24332
+ if (isAutoContextTerminalEvent(event, ctx)) {
24333
+ release();
24334
+ }
24335
+ });
24336
+ state.contexts.add(value);
24337
+ } catch (error) {
24338
+ logInstrumentationError3("Flue context subscription", error);
24479
24339
  }
24480
- return { originalResult, traced: traced2 };
24481
24340
  }
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;
24341
+ function isAutoContextTerminalEvent(event, ctx) {
24342
+ if (!isObjectLike(event)) {
24343
+ return false;
24488
24344
  }
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;
24345
+ const type = Reflect.get(event, "type");
24346
+ if (type === "run_end") {
24347
+ return true;
24348
+ }
24349
+ if (type !== "operation") {
24350
+ return false;
24351
+ }
24352
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
24502
24353
  }
24503
- function isPlausibleFlueContext(value) {
24504
- return !!value && typeof value === "object" && typeof value.init === "function";
24354
+ function isObservableFlueContext(value) {
24355
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
24505
24356
  }
24506
- function isPlausibleFlueHarness(value) {
24507
- return !!value && typeof value === "object" && typeof value.session === "function";
24357
+ function isFlueEvent(event) {
24358
+ const type = Reflect.get(event, "type");
24359
+ 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
24360
  }
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";
24361
+ function flueContextFromUnknown(ctx) {
24362
+ if (!isObjectLike(ctx)) {
24363
+ return void 0;
24364
+ }
24365
+ const id = Reflect.get(ctx, "id");
24366
+ const runId = Reflect.get(ctx, "runId");
24367
+ return {
24368
+ ...typeof id === "string" ? { id } : {},
24369
+ ...typeof runId === "string" ? { runId } : {}
24370
+ };
24511
24371
  }
24512
- function isFlueCallHandle(value) {
24513
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
24372
+ function isObjectLike(value) {
24373
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24514
24374
  }
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();
24375
+ var FlueObserveBridge = class {
24376
+ compactionsByKey = /* @__PURE__ */ new Map();
24377
+ operationsById = /* @__PURE__ */ new Map();
24378
+ runsById = /* @__PURE__ */ new Map();
24379
+ seenEvents = /* @__PURE__ */ new WeakSet();
24522
24380
  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();
24381
+ toolsByKey = /* @__PURE__ */ new Map();
24382
+ turnsByKey = /* @__PURE__ */ new Map();
24383
+ handle(event, ctx) {
24384
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
24385
+ return;
24534
24386
  }
24535
- this.unsubscribers = [];
24536
- this.activeOperationsById.clear();
24537
- this.activeOperationsByScope.clear();
24538
- this.compactionsByScope.clear();
24539
- this.pendingOperationsByKey.clear();
24387
+ if (this.seenEvents.has(event)) {
24388
+ return;
24389
+ }
24390
+ this.seenEvents.add(event);
24391
+ try {
24392
+ this.handleEvent(event, flueContextFromUnknown(ctx));
24393
+ } catch (error) {
24394
+ logInstrumentationError3("Flue observe", error);
24395
+ }
24396
+ }
24397
+ reset() {
24398
+ this.compactionsByKey.clear();
24399
+ this.operationsById.clear();
24400
+ this.runsById.clear();
24401
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
24540
24402
  this.tasksById.clear();
24541
- this.toolsById.clear();
24542
- this.turnsByScope.clear();
24403
+ this.toolsByKey.clear();
24404
+ this.turnsByKey.clear();
24543
24405
  }
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
- });
24406
+ handleEvent(event, ctx) {
24407
+ switch (event.type) {
24408
+ case "run_start":
24409
+ this.handleRunStart(event, ctx);
24410
+ return;
24411
+ case "run_end":
24412
+ this.handleRunEnd(event);
24413
+ return;
24414
+ case "operation_start":
24415
+ this.handleOperationStart(event);
24416
+ return;
24417
+ case "operation":
24418
+ this.handleOperation(event);
24419
+ return;
24420
+ case "turn_request":
24421
+ this.handleTurnRequest(event);
24422
+ return;
24423
+ case "turn":
24424
+ this.handleTurn(event);
24425
+ return;
24426
+ case "tool_start":
24427
+ this.handleToolStart(event);
24428
+ return;
24429
+ case "tool_call":
24430
+ this.handleToolCall(event);
24431
+ return;
24432
+ case "task_start":
24433
+ this.handleTaskStart(event);
24434
+ return;
24435
+ case "task":
24436
+ this.handleTask(event);
24437
+ return;
24438
+ case "compaction_start":
24439
+ this.handleCompactionStart(event);
24440
+ return;
24441
+ case "compaction":
24442
+ this.handleCompaction(event);
24443
+ return;
24444
+ default:
24445
+ return;
24446
+ }
24562
24447
  }
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
- }
24448
+ handleRunStart(event, ctx) {
24449
+ if (!event.runId) {
24450
+ return;
24451
+ }
24452
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
24453
+ const metadata = {
24454
+ ...extractPayloadMetadata(event.payload),
24455
+ ...extractEventMetadata(event, ctx),
24456
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
24457
+ provider: "flue"
24578
24458
  };
24579
- channel2.subscribe(handlers);
24580
- this.unsubscribers.push(() => {
24581
- channel2.unsubscribe(handlers);
24459
+ const span = startSpan({
24460
+ name: `workflow:${workflowName}`,
24461
+ spanAttributes: { type: "task" /* TASK */ },
24462
+ startTime: eventTime(event.startedAt ?? event.timestamp),
24463
+ event: {
24464
+ input: event.payload,
24465
+ metadata
24466
+ }
24582
24467
  });
24468
+ this.runsById.set(event.runId, { metadata, span });
24583
24469
  }
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
24470
+ handleRunEnd(event) {
24471
+ const state = this.runsById.get(event.runId);
24472
+ this.finishPendingSpansForRun(event);
24473
+ if (state) {
24474
+ safeLog3(state.span, {
24475
+ ...event.isError ? { error: errorToString(event.error) } : {},
24476
+ metadata: {
24477
+ ...state.metadata,
24478
+ ...extractEventMetadata(event),
24479
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24480
+ },
24481
+ metrics: durationMetrics2(event.durationMs),
24482
+ output: event.result
24603
24483
  });
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);
24484
+ safeEnd(state.span, eventTime(event.timestamp));
24485
+ this.runsById.delete(event.runId);
24486
+ }
24487
+ void flush().catch((error) => {
24488
+ logInstrumentationError3("Flue flush", error);
24632
24489
  });
24633
24490
  }
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;
24709
- }
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) {
24754
- return;
24755
- }
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);
24776
- }
24777
- removeScopedOperation(this.activeOperationsByScope, state);
24778
- state.span.end();
24779
- }
24780
- handleFlueEvent(event, options) {
24781
- switch (event.type) {
24782
- case "operation_start":
24783
- this.handleOperationStart(event);
24784
- return;
24785
- case "operation":
24786
- this.handleOperation(event);
24787
- 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);
24813
- return;
24814
- case "turn":
24815
- if (!options.captureTurnSpans) {
24816
- return;
24817
- }
24818
- this.handleTurn(event);
24819
- return;
24820
- case "tool_start":
24821
- this.handleToolStart(event, options);
24822
- return;
24823
- case "tool_call":
24824
- this.handleToolCall(event);
24825
- return;
24826
- case "task_start":
24827
- this.handleTaskStart(event);
24828
- return;
24829
- case "task":
24830
- this.handleTask(event);
24831
- return;
24832
- case "compaction_start":
24833
- this.handleCompactionStart(event);
24834
- return;
24835
- case "compaction":
24836
- this.handleCompaction(event);
24837
- return;
24838
- default:
24839
- return;
24840
- }
24841
- }
24842
24491
  handleOperationStart(event) {
24843
- if (!isInstrumentedOperation(event.operationKind)) {
24844
- return;
24845
- }
24846
- const state = this.takePendingOperationForEvent(event);
24847
- if (!state) {
24492
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
24848
24493
  return;
24849
24494
  }
24850
- state.operationId = event.operationId;
24851
- this.activeOperationsById.set(event.operationId, state);
24852
- addScopedOperation(this.activeOperationsByScope, event, state);
24853
- state.metadata = {
24854
- ...state.metadata,
24495
+ const metadata = {
24855
24496
  ...extractEventMetadata(event),
24856
- "flue.operation_id": event.operationId
24497
+ "flue.operation": event.operationKind,
24498
+ provider: "flue"
24857
24499
  };
24858
- safeLog3(state.span, { metadata: state.metadata });
24500
+ const parent = this.parentSpanForEvent(event);
24501
+ const span = startFlueSpan(parent, {
24502
+ name: `flue.${event.operationKind}`,
24503
+ spanAttributes: { type: "task" /* TASK */ },
24504
+ startTime: eventTime(event.timestamp),
24505
+ event: { metadata }
24506
+ });
24507
+ this.operationsById.set(event.operationId, { metadata, span });
24859
24508
  }
24860
24509
  handleOperation(event) {
24861
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24862
- if (!state) {
24510
+ if (!isInstrumentedOperation(event.operationKind)) {
24863
24511
  return;
24864
24512
  }
24513
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
24514
+ const output = operationOutput(event);
24865
24515
  const metadata = {
24866
24516
  ...state.metadata,
24867
24517
  ...extractEventMetadata(event),
24868
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24869
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24518
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24519
+ ...event.usage ? { "flue.usage": event.usage } : {}
24870
24520
  };
24871
- const metrics = metricsFromUsage(event.usage);
24521
+ this.finishPendingChildrenForOperation(event, output);
24872
24522
  safeLog3(state.span, {
24873
- ...event.error ? { error: errorToString(event.error) } : {},
24523
+ ...event.isError ? { error: errorToString(event.error) } : {},
24874
24524
  metadata,
24875
- ...Object.keys(metrics).length ? { metrics } : {}
24525
+ metrics: durationMetrics2(event.durationMs),
24526
+ output
24876
24527
  });
24528
+ safeEnd(state.span, eventTime(event.timestamp));
24529
+ this.operationsById.delete(event.operationId);
24877
24530
  }
24878
- ensureTurnState(event) {
24879
- const scope = scopeKey(event);
24880
- const existing = this.turnsByScope.get(scope);
24881
- if (existing) {
24882
- return existing;
24531
+ handleTurnRequest(event) {
24532
+ const key = turnKey(event);
24533
+ if (!key) {
24534
+ return;
24883
24535
  }
24884
- const parent = this.parentSpanForEvent(event);
24885
24536
  const metadata = {
24886
24537
  ...extractEventMetadata(event),
24887
- provider: "flue"
24538
+ ...event.api ? { "flue.api": event.api } : {},
24539
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24540
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24541
+ ...event.provider ? { "flue.provider": event.provider } : {},
24542
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24543
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
24544
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
24545
+ ...event.input?.tools ? { tools: event.input.tools } : {}
24888
24546
  };
24547
+ const parent = this.parentSpanForTurn(event);
24889
24548
  const span = startFlueSpan(parent, {
24890
- name: "flue.turn",
24891
- spanAttributes: { type: "llm" /* LLM */ }
24549
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24550
+ spanAttributes: { type: "llm" /* LLM */ },
24551
+ startTime: eventTime(event.timestamp),
24552
+ event: {
24553
+ input: event.input?.messages,
24554
+ metadata
24555
+ }
24892
24556
  });
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;
24557
+ this.logOperationInput(
24558
+ event.operationId,
24559
+ event.input?.messages ?? event.input
24560
+ );
24561
+ this.turnsByKey.set(key, { metadata, span });
24905
24562
  }
24906
24563
  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);
24564
+ const key = turnKey(event);
24565
+ if (!key) {
24566
+ return;
24567
+ }
24568
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
24912
24569
  const metadata = {
24913
24570
  ...state.metadata,
24914
24571
  ...extractEventMetadata(event),
24572
+ ...event.api ? { "flue.api": event.api } : {},
24915
24573
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
24574
+ ...event.provider ? { provider: event.provider } : {},
24575
+ ...event.provider ? { "flue.provider": event.provider } : {},
24576
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24916
24577
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24917
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24918
- provider: "flue"
24578
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24919
24579
  };
24920
24580
  safeLog3(state.span, {
24921
- ...event.error ? { error: errorToString(event.error) } : {},
24581
+ ...event.isError ? { error: errorToString(event.error) } : {},
24922
24582
  metadata,
24923
24583
  metrics: {
24924
- ...durationMsMetrics(event.durationMs),
24584
+ ...durationMetrics2(event.durationMs),
24925
24585
  ...metricsFromUsage(event.usage)
24926
24586
  },
24927
- output: toAssistantOutput(
24928
- text,
24929
- event.stopReason,
24930
- outputReasoning,
24931
- state.toolCalls
24932
- )
24587
+ output: event.output
24933
24588
  });
24934
- state.span.end();
24935
- this.turnsByScope.delete(scope);
24589
+ safeEnd(state.span, eventTime(event.timestamp));
24590
+ this.turnsByKey.delete(key);
24936
24591
  }
24937
- handleThinkingDelta(event) {
24938
- const delta = event.delta;
24939
- if (typeof delta !== "string" || !delta) {
24592
+ handleToolStart(event) {
24593
+ if (!event.toolCallId) {
24940
24594
  return;
24941
24595
  }
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
- }
24959
- }
24960
- handleToolStart(event, options) {
24961
- const toolCallId = event.toolCallId;
24962
- if (!toolCallId) {
24963
- return;
24964
- }
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
24596
  const metadata = {
24972
24597
  ...extractEventMetadata(event),
24973
24598
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24974
- "flue.tool_call_id": toolCallId,
24599
+ "flue.tool_call_id": event.toolCallId,
24975
24600
  provider: "flue"
24976
24601
  };
24602
+ const parent = this.parentSpanForTool(event);
24977
24603
  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()
24604
+ name: `tool:${event.toolName ?? "unknown"}`,
24605
+ spanAttributes: { type: "tool" /* TOOL */ },
24606
+ startTime: eventTime(event.timestamp),
24607
+ event: {
24608
+ input: event.args,
24609
+ metadata
24610
+ }
24996
24611
  });
24612
+ this.toolsByKey.set(toolKey(event), { metadata, span });
24997
24613
  }
24998
24614
  handleToolCall(event) {
24615
+ if (!event.toolCallId) {
24616
+ return;
24617
+ }
24999
24618
  const key = toolKey(event);
25000
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24619
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
25001
24620
  const metadata = {
25002
24621
  ...state.metadata,
25003
24622
  ...extractEventMetadata(event),
25004
24623
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
25005
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24624
+ "flue.tool_call_id": event.toolCallId,
25006
24625
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
25007
24626
  };
25008
24627
  safeLog3(state.span, {
25009
24628
  ...event.isError ? { error: errorToString(event.result) } : {},
25010
24629
  metadata,
25011
- metrics: durationMsMetrics(event.durationMs),
24630
+ metrics: durationMetrics2(event.durationMs),
25012
24631
  output: event.result
25013
24632
  });
25014
- state.span.end();
25015
- this.toolsById.delete(key);
24633
+ safeEnd(state.span, eventTime(event.timestamp));
24634
+ this.toolsByKey.delete(key);
25016
24635
  }
25017
24636
  handleTaskStart(event) {
25018
- const parent = this.parentSpanForEvent(event);
24637
+ if (!event.taskId) {
24638
+ return;
24639
+ }
25019
24640
  const metadata = {
25020
24641
  ...extractEventMetadata(event),
25021
- ...event.role ? { "flue.role": event.role } : {},
24642
+ ...event.agent ? { "flue.agent": event.agent } : {},
25022
24643
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
25023
24644
  "flue.task_id": event.taskId,
25024
24645
  provider: "flue"
25025
24646
  };
24647
+ const parent = this.parentSpanForEvent(event);
25026
24648
  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()
24649
+ name: event.agent ? `task:${event.agent}` : "flue.task",
24650
+ spanAttributes: { type: "task" /* TASK */ },
24651
+ startTime: eventTime(event.timestamp),
24652
+ event: {
24653
+ input: event.prompt,
24654
+ metadata
24655
+ }
25038
24656
  });
24657
+ this.tasksById.set(event.taskId, { metadata, span });
25039
24658
  }
25040
24659
  handleTask(event) {
25041
24660
  const state = this.tasksById.get(event.taskId);
@@ -25047,426 +24666,372 @@ var FluePlugin = class extends BasePlugin {
25047
24666
  metadata: {
25048
24667
  ...state.metadata,
25049
24668
  ...extractEventMetadata(event),
24669
+ ...event.agent ? { "flue.agent": event.agent } : {},
25050
24670
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
25051
24671
  },
25052
- metrics: durationMsMetrics(event.durationMs),
24672
+ metrics: durationMetrics2(event.durationMs),
25053
24673
  output: event.result
25054
24674
  });
25055
- state.span.end();
24675
+ safeEnd(state.span, eventTime(event.timestamp));
25056
24676
  this.tasksById.delete(event.taskId);
25057
24677
  }
25058
24678
  handleCompactionStart(event) {
25059
- const operationState = this.operationStateForEvent(event);
25060
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
24679
+ const key = compactionKey(event);
24680
+ const input = {
24681
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
24682
+ ...event.reason ? { reason: event.reason } : {}
24683
+ };
25061
24684
  const metadata = {
25062
24685
  ...extractEventMetadata(event),
25063
24686
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
25064
24687
  provider: "flue"
25065
24688
  };
25066
- const input = {
25067
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
25068
- ...event.reason ? { reason: event.reason } : {}
25069
- };
24689
+ const parent = this.parentSpanForEvent(event);
25070
24690
  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()
24691
+ name: `compaction:${event.reason ?? "unknown"}`,
24692
+ spanAttributes: { type: "task" /* TASK */ },
24693
+ startTime: eventTime(event.timestamp),
24694
+ event: {
24695
+ input,
24696
+ metadata
24697
+ }
25084
24698
  });
24699
+ this.logOperationInput(event.operationId, input);
24700
+ this.compactionsByKey.set(key, { metadata, span });
25085
24701
  }
25086
24702
  handleCompaction(event) {
25087
- const key = scopeKey(event);
25088
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
25089
- if (!state) {
25090
- return;
25091
- }
24703
+ const key = compactionKey(event);
24704
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
24705
+ const metadata = {
24706
+ ...state.metadata,
24707
+ ...extractEventMetadata(event),
24708
+ ...event.usage ? { "flue.usage": event.usage } : {}
24709
+ };
25092
24710
  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
- },
24711
+ metadata,
25099
24712
  metrics: {
25100
- ...durationMsMetrics(event.durationMs),
25101
- ...metricsFromUsage(event.usage)
24713
+ ...durationMetrics2(event.durationMs),
24714
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
24715
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
25102
24716
  },
25103
24717
  output: {
25104
24718
  messagesAfter: event.messagesAfter,
25105
24719
  messagesBefore: event.messagesBefore
25106
24720
  }
25107
24721
  });
25108
- state.span.end();
25109
- this.deleteCompactionState(state);
24722
+ safeEnd(state.span, eventTime(event.timestamp));
24723
+ this.compactionsByKey.delete(key);
25110
24724
  }
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;
24725
+ parentSpanForTurn(event) {
24726
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
24727
+ const compaction = this.compactionsByKey.get(compactionKey(event));
24728
+ if (compaction) {
24729
+ return compaction.span;
25116
24730
  }
25117
24731
  }
25118
- return void 0;
24732
+ return this.parentSpanForEvent(event);
25119
24733
  }
25120
- finishCompactionsForOperation(operationState) {
25121
- for (const state of [...this.compactionsByScope.values()]) {
25122
- if (state.operationState !== operationState) {
25123
- continue;
24734
+ parentSpanForEvent(event) {
24735
+ const turn = turnKey(event);
24736
+ if (turn) {
24737
+ const turnState = this.turnsByKey.get(turn);
24738
+ if (turnState) {
24739
+ return turnState.span;
25124
24740
  }
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
24741
  }
25136
- }
25137
- deleteCompactionState(state) {
25138
- for (const [key, candidate] of this.compactionsByScope) {
25139
- if (candidate !== state) {
25140
- continue;
24742
+ if (event.taskId) {
24743
+ const task = this.tasksById.get(event.taskId);
24744
+ if (task) {
24745
+ return task.span;
25141
24746
  }
25142
- this.compactionsByScope.delete(key);
25143
- return;
25144
24747
  }
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
24748
  if (event.operationId) {
25163
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24749
+ const operation = this.operationsById.get(event.operationId);
25164
24750
  if (operation) {
25165
- return operation;
24751
+ return operation.span;
25166
24752
  }
25167
24753
  }
25168
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24754
+ if (event.runId) {
24755
+ return this.runsById.get(event.runId)?.span;
24756
+ }
24757
+ return void 0;
25169
24758
  }
25170
- parentSpanForEvent(event) {
24759
+ parentSpanForTool(event) {
24760
+ if (event.taskId) {
24761
+ const task = this.tasksById.get(event.taskId);
24762
+ if (task) {
24763
+ return task.span;
24764
+ }
24765
+ }
25171
24766
  if (event.operationId) {
25172
- const operation = this.operationStateForEvent(event);
24767
+ const operation = this.operationsById.get(event.operationId);
25173
24768
  if (operation) {
25174
24769
  return operation.span;
25175
24770
  }
25176
24771
  }
25177
- if (event.taskId) {
25178
- return this.tasksById.get(event.taskId)?.span;
24772
+ if (event.runId) {
24773
+ return this.runsById.get(event.runId)?.span;
25179
24774
  }
25180
- return this.operationStateForEvent(event)?.span;
24775
+ return void 0;
25181
24776
  }
25182
- promotePendingOperationForEvent(event) {
25183
- if (!event.operationId) {
25184
- return void 0;
24777
+ logOperationInput(operationId, input) {
24778
+ if (!operationId || input === void 0) {
24779
+ return;
25185
24780
  }
25186
- const scopePrefixes = operationScopePrefixes(event);
25187
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25188
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24781
+ const operation = this.operationsById.get(operationId);
24782
+ if (!operation || operation.loggedInput) {
24783
+ return;
24784
+ }
24785
+ safeLog3(operation.span, { input });
24786
+ operation.loggedInput = true;
24787
+ }
24788
+ startSyntheticOperation(event) {
24789
+ const metadata = {
24790
+ ...extractEventMetadata(event),
24791
+ "flue.operation": event.operationKind,
24792
+ provider: "flue"
24793
+ };
24794
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24795
+ name: `flue.${event.operationKind}`,
24796
+ spanAttributes: { type: "task" /* TASK */ },
24797
+ startTime: eventTime(event.timestamp),
24798
+ event: { metadata }
24799
+ });
24800
+ return { metadata, span };
24801
+ }
24802
+ startSyntheticTurn(event) {
24803
+ const metadata = {
24804
+ ...extractEventMetadata(event),
24805
+ ...event.api ? { "flue.api": event.api } : {},
24806
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24807
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24808
+ ...event.provider ? { "flue.provider": event.provider } : {},
24809
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
24810
+ };
24811
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24812
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24813
+ spanAttributes: { type: "llm" /* LLM */ },
24814
+ startTime: eventTime(event.timestamp),
24815
+ event: { metadata }
24816
+ });
24817
+ return { metadata, span };
24818
+ }
24819
+ startSyntheticTool(event) {
24820
+ const metadata = {
24821
+ ...extractEventMetadata(event),
24822
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24823
+ "flue.tool_call_id": event.toolCallId,
24824
+ provider: "flue"
24825
+ };
24826
+ const span = startFlueSpan(this.parentSpanForTool(event), {
24827
+ name: `tool:${event.toolName ?? "unknown"}`,
24828
+ spanAttributes: { type: "tool" /* TOOL */ },
24829
+ startTime: eventTime(event.timestamp),
24830
+ event: { metadata }
24831
+ });
24832
+ return { metadata, span };
24833
+ }
24834
+ startSyntheticCompaction(event) {
24835
+ const metadata = {
24836
+ ...extractEventMetadata(event),
24837
+ provider: "flue"
24838
+ };
24839
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24840
+ name: "compaction:unknown",
24841
+ spanAttributes: { type: "task" /* TASK */ },
24842
+ startTime: eventTime(event.timestamp),
24843
+ event: { metadata }
24844
+ });
24845
+ return { metadata, span };
24846
+ }
24847
+ finishPendingChildrenForOperation(event, operationOutput2) {
24848
+ const endTime = eventTime(event.timestamp);
24849
+ const usage = event.usage ?? usageFromOperationResult(event.result);
24850
+ const turnEntries = [...this.turnsByKey].filter(
24851
+ ([, state]) => stateMatchesOperation(state, event.operationId)
24852
+ );
24853
+ turnEntries.forEach(([key, state], index) => {
24854
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
24855
+ safeLog3(state.span, {
24856
+ metadata: state.metadata,
24857
+ metrics: metricsFromUsage(usage),
24858
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
24859
+ });
24860
+ safeEnd(state.span, endTime);
24861
+ this.turnsByKey.delete(key);
24862
+ });
24863
+ for (const [key, state] of this.toolsByKey) {
24864
+ if (!stateMatchesOperation(state, event.operationId)) {
25189
24865
  continue;
25190
24866
  }
25191
- const state = candidateQueue.shift();
25192
- if (!state) {
25193
- return void 0;
24867
+ safeEnd(state.span, endTime);
24868
+ this.toolsByKey.delete(key);
24869
+ }
24870
+ for (const [key, state] of this.tasksById) {
24871
+ if (!stateMatchesOperation(state, event.operationId)) {
24872
+ continue;
25194
24873
  }
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;
24874
+ safeEnd(state.span, endTime);
24875
+ this.tasksById.delete(key);
25205
24876
  }
25206
- return void 0;
25207
- }
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];
24877
+ for (const [key, state] of this.compactionsByKey) {
24878
+ if (!stateMatchesOperation(state, event.operationId)) {
24879
+ continue;
25213
24880
  }
24881
+ safeLog3(state.span, {
24882
+ metadata: state.metadata,
24883
+ metrics: durationMetrics2(event.durationMs),
24884
+ output: { completed: true }
24885
+ });
24886
+ safeEnd(state.span, eventTime(event.timestamp));
24887
+ this.compactionsByKey.delete(key);
25214
24888
  }
25215
- return void 0;
25216
24889
  }
25217
- pendingOperationForEventScope(event) {
25218
- const scopePrefixes = operationScopePrefixes(event);
25219
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25220
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24890
+ finishPendingSpansForRun(event) {
24891
+ const endTime = eventTime(event.timestamp);
24892
+ for (const [key, state] of this.toolsByKey) {
24893
+ if (!stateMatchesRun(state, event.runId)) {
25221
24894
  continue;
25222
24895
  }
25223
- return candidateQueue[0];
24896
+ safeEnd(state.span, endTime);
24897
+ this.toolsByKey.delete(key);
25224
24898
  }
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();
24899
+ for (const [key, state] of this.turnsByKey) {
24900
+ if (!stateMatchesRun(state, event.runId)) {
24901
+ continue;
24902
+ }
24903
+ safeEnd(state.span, endTime);
24904
+ this.turnsByKey.delete(key);
25232
24905
  }
25233
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25234
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
25235
- return candidateQueue.shift();
24906
+ for (const [key, state] of this.tasksById) {
24907
+ if (!stateMatchesRun(state, event.runId)) {
24908
+ continue;
25236
24909
  }
24910
+ safeEnd(state.span, endTime);
24911
+ this.tasksById.delete(key);
25237
24912
  }
25238
- return void 0;
25239
- }
25240
- pendingOperationQueue(key) {
25241
- const existing = this.pendingOperationsByKey.get(key);
25242
- if (existing) {
25243
- return existing;
24913
+ for (const [key, state] of this.compactionsByKey) {
24914
+ if (!stateMatchesRun(state, event.runId)) {
24915
+ continue;
24916
+ }
24917
+ safeLog3(state.span, {
24918
+ metadata: state.metadata,
24919
+ output: { completed: true }
24920
+ });
24921
+ safeEnd(state.span, endTime);
24922
+ this.compactionsByKey.delete(key);
24923
+ }
24924
+ for (const [key, state] of this.operationsById) {
24925
+ if (!stateMatchesRun(state, event.runId)) {
24926
+ continue;
24927
+ }
24928
+ safeLog3(state.span, {
24929
+ metadata: state.metadata,
24930
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
24931
+ });
24932
+ safeEnd(state.span, endTime);
24933
+ this.operationsById.delete(key);
25244
24934
  }
25245
- const queue2 = [];
25246
- this.pendingOperationsByKey.set(key, queue2);
25247
- return queue2;
25248
24935
  }
25249
24936
  };
25250
24937
  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;
24938
+ return operation === "prompt" || operation === "skill" || operation === "compact";
25265
24939
  }
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 } : {};
25330
- }
25331
- function extractEventMetadata(event) {
24940
+ function extractEventMetadata(event, ctx) {
25332
24941
  return {
25333
24942
  ...event.runId ? { "flue.run_id": event.runId } : {},
24943
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
24944
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
25334
24945
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
25335
24946
  ...event.session ? { "flue.session": event.session } : {},
25336
24947
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
25337
24948
  ...event.harness ? { "flue.harness": event.harness } : {},
25338
24949
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
25339
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24950
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
24951
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
24952
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
24953
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
25340
24954
  };
25341
24955
  }
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;
24956
+ function extractPayloadMetadata(payload) {
24957
+ if (!isObjectLike(payload)) {
24958
+ return {};
25354
24959
  }
24960
+ const metadata = Reflect.get(payload, "metadata");
24961
+ if (!isObjectLike(metadata)) {
24962
+ return {};
24963
+ }
24964
+ return Object.fromEntries(Object.entries(metadata));
25355
24965
  }
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
- });
24966
+ function operationOutput(event) {
24967
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
24968
+ return llmResultFromOperationResult(event.result);
24969
+ }
24970
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
25395
24971
  }
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
- } : {};
24972
+ function llmResultFromOperationResult(result) {
24973
+ if (!isObjectLike(result)) {
24974
+ return result;
24975
+ }
24976
+ const text = Reflect.get(result, "text");
24977
+ return text === void 0 ? result : text;
25402
24978
  }
25403
- function extractOperationOutput(result) {
25404
- if (!result) {
24979
+ function usageFromOperationResult(result) {
24980
+ if (!isObjectLike(result)) {
25405
24981
  return void 0;
25406
24982
  }
25407
- if ("data" in result) {
25408
- return result.data;
25409
- }
25410
- if ("text" in result) {
25411
- return result.text;
25412
- }
25413
- return result;
24983
+ return Reflect.get(result, "usage");
25414
24984
  }
25415
24985
  function metricsFromUsage(usage) {
24986
+ if (!isObjectLike(usage)) {
24987
+ return {};
24988
+ }
24989
+ const cacheRead = Reflect.get(usage, "cacheRead");
24990
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
24991
+ const cost = Reflect.get(usage, "cost");
24992
+ const input = Reflect.get(usage, "input");
24993
+ const output = Reflect.get(usage, "output");
24994
+ const totalTokens = Reflect.get(usage, "totalTokens");
24995
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
25416
24996
  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)
24997
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
24998
+ ...typeof output === "number" ? { completion_tokens: output } : {},
24999
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
25000
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
25001
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
25002
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
25428
25003
  };
25429
25004
  }
25430
- function durationMsMetrics(durationMs) {
25005
+ function durationMetrics2(durationMs) {
25431
25006
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
25432
25007
  }
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}`;
25008
+ function eventTime(value) {
25009
+ if (typeof value !== "string") {
25010
+ return void 0;
25442
25011
  }
25443
- return "flue:unknown";
25012
+ const timestamp = Date.parse(value);
25013
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
25014
+ }
25015
+ function turnKey(event) {
25016
+ return event.turnId;
25444
25017
  }
25445
25018
  function toolKey(event) {
25446
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
25019
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
25447
25020
  }
25448
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
25021
+ function compactionKey(event) {
25449
25022
  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
- ];
25023
+ event.instanceId ?? "",
25024
+ event.runId ?? "",
25025
+ event.session ?? "",
25026
+ event.operationId ?? "",
25027
+ event.taskId ?? ""
25028
+ ].join(":");
25029
+ }
25030
+ function stateMatchesOperation(state, operationId) {
25031
+ return state.metadata["flue.operation_id"] === operationId;
25032
+ }
25033
+ function stateMatchesRun(state, runId) {
25034
+ return state.metadata["flue.run_id"] === runId;
25470
25035
  }
25471
25036
  function startFlueSpan(parent, args) {
25472
25037
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -25478,6 +25043,13 @@ function safeLog3(span, event) {
25478
25043
  logInstrumentationError3("Flue span log", error);
25479
25044
  }
25480
25045
  }
25046
+ function safeEnd(span, endTime) {
25047
+ try {
25048
+ span.end(endTime === void 0 ? void 0 : { endTime });
25049
+ } catch (error) {
25050
+ logInstrumentationError3("Flue span end", error);
25051
+ }
25052
+ }
25481
25053
  function errorToString(error) {
25482
25054
  if (error instanceof Error) {
25483
25055
  return error.message;
@@ -26387,6 +25959,7 @@ __export(exports_exports, {
26387
25959
  LEGACY_CACHED_HEADER: () => LEGACY_CACHED_HEADER,
26388
25960
  LOGS3_OVERFLOW_REFERENCE_TYPE: () => LOGS3_OVERFLOW_REFERENCE_TYPE,
26389
25961
  LazyValue: () => LazyValue,
25962
+ LocalTrace: () => LocalTrace,
26390
25963
  Logger: () => Logger,
26391
25964
  LoginInvalidOrgError: () => LoginInvalidOrgError,
26392
25965
  NOOP_SPAN: () => NOOP_SPAN,
@@ -26412,6 +25985,7 @@ __export(exports_exports, {
26412
25985
  _internalIso: () => isomorph_default,
26413
25986
  _internalSetInitialState: () => _internalSetInitialState,
26414
25987
  addAzureBlobHeaders: () => addAzureBlobHeaders,
25988
+ braintrustFlueObserver: () => braintrustFlueObserver,
26415
25989
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
26416
25990
  buildLocalSummary: () => buildLocalSummary,
26417
25991
  configureInstrumentation: () => configureInstrumentation,
@@ -26491,8 +26065,6 @@ __export(exports_exports, {
26491
26065
  wrapCohere: () => wrapCohere,
26492
26066
  wrapCopilotClient: () => wrapCopilotClient,
26493
26067
  wrapCursorSDK: () => wrapCursorSDK,
26494
- wrapFlueContext: () => wrapFlueContext,
26495
- wrapFlueSession: () => wrapFlueSession,
26496
26068
  wrapGenkit: () => wrapGenkit,
26497
26069
  wrapGoogleADK: () => wrapGoogleADK,
26498
26070
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -26621,6 +26193,7 @@ async function invoke(args) {
26621
26193
  mode,
26622
26194
  schema,
26623
26195
  strict,
26196
+ overrides,
26624
26197
  projectId,
26625
26198
  ...functionIdArgs
26626
26199
  } = args;
@@ -26657,7 +26230,8 @@ async function invoke(args) {
26657
26230
  tags,
26658
26231
  stream,
26659
26232
  mode,
26660
- strict
26233
+ strict,
26234
+ overrides
26661
26235
  };
26662
26236
  const headers = {
26663
26237
  Accept: stream ? "text/event-stream" : "application/json"