braintrust 3.14.0 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dev/dist/index.js +616 -1026
  2. package/dev/dist/index.mjs +577 -987
  3. package/dist/apply-auto-instrumentation.js +176 -186
  4. package/dist/apply-auto-instrumentation.mjs +6 -16
  5. package/dist/auto-instrumentations/bundler/esbuild.cjs +5 -39
  6. package/dist/auto-instrumentations/bundler/esbuild.mjs +1 -1
  7. package/dist/auto-instrumentations/bundler/next.cjs +5 -39
  8. package/dist/auto-instrumentations/bundler/next.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/rollup.cjs +5 -39
  10. package/dist/auto-instrumentations/bundler/rollup.mjs +1 -1
  11. package/dist/auto-instrumentations/bundler/vite.cjs +5 -39
  12. package/dist/auto-instrumentations/bundler/vite.mjs +1 -1
  13. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +5 -39
  14. package/dist/auto-instrumentations/bundler/webpack.cjs +5 -39
  15. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  16. package/dist/auto-instrumentations/{chunk-OTUQ7KH5.mjs → chunk-CNQ7BUKN.mjs} +1 -1
  17. package/dist/auto-instrumentations/{chunk-XKAAVWT6.mjs → chunk-VXJONZVX.mjs} +5 -39
  18. package/dist/auto-instrumentations/hook.mjs +5 -39
  19. package/dist/browser.d.mts +13 -17
  20. package/dist/browser.d.ts +13 -17
  21. package/dist/browser.js +581 -1015
  22. package/dist/browser.mjs +581 -1015
  23. package/dist/{chunk-NU2GSPHX.mjs → chunk-O4ZIWXO3.mjs} +0 -24
  24. package/dist/{chunk-NKD77KGB.js → chunk-VMBQETG3.js} +0 -24
  25. package/dist/cli.js +578 -988
  26. package/dist/edge-light.d.mts +1 -1
  27. package/dist/edge-light.d.ts +1 -1
  28. package/dist/edge-light.js +581 -1015
  29. package/dist/edge-light.mjs +581 -1015
  30. package/dist/index.d.mts +13 -17
  31. package/dist/index.d.ts +13 -17
  32. package/dist/index.js +967 -1377
  33. package/dist/index.mjs +582 -992
  34. package/dist/instrumentation/index.d.mts +11 -1
  35. package/dist/instrumentation/index.d.ts +11 -1
  36. package/dist/instrumentation/index.js +611 -1015
  37. package/dist/instrumentation/index.mjs +610 -1015
  38. package/dist/workerd.d.mts +1 -1
  39. package/dist/workerd.d.ts +1 -1
  40. package/dist/workerd.js +581 -1015
  41. package/dist/workerd.mjs +581 -1015
  42. package/package.json +1 -1
