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