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