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
@@ -6696,6 +6696,10 @@ ${stackTrace}` });
6696
6696
  function startSpan(args) {
6697
6697
  return startSpanAndIsLogger(args).span;
6698
6698
  }
6699
+ async function flush(options) {
6700
+ const state = options?.state ?? _globalState;
6701
+ return await state.bgLogger().flush();
6702
+ }
6699
6703
  function startSpanAndIsLogger(args) {
6700
6704
  const state = args?.state ?? _globalState;
6701
6705
  const parentObject = getSpanParentObject({
@@ -21937,803 +21941,440 @@ var flueChannels = defineChannels("@flue/runtime", {
21937
21941
  createContext: channel({
21938
21942
  channelName: "createFlueContext",
21939
21943
  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
21944
  })
21965
21945
  });
21966
21946
 
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;
21947
+ // src/instrumentation/plugins/flue-plugin.ts
21948
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
21949
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
21950
+ var braintrustFlueObserver = (event, ctx) => {
21951
+ getObserveBridge().handle(event, ctx);
21952
+ };
21953
+ var FluePlugin = class extends BasePlugin {
21954
+ onEnable() {
21955
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
22001
21956
  }
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 {
21957
+ onDisable() {
21958
+ for (const unsubscribe of this.unsubscribers) {
21959
+ unsubscribe();
22012
21960
  }
21961
+ this.unsubscribers = [];
22013
21962
  }
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
- });
21963
+ };
21964
+ function enableFlueAutoInstrumentation() {
21965
+ const state = getAutoState();
21966
+ state.refCount += 1;
21967
+ if (!state.handlers) {
21968
+ const channel2 = flueChannels.createContext.tracingChannel();
21969
+ const handlers = {
21970
+ end: (event) => {
21971
+ subscribeToFlueContext(event.result, state);
21972
+ }
21973
+ };
21974
+ channel2.subscribe(handlers);
21975
+ state.channel = channel2;
21976
+ state.handlers = handlers;
21977
+ }
21978
+ let released = false;
21979
+ return () => {
21980
+ if (released) {
21981
+ return;
22034
21982
  }
22035
- return unsubscribe;
22036
- } catch {
22037
- return void 0;
21983
+ released = true;
21984
+ releaseAutoState(state);
21985
+ };
21986
+ }
21987
+ function getAutoState() {
21988
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
21989
+ if (isAutoState(existing)) {
21990
+ return existing;
22038
21991
  }
21992
+ const state = {
21993
+ contexts: /* @__PURE__ */ new WeakSet(),
21994
+ refCount: 0
21995
+ };
21996
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
21997
+ return state;
22039
21998
  }
22040
- function wrapFlueHarness(harness) {
22041
- if (!isPlausibleFlueHarness(harness)) {
22042
- return harness;
21999
+ function getObserveBridge() {
22000
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
22001
+ if (isFlueObserveBridge(existing)) {
22002
+ return existing;
22043
22003
  }
22044
- const target = harness;
22045
- if (target[WRAPPED_FLUE_HARNESS]) {
22046
- return harness;
22004
+ const bridge = new FlueObserveBridge();
22005
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
22006
+ return bridge;
22007
+ }
22008
+ function isFlueObserveBridge(value) {
22009
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
22010
+ }
22011
+ function isAutoState(value) {
22012
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
22013
+ }
22014
+ function releaseAutoState(state) {
22015
+ state.refCount -= 1;
22016
+ if (state.refCount > 0) {
22017
+ return;
22047
22018
  }
22048
- const originalSession = target.session.bind(target);
22049
22019
  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");
22020
+ if (state.channel && state.handlers) {
22021
+ state.channel.unsubscribe(state.handlers);
22067
22022
  }
22068
- } catch {
22023
+ } finally {
22024
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
22069
22025
  }
22070
- return harness;
22071
22026
  }
22072
- function patchFlueSessionInPlace(session) {
22073
- if (session[WRAPPED_FLUE_SESSION]) {
22074
- return session;
22027
+ function subscribeToFlueContext(value, state) {
22028
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
22029
+ return;
22075
22030
  }
22031
+ const ctx = flueContextFromUnknown(value);
22032
+ let released = false;
22033
+ let unsubscribe;
22034
+ const release = () => {
22035
+ if (released) {
22036
+ return;
22037
+ }
22038
+ released = true;
22039
+ try {
22040
+ unsubscribe?.();
22041
+ } catch (error) {
22042
+ logInstrumentationError3("Flue context unsubscribe", error);
22043
+ }
22044
+ };
22076
22045
  try {
22077
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
22078
- configurable: false,
22079
- enumerable: false,
22080
- value: true
22046
+ unsubscribe = value.subscribeEvent((event) => {
22047
+ if (state.refCount <= 0) {
22048
+ release();
22049
+ return;
22050
+ }
22051
+ braintrustFlueObserver(event, ctx);
22052
+ if (isAutoContextTerminalEvent(event, ctx)) {
22053
+ release();
22054
+ }
22081
22055
  });
22082
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
22083
- patchCallHandleMethod(session, "skill", flueChannels.skill);
22084
- patchCallHandleMethod(session, "task", flueChannels.task);
22085
- patchCompact(session);
22086
- } catch {
22056
+ state.contexts.add(value);
22057
+ } catch (error) {
22058
+ logInstrumentationError3("Flue context subscription", error);
22087
22059
  }
22088
- return session;
22089
22060
  }
22090
- function patchFlueSessionFactory(sessions, method) {
22091
- const original = sessions[method];
22092
- if (typeof original !== "function") {
22093
- return;
22061
+ function isAutoContextTerminalEvent(event, ctx) {
22062
+ if (!isObjectLike(event)) {
22063
+ return false;
22094
22064
  }
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;
22065
+ const type = Reflect.get(event, "type");
22066
+ if (type === "run_end") {
22067
+ return true;
22109
22068
  }
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;
22069
+ if (type !== "operation") {
22070
+ return false;
22132
22071
  }
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
- });
22072
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
22146
22073
  }
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 };
22074
+ function isObservableFlueContext(value) {
22075
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
22185
22076
  }
22186
- function normalizeError3(error) {
22187
- return error instanceof Error ? error : new Error(String(error));
22077
+ function isFlueEvent(event) {
22078
+ const type = Reflect.get(event, "type");
22079
+ 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
22080
  }
22189
- function preserveCallHandle(originalHandle, traced) {
22190
- if (!isFlueCallHandle(originalHandle)) {
22191
- return traced;
22081
+ function flueContextFromUnknown(ctx) {
22082
+ if (!isObjectLike(ctx)) {
22083
+ return void 0;
22192
22084
  }
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
- }
22085
+ const id = Reflect.get(ctx, "id");
22086
+ const runId = Reflect.get(ctx, "runId");
22087
+ return {
22088
+ ...typeof id === "string" ? { id } : {},
22089
+ ...typeof runId === "string" ? { runId } : {}
22204
22090
  };
22205
- return wrapped;
22206
- }
22207
- function isPlausibleFlueHarness(value) {
22208
- return !!value && typeof value === "object" && typeof value.session === "function";
22209
22091
  }
22210
- function isFlueCallHandle(value) {
22211
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
22092
+ function isObjectLike(value) {
22093
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22212
22094
  }
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();
22095
+ var FlueObserveBridge = class {
22096
+ compactionsByKey = /* @__PURE__ */ new Map();
22097
+ operationsById = /* @__PURE__ */ new Map();
22098
+ runsById = /* @__PURE__ */ new Map();
22099
+ seenEvents = /* @__PURE__ */ new WeakSet();
22220
22100
  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();
22101
+ toolsByKey = /* @__PURE__ */ new Map();
22102
+ turnsByKey = /* @__PURE__ */ new Map();
22103
+ handle(event, ctx) {
22104
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
22105
+ return;
22232
22106
  }
22233
- this.unsubscribers = [];
22234
- this.activeOperationsById.clear();
22235
- this.activeOperationsByScope.clear();
22236
- this.compactionsByScope.clear();
22237
- this.pendingOperationsByKey.clear();
22107
+ if (this.seenEvents.has(event)) {
22108
+ return;
22109
+ }
22110
+ this.seenEvents.add(event);
22111
+ try {
22112
+ this.handleEvent(event, flueContextFromUnknown(ctx));
22113
+ } catch (error) {
22114
+ logInstrumentationError3("Flue observe", error);
22115
+ }
22116
+ }
22117
+ reset() {
22118
+ this.compactionsByKey.clear();
22119
+ this.operationsById.clear();
22120
+ this.runsById.clear();
22121
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
22238
22122
  this.tasksById.clear();
22239
- this.toolsById.clear();
22240
- this.turnsByScope.clear();
22123
+ this.toolsByKey.clear();
22124
+ this.turnsByKey.clear();
22241
22125
  }
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
- });
22126
+ handleEvent(event, ctx) {
22127
+ switch (event.type) {
22128
+ case "run_start":
22129
+ this.handleRunStart(event, ctx);
22130
+ return;
22131
+ case "run_end":
22132
+ this.handleRunEnd(event);
22133
+ return;
22134
+ case "operation_start":
22135
+ this.handleOperationStart(event);
22136
+ return;
22137
+ case "operation":
22138
+ this.handleOperation(event);
22139
+ return;
22140
+ case "turn_request":
22141
+ this.handleTurnRequest(event);
22142
+ return;
22143
+ case "turn":
22144
+ this.handleTurn(event);
22145
+ return;
22146
+ case "tool_start":
22147
+ this.handleToolStart(event);
22148
+ return;
22149
+ case "tool_call":
22150
+ this.handleToolCall(event);
22151
+ return;
22152
+ case "task_start":
22153
+ this.handleTaskStart(event);
22154
+ return;
22155
+ case "task":
22156
+ this.handleTask(event);
22157
+ return;
22158
+ case "compaction_start":
22159
+ this.handleCompactionStart(event);
22160
+ return;
22161
+ case "compaction":
22162
+ this.handleCompaction(event);
22163
+ return;
22164
+ default:
22165
+ return;
22166
+ }
22260
22167
  }
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
- }
22168
+ handleRunStart(event, ctx) {
22169
+ if (!event.runId) {
22170
+ return;
22171
+ }
22172
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
22173
+ const metadata = {
22174
+ ...extractPayloadMetadata(event.payload),
22175
+ ...extractEventMetadata(event, ctx),
22176
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
22177
+ provider: "flue"
22276
22178
  };
22277
- channel2.subscribe(handlers);
22278
- this.unsubscribers.push(() => {
22279
- channel2.unsubscribe(handlers);
22179
+ const span = startSpan({
22180
+ name: `workflow:${workflowName}`,
22181
+ spanAttributes: { type: "task" /* TASK */ },
22182
+ startTime: eventTime(event.startedAt ?? event.timestamp),
22183
+ event: {
22184
+ input: event.payload,
22185
+ metadata
22186
+ }
22280
22187
  });
22188
+ this.runsById.set(event.runId, { metadata, span });
22281
22189
  }
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
22190
+ handleRunEnd(event) {
22191
+ const state = this.runsById.get(event.runId);
22192
+ this.finishPendingSpansForRun(event);
22193
+ if (state) {
22194
+ safeLog3(state.span, {
22195
+ ...event.isError ? { error: errorToString(event.error) } : {},
22196
+ metadata: {
22197
+ ...state.metadata,
22198
+ ...extractEventMetadata(event),
22199
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22200
+ },
22201
+ metrics: durationMetrics2(event.durationMs),
22202
+ output: event.result
22301
22203
  });
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);
22204
+ safeEnd(state.span, eventTime(event.timestamp));
22205
+ this.runsById.delete(event.runId);
22206
+ }
22207
+ void flush().catch((error) => {
22208
+ logInstrumentationError3("Flue flush", error);
22330
22209
  });
22331
22210
  }
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
22211
  handleOperationStart(event) {
22541
- if (!isInstrumentedOperation(event.operationKind)) {
22212
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
22542
22213
  return;
22543
22214
  }
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,
22215
+ const metadata = {
22553
22216
  ...extractEventMetadata(event),
22554
- "flue.operation_id": event.operationId
22217
+ "flue.operation": event.operationKind,
22218
+ provider: "flue"
22555
22219
  };
22556
- safeLog3(state.span, { metadata: state.metadata });
22220
+ const parent = this.parentSpanForEvent(event);
22221
+ const span = startFlueSpan(parent, {
22222
+ name: `flue.${event.operationKind}`,
22223
+ spanAttributes: { type: "task" /* TASK */ },
22224
+ startTime: eventTime(event.timestamp),
22225
+ event: { metadata }
22226
+ });
22227
+ this.operationsById.set(event.operationId, { metadata, span });
22557
22228
  }
22558
22229
  handleOperation(event) {
22559
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
22560
- if (!state) {
22230
+ if (!isInstrumentedOperation(event.operationKind)) {
22561
22231
  return;
22562
22232
  }
22233
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
22234
+ const output = operationOutput(event);
22563
22235
  const metadata = {
22564
22236
  ...state.metadata,
22565
22237
  ...extractEventMetadata(event),
22566
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
22567
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22238
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
22239
+ ...event.usage ? { "flue.usage": event.usage } : {}
22568
22240
  };
22569
- const metrics = metricsFromUsage(event.usage);
22241
+ this.finishPendingChildrenForOperation(event, output);
22570
22242
  safeLog3(state.span, {
22571
- ...event.error ? { error: errorToString(event.error) } : {},
22243
+ ...event.isError ? { error: errorToString(event.error) } : {},
22572
22244
  metadata,
22573
- ...Object.keys(metrics).length ? { metrics } : {}
22245
+ metrics: durationMetrics2(event.durationMs),
22246
+ output
22574
22247
  });
22248
+ safeEnd(state.span, eventTime(event.timestamp));
22249
+ this.operationsById.delete(event.operationId);
22575
22250
  }
22576
- ensureTurnState(event) {
22577
- const scope = scopeKey(event);
22578
- const existing = this.turnsByScope.get(scope);
22579
- if (existing) {
22580
- return existing;
22251
+ handleTurnRequest(event) {
22252
+ const key = turnKey(event);
22253
+ if (!key) {
22254
+ return;
22581
22255
  }
22582
- const parent = this.parentSpanForEvent(event);
22583
22256
  const metadata = {
22584
22257
  ...extractEventMetadata(event),
22585
- provider: "flue"
22258
+ ...event.api ? { "flue.api": event.api } : {},
22259
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
22260
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
22261
+ ...event.provider ? { "flue.provider": event.provider } : {},
22262
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
22263
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
22264
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
22265
+ ...event.input?.tools ? { tools: event.input.tools } : {}
22586
22266
  };
22267
+ const parent = this.parentSpanForTurn(event);
22587
22268
  const span = startFlueSpan(parent, {
22588
- name: "flue.turn",
22589
- spanAttributes: { type: "llm" /* LLM */ }
22269
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
22270
+ spanAttributes: { type: "llm" /* LLM */ },
22271
+ startTime: eventTime(event.timestamp),
22272
+ event: {
22273
+ input: event.input?.messages,
22274
+ metadata
22275
+ }
22590
22276
  });
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;
22277
+ this.logOperationInput(
22278
+ event.operationId,
22279
+ event.input?.messages ?? event.input
22280
+ );
22281
+ this.turnsByKey.set(key, { metadata, span });
22603
22282
  }
22604
22283
  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);
22284
+ const key = turnKey(event);
22285
+ if (!key) {
22286
+ return;
22287
+ }
22288
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
22610
22289
  const metadata = {
22611
22290
  ...state.metadata,
22612
22291
  ...extractEventMetadata(event),
22292
+ ...event.api ? { "flue.api": event.api } : {},
22613
22293
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
22294
+ ...event.provider ? { provider: event.provider } : {},
22295
+ ...event.provider ? { "flue.provider": event.provider } : {},
22296
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
22614
22297
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
22615
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
22616
- provider: "flue"
22298
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22617
22299
  };
22618
22300
  safeLog3(state.span, {
22619
- ...event.error ? { error: errorToString(event.error) } : {},
22301
+ ...event.isError ? { error: errorToString(event.error) } : {},
22620
22302
  metadata,
22621
22303
  metrics: {
22622
- ...durationMsMetrics(event.durationMs),
22304
+ ...durationMetrics2(event.durationMs),
22623
22305
  ...metricsFromUsage(event.usage)
22624
22306
  },
22625
- output: toAssistantOutput(
22626
- text,
22627
- event.stopReason,
22628
- outputReasoning,
22629
- state.toolCalls
22630
- )
22307
+ output: event.output
22631
22308
  });
22632
- state.span.end();
22633
- this.turnsByScope.delete(scope);
22634
- }
22635
- handleThinkingDelta(event) {
22636
- const delta = event.delta;
22637
- if (typeof delta !== "string" || !delta) {
22638
- return;
22639
- }
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
- }
22309
+ safeEnd(state.span, eventTime(event.timestamp));
22310
+ this.turnsByKey.delete(key);
22657
22311
  }
22658
- handleToolStart(event, options) {
22659
- const toolCallId = event.toolCallId;
22660
- if (!toolCallId) {
22312
+ handleToolStart(event) {
22313
+ if (!event.toolCallId) {
22661
22314
  return;
22662
22315
  }
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
22316
  const metadata = {
22670
22317
  ...extractEventMetadata(event),
22671
22318
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22672
- "flue.tool_call_id": toolCallId,
22319
+ "flue.tool_call_id": event.toolCallId,
22673
22320
  provider: "flue"
22674
22321
  };
22322
+ const parent = this.parentSpanForTool(event);
22675
22323
  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()
22324
+ name: `tool:${event.toolName ?? "unknown"}`,
22325
+ spanAttributes: { type: "tool" /* TOOL */ },
22326
+ startTime: eventTime(event.timestamp),
22327
+ event: {
22328
+ input: event.args,
22329
+ metadata
22330
+ }
22694
22331
  });
22332
+ this.toolsByKey.set(toolKey(event), { metadata, span });
22695
22333
  }
22696
22334
  handleToolCall(event) {
22335
+ if (!event.toolCallId) {
22336
+ return;
22337
+ }
22697
22338
  const key = toolKey(event);
22698
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
22339
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
22699
22340
  const metadata = {
22700
22341
  ...state.metadata,
22701
22342
  ...extractEventMetadata(event),
22702
22343
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22703
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
22344
+ "flue.tool_call_id": event.toolCallId,
22704
22345
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22705
22346
  };
22706
22347
  safeLog3(state.span, {
22707
22348
  ...event.isError ? { error: errorToString(event.result) } : {},
22708
22349
  metadata,
22709
- metrics: durationMsMetrics(event.durationMs),
22350
+ metrics: durationMetrics2(event.durationMs),
22710
22351
  output: event.result
22711
22352
  });
22712
- state.span.end();
22713
- this.toolsById.delete(key);
22353
+ safeEnd(state.span, eventTime(event.timestamp));
22354
+ this.toolsByKey.delete(key);
22714
22355
  }
22715
22356
  handleTaskStart(event) {
22716
- const parent = this.parentSpanForEvent(event);
22357
+ if (!event.taskId) {
22358
+ return;
22359
+ }
22717
22360
  const metadata = {
22718
22361
  ...extractEventMetadata(event),
22719
- ...event.role ? { "flue.role": event.role } : {},
22362
+ ...event.agent ? { "flue.agent": event.agent } : {},
22720
22363
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
22721
22364
  "flue.task_id": event.taskId,
22722
22365
  provider: "flue"
22723
22366
  };
22367
+ const parent = this.parentSpanForEvent(event);
22724
22368
  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()
22369
+ name: event.agent ? `task:${event.agent}` : "flue.task",
22370
+ spanAttributes: { type: "task" /* TASK */ },
22371
+ startTime: eventTime(event.timestamp),
22372
+ event: {
22373
+ input: event.prompt,
22374
+ metadata
22375
+ }
22736
22376
  });
22377
+ this.tasksById.set(event.taskId, { metadata, span });
22737
22378
  }
22738
22379
  handleTask(event) {
22739
22380
  const state = this.tasksById.get(event.taskId);
@@ -22745,426 +22386,372 @@ var FluePlugin = class extends BasePlugin {
22745
22386
  metadata: {
22746
22387
  ...state.metadata,
22747
22388
  ...extractEventMetadata(event),
22389
+ ...event.agent ? { "flue.agent": event.agent } : {},
22748
22390
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22749
22391
  },
22750
- metrics: durationMsMetrics(event.durationMs),
22392
+ metrics: durationMetrics2(event.durationMs),
22751
22393
  output: event.result
22752
22394
  });
22753
- state.span.end();
22395
+ safeEnd(state.span, eventTime(event.timestamp));
22754
22396
  this.tasksById.delete(event.taskId);
22755
22397
  }
22756
22398
  handleCompactionStart(event) {
22757
- const operationState = this.operationStateForEvent(event);
22758
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
22399
+ const key = compactionKey(event);
22400
+ const input = {
22401
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
22402
+ ...event.reason ? { reason: event.reason } : {}
22403
+ };
22759
22404
  const metadata = {
22760
22405
  ...extractEventMetadata(event),
22761
22406
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
22762
22407
  provider: "flue"
22763
22408
  };
22764
- const input = {
22765
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
22766
- ...event.reason ? { reason: event.reason } : {}
22767
- };
22409
+ const parent = this.parentSpanForEvent(event);
22768
22410
  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()
22411
+ name: `compaction:${event.reason ?? "unknown"}`,
22412
+ spanAttributes: { type: "task" /* TASK */ },
22413
+ startTime: eventTime(event.timestamp),
22414
+ event: {
22415
+ input,
22416
+ metadata
22417
+ }
22782
22418
  });
22419
+ this.logOperationInput(event.operationId, input);
22420
+ this.compactionsByKey.set(key, { metadata, span });
22783
22421
  }
22784
22422
  handleCompaction(event) {
22785
- const key = scopeKey(event);
22786
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
22787
- if (!state) {
22788
- return;
22789
- }
22423
+ const key = compactionKey(event);
22424
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
22425
+ const metadata = {
22426
+ ...state.metadata,
22427
+ ...extractEventMetadata(event),
22428
+ ...event.usage ? { "flue.usage": event.usage } : {}
22429
+ };
22790
22430
  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
- },
22431
+ metadata,
22797
22432
  metrics: {
22798
- ...durationMsMetrics(event.durationMs),
22799
- ...metricsFromUsage(event.usage)
22433
+ ...durationMetrics2(event.durationMs),
22434
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
22435
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
22800
22436
  },
22801
22437
  output: {
22802
22438
  messagesAfter: event.messagesAfter,
22803
22439
  messagesBefore: event.messagesBefore
22804
22440
  }
22805
22441
  });
22806
- state.span.end();
22807
- this.deleteCompactionState(state);
22442
+ safeEnd(state.span, eventTime(event.timestamp));
22443
+ this.compactionsByKey.delete(key);
22808
22444
  }
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;
22445
+ parentSpanForTurn(event) {
22446
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
22447
+ const compaction = this.compactionsByKey.get(compactionKey(event));
22448
+ if (compaction) {
22449
+ return compaction.span;
22814
22450
  }
22815
22451
  }
22816
- return void 0;
22452
+ return this.parentSpanForEvent(event);
22817
22453
  }
22818
- finishCompactionsForOperation(operationState) {
22819
- for (const state of [...this.compactionsByScope.values()]) {
22820
- if (state.operationState !== operationState) {
22821
- continue;
22454
+ parentSpanForEvent(event) {
22455
+ const turn = turnKey(event);
22456
+ if (turn) {
22457
+ const turnState = this.turnsByKey.get(turn);
22458
+ if (turnState) {
22459
+ return turnState.span;
22822
22460
  }
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
22461
  }
22834
- }
22835
- deleteCompactionState(state) {
22836
- for (const [key, candidate] of this.compactionsByScope) {
22837
- if (candidate !== state) {
22838
- continue;
22462
+ if (event.taskId) {
22463
+ const task = this.tasksById.get(event.taskId);
22464
+ if (task) {
22465
+ return task.span;
22839
22466
  }
22840
- this.compactionsByScope.delete(key);
22841
- return;
22842
22467
  }
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
22468
  if (event.operationId) {
22861
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
22469
+ const operation = this.operationsById.get(event.operationId);
22862
22470
  if (operation) {
22863
- return operation;
22471
+ return operation.span;
22864
22472
  }
22865
22473
  }
22866
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
22474
+ if (event.runId) {
22475
+ return this.runsById.get(event.runId)?.span;
22476
+ }
22477
+ return void 0;
22867
22478
  }
22868
- parentSpanForEvent(event) {
22479
+ parentSpanForTool(event) {
22480
+ if (event.taskId) {
22481
+ const task = this.tasksById.get(event.taskId);
22482
+ if (task) {
22483
+ return task.span;
22484
+ }
22485
+ }
22869
22486
  if (event.operationId) {
22870
- const operation = this.operationStateForEvent(event);
22487
+ const operation = this.operationsById.get(event.operationId);
22871
22488
  if (operation) {
22872
22489
  return operation.span;
22873
22490
  }
22874
22491
  }
22875
- if (event.taskId) {
22876
- return this.tasksById.get(event.taskId)?.span;
22492
+ if (event.runId) {
22493
+ return this.runsById.get(event.runId)?.span;
22877
22494
  }
22878
- return this.operationStateForEvent(event)?.span;
22495
+ return void 0;
22879
22496
  }
22880
- promotePendingOperationForEvent(event) {
22881
- if (!event.operationId) {
22882
- return void 0;
22497
+ logOperationInput(operationId, input) {
22498
+ if (!operationId || input === void 0) {
22499
+ return;
22883
22500
  }
22884
- const scopePrefixes = operationScopePrefixes(event);
22885
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22886
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22501
+ const operation = this.operationsById.get(operationId);
22502
+ if (!operation || operation.loggedInput) {
22503
+ return;
22504
+ }
22505
+ safeLog3(operation.span, { input });
22506
+ operation.loggedInput = true;
22507
+ }
22508
+ startSyntheticOperation(event) {
22509
+ const metadata = {
22510
+ ...extractEventMetadata(event),
22511
+ "flue.operation": event.operationKind,
22512
+ provider: "flue"
22513
+ };
22514
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22515
+ name: `flue.${event.operationKind}`,
22516
+ spanAttributes: { type: "task" /* TASK */ },
22517
+ startTime: eventTime(event.timestamp),
22518
+ event: { metadata }
22519
+ });
22520
+ return { metadata, span };
22521
+ }
22522
+ startSyntheticTurn(event) {
22523
+ const metadata = {
22524
+ ...extractEventMetadata(event),
22525
+ ...event.api ? { "flue.api": event.api } : {},
22526
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
22527
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
22528
+ ...event.provider ? { "flue.provider": event.provider } : {},
22529
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
22530
+ };
22531
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22532
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
22533
+ spanAttributes: { type: "llm" /* LLM */ },
22534
+ startTime: eventTime(event.timestamp),
22535
+ event: { metadata }
22536
+ });
22537
+ return { metadata, span };
22538
+ }
22539
+ startSyntheticTool(event) {
22540
+ const metadata = {
22541
+ ...extractEventMetadata(event),
22542
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22543
+ "flue.tool_call_id": event.toolCallId,
22544
+ provider: "flue"
22545
+ };
22546
+ const span = startFlueSpan(this.parentSpanForTool(event), {
22547
+ name: `tool:${event.toolName ?? "unknown"}`,
22548
+ spanAttributes: { type: "tool" /* TOOL */ },
22549
+ startTime: eventTime(event.timestamp),
22550
+ event: { metadata }
22551
+ });
22552
+ return { metadata, span };
22553
+ }
22554
+ startSyntheticCompaction(event) {
22555
+ const metadata = {
22556
+ ...extractEventMetadata(event),
22557
+ provider: "flue"
22558
+ };
22559
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
22560
+ name: "compaction:unknown",
22561
+ spanAttributes: { type: "task" /* TASK */ },
22562
+ startTime: eventTime(event.timestamp),
22563
+ event: { metadata }
22564
+ });
22565
+ return { metadata, span };
22566
+ }
22567
+ finishPendingChildrenForOperation(event, operationOutput2) {
22568
+ const endTime = eventTime(event.timestamp);
22569
+ const usage = event.usage ?? usageFromOperationResult(event.result);
22570
+ const turnEntries = [...this.turnsByKey].filter(
22571
+ ([, state]) => stateMatchesOperation(state, event.operationId)
22572
+ );
22573
+ turnEntries.forEach(([key, state], index) => {
22574
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
22575
+ safeLog3(state.span, {
22576
+ metadata: state.metadata,
22577
+ metrics: metricsFromUsage(usage),
22578
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
22579
+ });
22580
+ safeEnd(state.span, endTime);
22581
+ this.turnsByKey.delete(key);
22582
+ });
22583
+ for (const [key, state] of this.toolsByKey) {
22584
+ if (!stateMatchesOperation(state, event.operationId)) {
22887
22585
  continue;
22888
22586
  }
22889
- const state = candidateQueue.shift();
22890
- if (!state) {
22891
- return void 0;
22587
+ safeEnd(state.span, endTime);
22588
+ this.toolsByKey.delete(key);
22589
+ }
22590
+ for (const [key, state] of this.tasksById) {
22591
+ if (!stateMatchesOperation(state, event.operationId)) {
22592
+ continue;
22892
22593
  }
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;
22594
+ safeEnd(state.span, endTime);
22595
+ this.tasksById.delete(key);
22903
22596
  }
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];
22597
+ for (const [key, state] of this.compactionsByKey) {
22598
+ if (!stateMatchesOperation(state, event.operationId)) {
22599
+ continue;
22911
22600
  }
22601
+ safeLog3(state.span, {
22602
+ metadata: state.metadata,
22603
+ metrics: durationMetrics2(event.durationMs),
22604
+ output: { completed: true }
22605
+ });
22606
+ safeEnd(state.span, eventTime(event.timestamp));
22607
+ this.compactionsByKey.delete(key);
22912
22608
  }
22913
- return void 0;
22914
22609
  }
22915
- pendingOperationForEventScope(event) {
22916
- const scopePrefixes = operationScopePrefixes(event);
22917
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22918
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22610
+ finishPendingSpansForRun(event) {
22611
+ const endTime = eventTime(event.timestamp);
22612
+ for (const [key, state] of this.toolsByKey) {
22613
+ if (!stateMatchesRun(state, event.runId)) {
22919
22614
  continue;
22920
22615
  }
22921
- return candidateQueue[0];
22616
+ safeEnd(state.span, endTime);
22617
+ this.toolsByKey.delete(key);
22922
22618
  }
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();
22619
+ for (const [key, state] of this.turnsByKey) {
22620
+ if (!stateMatchesRun(state, event.runId)) {
22621
+ continue;
22622
+ }
22623
+ safeEnd(state.span, endTime);
22624
+ this.turnsByKey.delete(key);
22930
22625
  }
22931
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22932
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
22933
- return candidateQueue.shift();
22626
+ for (const [key, state] of this.tasksById) {
22627
+ if (!stateMatchesRun(state, event.runId)) {
22628
+ continue;
22934
22629
  }
22630
+ safeEnd(state.span, endTime);
22631
+ this.tasksById.delete(key);
22935
22632
  }
22936
- return void 0;
22937
- }
22938
- pendingOperationQueue(key) {
22939
- const existing = this.pendingOperationsByKey.get(key);
22940
- if (existing) {
22941
- return existing;
22633
+ for (const [key, state] of this.compactionsByKey) {
22634
+ if (!stateMatchesRun(state, event.runId)) {
22635
+ continue;
22636
+ }
22637
+ safeLog3(state.span, {
22638
+ metadata: state.metadata,
22639
+ output: { completed: true }
22640
+ });
22641
+ safeEnd(state.span, endTime);
22642
+ this.compactionsByKey.delete(key);
22643
+ }
22644
+ for (const [key, state] of this.operationsById) {
22645
+ if (!stateMatchesRun(state, event.runId)) {
22646
+ continue;
22647
+ }
22648
+ safeLog3(state.span, {
22649
+ metadata: state.metadata,
22650
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
22651
+ });
22652
+ safeEnd(state.span, endTime);
22653
+ this.operationsById.delete(key);
22942
22654
  }
22943
- const queue = [];
22944
- this.pendingOperationsByKey.set(key, queue);
22945
- return queue;
22946
22655
  }
22947
22656
  };
22948
22657
  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 } : {};
22658
+ return operation === "prompt" || operation === "skill" || operation === "compact";
23028
22659
  }
23029
- function extractEventMetadata(event) {
22660
+ function extractEventMetadata(event, ctx) {
23030
22661
  return {
23031
22662
  ...event.runId ? { "flue.run_id": event.runId } : {},
22663
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
22664
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
23032
22665
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
23033
22666
  ...event.session ? { "flue.session": event.session } : {},
23034
22667
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
23035
22668
  ...event.harness ? { "flue.harness": event.harness } : {},
23036
22669
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
23037
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
22670
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
22671
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
22672
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
22673
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
23038
22674
  };
23039
22675
  }
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;
22676
+ function extractPayloadMetadata(payload) {
22677
+ if (!isObjectLike(payload)) {
22678
+ return {};
23052
22679
  }
22680
+ const metadata = Reflect.get(payload, "metadata");
22681
+ if (!isObjectLike(metadata)) {
22682
+ return {};
22683
+ }
22684
+ return Object.fromEntries(Object.entries(metadata));
23053
22685
  }
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
- });
22686
+ function operationOutput(event) {
22687
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
22688
+ return llmResultFromOperationResult(event.result);
22689
+ }
22690
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
23093
22691
  }
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
- } : {};
22692
+ function llmResultFromOperationResult(result) {
22693
+ if (!isObjectLike(result)) {
22694
+ return result;
22695
+ }
22696
+ const text = Reflect.get(result, "text");
22697
+ return text === void 0 ? result : text;
23100
22698
  }
23101
- function extractOperationOutput(result) {
23102
- if (!result) {
22699
+ function usageFromOperationResult(result) {
22700
+ if (!isObjectLike(result)) {
23103
22701
  return void 0;
23104
22702
  }
23105
- if ("data" in result) {
23106
- return result.data;
23107
- }
23108
- if ("text" in result) {
23109
- return result.text;
23110
- }
23111
- return result;
22703
+ return Reflect.get(result, "usage");
23112
22704
  }
23113
22705
  function metricsFromUsage(usage) {
22706
+ if (!isObjectLike(usage)) {
22707
+ return {};
22708
+ }
22709
+ const cacheRead = Reflect.get(usage, "cacheRead");
22710
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
22711
+ const cost = Reflect.get(usage, "cost");
22712
+ const input = Reflect.get(usage, "input");
22713
+ const output = Reflect.get(usage, "output");
22714
+ const totalTokens = Reflect.get(usage, "totalTokens");
22715
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
23114
22716
  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)
22717
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
22718
+ ...typeof output === "number" ? { completion_tokens: output } : {},
22719
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
22720
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
22721
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
22722
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
23126
22723
  };
23127
22724
  }
23128
- function durationMsMetrics(durationMs) {
22725
+ function durationMetrics2(durationMs) {
23129
22726
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
23130
22727
  }
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}`;
22728
+ function eventTime(value) {
22729
+ if (typeof value !== "string") {
22730
+ return void 0;
23140
22731
  }
23141
- return "flue:unknown";
22732
+ const timestamp = Date.parse(value);
22733
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
22734
+ }
22735
+ function turnKey(event) {
22736
+ return event.turnId;
23142
22737
  }