@@ -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,
@@ -6736,6 +6737,10 @@ ${stackTrace}` });
6736
6737
  function startSpan(args) {
6737
6738
  return startSpanAndIsLogger(args).span;
6738
6739
  }
6740
+ async function flush(options) {
6741
+ const state = options?.state ?? _globalState;
6742
+ return await state.bgLogger().flush();
6743
+ }
6739
6744
  function startSpanAndIsLogger(args) {
6740
6745
  const state = args?.state ?? _globalState;
6741
6746
  const parentObject = getSpanParentObject({
@@ -21977,803 +21982,440 @@ var flueChannels = defineChannels("@flue/runtime", {
21977
21982
  createContext: channel({
21978
21983
  channelName: "createFlueContext",
21979
21984
  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
21985
  })
22005
21986
  });
22006
21987
 
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;
21988
+ // src/instrumentation/plugins/flue-plugin.ts
21989
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
21990
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
21991
+ var braintrustFlueObserver = (event, ctx) => {
21992
+ getObserveBridge().handle(event, ctx);
21993
+ };
21994
+ var FluePlugin = class extends BasePlugin {
21995
+ onEnable() {
21996
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
22041
21997
  }
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 {
21998
+ onDisable() {
21999
+ for (const unsubscribe of this.unsubscribers) {
22000
+ unsubscribe();
22052
22001
  }
22002
+ this.unsubscribers = [];
22053
22003
  }
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
- });
22004
+ };
22005
+ function enableFlueAutoInstrumentation() {
22006
+ const state = getAutoState();
22007
+ state.refCount += 1;
22008
+ if (!state.handlers) {
22009
+ const channel2 = flueChannels.createContext.tracingChannel();
22010
+ const handlers = {
22011
+ end: (event) => {
22012
+ subscribeToFlueContext(event.result, state);
22013
+ }
22014
+ };
22015
+ channel2.subscribe(handlers);
22016
+ state.channel = channel2;
22017
+ state.handlers = handlers;
22018
+ }
22019
+ let released = false;
22020
+ return () => {
22021
+ if (released) {
22022
+ return;
22074
22023
  }
22075
- return unsubscribe;
22076
- } catch {
22077
- return void 0;
22024
+ released = true;
22025
+ releaseAutoState(state);
22026
+ };
22027
+ }
22028
+ function getAutoState() {
22029
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
22030
+ if (isAutoState(existing)) {
22031
+ return existing;
22078
22032
  }
22033
+ const state = {
22034
+ contexts: /* @__PURE__ */ new WeakSet(),
22035
+ refCount: 0
22036
+ };
22037
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
22038
+ return state;
22079
22039
  }
22080
- function wrapFlueHarness(harness) {
22081
- if (!isPlausibleFlueHarness(harness)) {
22082
- return harness;
22040
+ function getObserveBridge() {
22041
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
22042
+ if (isFlueObserveBridge(existing)) {
22043
+ return existing;
22083
22044
  }
22084
- const target = harness;
22085
- if (target[WRAPPED_FLUE_HARNESS]) {
22086
- return harness;
22045
+ const bridge = new FlueObserveBridge();
22046
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
22047
+ return bridge;
22048
+ }
22049
+ function isFlueObserveBridge(value) {
22050
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
22051
+ }
22052
+ function isAutoState(value) {
22053
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
22054
+ }
22055
+ function releaseAutoState(state) {
22056
+ state.refCount -= 1;
22057
+ if (state.refCount > 0) {
22058
+ return;
22087
22059
  }
22088
- const originalSession = target.session.bind(target);
22089
22060
  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");
22061
+ if (state.channel && state.handlers) {
22062
+ state.channel.unsubscribe(state.handlers);
22107
22063
  }
22108
- } catch {
22064
+ } finally {
22065
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
22109
22066
  }
22110
- return harness;
22111
22067
  }
22112
- function patchFlueSessionInPlace(session) {
22113
- if (session[WRAPPED_FLUE_SESSION]) {
22114
- return session;
22068
+ function subscribeToFlueContext(value, state) {
22069
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
22070
+ return;
22115
22071
  }
22072
+ const ctx = flueContextFromUnknown(value);
22073
+ let released = false;
22074
+ let unsubscribe;
22075
+ const release = () => {
22076
+ if (released) {
22077
+ return;
22078
+ }
22079
+ released = true;
22080
+ try {
22081
+ unsubscribe?.();
22082
+ } catch (error) {
22083
+ logInstrumentationError3("Flue context unsubscribe", error);
22084
+ }
22085
+ };
22116
22086
  try {
22117
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
22118
- configurable: false,
22119
- enumerable: false,
22120
- value: true
22087
+ unsubscribe = value.subscribeEvent((event) => {
22088
+ if (state.refCount <= 0) {
22089
+ release();
22090
+ return;
22091
+ }
22092
+ braintrustFlueObserver(event, ctx);
22093
+ if (isAutoContextTerminalEvent(event, ctx)) {
22094
+ release();
22095
+ }
22121
22096
  });
22122
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
22123
- patchCallHandleMethod(session, "skill", flueChannels.skill);
22124
- patchCallHandleMethod(session, "task", flueChannels.task);
22125
- patchCompact(session);
22126
- } catch {
22097
+ state.contexts.add(value);
22098
+ } catch (error) {
22099
+ logInstrumentationError3("Flue context subscription", error);
22127
22100
  }
22128
- return session;
22129
22101
  }
22130
- function patchFlueSessionFactory(sessions, method) {
22131
- const original = sessions[method];
22132
- if (typeof original !== "function") {
22133
- return;
22102
+ function isAutoContextTerminalEvent(event, ctx) {
22103
+ if (!isObjectLike(event)) {
22104
+ return false;
22134
22105
  }
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;
22106
+ const type = Reflect.get(event, "type");
22107
+ if (type === "run_end") {
22108
+ return true;
22149
22109
  }
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;
22110
+ if (type !== "operation") {
22111
+ return false;
22172
22112
  }
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
- });
22113
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
22186
22114
  }
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 };
22115
+ function isObservableFlueContext(value) {
22116
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
22225
22117
  }
22226
- function normalizeError3(error) {
22227
- return error instanceof Error ? error : new Error(String(error));
22118
+ function isFlueEvent(event) {
22119
+ const type = Reflect.get(event, "type");
22120
+ 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
22121
  }
22229
- function preserveCallHandle(originalHandle, traced) {
22230
- if (!isFlueCallHandle(originalHandle)) {
22231
- return traced;
22122
+ function flueContextFromUnknown(ctx) {
22123
+ if (!isObjectLike(ctx)) {
22124
+ return void 0;
22232
22125
  }
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
- }
22126
+ const id = Reflect.get(ctx, "id");
22127
+ const runId = Reflect.get(ctx, "runId");
22128
+ return {
22129
+ ...typeof id === "string" ? { id } : {},
22130
+ ...typeof runId === "string" ? { runId } : {}
22244
22131
  };
22245
- return wrapped;
22246
- }
22247
- function isPlausibleFlueHarness(value) {
22248
- return !!value && typeof value === "object" && typeof value.session === "function";
22249
22132
  }
22250
- function isFlueCallHandle(value) {
22251
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
22133
+ function isObjectLike(value) {
22134
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22252
22135
  }
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();
22136
+ var FlueObserveBridge = class {
22137
+ compactionsByKey = /* @__PURE__ */ new Map();
22138
+ operationsById = /* @__PURE__ */ new Map();
22139
+ runsById = /* @__PURE__ */ new Map();
22140
+ seenEvents = /* @__PURE__ */ new WeakSet();
22260
22141
  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();
22142
+ toolsByKey = /* @__PURE__ */ new Map();
22143
+ turnsByKey = /* @__PURE__ */ new Map();
22144
+ handle(event, ctx) {
22145
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
22146
+ return;
22272
22147
  }
22273
- this.unsubscribers = [];
22274
- this.activeOperationsById.clear();
22275
- this.activeOperationsByScope.clear();
22276
- this.compactionsByScope.clear();
22277
- this.pendingOperationsByKey.clear();
22148
+ if (this.seenEvents.has(event)) {
22149
+ return;
22150
+ }
22151
+ this.seenEvents.add(event);
22152
+ try {
22153
+ this.handleEvent(event, flueContextFromUnknown(ctx));
22154
+ } catch (error) {
22155
+ logInstrumentationError3("Flue observe", error);
22156
+ }
22157
+ }
22158
+ reset() {
22159
+ this.compactionsByKey.clear();
22160
+ this.operationsById.clear();
22161
+ this.runsById.clear();
22162
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
22278
22163
  this.tasksById.clear();
22279
- this.toolsById.clear();
22280
- this.turnsByScope.clear();
22164
+ this.toolsByKey.clear();
22165
+ this.turnsByKey.clear();
22281
22166
  }
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
- });
22167
+ handleEvent(event, ctx) {
22168
+ switch (event.type) {
22169
+ case "run_start":
22170
+ this.handleRunStart(event, ctx);
22171
+ return;
22172
+ case "run_end":
22173
+ this.handleRunEnd(event);
22174
+ return;
22175
+ case "operation_start":
22176
+ this.handleOperationStart(event);
22177
+ return;
22178
+ case "operation":
22179
+ this.handleOperation(event);
22180
+ return;
22181
+ case "turn_request":
22182
+ this.handleTurnRequest(event);
22183
+ return;
22184
+ case "turn":
22185
+ this.handleTurn(event);
22186
+ return;
22187
+ case "tool_start":
22188
+ this.handleToolStart(event);
22189
+ return;
22190
+ case "tool_call":
22191
+ this.handleToolCall(event);
22192
+ return;
22193
+ case "task_start":
22194
+ this.handleTaskStart(event);
22195
+ return;
22196
+ case "task":
22197
+ this.handleTask(event);
22198
+ return;
22199
+ case "compaction_start":
22200
+ this.handleCompactionStart(event);
22201
+ return;
22202
+ case "compaction":
22203
+ this.handleCompaction(event);
22204
+ return;
22205
+ default:
22206
+ return;
22207
+ }
22300
22208
  }
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
- }
22209
+ handleRunStart(event, ctx) {
22210
+ if (!event.runId) {
22211
+ return;
22212
+ }
22213
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
22214
+ const metadata = {
22215
+ ...extractPayloadMetadata(event.payload),
22216
+ ...extractEventMetadata(event, ctx),
22217
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
22218
+ provider: "flue"
22316
22219
  };
22317
- channel2.subscribe(handlers);
22318
- this.unsubscribers.push(() => {
22319
- channel2.unsubscribe(handlers);
22220
+ const span = startSpan({
22221
+ name: `workflow:${workflowName}`,
22222
+ spanAttributes: { type: "task" /* TASK */ },
22223
+ startTime: eventTime(event.startedAt ?? event.timestamp),
22224
+ event: {
22225
+ input: event.payload,
22226
+ metadata
22227
+ }
22320
22228
  });
22229
+ this.runsById.set(event.runId, { metadata, span });
22321
22230
  }
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
22231
+ handleRunEnd(event) {
22232
+ const state = this.runsById.get(event.runId);
22233
+ this.finishPendingSpansForRun(event);
22234
+ if (state) {
22235
+ safeLog3(state.span, {
22236
+ ...event.isError ? { error: errorToString(event.error) } : {},
22237
+ metadata: {
22238
+ ...state.metadata,
22239
+ ...extractEventMetadata(event),
22240
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22241
+ },
22242
+ metrics: durationMetrics2(event.durationMs),
22243
+ output: event.result
22341
22244
  });
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);
22245
+ safeEnd(state.span, eventTime(event.timestamp));
22246
+ this.runsById.delete(event.runId);
22247
+ }
22248
+ void flush().catch((error) => {
22249
+ logInstrumentationError3("Flue flush", error);
22370
22250
  });
22371
22251
  }
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
22252
  handleOperationStart(event) {
22581
- if (!isInstrumentedOperation(event.operationKind)) {
22253
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
22582
22254
  return;
22583
22255
  }
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,
22256
+ const metadata = {
22593
22257
  ...extractEventMetadata(event),
22594
- "flue.operation_id": event.operationId
22258
+ "flue.operation": event.operationKind,
22259
+ provider: "flue"
22595
22260
  };
22596
- safeLog3(state.span, { metadata: state.metadata });
22261
+ const parent = this.parentSpanForEvent(event);
22262
+ const span = startFlueSpan(parent, {
22263
+ name: `flue.${event.operationKind}`,
22264
+ spanAttributes: { type: "task" /* TASK */ },
22265
+ startTime: eventTime(event.timestamp),
22266
+ event: { metadata }
22267
+ });
22268
+ this.operationsById.set(event.operationId, { metadata, span });
22597
22269
  }
22598
22270
  handleOperation(event) {
22599
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
22600
- if (!state) {
22271
+ if (!isInstrumentedOperation(event.operationKind)) {
22601
22272
  return;
22602
22273
  }
22274
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
22275
+ const output = operationOutput(event);
22603
22276
  const metadata = {
22604
22277
  ...state.metadata,
22605
22278
  ...extractEventMetadata(event),
22606
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
22607
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22279
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
22280
+ ...event.usage ? { "flue.usage": event.usage } : {}
22608
22281
  };
22609
- const metrics = metricsFromUsage(event.usage);
22282
+ this.finishPendingChildrenForOperation(event, output);
22610
22283
  safeLog3(state.span, {
22611
- ...event.error ? { error: errorToString(event.error) } : {},
22284
+ ...event.isError ? { error: errorToString(event.error) } : {},
22612
22285
  metadata,
22613
- ...Object.keys(metrics).length ? { metrics } : {}
22286
+ metrics: durationMetrics2(event.durationMs),
22287
+ output
22614
22288
  });
22289
+ safeEnd(state.span, eventTime(event.timestamp));
22290
+ this.operationsById.delete(event.operationId);
22615
22291
  }
22616
- ensureTurnState(event) {
22617
- const scope = scopeKey(event);
22618
- const existing = this.turnsByScope.get(scope);
22619
- if (existing) {
22620
- return existing;
22292
+ handleTurnRequest(event) {
22293
+ const key = turnKey(event);
22294
+ if (!key) {
22295
+ return;
22621
22296
  }
22622
- const parent = this.parentSpanForEvent(event);
22623
22297
  const metadata = {
22624
22298
  ...extractEventMetadata(event),
22625
- provider: "flue"
22299
+ ...event.api ? { "flue.api": event.api } : {},
22300
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
22301
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
22302
+ ...event.provider ? { "flue.provider": event.provider } : {},
22303
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
22304
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
22305
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
22306
+ ...event.input?.tools ? { tools: event.input.tools } : {}
22626
22307
  };
22308
+ const parent = this.parentSpanForTurn(event);
22627
22309
  const span = startFlueSpan(parent, {
22628
- name: "flue.turn",
22629
- spanAttributes: { type: "llm" /* LLM */ }
22310
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
22311
+ spanAttributes: { type: "llm" /* LLM */ },
22312
+ startTime: eventTime(event.timestamp),
22313
+ event: {
22314
+ input: event.input?.messages,
22315
+ metadata
22316
+ }
22630
22317
  });
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;
22318
+ this.logOperationInput(
22319
+ event.operationId,
22320
+ event.input?.messages ?? event.input
22321
+ );
22322
+ this.turnsByKey.set(key, { metadata, span });
22643
22323
  }
22644
22324
  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);
22325
+ const key = turnKey(event);
22326
+ if (!key) {
22327
+ return;
22328
+ }
22329
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
22650
22330
  const metadata = {
22651
22331
  ...state.metadata,
22652
22332
  ...extractEventMetadata(event),
22333
+ ...event.api ? { "flue.api": event.api } : {},
22653
22334
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
22335
+ ...event.provider ? { provider: event.provider } : {},
22336
+ ...event.provider ? { "flue.provider": event.provider } : {},
22337
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
22654
22338
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
22655
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
22656
- provider: "flue"
22339
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22657
22340
  };
22658
22341
  safeLog3(state.span, {
22659
- ...event.error ? { error: errorToString(event.error) } : {},
22342
+ ...event.isError ? { error: errorToString(event.error) } : {},
22660
22343
  metadata,
22661
22344
  metrics: {
22662
- ...durationMsMetrics(event.durationMs),
22345
+ ...durationMetrics2(event.durationMs),
22663
22346
  ...metricsFromUsage(event.usage)
22664
22347
  },
22665
- output: toAssistantOutput(
22666
- text,
22667
- event.stopReason,
22668
- outputReasoning,
22669
- state.toolCalls
22670
- )
22348
+ output: event.output
22671
22349
  });
22672
- state.span.end();
22673
- this.turnsByScope.delete(scope);
22674
- }
22675
- handleThinkingDelta(event) {
22676
- const delta = event.delta;
22677
- if (typeof delta !== "string" || !delta) {
22678
- return;
22679
- }
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
- }
22350
+ safeEnd(state.span, eventTime(event.timestamp));
22351
+ this.turnsByKey.delete(key);
22697
22352
  }
22698
- handleToolStart(event, options) {
22699
- const toolCallId = event.toolCallId;
22700
- if (!toolCallId) {
22353
+ handleToolStart(event) {
22354
+ if (!event.toolCallId) {
22701
22355
  return;
22702
22356
  }
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
22357
  const metadata = {
22710
22358
  ...extractEventMetadata(event),
22711
22359
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22712
- "flue.tool_call_id": toolCallId,
22360
+ "flue.tool_call_id": event.toolCallId,
22713
22361
  provider: "flue"
22714
22362
  };
22363
+ const parent = this.parentSpanForTool(event);
22715
22364
  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()
22365
+ name: `tool:${event.toolName ?? "unknown"}`,
22366
+ spanAttributes: { type: "tool" /* TOOL */ },
22367
+ startTime: eventTime(event.timestamp),
22368
+ event: {
22369
+ input: event.args,
22370
+ metadata
22371
+ }
22734
22372
  });
22373
+ this.toolsByKey.set(toolKey(event), { metadata, span });
22735
22374
  }
22736
22375
  handleToolCall(event) {
22376
+ if (!event.toolCallId) {
22377
+ return;
22378
+ }
22737
22379
  const key = toolKey(event);
22738
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
22380
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
22739
22381
  const metadata = {
22740
22382
  ...state.metadata,
22741
22383
  ...extractEventMetadata(event),
22742
22384
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22743
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
22385
+ "flue.tool_call_id": event.toolCallId,
22744
22386
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22745
22387
  };
22746
22388
  safeLog3(state.span, {
22747
22389
  ...event.isError ? { error: errorToString(event.result) } : {},
22748
22390
  metadata,
22749
- metrics: durationMsMetrics(event.durationMs),
22391
+ metrics: durationMetrics2(event.durationMs),
22750
22392
  output: event.result
22751
22393
  });
22752
- state.span.end();
22753
- this.toolsById.delete(key);
22394
+ safeEnd(state.span, eventTime(event.timestamp));
22395
+ this.toolsByKey.delete(key);
22754
22396
  }
22755
22397
  handleTaskStart(event) {
22756
- const parent = this.parentSpanForEvent(event);
22398
+ if (!event.taskId) {
22399
+ return;
22400
+ }
22757
22401
  const metadata = {
22758
22402
  ...extractEventMetadata(event),
22759
- ...event.role ? { "flue.role": event.role } : {},
22403
+ ...event.agent ? { "flue.agent": event.agent } : {},
22760
22404
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
22761
22405
  "flue.task_id": event.taskId,
22762
22406
  provider: "flue"
22763
22407
  };
22408
+ const parent = this.parentSpanForEvent(event);
22764
22409
  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()
22410
+ name: event.agent ? `task:${event.agent}` : "flue.task",
22411
+ spanAttributes: { type: "task" /* TASK */ },
22412
+ startTime: eventTime(event.timestamp),
22413
+ event: {
22414
+ input: event.prompt,
22415
+ metadata
22416
+ }
22776
22417
  });
22418
+ this.tasksById.set(event.taskId, { metadata, span });
22777
22419
  }
22778
22420
  handleTask(event) {
22779
22421
  const state = this.tasksById.get(event.taskId);
@@ -22785,426 +22427,372 @@ var FluePlugin = class extends BasePlugin {
22785
22427
  metadata: {
22786
22428
  ...state.metadata,
22787
22429
  ...extractEventMetadata(event),
22430
+ ...event.agent ? { "flue.agent": event.agent } : {},
22788
22431
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22789
22432
  },
22790
- metrics: durationMsMetrics(event.durationMs),
22433
+ metrics: durationMetrics2(event.durationMs),
22791
22434
  output: event.result
22792
22435
  });
22793
- state.span.end();
22436
+ safeEnd(state.span, eventTime(event.timestamp));
22794
22437
  this.tasksById.delete(event.taskId);
22795
22438
  }
22796
22439
  handleCompactionStart(event) {
22797
- const operationState = this.operationStateForEvent(event);
22798
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
22440
+ const key = compactionKey(event);
22441
+ const input = {
22442
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
22443
+ ...event.reason ? { reason: event.reason } : {}
22444
+ };
22799
22445
  const metadata = {
22800
22446
  ...extractEventMetadata(event),
22801
22447
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
22802
22448
  provider: "flue"
22803
22449
  };
22804
- const input = {
22805
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
22806
- ...event.reason ? { reason: event.reason } : {}
22807
- };
22450
+ const parent = this.parentSpanForEvent(event);
22808
22451
  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()
22452
+ name: `compaction:${event.reason ?? "unknown"}`,
22453
+ spanAttributes: { type: "task" /* TASK */ },
22454
+ startTime: eventTime(event.timestamp),
22455
+ event: {
22456
+ input,
22457
+ metadata
22458
+ }
22822
22459
  });
22460
+ this.logOperationInput(event.operationId, input);
22461
+ this.compactionsByKey.set(key, { metadata, span });
22823
22462
  }
22824
22463
  handleCompaction(event) {
22825
- const key = scopeKey(event);
22826
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
22827
- if (!state) {
22828
- return;
22829
- }
22464
+ const key = compactionKey(event);
22465
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
22466
+ const metadata = {
22467
+ ...state.metadata,
22468
+ ...extractEventMetadata(event),
22469
+ ...event.usage ? { "flue.usage": event.usage } : {}
22470
+ };
22830
22471
  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
- },
22472
+ metadata,
22837
22473
  metrics: {
22838
- ...durationMsMetrics(event.durationMs),
22839
- ...metricsFromUsage(event.usage)
22474
+ ...durationMetrics2(event.durationMs),
22475
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
22476
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
22840
22477
  },
22841
22478
  output: {
22842
22479
  messagesAfter: event.messagesAfter,
22843
22480
  messagesBefore: event.messagesBefore
22844
22481
  }
22845
22482
  });
22846
- state.span.end();
22847
- this.deleteCompactionState(state);
22483
+ safeEnd(state.span, eventTime(event.timestamp));
22484
+ this.compactionsByKey.delete(key);
22848
22485
  }
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;
22486
+ parentSpanForTurn(event) {
22487
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
22488
+ const compaction = this.compactionsByKey.get(compactionKey(event));
22489
+ if (compaction) {
22490
+ return compaction.span;
22854
22491
  }
22855
22492
  }
22856
- return void 0;
22493
+ return this.parentSpanForEvent(event);
22857
22494
  }
22858
- finishCompactionsForOperation(operationState) {
22859
- for (const state of [...this.compactionsByScope.values()]) {
22860
- if (state.operationState !== operationState) {
22861
- continue;
22495
+ parentSpanForEvent(event) {
22496
+ const turn = turnKey(event);
22497
+ if (turn) {
22498
+ const turnState = this.turnsByKey.get(turn);
22499
+ if (turnState) {
22500
+ return turnState.span;
22862
22501
  }
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
22502
  }
22874
- }
22875
- deleteCompactionState(state) {
22876
- for (const [key, candidate] of this.compactionsByScope) {
22877
- if (candidate !== state) {
22878
- continue;
22503
+ if (event.taskId) {
22504
+ const task = this.tasksById.get(event.taskId);
22505
+ if (task) {
22506
+ return task.span;
22879
22507
  }
22880
- this.compactionsByScope.delete(key);
22881
- return;
22882
22508
  }
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
22509
  if (event.operationId) {
22901
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
22510
+ const operation = this.operationsById.get(event.operationId);
22902
22511
  if (operation) {
22903
- return operation;
22512
+ return operation.span;
22904
22513
  }
22905
22514
  }
22906
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
22515
+ if (event.runId) {
22516
+ return this.runsById.get(event.runId)?.span;
22517
+ }
22518
+ return void 0;
22907
22519
  }
22908
- parentSpanForEvent(event) {
22520
+ parentSpanForTool(event) {
22521
+ if (event.taskId) {
22522
+ const task = this.tasksById.get(event.taskId);
22523
+ if (task) {
22524
+ return task.span;
22525
+ }
22526
+ }
22909
22527
  if (event.operationId) {
22910
- const operation = this.operationStateForEvent(event);
22528
+ const operation = this.operationsById.get(event.operationId);
22911
22529
  if (operation) {
22912
22530
  return operation.span;
22913
22531
  }
22914
22532
  }
22915
- if (event.taskId) {
22916
- return this.tasksById.get(event.taskId)?.span;
22533
+ if (event.runId) {
22534
+ return this.runsById.get(event.runId)?.span;
22917
22535
  }
22918
- return this.operationStateForEvent(event)?.span;
22536
+ return void 0;
22919
22537
  }
22920
- promotePendingOperationForEvent(event) {
22921
- if (!event.operationId) {
22922
- return void 0;
22538
+ logOperationInput(operationId, input) {
22539
+ if (!operationId || input === void 0) {
22540
+ return;
22923
22541
  }
22924
- const scopePrefixes = operationScopePrefixes(event);
22925
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22926
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22542
+ const operation = this.operationsById.get(operationId);
22543
+ if (!operation || operation.loggedInput) {
22544
+ return;
22545
+ }
22546
+ safeLog3(operation.span, { input });
22547
+ operation.loggedInput = true;
22548
+ }
22549
+ startSyntheticOperation(event) {
22550
+ const metadata = {
22551
+ ...extractEventMetadata(event),
22552
+ "flue.operation": event.operationKind,
22553
+ provider: "flue"
22554
+ };
22555
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22556
+ name: `flue.${event.operationKind}`,
22557
+ spanAttributes: { type: "task" /* TASK */ },
22558
+ startTime: eventTime(event.timestamp),
22559
+ event: { metadata }
22560
+ });
22561
+ return { metadata, span };
22562
+ }
22563
+ startSyntheticTurn(event) {
22564
+ const metadata = {
22565
+ ...extractEventMetadata(event),
22566
+ ...event.api ? { "flue.api": event.api } : {},
22567
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
22568
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
22569
+ ...event.provider ? { "flue.provider": event.provider } : {},
22570
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
22571
+ };
22572
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22573
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
22574
+ spanAttributes: { type: "llm" /* LLM */ },
22575
+ startTime: eventTime(event.timestamp),
22576
+ event: { metadata }
22577
+ });
22578
+ return { metadata, span };
22579
+ }
22580
+ startSyntheticTool(event) {
22581
+ const metadata = {
22582
+ ...extractEventMetadata(event),
22583
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22584
+ "flue.tool_call_id": event.toolCallId,
22585
+ provider: "flue"
22586
+ };
22587
+ const span = startFlueSpan(this.parentSpanForTool(event), {
22588
+ name: `tool:${event.toolName ?? "unknown"}`,
22589
+ spanAttributes: { type: "tool" /* TOOL */ },
22590
+ startTime: eventTime(event.timestamp),
22591
+ event: { metadata }
22592
+ });
22593
+ return { metadata, span };
22594
+ }
22595
+ startSyntheticCompaction(event) {
22596
+ const metadata = {
22597
+ ...extractEventMetadata(event),
22598
+ provider: "flue"
22599
+ };
22600
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22601
+ name: "compaction:unknown",
22602
+ spanAttributes: { type: "task" /* TASK */ },
22603
+ startTime: eventTime(event.timestamp),
22604
+ event: { metadata }
22605
+ });
22606
+ return { metadata, span };
22607
+ }
22608
+ finishPendingChildrenForOperation(event, operationOutput2) {
22609
+ const endTime = eventTime(event.timestamp);
22610
+ const usage = event.usage ?? usageFromOperationResult(event.result);
22611
+ const turnEntries = [...this.turnsByKey].filter(
22612
+ ([, state]) => stateMatchesOperation(state, event.operationId)
22613
+ );
22614
+ turnEntries.forEach(([key, state], index) => {
22615
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
22616
+ safeLog3(state.span, {
22617
+ metadata: state.metadata,
22618
+ metrics: metricsFromUsage(usage),
22619
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
22620
+ });
22621
+ safeEnd(state.span, endTime);
22622
+ this.turnsByKey.delete(key);
22623
+ });
22624
+ for (const [key, state] of this.toolsByKey) {
22625
+ if (!stateMatchesOperation(state, event.operationId)) {
22927
22626
  continue;
22928
22627
  }
22929
- const state = candidateQueue.shift();
22930
- if (!state) {
22931
- return void 0;
22628
+ safeEnd(state.span, endTime);
22629
+ this.toolsByKey.delete(key);
22630
+ }
22631
+ for (const [key, state] of this.tasksById) {
22632
+ if (!stateMatchesOperation(state, event.operationId)) {
22633
+ continue;
22932
22634
  }
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;
22635
+ safeEnd(state.span, endTime);
22636
+ this.tasksById.delete(key);
22943
22637
  }
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];
22638
+ for (const [key, state] of this.compactionsByKey) {
22639
+ if (!stateMatchesOperation(state, event.operationId)) {
22640
+ continue;
22951
22641
  }
22642
+ safeLog3(state.span, {
22643
+ metadata: state.metadata,
22644
+ metrics: durationMetrics2(event.durationMs),
22645
+ output: { completed: true }
22646
+ });
22647
+ safeEnd(state.span, eventTime(event.timestamp));
22648
+ this.compactionsByKey.delete(key);
22952
22649
  }
22953
- return void 0;
22954
22650
  }
22955
- pendingOperationForEventScope(event) {
22956
- const scopePrefixes = operationScopePrefixes(event);
22957
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22958
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22651
+ finishPendingSpansForRun(event) {
22652
+ const endTime = eventTime(event.timestamp);
22653
+ for (const [key, state] of this.toolsByKey) {
22654
+ if (!stateMatchesRun(state, event.runId)) {
22959
22655
  continue;
22960
22656
  }
22961
- return candidateQueue[0];
22657
+ safeEnd(state.span, endTime);
22658
+ this.toolsByKey.delete(key);
22962
22659
  }
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();
22660
+ for (const [key, state] of this.turnsByKey) {
22661
+ if (!stateMatchesRun(state, event.runId)) {
22662
+ continue;
22663
+ }
22664
+ safeEnd(state.span, endTime);
22665
+ this.turnsByKey.delete(key);
22970
22666
  }
22971
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22972
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
22973
- return candidateQueue.shift();
22667
+ for (const [key, state] of this.tasksById) {
22668
+ if (!stateMatchesRun(state, event.runId)) {
22669
+ continue;
22974
22670
  }
22671
+ safeEnd(state.span, endTime);
22672
+ this.tasksById.delete(key);
22975
22673
  }
22976
- return void 0;
22977
- }
22978
- pendingOperationQueue(key) {
22979
- const existing = this.pendingOperationsByKey.get(key);
22980
- if (existing) {
22981
- return existing;
22674
+ for (const [key, state] of this.compactionsByKey) {
22675
+ if (!stateMatchesRun(state, event.runId)) {
22676
+ continue;
22677
+ }
22678
+ safeLog3(state.span, {
22679
+ metadata: state.metadata,
22680
+ output: { completed: true }
22681
+ });
22682
+ safeEnd(state.span, endTime);
22683
+ this.compactionsByKey.delete(key);
22684
+ }
22685
+ for (const [key, state] of this.operationsById) {
22686
+ if (!stateMatchesRun(state, event.runId)) {
22687
+ continue;
22688
+ }
22689
+ safeLog3(state.span, {
22690
+ metadata: state.metadata,
22691
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
22692
+ });
22693
+ safeEnd(state.span, endTime);
22694
+ this.operationsById.delete(key);
22982
22695
  }
22983
- const queue = [];
22984
- this.pendingOperationsByKey.set(key, queue);
22985
- return queue;
22986
22696
  }
22987
22697
  };
22988
22698
  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 } : {};
22699
+ return operation === "prompt" || operation === "skill" || operation === "compact";
23068
22700
  }
23069
- function extractEventMetadata(event) {
22701
+ function extractEventMetadata(event, ctx) {
23070
22702
  return {
23071
22703
  ...event.runId ? { "flue.run_id": event.runId } : {},
22704
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
22705
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
23072
22706
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
23073
22707
  ...event.session ? { "flue.session": event.session } : {},
23074
22708
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
23075
22709
  ...event.harness ? { "flue.harness": event.harness } : {},
23076
22710
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
23077
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
22711
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
22712
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
22713
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
22714
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
23078
22715
  };
23079
22716
  }
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;
22717
+ function extractPayloadMetadata(payload) {
22718
+ if (!isObjectLike(payload)) {
22719
+ return {};
23092
22720
  }
22721
+ const metadata = Reflect.get(payload, "metadata");
22722
+ if (!isObjectLike(metadata)) {
22723
+ return {};
22724
+ }
22725
+ return Object.fromEntries(Object.entries(metadata));
23093
22726
  }
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
- });
22727
+ function operationOutput(event) {
22728
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
22729
+ return llmResultFromOperationResult(event.result);
22730
+ }
22731
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
23133
22732
  }
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
- } : {};
22733
+ function llmResultFromOperationResult(result) {
22734
+ if (!isObjectLike(result)) {
22735
+ return result;
22736
+ }
22737
+ const text = Reflect.get(result, "text");
22738
+ return text === void 0 ? result : text;
23140
22739
  }
23141
- function extractOperationOutput(result) {
23142
- if (!result) {
22740
+ function usageFromOperationResult(result) {
22741
+ if (!isObjectLike(result)) {
23143
22742
  return void 0;
23144
22743
  }
23145
- if ("data" in result) {
23146
- return result.data;
23147
- }
23148
- if ("text" in result) {
23149
- return result.text;
23150
- }
23151
- return result;
22744
+ return Reflect.get(result, "usage");
23152
22745
  }
23153
22746
  function metricsFromUsage(usage) {
22747
+ if (!isObjectLike(usage)) {
22748
+ return {};
22749
+ }
22750
+ const cacheRead = Reflect.get(usage, "cacheRead");
22751
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
22752
+ const cost = Reflect.get(usage, "cost");
22753
+ const input = Reflect.get(usage, "input");
22754
+ const output = Reflect.get(usage, "output");
22755
+ const totalTokens = Reflect.get(usage, "totalTokens");
22756
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
23154
22757
  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)
22758
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
22759
+ ...typeof output === "number" ? { completion_tokens: output } : {},
22760
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
22761
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
22762
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
22763
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
23166
22764
  };
23167
22765
  }
23168
- function durationMsMetrics(durationMs) {
22766
+ function durationMetrics2(durationMs) {
23169
22767
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
23170
22768
  }
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}`;
22769
+ function eventTime(value) {
22770
+ if (typeof value !== "string") {
22771
+ return void 0;
23180
22772
  }
23181
- return "flue:unknown";
22773
+ const timestamp = Date.parse(value);
22774
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
22775
+ }
22776
+ function turnKey(event) {
22777
+ return event.turnId;
23182
22778
  }
