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
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  BasePlugin: () => BasePlugin,
34
34
  BraintrustPlugin: () => BraintrustPlugin,
35
35
  OpenAIAgentsTraceProcessor: () => OpenAIAgentsTraceProcessor,
36
+ braintrustFlueObserver: () => braintrustFlueObserver,
36
37
  configureInstrumentation: () => configureInstrumentation,
37
38
  createChannelName: () => createChannelName,
38
39
  isValidChannelName: () => isValidChannelName,
@@ -3786,7 +3787,7 @@ function btStreamParser() {
3786
3787
  },
3787
3788
  async transform(chunk, controller) {
3788
3789
  if (chunk instanceof Uint8Array) {
3789
- parser.feed(decoder.decode(chunk));
3790
+ parser.feed(decoder.decode(chunk, { stream: true }));
3790
3791
  } else if (typeof chunk === "string") {
3791
3792
  parser.feed(chunk);
3792
3793
  } else {
@@ -3794,6 +3795,10 @@ function btStreamParser() {
3794
3795
  }
3795
3796
  },
3796
3797
  async flush(controller) {
3798
+ const tail = decoder.decode();
3799
+ if (tail) {
3800
+ parser.feed(tail);
3801
+ }
3797
3802
  controller.terminate();
3798
3803
  }
3799
3804
  });