23143
22738
  function toolKey(event) {
23144
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
22739
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
23145
22740
  }
23146
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
22741
+ function compactionKey(event) {
23147
22742
  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
- ];
22743
+ event.instanceId ?? "",
22744
+ event.runId ?? "",
22745
+ event.session ?? "",
22746
+ event.operationId ?? "",
22747
+ event.taskId ?? ""
22748
+ ].join(":");
22749
+ }
22750
+ function stateMatchesOperation(state, operationId) {
22751
+ return state.metadata["flue.operation_id"] === operationId;
22752
+ }
22753
+ function stateMatchesRun(state, runId) {
22754
+ return state.metadata["flue.run_id"] === runId;
23168
22755
  }
23169
22756
  function startFlueSpan(parent, args) {
23170
22757
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -23176,6 +22763,13 @@ function safeLog3(span, event) {
23176
22763
  logInstrumentationError3("Flue span log", error);
23177
22764
  }
23178
22765
  }
22766
+ function safeEnd(span, endTime) {
22767
+ try {
22768
+ span.end(endTime === void 0 ? void 0 : { endTime });
22769
+ } catch (error) {
22770
+ logInstrumentationError3("Flue span end", error);
22771
+ }
22772
+ }
23179
22773
  function errorToString(error) {
23180
22774
  if (error instanceof Error) {
23181
22775
  return error.message;
@@ -24014,6 +23608,7 @@ export {
24014
23608
  BasePlugin,
24015
23609
  BraintrustPlugin,
24016
23610
  OpenAIAgentsTraceProcessor,
23611
+ braintrustFlueObserver,
24017
23612
  configureInstrumentation,
24018
23613
  createChannelName,
24019
23614
  isValidChannelName,