23183
22779
  function toolKey(event) {
23184
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
22780
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
23185
22781
  }
23186
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
22782
+ function compactionKey(event) {
23187
22783
  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
- ];
22784
+ event.instanceId ?? "",
22785
+ event.runId ?? "",
22786
+ event.session ?? "",
22787
+ event.operationId ?? "",
22788
+ event.taskId ?? ""
22789
+ ].join(":");
22790
+ }
22791
+ function stateMatchesOperation(state, operationId) {
22792
+ return state.metadata["flue.operation_id"] === operationId;
22793
+ }
22794
+ function stateMatchesRun(state, runId) {
22795
+ return state.metadata["flue.run_id"] === runId;
23208
22796
  }
23209
22797
  function startFlueSpan(parent, args) {
23210
22798
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -23216,6 +22804,13 @@ function safeLog3(span, event) {
23216
22804
  logInstrumentationError3("Flue span log", error);
23217
22805
  }
23218
22806
  }
22807
+ function safeEnd(span, endTime) {
22808
+ try {
22809
+ span.end(endTime === void 0 ? void 0 : { endTime });
22810
+ } catch (error) {
22811
+ logInstrumentationError3("Flue span end", error);
22812
+ }
22813
+ }
23219
22814
  function errorToString(error) {
23220
22815
  if (error instanceof Error) {
23221
22816
  return error.message;
@@ -24055,6 +23650,7 @@ function configureInstrumentation(config) {
24055
23650
  BasePlugin,
24056
23651
  BraintrustPlugin,
24057
23652
  OpenAIAgentsTraceProcessor,
23653
+ braintrustFlueObserver,
24058
23654
  configureInstrumentation,
24059
23655
  createChannelName,
24060
23656
  isValidChannelName,