@@ -6736,6 +6741,10 @@ ${stackTrace}` });
6736
6741
  function startSpan(args) {
6737
6742
  return startSpanAndIsLogger(args).span;
6738
6743
  }
6744
+ async function flush(options) {
6745
+ const state = options?.state ?? _globalState;
6746
+ return await state.bgLogger().flush();
6747
+ }
6739
6748
  function startSpanAndIsLogger(args) {
6740
6749
  const state = args?.state ?? _globalState;
6741
6750
  const parentObject = getSpanParentObject({
@@ -21977,803 +21986,440 @@ var flueChannels = defineChannels("@flue/runtime", {
21977
21986
  createContext: channel({
21978
21987
  channelName: "createFlueContext",
21979
21988
  kind: "sync-stream"
21980
- }),
21981
- openSession: channel({
21982
- channelName: "Harness.openSession",
21983
- kind: "async"
21984
- }),
21985
- contextEvent: channel({
21986
- channelName: "context.event",
21987
- kind: "sync-stream"
21988
- }),
21989
- prompt: channel({
21990
- channelName: "session.prompt",
21991
- kind: "async"
21992
- }),
21993
- skill: channel({
21994
- channelName: "session.skill",
21995
- kind: "async"
21996
- }),
21997
- task: channel({
21998
- channelName: "session.task",
21999
- kind: "async"
22000
- }),
22001
- compact: channel({
22002
- channelName: "session.compact",
22003
- kind: "async"
22004
21989
  })
22005
21990
  });
22006
21991
 
22007
- // src/wrappers/flue.ts
22008
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
22009
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
22010
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
22011
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
22012
- "braintrust.flue.subscribed-context-events"
22013
- );
22014
- function patchFlueContextInPlace(ctx) {
22015
- const context = ctx;
22016
- if (context[WRAPPED_FLUE_CONTEXT]) {
22017
- return ctx;
22018
- }
22019
- const originalInit = context.init.bind(context);
22020
- try {
22021
- Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
22022
- configurable: false,
22023
- enumerable: false,
22024
- value: true
22025
- });
22026
- Object.defineProperty(context, "init", {
22027
- configurable: true,
22028
- value: async function wrappedFlueInit(options) {
22029
- const harness = await originalInit(options);
22030
- return wrapFlueHarness(harness);
22031
- },
22032
- writable: true
22033
- });
22034
- } catch {
22035
- }
22036
- return ctx;
22037
- }
22038
- function subscribeFlueContextEvents(ctx, options = {}) {
22039
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
22040
- return void 0;
21992
+ // src/instrumentation/plugins/flue-plugin.ts
21993
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
21994
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
21995
+ var braintrustFlueObserver = (event, ctx) => {
21996
+ getObserveBridge().handle(event, ctx);
21997
+ };
21998
+ var FluePlugin = class extends BasePlugin {
21999
+ onEnable() {
22000
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
22041
22001
  }
22042
- const context = ctx;
22043
- const captureTurnSpans = options.captureTurnSpans ?? true;
22044
- const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
22045
- if (existingSubscription) {
22046
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
22047
- return void 0;
22048
- }
22049
- try {
22050
- existingSubscription.unsubscribe();
22051
- } catch {
22002
+ onDisable() {
22003
+ for (const unsubscribe of this.unsubscribers) {
22004
+ unsubscribe();
22052
22005
  }
22006
+ this.unsubscribers = [];
22053
22007
  }
22054
- try {
22055
- const unsubscribe = ctx.subscribeEvent((event) => {
22056
- flueChannels.contextEvent.traceSync(() => void 0, {
22057
- arguments: [event],
22058
- captureTurnSpans,
22059
- context: ctx
22060
- });
22061
- });
22062
- if (existingSubscription) {
22063
- existingSubscription.captureTurnSpans = captureTurnSpans;
22064
- existingSubscription.unsubscribe = unsubscribe;
22065
- } else {
22066
- Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
22067
- configurable: false,
22068
- enumerable: false,
22069
- value: {
22070
- captureTurnSpans,
22071
- unsubscribe
22072
- }
22073
- });
22008
+ };
22009
+ function enableFlueAutoInstrumentation() {
22010
+ const state = getAutoState();
22011
+ state.refCount += 1;
22012
+ if (!state.handlers) {
22013
+ const channel2 = flueChannels.createContext.tracingChannel();
22014
+ const handlers = {
22015
+ end: (event) => {
22016
+ subscribeToFlueContext(event.result, state);
22017
+ }
22018
+ };
22019
+ channel2.subscribe(handlers);
22020
+ state.channel = channel2;
22021
+ state.handlers = handlers;
22022
+ }
22023
+ let released = false;
22024
+ return () => {
22025
+ if (released) {
22026
+ return;
22074
22027
  }
22075
- return unsubscribe;
22076
- } catch {
22077
- return void 0;
22028
+ released = true;
22029
+ releaseAutoState(state);
22030
+ };
22031
+ }
22032
+ function getAutoState() {
22033
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
22034
+ if (isAutoState(existing)) {
22035
+ return existing;
22078
22036
  }
22037
+ const state = {
22038
+ contexts: /* @__PURE__ */ new WeakSet(),
22039
+ refCount: 0
22040
+ };
22041
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
22042
+ return state;
22079
22043
  }
22080
- function wrapFlueHarness(harness) {
22081
- if (!isPlausibleFlueHarness(harness)) {
22082
- return harness;
22044
+ function getObserveBridge() {
22045
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
22046
+ if (isFlueObserveBridge(existing)) {
22047
+ return existing;
22083
22048
  }
22084
- const target = harness;
22085
- if (target[WRAPPED_FLUE_HARNESS]) {
22086
- return harness;
22049
+ const bridge = new FlueObserveBridge();
22050
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
22051
+ return bridge;
22052
+ }
22053
+ function isFlueObserveBridge(value) {
22054
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
22055
+ }
22056
+ function isAutoState(value) {
22057
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
22058
+ }
22059
+ function releaseAutoState(state) {
22060
+ state.refCount -= 1;
22061
+ if (state.refCount > 0) {
22062
+ return;
22087
22063
  }
22088
- const originalSession = target.session.bind(target);
22089
22064
  try {
22090
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
22091
- configurable: false,
22092
- enumerable: false,
22093
- value: true
22094
- });
22095
- Object.defineProperty(target, "session", {
22096
- configurable: true,
22097
- value: async function wrappedFlueHarnessSession(name, options) {
22098
- const session = await originalSession(name, options);
22099
- return patchFlueSessionInPlace(session);
22100
- },
22101
- writable: true
22102
- });
22103
- const sessions = target.sessions;
22104
- if (sessions && typeof sessions === "object") {
22105
- patchFlueSessionFactory(sessions, "get");
22106
- patchFlueSessionFactory(sessions, "create");
22065
+ if (state.channel && state.handlers) {
22066
+ state.channel.unsubscribe(state.handlers);
22107
22067
  }
22108
- } catch {
22068
+ } finally {
22069
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
22109
22070
  }
22110
- return harness;
22111
22071
  }
22112
- function patchFlueSessionInPlace(session) {
22113
- if (session[WRAPPED_FLUE_SESSION]) {
22114
- return session;
22072
+ function subscribeToFlueContext(value, state) {
22073
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
22074
+ return;
22115
22075
  }
22076
+ const ctx = flueContextFromUnknown(value);
22077
+ let released = false;
22078
+ let unsubscribe;
22079
+ const release = () => {
22080
+ if (released) {
22081
+ return;
22082
+ }
22083
+ released = true;
22084
+ try {
22085
+ unsubscribe?.();
22086
+ } catch (error) {
22087
+ logInstrumentationError3("Flue context unsubscribe", error);
22088
+ }
22089
+ };
22116
22090
  try {
22117
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
22118
- configurable: false,
22119
- enumerable: false,
22120
- value: true
22091
+ unsubscribe = value.subscribeEvent((event) => {
22092
+ if (state.refCount <= 0) {
22093
+ release();
22094
+ return;
22095
+ }
22096
+ braintrustFlueObserver(event, ctx);
22097
+ if (isAutoContextTerminalEvent(event, ctx)) {
22098
+ release();
22099
+ }
22121
22100
  });
22122
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
22123
- patchCallHandleMethod(session, "skill", flueChannels.skill);
22124
- patchCallHandleMethod(session, "task", flueChannels.task);
22125
- patchCompact(session);
22126
- } catch {
22101
+ state.contexts.add(value);
22102
+ } catch (error) {
22103
+ logInstrumentationError3("Flue context subscription", error);
22127
22104
  }
22128
- return session;
22129
22105
  }
22130
- function patchFlueSessionFactory(sessions, method) {
22131
- const original = sessions[method];
22132
- if (typeof original !== "function") {
22133
- return;
22106
+ function isAutoContextTerminalEvent(event, ctx) {
22107
+ if (!isObjectLike(event)) {
22108
+ return false;
22134
22109
  }
22135
- const bound = original.bind(sessions);
22136
- Object.defineProperty(sessions, method, {
22137
- configurable: true,
22138
- value: async function wrappedFlueSessionFactory(name, options) {
22139
- const session = await bound(name, options);
22140
- return patchFlueSessionInPlace(session);
22141
- },
22142
- writable: true
22143
- });
22144
- }
22145
- function patchCallHandleMethod(session, method, channel2) {
22146
- const original = session[method];
22147
- if (typeof original !== "function") {
22148
- return;
22110
+ const type = Reflect.get(event, "type");
22111
+ if (type === "run_end") {
22112
+ return true;
22149
22113
  }
22150
- const bound = original.bind(session);
22151
- Object.defineProperty(session, method, {
22152
- configurable: true,
22153
- value(input, options) {
22154
- const args = [input, options];
22155
- const { originalResult, traced } = traceFlueOperation(channel2, {
22156
- context: {
22157
- arguments: args,
22158
- operation: method,
22159
- session
22160
- },
22161
- run: () => bound(input, options)
22162
- });
22163
- return preserveCallHandle(originalResult, traced);
22164
- },
22165
- writable: true
22166
- });
22167
- }
22168
- function patchCompact(session) {
22169
- const original = session.compact;
22170
- if (typeof original !== "function") {
22171
- return;
22114
+ if (type !== "operation") {
22115
+ return false;
22172
22116
  }
22173
- const bound = original.bind(session);
22174
- Object.defineProperty(session, "compact", {
22175
- configurable: true,
22176
- value() {
22177
- const context = {
22178
- arguments: [],
22179
- operation: "compact",
22180
- session
22181
- };
22182
- return flueChannels.compact.tracePromise(() => bound(), context);
22183
- },
22184
- writable: true
22185
- });
22117
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
22186
22118
  }
22187
- function traceFlueOperation(channel2, args) {
22188
- const tracingChannel = channel2.tracingChannel();
22189
- const context = args.context;
22190
- let originalResult;
22191
- let traced;
22192
- const run = () => {
22193
- try {
22194
- originalResult = args.run();
22195
- tracingChannel.end?.publish(context);
22196
- } catch (error) {
22197
- context.error = normalizeError3(error);
22198
- tracingChannel.error?.publish(context);
22199
- tracingChannel.end?.publish(context);
22200
- throw error;
22201
- }
22202
- traced = Promise.resolve(originalResult).then(
22203
- (result) => {
22204
- context.result = result;
22205
- tracingChannel.asyncStart?.publish(context);
22206
- tracingChannel.asyncEnd?.publish(context);
22207
- return result;
22208
- },
22209
- (error) => {
22210
- context.error = normalizeError3(error);
22211
- tracingChannel.error?.publish(context);
22212
- tracingChannel.asyncStart?.publish(context);
22213
- tracingChannel.asyncEnd?.publish(context);
22214
- throw error;
22215
- }
22216
- );
22217
- };
22218
- if (tracingChannel.start?.runStores) {
22219
- tracingChannel.start.runStores(context, run);
22220
- } else {
22221
- tracingChannel.start?.publish(context);
22222
- run();
22223
- }
22224
- return { originalResult, traced };
22119
+ function isObservableFlueContext(value) {
22120
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
22225
22121
  }
22226
- function normalizeError3(error) {
22227
- return error instanceof Error ? error : new Error(String(error));
22122
+ function isFlueEvent(event) {
22123
+ const type = Reflect.get(event, "type");
22124
+ 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";
22228
22125
  }
22229
- function preserveCallHandle(originalHandle, traced) {
22230
- if (!isFlueCallHandle(originalHandle)) {
22231
- return traced;
22126
+ function flueContextFromUnknown(ctx) {
22127
+ if (!isObjectLike(ctx)) {
22128
+ return void 0;
22232
22129
  }
22233
- const handle = originalHandle;
22234
- const wrapped = {
22235
- get signal() {
22236
- return handle.signal;
22237
- },
22238
- abort(reason) {
22239
- return handle.abort(reason);
22240
- },
22241
- then(onfulfilled, onrejected) {
22242
- return traced.then(onfulfilled, onrejected);
22243
- }
22130
+ const id = Reflect.get(ctx, "id");
22131
+ const runId = Reflect.get(ctx, "runId");
22132
+ return {
22133
+ ...typeof id === "string" ? { id } : {},
22134
+ ...typeof runId === "string" ? { runId } : {}
22244
22135
  };
22245
- return wrapped;
22246
22136
  }
22247
- function isPlausibleFlueHarness(value) {
22248
- return !!value && typeof value === "object" && typeof value.session === "function";
22249
- }
22250
- function isFlueCallHandle(value) {
22251
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
22137
+ function isObjectLike(value) {
22138
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22252
22139
  }
22253
-
22254
- // src/instrumentation/plugins/flue-plugin.ts
22255
- var FluePlugin = class extends BasePlugin {
22256
- activeOperationsById = /* @__PURE__ */ new Map();
22257
- activeOperationsByScope = /* @__PURE__ */ new Map();
22258
- compactionsByScope = /* @__PURE__ */ new Map();
22259
- pendingOperationsByKey = /* @__PURE__ */ new Map();
22140
+ var FlueObserveBridge = class {
22141
+ compactionsByKey = /* @__PURE__ */ new Map();
22142
+ operationsById = /* @__PURE__ */ new Map();
22143
+ runsById = /* @__PURE__ */ new Map();
22144
+ seenEvents = /* @__PURE__ */ new WeakSet();
22260
22145
  tasksById = /* @__PURE__ */ new Map();
22261
- toolsById = /* @__PURE__ */ new Map();
22262
- turnsByScope = /* @__PURE__ */ new Map();
22263
- onEnable() {
22264
- this.subscribeToContextCreation();
22265
- this.subscribeToSessionCreation();
22266
- this.subscribeToContextEvents();
22267
- this.subscribeToSessionOperations();
22268
- }
22269
- onDisable() {
22270
- for (const unsubscribe of this.unsubscribers) {
22271
- unsubscribe();
22146
+ toolsByKey = /* @__PURE__ */ new Map();
22147
+ turnsByKey = /* @__PURE__ */ new Map();
22148
+ handle(event, ctx) {
22149
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
22150
+ return;
22272
22151
  }
22273
- this.unsubscribers = [];
22274
- this.activeOperationsById.clear();
22275
- this.activeOperationsByScope.clear();
22276
- this.compactionsByScope.clear();
22277
- this.pendingOperationsByKey.clear();
22152
+ if (this.seenEvents.has(event)) {
22153
+ return;
22154
+ }
22155
+ this.seenEvents.add(event);
22156
+ try {
22157
+ this.handleEvent(event, flueContextFromUnknown(ctx));
22158
+ } catch (error) {
22159
+ logInstrumentationError3("Flue observe", error);
22160
+ }
22161
+ }
22162
+ reset() {
22163
+ this.compactionsByKey.clear();
22164
+ this.operationsById.clear();
22165
+ this.runsById.clear();
22166
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
22278
22167
  this.tasksById.clear();
22279
- this.toolsById.clear();
22280
- this.turnsByScope.clear();
22168
+ this.toolsByKey.clear();
22169
+ this.turnsByKey.clear();
22281
22170
  }
22282
- subscribeToContextCreation() {
22283
- const channel2 = flueChannels.createContext.tracingChannel();
22284
- const handlers = {
22285
- end: (event) => {
22286
- const ctx = event.result;
22287
- if (!ctx) {
22288
- return;
22289
- }
22290
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
22291
- patchFlueContextInPlace(ctx);
22292
- },
22293
- error: () => {
22294
- }
22295
- };
22296
- channel2.subscribe(handlers);
22297
- this.unsubscribers.push(() => {
22298
- channel2.unsubscribe(handlers);
22299
- });
22171
+ handleEvent(event, ctx) {
22172
+ switch (event.type) {
22173
+ case "run_start":
22174
+ this.handleRunStart(event, ctx);
22175
+ return;
22176
+ case "run_end":
22177
+ this.handleRunEnd(event);
22178
+ return;
22179
+ case "operation_start":
22180
+ this.handleOperationStart(event);
22181
+ return;
22182
+ case "operation":
22183
+ this.handleOperation(event);
22184
+ return;
22185
+ case "turn_request":
22186
+ this.handleTurnRequest(event);
22187
+ return;
22188
+ case "turn":
22189
+ this.handleTurn(event);
22190
+ return;
22191
+ case "tool_start":
22192
+ this.handleToolStart(event);
22193
+ return;
22194
+ case "tool_call":
22195
+ this.handleToolCall(event);
22196
+ return;
22197
+ case "task_start":
22198
+ this.handleTaskStart(event);
22199
+ return;
22200
+ case "task":
22201
+ this.handleTask(event);
22202
+ return;
22203
+ case "compaction_start":
22204
+ this.handleCompactionStart(event);
22205
+ return;
22206
+ case "compaction":
22207
+ this.handleCompaction(event);
22208
+ return;
22209
+ default:
22210
+ return;
22211
+ }
22300
22212
  }
22301
- subscribeToSessionCreation() {
22302
- const channel2 = flueChannels.openSession.tracingChannel();
22303
- const handlers = {
22304
- asyncEnd: (event) => {
22305
- if (event.result) {
22306
- patchFlueSessionInPlace(
22307
- event.result
22308
- );
22309
- }
22310
- if (event.harness) {
22311
- wrapFlueHarness(event.harness);
22312
- }
22313
- },
22314
- error: () => {
22315
- }
22213
+ handleRunStart(event, ctx) {
22214
+ if (!event.runId) {
22215
+ return;
22216
+ }
22217
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
22218
+ const metadata = {
22219
+ ...extractPayloadMetadata(event.payload),
22220
+ ...extractEventMetadata(event, ctx),
22221
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
22222
+ provider: "flue"
22316
22223
  };
22317
- channel2.subscribe(handlers);
22318
- this.unsubscribers.push(() => {
22319
- channel2.unsubscribe(handlers);
22224
+ const span = startSpan({
22225
+ name: `workflow:${workflowName}`,
22226
+ spanAttributes: { type: "task" /* TASK */ },
22227
+ startTime: eventTime(event.startedAt ?? event.timestamp),
22228
+ event: {
22229
+ input: event.payload,
22230
+ metadata
22231
+ }
22320
22232
  });
22233
+ this.runsById.set(event.runId, { metadata, span });
22321
22234
  }
22322
- subscribeToSessionOperations() {
22323
- this.subscribeToSessionOperation(flueChannels.prompt);
22324
- this.subscribeToSessionOperation(flueChannels.skill);
22325
- this.subscribeToSessionOperation(flueChannels.task);
22326
- this.subscribeToCompact();
22327
- }
22328
- subscribeToSessionOperation(channel2) {
22329
- const tracingChannel = channel2.tracingChannel();
22330
- const states = /* @__PURE__ */ new WeakMap();
22331
- const ensureState2 = (event) => {
22332
- const existing = states.get(event);
22333
- if (existing) {
22334
- return existing;
22335
- }
22336
- const state = this.startOperationState({
22337
- args: event.arguments,
22338
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
22339
- operation: event.operation,
22340
- session: event.session
22235
+ handleRunEnd(event) {
22236
+ const state = this.runsById.get(event.runId);
22237
+ this.finishPendingSpansForRun(event);
22238
+ if (state) {
22239
+ safeLog3(state.span, {
22240
+ ...event.isError ? { error: errorToString(event.error) } : {},
22241
+ metadata: {
22242
+ ...state.metadata,
22243
+ ...extractEventMetadata(event),
22244
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22245
+ },
22246
+ metrics: durationMetrics2(event.durationMs),
22247
+ output: event.result
22341
22248
  });
22342
- states.set(event, state);
22343
- return state;
22344
- };
22345
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
22346
- tracingChannel,
22347
- ensureState2
22348
- );
22349
- const handlers = {
22350
- start: (event) => {
22351
- ensureState2(event);
22352
- },
22353
- asyncEnd: (event) => {
22354
- this.endOperationState(states.get(event), event.result);
22355
- states.delete(event);
22356
- },
22357
- error: (event) => {
22358
- const state = states.get(event);
22359
- if (state && event.error) {
22360
- safeLog3(state.span, { error: errorToString(event.error) });
22361
- this.finishOperationState(state);
22362
- }
22363
- states.delete(event);
22364
- }
22365
- };
22366
- tracingChannel.subscribe(handlers);
22367
- this.unsubscribers.push(() => {
22368
- unbindCurrentSpanStore?.();
22369
- tracingChannel.unsubscribe(handlers);
22249
+ safeEnd(state.span, eventTime(event.timestamp));
22250
+ this.runsById.delete(event.runId);
22251
+ }
22252
+ void flush().catch((error) => {
22253
+ logInstrumentationError3("Flue flush", error);
22370
22254
  });
22371
22255
  }
22372
- subscribeToCompact() {
22373
- const tracingChannel = flueChannels.compact.tracingChannel();
22374
- const states = /* @__PURE__ */ new WeakMap();
22375
- const ensureState2 = (event) => {
22376
- const existing = states.get(event);
22377
- if (existing) {
22378
- return existing;
22379
- }
22380
- const state = this.startOperationState({
22381
- args: [],
22382
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
22383
- operation: event.operation,
22384
- session: event.session
22385
- });
22386
- states.set(event, state);
22387
- return state;
22388
- };
22389
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
22390
- tracingChannel,
22391
- ensureState2
22392
- );
22393
- const handlers = {
22394
- start: (event) => {
22395
- ensureState2(event);
22396
- },
22397
- asyncEnd: (event) => {
22398
- this.endOperationState(states.get(event), void 0);
22399
- states.delete(event);
22400
- },
22401
- error: (event) => {
22402
- const state = states.get(event);
22403
- if (state && event.error) {
22404
- safeLog3(state.span, { error: errorToString(event.error) });
22405
- this.finishOperationState(state);
22406
- }
22407
- states.delete(event);
22408
- }
22409
- };
22410
- tracingChannel.subscribe(handlers);
22411
- this.unsubscribers.push(() => {
22412
- unbindCurrentSpanStore?.();
22413
- tracingChannel.unsubscribe(handlers);
22414
- });
22415
- }
22416
- subscribeToContextEvents() {
22417
- const channel2 = flueChannels.contextEvent.tracingChannel();
22418
- const handlers = {
22419
- start: (event) => {
22420
- const flueEvent = event.arguments[0];
22421
- if (!flueEvent) {
22422
- return;
22423
- }
22424
- try {
22425
- this.handleFlueEvent(flueEvent, {
22426
- captureTurnSpans: event.captureTurnSpans !== false
22427
- });
22428
- } catch (error) {
22429
- logInstrumentationError3("Flue event", error);
22430
- }
22431
- },
22432
- error: () => {
22433
- }
22434
- };
22435
- channel2.subscribe(handlers);
22436
- this.unsubscribers.push(() => {
22437
- channel2.unsubscribe(handlers);
22438
- });
22439
- }
22440
- bindCurrentSpanStoreToOperationStart(tracingChannel, ensureState2) {
22441
- const state = _internalGetGlobalState();
22442
- const startChannel = tracingChannel.start;
22443
- const contextManager = state?.contextManager;
22444
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
22445
- if (!currentSpanStore || !startChannel) {
22446
- return void 0;
22447
- }
22448
- startChannel.bindStore(currentSpanStore, (event) => {
22449
- const operationState = ensureState2(event);
22450
- return contextManager.wrapSpanForStore(operationState.span);
22451
- });
22452
- return () => {
22453
- startChannel.unbindStore(currentSpanStore);
22454
- };
22455
- }
22456
- startOperationState(args) {
22457
- const sessionName = getSessionName(args.session);
22458
- const metadata = {
22459
- ...extractOperationInputMetadata(args.operation, args.args),
22460
- ...extractSessionMetadata(args.session),
22461
- "flue.operation": args.operation,
22462
- provider: "flue",
22463
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
22464
- };
22465
- const span = startSpan({
22466
- name: `flue.session.${args.operation}`,
22467
- spanAttributes: { type: "task" /* TASK */ }
22468
- });
22469
- const state = {
22470
- metadata,
22471
- operation: args.operation,
22472
- sessionName,
22473
- span,
22474
- startTime: getCurrentUnixTimestamp()
22475
- };
22476
- safeLog3(span, {
22477
- input: extractOperationInput(args.operation, args.args),
22478
- metadata
22479
- });
22480
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
22481
- state
22482
- );
22483
- addOperationToScope(
22484
- this.activeOperationsByScope,
22485
- sessionName ?? "unknown",
22486
- state
22487
- );
22488
- return state;
22489
- }
22490
- endOperationState(state, result) {
22491
- if (!state) {
22492
- return;
22493
- }
22494
- const metadata = {
22495
- ...state.metadata,
22496
- ...extractPromptResponseMetadata(result)
22497
- };
22498
- const metrics = {
22499
- ...buildDurationMetrics3(state.startTime),
22500
- ...metricsFromUsage(result?.usage)
22501
- };
22502
- safeLog3(state.span, {
22503
- metadata,
22504
- metrics,
22505
- output: extractOperationOutput(result)
22506
- });
22507
- this.finishCompactionsForOperation(state);
22508
- this.finishOperationState(state);
22509
- }
22510
- finishOperationState(state) {
22511
- removePendingOperation(this.pendingOperationsByKey, state);
22512
- if (state.operationId) {
22513
- this.activeOperationsById.delete(state.operationId);
22514
- }
22515
- removeScopedOperation(this.activeOperationsByScope, state);
22516
- state.span.end();
22517
- }
22518
- handleFlueEvent(event, options) {
22519
- switch (event.type) {
22520
- case "operation_start":
22521
- this.handleOperationStart(event);
22522
- return;
22523
- case "operation":
22524
- this.handleOperation(event);
22525
- return;
22526
- case "text_delta":
22527
- if (!options.captureTurnSpans) {
22528
- return;
22529
- }
22530
- this.ensureTurnState(event).text.push(
22531
- typeof event.text === "string" ? event.text : ""
22532
- );
22533
- return;
22534
- case "thinking_start":
22535
- if (!options.captureTurnSpans) {
22536
- return;
22537
- }
22538
- this.handleThinkingStart(event);
22539
- return;
22540
- case "thinking_delta":
22541
- if (!options.captureTurnSpans) {
22542
- return;
22543
- }
22544
- this.handleThinkingDelta(event);
22545
- return;
22546
- case "thinking_end":
22547
- if (!options.captureTurnSpans) {
22548
- return;
22549
- }
22550
- this.handleThinkingEnd(event);
22551
- return;
22552
- case "turn":
22553
- if (!options.captureTurnSpans) {
22554
- return;
22555
- }
22556
- this.handleTurn(event);
22557
- return;
22558
- case "tool_start":
22559
- this.handleToolStart(event, options);
22560
- return;
22561
- case "tool_call":
22562
- this.handleToolCall(event);
22563
- return;
22564
- case "task_start":
22565
- this.handleTaskStart(event);
22566
- return;
22567
- case "task":
22568
- this.handleTask(event);
22569
- return;
22570
- case "compaction_start":
22571
- this.handleCompactionStart(event);
22572
- return;
22573
- case "compaction":
22574
- this.handleCompaction(event);
22575
- return;
22576
- default:
22577
- return;
22578
- }
22579
- }
22580
22256
  handleOperationStart(event) {
22581
- if (!isInstrumentedOperation(event.operationKind)) {
22257
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
22582
22258
  return;
22583
22259
  }
22584
- const state = this.takePendingOperationForEvent(event);
22585
- if (!state) {
22586
- return;
22587
- }
22588
- state.operationId = event.operationId;
22589
- this.activeOperationsById.set(event.operationId, state);
22590
- addScopedOperation(this.activeOperationsByScope, event, state);
22591
- state.metadata = {
22592
- ...state.metadata,
22260
+ const metadata = {
22593
22261
  ...extractEventMetadata(event),
22594
- "flue.operation_id": event.operationId
22262
+ "flue.operation": event.operationKind,
22263
+ provider: "flue"
22595
22264
  };
22596
- safeLog3(state.span, { metadata: state.metadata });
22265
+ const parent = this.parentSpanForEvent(event);
22266
+ const span = startFlueSpan(parent, {
22267
+ name: `flue.${event.operationKind}`,
22268
+ spanAttributes: { type: "task" /* TASK */ },
22269
+ startTime: eventTime(event.timestamp),
22270
+ event: { metadata }
22271
+ });
22272
+ this.operationsById.set(event.operationId, { metadata, span });
22597
22273
  }
22598
22274
  handleOperation(event) {
22599
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
22600
- if (!state) {
22275
+ if (!isInstrumentedOperation(event.operationKind)) {
22601
22276
  return;
22602
22277
  }
22278
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
22279
+ const output = operationOutput(event);
22603
22280
  const metadata = {
22604
22281
  ...state.metadata,
22605
22282
  ...extractEventMetadata(event),
22606
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
22607
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22283
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
22284
+ ...event.usage ? { "flue.usage": event.usage } : {}
22608
22285
  };
22609
- const metrics = metricsFromUsage(event.usage);
22286
+ this.finishPendingChildrenForOperation(event, output);
22610
22287
  safeLog3(state.span, {
22611
- ...event.error ? { error: errorToString(event.error) } : {},
22288
+ ...event.isError ? { error: errorToString(event.error) } : {},
22612
22289
  metadata,
22613
- ...Object.keys(metrics).length ? { metrics } : {}
22290
+ metrics: durationMetrics2(event.durationMs),
22291
+ output
22614
22292
  });
22293
+ safeEnd(state.span, eventTime(event.timestamp));
22294
+ this.operationsById.delete(event.operationId);
22615
22295
  }
22616
- ensureTurnState(event) {
22617
- const scope = scopeKey(event);
22618
- const existing = this.turnsByScope.get(scope);
22619
- if (existing) {
22620
- return existing;
22296
+ handleTurnRequest(event) {
22297
+ const key = turnKey(event);
22298
+ if (!key) {
22299
+ return;
22621
22300
  }
22622
- const parent = this.parentSpanForEvent(event);
22623
22301
  const metadata = {
22624
22302
  ...extractEventMetadata(event),
22625
- provider: "flue"
22303
+ ...event.api ? { "flue.api": event.api } : {},
22304
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
22305
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
22306
+ ...event.provider ? { "flue.provider": event.provider } : {},
22307
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
22308
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
22309
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
22310
+ ...event.input?.tools ? { tools: event.input.tools } : {}
22626
22311
  };
22312
+ const parent = this.parentSpanForTurn(event);
22627
22313
  const span = startFlueSpan(parent, {
22628
- name: "flue.turn",
22629
- spanAttributes: { type: "llm" /* LLM */ }
22314
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
22315
+ spanAttributes: { type: "llm" /* LLM */ },
22316
+ startTime: eventTime(event.timestamp),
22317
+ event: {
22318
+ input: event.input?.messages,
22319
+ metadata
22320
+ }
22630
22321
  });
22631
- const state = {
22632
- metadata,
22633
- span,
22634
- hasThinking: false,
22635
- startTime: getCurrentUnixTimestamp(),
22636
- text: [],
22637
- thinking: [],
22638
- toolCalls: []
22639
- };
22640
- safeLog3(span, { metadata });
22641
- this.turnsByScope.set(scope, state);
22642
- return state;
22322
+ this.logOperationInput(
22323
+ event.operationId,
22324
+ event.input?.messages ?? event.input
22325
+ );
22326
+ this.turnsByKey.set(key, { metadata, span });
22643
22327
  }
22644
22328
  handleTurn(event) {
22645
- const scope = scopeKey(event);
22646
- const state = this.ensureTurnState(event);
22647
- const text = state.text.join("");
22648
- const reasoning = state.finalThinking ?? state.thinking.join("");
22649
- const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
22329
+ const key = turnKey(event);
22330
+ if (!key) {
22331
+ return;
22332
+ }
22333
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
22650
22334
  const metadata = {
22651
22335
  ...state.metadata,
22652
22336
  ...extractEventMetadata(event),
22337
+ ...event.api ? { "flue.api": event.api } : {},
22653
22338
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
22339
+ ...event.provider ? { provider: event.provider } : {},
22340
+ ...event.provider ? { "flue.provider": event.provider } : {},
22341
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
22654
22342
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
22655
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
22656
- provider: "flue"
22343
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22657
22344
  };
22658
22345
  safeLog3(state.span, {
22659
- ...event.error ? { error: errorToString(event.error) } : {},
22346
+ ...event.isError ? { error: errorToString(event.error) } : {},
22660
22347
  metadata,
22661
22348
  metrics: {
22662
- ...durationMsMetrics(event.durationMs),
22349
+ ...durationMetrics2(event.durationMs),
22663
22350
  ...metricsFromUsage(event.usage)
22664
22351
  },
22665
- output: toAssistantOutput(
22666
- text,
22667
- event.stopReason,
22668
- outputReasoning,
22669
- state.toolCalls
22670
- )
22352
+ output: event.output
22671
22353
  });
22672
- state.span.end();
22673
- this.turnsByScope.delete(scope);
22354
+ safeEnd(state.span, eventTime(event.timestamp));
22355
+ this.turnsByKey.delete(key);
22674
22356
  }
22675
- handleThinkingDelta(event) {
22676
- const delta = event.delta;
22677
- if (typeof delta !== "string" || !delta) {
22357
+ handleToolStart(event) {
22358
+ if (!event.toolCallId) {
22678
22359
  return;
22679
22360
  }
22680
- const state = this.ensureTurnState(event);
22681
- state.hasThinking = true;
22682
- state.metadata["flue.thinking"] = true;
22683
- state.thinking.push(delta);
22684
- }
22685
- handleThinkingStart(event) {
22686
- const state = this.ensureTurnState(event);
22687
- state.hasThinking = true;
22688
- state.metadata["flue.thinking"] = true;
22689
- }
22690
- handleThinkingEnd(event) {
22691
- const state = this.ensureTurnState(event);
22692
- state.hasThinking = true;
22693
- state.metadata["flue.thinking"] = true;
22694
- if (typeof event.content === "string" && event.content) {
22695
- state.finalThinking = event.content;
22696
- }
22697
- }
22698
- handleToolStart(event, options) {
22699
- const toolCallId = event.toolCallId;
22700
- if (!toolCallId) {
22701
- return;
22702
- }
22703
- const parent = this.parentSpanForEvent(event);
22704
- const scope = scopeKey(event);
22705
- let turnState = this.turnsByScope.get(scope);
22706
- if (!turnState && parent && options.captureTurnSpans) {
22707
- turnState = this.ensureTurnState(event);
22708
- }
22709
22361
  const metadata = {
22710
22362
  ...extractEventMetadata(event),
22711
22363
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22712
- "flue.tool_call_id": toolCallId,
22364
+ "flue.tool_call_id": event.toolCallId,
22713
22365
  provider: "flue"
22714
22366
  };
22367
+ const parent = this.parentSpanForTool(event);
22715
22368
  const span = startFlueSpan(parent, {
22716
- name: `tool: ${event.toolName ?? "unknown"}`,
22717
- spanAttributes: { type: "tool" /* TOOL */ }
22718
- });
22719
- if (turnState) {
22720
- turnState.toolCalls.push({
22721
- args: event.args,
22722
- toolCallId,
22723
- toolName: event.toolName
22724
- });
22725
- }
22726
- safeLog3(span, {
22727
- input: event.args,
22728
- metadata
22729
- });
22730
- this.toolsById.set(toolKey(event), {
22731
- metadata,
22732
- span,
22733
- startTime: getCurrentUnixTimestamp()
22369
+ name: `tool:${event.toolName ?? "unknown"}`,
22370
+ spanAttributes: { type: "tool" /* TOOL */ },
22371
+ startTime: eventTime(event.timestamp),
22372
+ event: {
22373
+ input: event.args,
22374
+ metadata
22375
+ }
22734
22376
  });
22377
+ this.toolsByKey.set(toolKey(event), { metadata, span });
22735
22378
  }
22736
22379
  handleToolCall(event) {
22380
+ if (!event.toolCallId) {
22381
+ return;
22382
+ }
22737
22383
  const key = toolKey(event);
22738
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
22384
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
22739
22385
  const metadata = {
22740
22386
  ...state.metadata,
22741
22387
  ...extractEventMetadata(event),
22742
22388
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22743
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
22389
+ "flue.tool_call_id": event.toolCallId,
22744
22390
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22745
22391
  };
22746
22392
  safeLog3(state.span, {
22747
22393
  ...event.isError ? { error: errorToString(event.result) } : {},
22748
22394
  metadata,
22749
- metrics: durationMsMetrics(event.durationMs),
22395
+ metrics: durationMetrics2(event.durationMs),
22750
22396
  output: event.result
22751
22397
  });
22752
- state.span.end();
22753
- this.toolsById.delete(key);
22398
+ safeEnd(state.span, eventTime(event.timestamp));
22399
+ this.toolsByKey.delete(key);
22754
22400
  }
22755
22401
  handleTaskStart(event) {
22756
- const parent = this.parentSpanForEvent(event);
22402
+ if (!event.taskId) {
22403
+ return;
22404
+ }
22757
22405
  const metadata = {
22758
22406
  ...extractEventMetadata(event),
22759
- ...event.role ? { "flue.role": event.role } : {},
22407
+ ...event.agent ? { "flue.agent": event.agent } : {},
22760
22408
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
22761
22409
  "flue.task_id": event.taskId,
22762
22410
  provider: "flue"
22763
22411
  };
22412
+ const parent = this.parentSpanForEvent(event);
22764
22413
  const span = startFlueSpan(parent, {
22765
- name: "flue.task",
22766
- spanAttributes: { type: "task" /* TASK */ }
22767
- });
22768
- safeLog3(span, {
22769
- input: event.prompt,
22770
- metadata
22771
- });
22772
- this.tasksById.set(event.taskId, {
22773
- metadata,
22774
- span,
22775
- startTime: getCurrentUnixTimestamp()
22414
+ name: event.agent ? `task:${event.agent}` : "flue.task",
22415
+ spanAttributes: { type: "task" /* TASK */ },
22416
+ startTime: eventTime(event.timestamp),
22417
+ event: {
22418
+ input: event.prompt,
22419
+ metadata
22420
+ }
22776
22421
  });
22422
+ this.tasksById.set(event.taskId, { metadata, span });
22777
22423
  }
22778
22424
  handleTask(event) {
22779
22425
  const state = this.tasksById.get(event.taskId);
@@ -22785,426 +22431,372 @@ var FluePlugin = class extends BasePlugin {
22785
22431
  metadata: {
22786
22432
  ...state.metadata,
22787
22433
  ...extractEventMetadata(event),
22434
+ ...event.agent ? { "flue.agent": event.agent } : {},
22788
22435
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22789
22436
  },
22790
- metrics: durationMsMetrics(event.durationMs),
22437
+ metrics: durationMetrics2(event.durationMs),
22791
22438
  output: event.result
22792
22439
  });
22793
- state.span.end();
22440
+ safeEnd(state.span, eventTime(event.timestamp));
22794
22441
  this.tasksById.delete(event.taskId);
22795
22442
  }
22796
22443
  handleCompactionStart(event) {
22797
- const operationState = this.operationStateForEvent(event);
22798
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
22444
+ const key = compactionKey(event);
22445
+ const input = {
22446
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
22447
+ ...event.reason ? { reason: event.reason } : {}
22448
+ };
22799
22449
  const metadata = {
22800
22450
  ...extractEventMetadata(event),
22801
22451
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
22802
22452
  provider: "flue"
22803
22453
  };
22804
- const input = {
22805
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
22806
- ...event.reason ? { reason: event.reason } : {}
22807
- };
22454
+ const parent = this.parentSpanForEvent(event);
22808
22455
  const span = startFlueSpan(parent, {
22809
- name: "flue.compaction",
22810
- spanAttributes: { type: "task" /* TASK */ }
22811
- });
22812
- safeLog3(span, {
22813
- input,
22814
- metadata
22815
- });
22816
- this.compactionsByScope.set(scopeKey(event), {
22817
- input,
22818
- metadata,
22819
- operationState,
22820
- span,
22821
- startTime: getCurrentUnixTimestamp()
22456
+ name: `compaction:${event.reason ?? "unknown"}`,
22457
+ spanAttributes: { type: "task" /* TASK */ },
22458
+ startTime: eventTime(event.timestamp),
22459
+ event: {
22460
+ input,
22461
+ metadata
22462
+ }
22822
22463
  });
22464
+ this.logOperationInput(event.operationId, input);
22465
+ this.compactionsByKey.set(key, { metadata, span });
22823
22466
  }
22824
22467
  handleCompaction(event) {
22825
- const key = scopeKey(event);
22826
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
22827
- if (!state) {
22828
- return;
22829
- }
22468
+ const key = compactionKey(event);
22469
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
22470
+ const metadata = {
22471
+ ...state.metadata,
22472
+ ...extractEventMetadata(event),
22473
+ ...event.usage ? { "flue.usage": event.usage } : {}
22474
+ };
22830
22475
  safeLog3(state.span, {
22831
- metadata: {
22832
- ...state.metadata,
22833
- ...extractEventMetadata(event),
22834
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
22835
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
22836
- },
22476
+ metadata,
22837
22477
  metrics: {
22838
- ...durationMsMetrics(event.durationMs),
22839
- ...metricsFromUsage(event.usage)
22478
+ ...durationMetrics2(event.durationMs),
22479
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
22480
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
22840
22481
  },
22841
22482
  output: {
22842
22483
  messagesAfter: event.messagesAfter,
22843
22484
  messagesBefore: event.messagesBefore
22844
22485
  }
22845
22486
  });
22846
- state.span.end();
22847
- this.deleteCompactionState(state);
22487
+ safeEnd(state.span, eventTime(event.timestamp));
22488
+ this.compactionsByKey.delete(key);
22848
22489
  }
22849
- findCompactionState(event) {
22850
- const operationState = this.operationStateForEvent(event);
22851
- for (const state of this.compactionsByScope.values()) {
22852
- if (operationState && state.operationState === operationState) {
22853
- return state;
22490
+ parentSpanForTurn(event) {
22491
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
22492
+ const compaction = this.compactionsByKey.get(compactionKey(event));
22493
+ if (compaction) {
22494
+ return compaction.span;
22854
22495
  }
22855
22496
  }
22856
- return void 0;
22497
+ return this.parentSpanForEvent(event);
22857
22498
  }
22858
- finishCompactionsForOperation(operationState) {
22859
- for (const state of [...this.compactionsByScope.values()]) {
22860
- if (state.operationState !== operationState) {
22861
- continue;
22499
+ parentSpanForEvent(event) {
22500
+ const turn = turnKey(event);
22501
+ if (turn) {
22502
+ const turnState = this.turnsByKey.get(turn);
22503
+ if (turnState) {
22504
+ return turnState.span;
22862
22505
  }
22863
- safeLog3(state.span, {
22864
- input: state.input,
22865
- metadata: state.metadata,
22866
- metrics: {
22867
- ...buildDurationMetrics3(state.startTime)
22868
- },
22869
- output: { completed: true }
22870
- });
22871
- state.span.end();
22872
- this.deleteCompactionState(state);
22873
22506
  }
22874
- }
22875
- deleteCompactionState(state) {
22876
- for (const [key, candidate] of this.compactionsByScope) {
22877
- if (candidate !== state) {
22878
- continue;
22507
+ if (event.taskId) {
22508
+ const task = this.tasksById.get(event.taskId);
22509
+ if (task) {
22510
+ return task.span;
22879
22511
  }
22880
- this.compactionsByScope.delete(key);
22881
- return;
22882
22512
  }
22883
- }
22884
- startSyntheticToolState(event, toolName) {
22885
- const parent = this.parentSpanForEvent(event);
22886
- const metadata = {
22887
- ...extractEventMetadata(event),
22888
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
22889
- "flue.tool_name": toolName,
22890
- provider: "flue"
22891
- };
22892
- const span = startFlueSpan(parent, {
22893
- name: `tool: ${toolName}`,
22894
- spanAttributes: { type: "tool" /* TOOL */ }
22895
- });
22896
- safeLog3(span, { metadata });
22897
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
22898
- }
22899
- operationStateForEvent(event) {
22900
22513
  if (event.operationId) {
22901
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
22514
+ const operation = this.operationsById.get(event.operationId);
22902
22515
  if (operation) {
22903
- return operation;
22516
+ return operation.span;
22904
22517
  }
22905
22518
  }
22906
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
22519
+ if (event.runId) {
22520
+ return this.runsById.get(event.runId)?.span;
22521
+ }
22522
+ return void 0;
22907
22523
  }
22908
- parentSpanForEvent(event) {
22524
+ parentSpanForTool(event) {
22525
+ if (event.taskId) {
22526
+ const task = this.tasksById.get(event.taskId);
22527
+ if (task) {
22528
+ return task.span;
22529
+ }
22530
+ }
22909
22531
  if (event.operationId) {
22910
- const operation = this.operationStateForEvent(event);
22532
+ const operation = this.operationsById.get(event.operationId);
22911
22533
  if (operation) {
22912
22534
  return operation.span;
22913
22535
  }
22914
22536
  }
22915
- if (event.taskId) {
22916
- return this.tasksById.get(event.taskId)?.span;
22537
+ if (event.runId) {
22538
+ return this.runsById.get(event.runId)?.span;
22917
22539
  }
22918
- return this.operationStateForEvent(event)?.span;
22540
+ return void 0;
22919
22541
  }
22920
- promotePendingOperationForEvent(event) {
22921
- if (!event.operationId) {
22922
- return void 0;
22542
+ logOperationInput(operationId, input) {
22543
+ if (!operationId || input === void 0) {
22544
+ return;
22545
+ }
22546
+ const operation = this.operationsById.get(operationId);
22547
+ if (!operation || operation.loggedInput) {
22548
+ return;
22923
22549
  }
22924
- const scopePrefixes = operationScopePrefixes(event);
22925
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22926
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22550
+ safeLog3(operation.span, { input });
22551
+ operation.loggedInput = true;
22552
+ }
22553
+ startSyntheticOperation(event) {
22554
+ const metadata = {
22555
+ ...extractEventMetadata(event),
22556
+ "flue.operation": event.operationKind,
22557
+ provider: "flue"
22558
+ };
22559
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22560
+ name: `flue.${event.operationKind}`,
22561
+ spanAttributes: { type: "task" /* TASK */ },
22562
+ startTime: eventTime(event.timestamp),
22563
+ event: { metadata }
22564
+ });
22565
+ return { metadata, span };
22566
+ }
22567
+ startSyntheticTurn(event) {
22568
+ const metadata = {
22569
+ ...extractEventMetadata(event),
22570
+ ...event.api ? { "flue.api": event.api } : {},
22571
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
22572
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
22573
+ ...event.provider ? { "flue.provider": event.provider } : {},
22574
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
22575
+ };
22576
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22577
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
22578
+ spanAttributes: { type: "llm" /* LLM */ },
22579
+ startTime: eventTime(event.timestamp),
22580
+ event: { metadata }
22581
+ });
22582
+ return { metadata, span };
22583
+ }
22584
+ startSyntheticTool(event) {
22585
+ const metadata = {
22586
+ ...extractEventMetadata(event),
22587
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22588
+ "flue.tool_call_id": event.toolCallId,
22589
+ provider: "flue"
22590
+ };
22591
+ const span = startFlueSpan(this.parentSpanForTool(event), {
22592
+ name: `tool:${event.toolName ?? "unknown"}`,
22593
+ spanAttributes: { type: "tool" /* TOOL */ },
22594
+ startTime: eventTime(event.timestamp),
22595
+ event: { metadata }
22596
+ });
22597
+ return { metadata, span };
22598
+ }
22599
+ startSyntheticCompaction(event) {
22600
+ const metadata = {
22601
+ ...extractEventMetadata(event),
22602
+ provider: "flue"
22603
+ };
22604
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22605
+ name: "compaction:unknown",
22606
+ spanAttributes: { type: "task" /* TASK */ },
22607
+ startTime: eventTime(event.timestamp),
22608
+ event: { metadata }
22609
+ });
22610
+ return { metadata, span };
22611
+ }
22612
+ finishPendingChildrenForOperation(event, operationOutput2) {
22613
+ const endTime = eventTime(event.timestamp);
22614
+ const usage = event.usage ?? usageFromOperationResult(event.result);
22615
+ const turnEntries = [...this.turnsByKey].filter(
22616
+ ([, state]) => stateMatchesOperation(state, event.operationId)
22617
+ );
22618
+ turnEntries.forEach(([key, state], index) => {
22619
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
22620
+ safeLog3(state.span, {
22621
+ metadata: state.metadata,
22622
+ metrics: metricsFromUsage(usage),
22623
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
22624
+ });
22625
+ safeEnd(state.span, endTime);
22626
+ this.turnsByKey.delete(key);
22627
+ });
22628
+ for (const [key, state] of this.toolsByKey) {
22629
+ if (!stateMatchesOperation(state, event.operationId)) {
22927
22630
  continue;
22928
22631
  }
22929
- const state = candidateQueue.shift();
22930
- if (!state) {
22931
- return void 0;
22632
+ safeEnd(state.span, endTime);
22633
+ this.toolsByKey.delete(key);
22634
+ }
22635
+ for (const [key, state] of this.tasksById) {
22636
+ if (!stateMatchesOperation(state, event.operationId)) {
22637
+ continue;
22932
22638
  }
22933
- state.operationId = event.operationId;
22934
- this.activeOperationsById.set(event.operationId, state);
22935
- addScopedOperation(this.activeOperationsByScope, event, state);
22936
- state.metadata = {
22937
- ...state.metadata,
22938
- ...extractEventMetadata(event),
22939
- "flue.operation_id": event.operationId
22940
- };
22941
- safeLog3(state.span, { metadata: state.metadata });
22942
- return state;
22639
+ safeEnd(state.span, endTime);
22640
+ this.tasksById.delete(key);
22943
22641
  }
22944
- return void 0;
22945
- }
22946
- activeOperationForEventScope(event) {
22947
- for (const scope of operationScopeNames(event)) {
22948
- const operations = this.activeOperationsByScope.get(scope);
22949
- if (operations?.length) {
22950
- return operations[operations.length - 1];
22642
+ for (const [key, state] of this.compactionsByKey) {
22643
+ if (!stateMatchesOperation(state, event.operationId)) {
22644
+ continue;
22951
22645
  }
22646
+ safeLog3(state.span, {
22647
+ metadata: state.metadata,
22648
+ metrics: durationMetrics2(event.durationMs),
22649
+ output: { completed: true }
22650
+ });
22651
+ safeEnd(state.span, eventTime(event.timestamp));
22652
+ this.compactionsByKey.delete(key);
22952
22653
  }
22953
- return void 0;
22954
22654
  }
22955
- pendingOperationForEventScope(event) {
22956
- const scopePrefixes = operationScopePrefixes(event);
22957
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22958
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22655
+ finishPendingSpansForRun(event) {
22656
+ const endTime = eventTime(event.timestamp);
22657
+ for (const [key, state] of this.toolsByKey) {
22658
+ if (!stateMatchesRun(state, event.runId)) {
22959
22659
  continue;
22960
22660
  }
22961
- return candidateQueue[0];
22661
+ safeEnd(state.span, endTime);
22662
+ this.toolsByKey.delete(key);
22962
22663
  }
22963
- return void 0;
22964
- }
22965
- takePendingOperationForEvent(event) {
22966
- const key = operationKey(event.session, event.operationKind);
22967
- const queue = this.pendingOperationsByKey.get(key);
22968
- if (queue?.length) {
22969
- return queue.shift();
22664
+ for (const [key, state] of this.turnsByKey) {
22665
+ if (!stateMatchesRun(state, event.runId)) {
22666
+ continue;
22667
+ }
22668
+ safeEnd(state.span, endTime);
22669
+ this.turnsByKey.delete(key);
22970
22670
  }
22971
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22972
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
22973
- return candidateQueue.shift();
22671
+ for (const [key, state] of this.tasksById) {
22672
+ if (!stateMatchesRun(state, event.runId)) {
22673
+ continue;
22974
22674
  }
22675
+ safeEnd(state.span, endTime);
22676
+ this.tasksById.delete(key);
22975
22677
  }
22976
- return void 0;
22977
- }
22978
- pendingOperationQueue(key) {
22979
- const existing = this.pendingOperationsByKey.get(key);
22980
- if (existing) {
22981
- return existing;
22678
+ for (const [key, state] of this.compactionsByKey) {
22679
+ if (!stateMatchesRun(state, event.runId)) {
22680
+ continue;
22681
+ }
22682
+ safeLog3(state.span, {
22683
+ metadata: state.metadata,
22684
+ output: { completed: true }
22685
+ });
22686
+ safeEnd(state.span, endTime);
22687
+ this.compactionsByKey.delete(key);
22688
+ }
22689
+ for (const [key, state] of this.operationsById) {
22690
+ if (!stateMatchesRun(state, event.runId)) {
22691
+ continue;
22692
+ }
22693
+ safeLog3(state.span, {
22694
+ metadata: state.metadata,
22695
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
22696
+ });
22697
+ safeEnd(state.span, endTime);
22698
+ this.operationsById.delete(key);
22982
22699
  }
22983
- const queue = [];
22984
- this.pendingOperationsByKey.set(key, queue);
22985
- return queue;
22986
22700
  }
22987
22701
  };
22988
22702
  function isInstrumentedOperation(operation) {
22989
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
22990
- }
22991
- function getSessionName(session) {
22992
- return typeof session?.name === "string" ? session.name : void 0;
22993
- }
22994
- function operationKey(sessionName, operation) {
22995
- return `${sessionName ?? "unknown"}::${operation}`;
22996
- }
22997
- function operationScopePrefixes(event) {
22998
- const scopes = /* @__PURE__ */ new Set();
22999
- for (const scope of operationScopeNames(event)) {
23000
- scopes.add(`${scope}::`);
23001
- }
23002
- return scopes;
23003
- }
23004
- function operationKeyMatchesScopes(key, scopes) {
23005
- for (const scope of scopes) {
23006
- if (key.startsWith(scope)) {
23007
- return true;
23008
- }
23009
- }
23010
- return false;
23011
- }
23012
- function operationScopeNames(event) {
23013
- const scopes = /* @__PURE__ */ new Set();
23014
- if (event.session) {
23015
- scopes.add(event.session);
23016
- }
23017
- if (event.parentSession) {
23018
- scopes.add(event.parentSession);
23019
- }
23020
- if (!scopes.size) {
23021
- scopes.add("unknown");
23022
- }
23023
- return scopes;
23024
- }
23025
- function addScopedOperation(operationsByScope, event, state) {
23026
- for (const scope of operationScopeNames(event)) {
23027
- addOperationToScope(operationsByScope, scope, state);
23028
- }
23029
- }
23030
- function addOperationToScope(operationsByScope, scope, state) {
23031
- const operations = operationsByScope.get(scope);
23032
- if (operations) {
23033
- if (!operations.includes(state)) {
23034
- operations.push(state);
23035
- }
23036
- } else {
23037
- operationsByScope.set(scope, [state]);
23038
- }
23039
- }
23040
- function removeScopedOperation(operationsByScope, state) {
23041
- for (const [scope, operations] of operationsByScope) {
23042
- const index = operations.indexOf(state);
23043
- if (index === -1) {
23044
- continue;
23045
- }
23046
- operations.splice(index, 1);
23047
- if (operations.length === 0) {
23048
- operationsByScope.delete(scope);
23049
- }
23050
- }
23051
- }
23052
- function removePendingOperation(pendingOperationsByKey, state) {
23053
- for (const [key, queue] of pendingOperationsByKey) {
23054
- const index = queue.indexOf(state);
23055
- if (index === -1) {
23056
- continue;
23057
- }
23058
- queue.splice(index, 1);
23059
- if (queue.length === 0) {
23060
- pendingOperationsByKey.delete(key);
23061
- }
23062
- return;
23063
- }
23064
- }
23065
- function extractSessionMetadata(session) {
23066
- const sessionName = getSessionName(session);
23067
- return sessionName ? { "flue.session": sessionName } : {};
22703
+ return operation === "prompt" || operation === "skill" || operation === "compact";
23068
22704
  }
23069
- function extractEventMetadata(event) {
22705
+ function extractEventMetadata(event, ctx) {
23070
22706
  return {
23071
22707
  ...event.runId ? { "flue.run_id": event.runId } : {},
22708
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
22709
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
23072
22710
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
23073
22711
  ...event.session ? { "flue.session": event.session } : {},
23074
22712
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
23075
22713
  ...event.harness ? { "flue.harness": event.harness } : {},
23076
22714
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
23077
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
22715
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
22716
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
22717
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
22718
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
23078
22719
  };
23079
22720
  }
23080
- function extractOperationInput(operation, args) {
23081
- switch (operation) {
23082
- case "prompt":
23083
- case "task":
23084
- return args[0];
23085
- case "skill":
23086
- return {
23087
- args: getOptionObject(args[1])?.args,
23088
- name: args[0]
23089
- };
23090
- case "compact":
23091
- return void 0;
22721
+ function extractPayloadMetadata(payload) {
22722
+ if (!isObjectLike(payload)) {
22723
+ return {};
23092
22724
  }
22725
+ const metadata = Reflect.get(payload, "metadata");
22726
+ if (!isObjectLike(metadata)) {
22727
+ return {};
22728
+ }
22729
+ return Object.fromEntries(Object.entries(metadata));
23093
22730
  }
23094
- function extractOperationInputMetadata(operation, args) {
23095
- const options = getOptionObject(args[1]);
23096
- return {
23097
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
23098
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
23099
- ...options?.role ? { "flue.role": options.role } : {},
23100
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
23101
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
23102
- ...Array.isArray(options?.tools) ? {
23103
- "flue.tools_count": options.tools.length,
23104
- tools: summarizeTools(options.tools)
23105
- } : {},
23106
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
23107
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
23108
- };
23109
- }
23110
- function getOptionObject(value) {
23111
- return isObject(value) ? value : void 0;
23112
- }
23113
- function summarizeTools(tools) {
23114
- return tools.flatMap((tool) => {
23115
- if (!isObject(tool)) {
23116
- return [];
23117
- }
23118
- const name = typeof tool.name === "string" ? tool.name : void 0;
23119
- if (!name) {
23120
- return [];
23121
- }
23122
- return [
23123
- {
23124
- function: {
23125
- description: typeof tool.description === "string" ? tool.description : void 0,
23126
- name,
23127
- parameters: tool.parameters
23128
- },
23129
- type: "function"
23130
- }
23131
- ];
23132
- });
22731
+ function operationOutput(event) {
22732
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
22733
+ return llmResultFromOperationResult(event.result);
22734
+ }
22735
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
23133
22736
  }
23134
- function extractPromptResponseMetadata(result) {
23135
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
23136
- return modelId ? {
23137
- model: modelId,
23138
- "flue.model": modelId
23139
- } : {};
22737
+ function llmResultFromOperationResult(result) {
22738
+ if (!isObjectLike(result)) {
22739
+ return result;
22740
+ }
22741
+ const text = Reflect.get(result, "text");
22742
+ return text === void 0 ? result : text;
23140
22743
  }
23141
- function extractOperationOutput(result) {
23142
- if (!result) {
22744
+ function usageFromOperationResult(result) {
22745
+ if (!isObjectLike(result)) {
23143
22746
  return void 0;
23144
22747
  }
23145
- if ("data" in result) {
23146
- return result.data;
23147
- }
23148
- if ("text" in result) {
23149
- return result.text;
23150
- }
23151
- return result;
22748
+ return Reflect.get(result, "usage");
23152
22749
  }
23153
22750
  function metricsFromUsage(usage) {
22751
+ if (!isObjectLike(usage)) {
22752
+ return {};
22753
+ }
22754
+ const cacheRead = Reflect.get(usage, "cacheRead");
22755
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
22756
+ const cost = Reflect.get(usage, "cost");
22757
+ const input = Reflect.get(usage, "input");
22758
+ const output = Reflect.get(usage, "output");
22759
+ const totalTokens = Reflect.get(usage, "totalTokens");
22760
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
23154
22761
  return {
23155
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
23156
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
23157
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
23158
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
23159
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
23160
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
23161
- };
23162
- }
23163
- function buildDurationMetrics3(startTime) {
23164
- return {
23165
- duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
22762
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
22763
+ ...typeof output === "number" ? { completion_tokens: output } : {},
22764
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
22765
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
22766
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
22767
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
23166
22768
  };
23167
22769
  }
23168
- function durationMsMetrics(durationMs) {
22770
+ function durationMetrics2(durationMs) {
23169
22771
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
23170
22772
  }
23171
- function scopeKey(event) {
23172
- if (event.operationId) {
23173
- return `operation:${event.operationId}`;
23174
- }
23175
- if (event.taskId) {
23176
- return `task:${event.taskId}`;
23177
- }
23178
- if (event.session) {
23179
- return `session:${event.session}`;
22773
+ function eventTime(value) {
22774
+ if (typeof value !== "string") {
22775
+ return void 0;
23180
22776
  }
23181
- return "flue:unknown";
22777
+ const timestamp = Date.parse(value);
22778
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
22779
+ }
22780
+ function turnKey(event) {
22781
+ return event.turnId;
23182
22782
  }
23183
22783
  function toolKey(event) {
23184
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
22784
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
23185
22785
  }
23186
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
22786
+ function compactionKey(event) {
23187
22787
  return [
23188
- {
23189
- finish_reason: finishReason ?? "stop",
23190
- index: 0,
23191
- message: {
23192
- content: text,
23193
- ...reasoning ? { reasoning } : {},
23194
- role: "assistant",
23195
- ...toolCalls?.length ? {
23196
- tool_calls: toolCalls.map((toolCall) => ({
23197
- function: {
23198
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
23199
- name: toolCall.toolName ?? "unknown"
23200
- },
23201
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
23202
- type: "function"
23203
- }))
23204
- } : {}
23205
- }
23206
- }
23207
- ];
22788
+ event.instanceId ?? "",
22789
+ event.runId ?? "",
22790
+ event.session ?? "",
22791
+ event.operationId ?? "",
22792
+ event.taskId ?? ""
22793
+ ].join(":");
22794
+ }
22795
+ function stateMatchesOperation(state, operationId) {
22796
+ return state.metadata["flue.operation_id"] === operationId;
22797
+ }
22798
+ function stateMatchesRun(state, runId) {
22799
+ return state.metadata["flue.run_id"] === runId;
23208
22800
  }
23209
22801
  function startFlueSpan(parent, args) {
23210
22802
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -23216,6 +22808,13 @@ function safeLog3(span, event) {
23216
22808
  logInstrumentationError3("Flue span log", error);
23217
22809
  }
23218
22810
  }
22811
+ function safeEnd(span, endTime) {
22812
+ try {
22813
+ span.end(endTime === void 0 ? void 0 : { endTime });
22814
+ } catch (error) {
22815
+ logInstrumentationError3("Flue span end", error);
22816
+ }
22817
+ }
23219
22818
  function errorToString(error) {
23220
22819
  if (error instanceof Error) {
23221
22820
  return error.message;
@@ -24055,6 +23654,7 @@ function configureInstrumentation(config) {
24055
23654
  BasePlugin,
24056
23655
  BraintrustPlugin,
24057
23656
  OpenAIAgentsTraceProcessor,
23657
+ braintrustFlueObserver,
24058
23658
  configureInstrumentation,
24059
23659
  createChannelName,
24060
23660
  isValidChannelName,