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
package/dist/cli.js CHANGED
@@ -1232,7 +1232,7 @@ var require_package = __commonJS({
1232
1232
  "package.json"(exports2, module2) {
1233
1233
  module2.exports = {
1234
1234
  name: "braintrust",
1235
- version: "3.14.0",
1235
+ version: "3.15.0",
1236
1236
  description: "SDK for integrating Braintrust",
1237
1237
  repository: {
1238
1238
  type: "git",
@@ -27680,586 +27680,210 @@ var flueChannels = defineChannels("@flue/runtime", {
27680
27680
  createContext: channel({
27681
27681
  channelName: "createFlueContext",
27682
27682
  kind: "sync-stream"
27683
- }),
27684
- openSession: channel({
27685
- channelName: "Harness.openSession",
27686
- kind: "async"
27687
- }),
27688
- contextEvent: channel({
27689
- channelName: "context.event",
27690
- kind: "sync-stream"
27691
- }),
27692
- prompt: channel({
27693
- channelName: "session.prompt",
27694
- kind: "async"
27695
- }),
27696
- skill: channel({
27697
- channelName: "session.skill",
27698
- kind: "async"
27699
- }),
27700
- task: channel({
27701
- channelName: "session.task",
27702
- kind: "async"
27703
- }),
27704
- compact: channel({
27705
- channelName: "session.compact",
27706
- kind: "async"
27707
27683
  })
27708
27684
  });
27709
27685
 
27710
- // src/wrappers/flue.ts
27711
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
27712
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
27713
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
27714
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
27715
- "braintrust.flue.subscribed-context-events"
27716
- );
27717
- function patchFlueContextInPlace(ctx) {
27718
- const context2 = ctx;
27719
- if (context2[WRAPPED_FLUE_CONTEXT]) {
27720
- return ctx;
27721
- }
27722
- const originalInit = context2.init.bind(context2);
27723
- try {
27724
- Object.defineProperty(context2, WRAPPED_FLUE_CONTEXT, {
27725
- configurable: false,
27726
- enumerable: false,
27727
- value: true
27728
- });
27729
- Object.defineProperty(context2, "init", {
27730
- configurable: true,
27731
- value: async function wrappedFlueInit(options) {
27732
- const harness = await originalInit(options);
27733
- return wrapFlueHarness(harness);
27734
- },
27735
- writable: true
27736
- });
27737
- } catch {
27738
- }
27739
- return ctx;
27740
- }
27741
- function subscribeFlueContextEvents(ctx, options = {}) {
27742
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
27743
- return void 0;
27686
+ // src/instrumentation/plugins/flue-plugin.ts
27687
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
27688
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
27689
+ var braintrustFlueObserver = (event, ctx) => {
27690
+ getObserveBridge().handle(event, ctx);
27691
+ };
27692
+ var FluePlugin = class extends BasePlugin {
27693
+ onEnable() {
27694
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
27744
27695
  }
27745
- const context2 = ctx;
27746
- const captureTurnSpans = options.captureTurnSpans ?? true;
27747
- const existingSubscription = context2[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
27748
- if (existingSubscription) {
27749
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
27750
- return void 0;
27751
- }
27752
- try {
27753
- existingSubscription.unsubscribe();
27754
- } catch {
27696
+ onDisable() {
27697
+ for (const unsubscribe of this.unsubscribers) {
27698
+ unsubscribe();
27755
27699
  }
27700
+ this.unsubscribers = [];
27756
27701
  }
27757
- try {
27758
- const unsubscribe = ctx.subscribeEvent((event) => {
27759
- flueChannels.contextEvent.traceSync(() => void 0, {
27760
- arguments: [event],
27761
- captureTurnSpans,
27762
- context: ctx
27763
- });
27764
- });
27765
- if (existingSubscription) {
27766
- existingSubscription.captureTurnSpans = captureTurnSpans;
27767
- existingSubscription.unsubscribe = unsubscribe;
27768
- } else {
27769
- Object.defineProperty(context2, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
27770
- configurable: false,
27771
- enumerable: false,
27772
- value: {
27773
- captureTurnSpans,
27774
- unsubscribe
27775
- }
27776
- });
27702
+ };
27703
+ function enableFlueAutoInstrumentation() {
27704
+ const state = getAutoState();
27705
+ state.refCount += 1;
27706
+ if (!state.handlers) {
27707
+ const channel2 = flueChannels.createContext.tracingChannel();
27708
+ const handlers = {
27709
+ end: (event) => {
27710
+ subscribeToFlueContext(event.result, state);
27711
+ }
27712
+ };
27713
+ channel2.subscribe(handlers);
27714
+ state.channel = channel2;
27715
+ state.handlers = handlers;
27716
+ }
27717
+ let released = false;
27718
+ return () => {
27719
+ if (released) {
27720
+ return;
27777
27721
  }
27778
- return unsubscribe;
27779
- } catch {
27780
- return void 0;
27722
+ released = true;
27723
+ releaseAutoState(state);
27724
+ };
27725
+ }
27726
+ function getAutoState() {
27727
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
27728
+ if (isAutoState(existing)) {
27729
+ return existing;
27781
27730
  }
27731
+ const state = {
27732
+ contexts: /* @__PURE__ */ new WeakSet(),
27733
+ refCount: 0
27734
+ };
27735
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
27736
+ return state;
27782
27737
  }
27783
- function wrapFlueHarness(harness) {
27784
- if (!isPlausibleFlueHarness(harness)) {
27785
- return harness;
27738
+ function getObserveBridge() {
27739
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
27740
+ if (isFlueObserveBridge(existing)) {
27741
+ return existing;
27786
27742
  }
27787
- const target = harness;
27788
- if (target[WRAPPED_FLUE_HARNESS]) {
27789
- return harness;
27743
+ const bridge = new FlueObserveBridge();
27744
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
27745
+ return bridge;
27746
+ }
27747
+ function isFlueObserveBridge(value) {
27748
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
27749
+ }
27750
+ function isAutoState(value) {
27751
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
27752
+ }
27753
+ function releaseAutoState(state) {
27754
+ state.refCount -= 1;
27755
+ if (state.refCount > 0) {
27756
+ return;
27790
27757
  }
27791
- const originalSession = target.session.bind(target);
27792
27758
  try {
27793
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
27794
- configurable: false,
27795
- enumerable: false,
27796
- value: true
27797
- });
27798
- Object.defineProperty(target, "session", {
27799
- configurable: true,
27800
- value: async function wrappedFlueHarnessSession(name, options) {
27801
- const session = await originalSession(name, options);
27802
- return patchFlueSessionInPlace(session);
27803
- },
27804
- writable: true
27805
- });
27806
- const sessions = target.sessions;
27807
- if (sessions && typeof sessions === "object") {
27808
- patchFlueSessionFactory(sessions, "get");
27809
- patchFlueSessionFactory(sessions, "create");
27759
+ if (state.channel && state.handlers) {
27760
+ state.channel.unsubscribe(state.handlers);
27810
27761
  }
27811
- } catch {
27762
+ } finally {
27763
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
27812
27764
  }
27813
- return harness;
27814
27765
  }
27815
- function patchFlueSessionInPlace(session) {
27816
- if (session[WRAPPED_FLUE_SESSION]) {
27817
- return session;
27766
+ function subscribeToFlueContext(value, state) {
27767
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
27768
+ return;
27818
27769
  }
27770
+ const ctx = flueContextFromUnknown(value);
27771
+ let released = false;
27772
+ let unsubscribe;
27773
+ const release = () => {
27774
+ if (released) {
27775
+ return;
27776
+ }
27777
+ released = true;
27778
+ try {
27779
+ unsubscribe?.();
27780
+ } catch (error2) {
27781
+ logInstrumentationError3("Flue context unsubscribe", error2);
27782
+ }
27783
+ };
27819
27784
  try {
27820
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
27821
- configurable: false,
27822
- enumerable: false,
27823
- value: true
27785
+ unsubscribe = value.subscribeEvent((event) => {
27786
+ if (state.refCount <= 0) {
27787
+ release();
27788
+ return;
27789
+ }
27790
+ braintrustFlueObserver(event, ctx);
27791
+ if (isAutoContextTerminalEvent(event, ctx)) {
27792
+ release();
27793
+ }
27824
27794
  });
27825
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
27826
- patchCallHandleMethod(session, "skill", flueChannels.skill);
27827
- patchCallHandleMethod(session, "task", flueChannels.task);
27828
- patchCompact(session);
27829
- } catch {
27795
+ state.contexts.add(value);
27796
+ } catch (error2) {
27797
+ logInstrumentationError3("Flue context subscription", error2);
27830
27798
  }
27831
- return session;
27832
27799
  }
27833
- function patchFlueSessionFactory(sessions, method) {
27834
- const original = sessions[method];
27835
- if (typeof original !== "function") {
27836
- return;
27800
+ function isAutoContextTerminalEvent(event, ctx) {
27801
+ if (!isObjectLike(event)) {
27802
+ return false;
27837
27803
  }
27838
- const bound = original.bind(sessions);
27839
- Object.defineProperty(sessions, method, {
27840
- configurable: true,
27841
- value: async function wrappedFlueSessionFactory(name, options) {
27842
- const session = await bound(name, options);
27843
- return patchFlueSessionInPlace(session);
27844
- },
27845
- writable: true
27846
- });
27847
- }
27848
- function patchCallHandleMethod(session, method, channel2) {
27849
- const original = session[method];
27850
- if (typeof original !== "function") {
27851
- return;
27804
+ const type = Reflect.get(event, "type");
27805
+ if (type === "run_end") {
27806
+ return true;
27852
27807
  }
27853
- const bound = original.bind(session);
27854
- Object.defineProperty(session, method, {
27855
- configurable: true,
27856
- value(input, options) {
27857
- const args = [input, options];
27858
- const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
27859
- context: {
27860
- arguments: args,
27861
- operation: method,
27862
- session
27863
- },
27864
- run: () => bound(input, options)
27865
- });
27866
- return preserveCallHandle(originalResult, traced2);
27867
- },
27868
- writable: true
27869
- });
27870
- }
27871
- function patchCompact(session) {
27872
- const original = session.compact;
27873
- if (typeof original !== "function") {
27874
- return;
27808
+ if (type !== "operation") {
27809
+ return false;
27875
27810
  }
27876
- const bound = original.bind(session);
27877
- Object.defineProperty(session, "compact", {
27878
- configurable: true,
27879
- value() {
27880
- const context2 = {
27881
- arguments: [],
27882
- operation: "compact",
27883
- session
27884
- };
27885
- return flueChannels.compact.tracePromise(() => bound(), context2);
27886
- },
27887
- writable: true
27888
- });
27811
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
27889
27812
  }
27890
- function traceFlueOperation(channel2, args) {
27891
- const tracingChannel2 = channel2.tracingChannel();
27892
- const context2 = args.context;
27893
- let originalResult;
27894
- let traced2;
27895
- const run2 = () => {
27896
- try {
27897
- originalResult = args.run();
27898
- tracingChannel2.end?.publish(context2);
27899
- } catch (error2) {
27900
- context2.error = normalizeError3(error2);
27901
- tracingChannel2.error?.publish(context2);
27902
- tracingChannel2.end?.publish(context2);
27903
- throw error2;
27904
- }
27905
- traced2 = Promise.resolve(originalResult).then(
27906
- (result) => {
27907
- context2.result = result;
27908
- tracingChannel2.asyncStart?.publish(context2);
27909
- tracingChannel2.asyncEnd?.publish(context2);
27910
- return result;
27911
- },
27912
- (error2) => {
27913
- context2.error = normalizeError3(error2);
27914
- tracingChannel2.error?.publish(context2);
27915
- tracingChannel2.asyncStart?.publish(context2);
27916
- tracingChannel2.asyncEnd?.publish(context2);
27917
- throw error2;
27918
- }
27919
- );
27920
- };
27921
- if (tracingChannel2.start?.runStores) {
27922
- tracingChannel2.start.runStores(context2, run2);
27923
- } else {
27924
- tracingChannel2.start?.publish(context2);
27925
- run2();
27926
- }
27927
- return { originalResult, traced: traced2 };
27813
+ function isObservableFlueContext(value) {
27814
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
27928
27815
  }
27929
- function normalizeError3(error2) {
27930
- return error2 instanceof Error ? error2 : new Error(String(error2));
27816
+ function isFlueEvent(event) {
27817
+ const type = Reflect.get(event, "type");
27818
+ 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";
27931
27819
  }
27932
- function preserveCallHandle(originalHandle, traced2) {
27933
- if (!isFlueCallHandle(originalHandle)) {
27934
- return traced2;
27820
+ function flueContextFromUnknown(ctx) {
27821
+ if (!isObjectLike(ctx)) {
27822
+ return void 0;
27935
27823
  }
27936
- const handle = originalHandle;
27937
- const wrapped = {
27938
- get signal() {
27939
- return handle.signal;
27940
- },
27941
- abort(reason) {
27942
- return handle.abort(reason);
27943
- },
27944
- then(onfulfilled, onrejected) {
27945
- return traced2.then(onfulfilled, onrejected);
27946
- }
27824
+ const id = Reflect.get(ctx, "id");
27825
+ const runId = Reflect.get(ctx, "runId");
27826
+ return {
27827
+ ...typeof id === "string" ? { id } : {},
27828
+ ...typeof runId === "string" ? { runId } : {}
27947
27829
  };
27948
- return wrapped;
27949
- }
27950
- function isPlausibleFlueHarness(value) {
27951
- return !!value && typeof value === "object" && typeof value.session === "function";
27952
27830
  }
27953
- function isFlueCallHandle(value) {
27954
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
27831
+ function isObjectLike(value) {
27832
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27955
27833
  }
27956
-
27957
- // src/instrumentation/plugins/flue-plugin.ts
27958
- var FluePlugin = class extends BasePlugin {
27959
- activeOperationsById = /* @__PURE__ */ new Map();
27960
- activeOperationsByScope = /* @__PURE__ */ new Map();
27961
- compactionsByScope = /* @__PURE__ */ new Map();
27962
- pendingOperationsByKey = /* @__PURE__ */ new Map();
27834
+ var FlueObserveBridge = class {
27835
+ compactionsByKey = /* @__PURE__ */ new Map();
27836
+ operationsById = /* @__PURE__ */ new Map();
27837
+ runsById = /* @__PURE__ */ new Map();
27838
+ seenEvents = /* @__PURE__ */ new WeakSet();
27963
27839
  tasksById = /* @__PURE__ */ new Map();
27964
- toolsById = /* @__PURE__ */ new Map();
27965
- turnsByScope = /* @__PURE__ */ new Map();
27966
- onEnable() {
27967
- this.subscribeToContextCreation();
27968
- this.subscribeToSessionCreation();
27969
- this.subscribeToContextEvents();
27970
- this.subscribeToSessionOperations();
27971
- }
27972
- onDisable() {
27973
- for (const unsubscribe of this.unsubscribers) {
27974
- unsubscribe();
27975
- }
27976
- this.unsubscribers = [];
27977
- this.activeOperationsById.clear();
27978
- this.activeOperationsByScope.clear();
27979
- this.compactionsByScope.clear();
27980
- this.pendingOperationsByKey.clear();
27981
- this.tasksById.clear();
27982
- this.toolsById.clear();
27983
- this.turnsByScope.clear();
27984
- }
27985
- subscribeToContextCreation() {
27986
- const channel2 = flueChannels.createContext.tracingChannel();
27987
- const handlers = {
27988
- end: (event) => {
27989
- const ctx = event.result;
27990
- if (!ctx) {
27991
- return;
27992
- }
27993
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
27994
- patchFlueContextInPlace(ctx);
27995
- },
27996
- error: () => {
27997
- }
27998
- };
27999
- channel2.subscribe(handlers);
28000
- this.unsubscribers.push(() => {
28001
- channel2.unsubscribe(handlers);
28002
- });
28003
- }
28004
- subscribeToSessionCreation() {
28005
- const channel2 = flueChannels.openSession.tracingChannel();
28006
- const handlers = {
28007
- asyncEnd: (event) => {
28008
- if (event.result) {
28009
- patchFlueSessionInPlace(
28010
- event.result
28011
- );
28012
- }
28013
- if (event.harness) {
28014
- wrapFlueHarness(event.harness);
28015
- }
28016
- },
28017
- error: () => {
28018
- }
28019
- };
28020
- channel2.subscribe(handlers);
28021
- this.unsubscribers.push(() => {
28022
- channel2.unsubscribe(handlers);
28023
- });
28024
- }
28025
- subscribeToSessionOperations() {
28026
- this.subscribeToSessionOperation(flueChannels.prompt);
28027
- this.subscribeToSessionOperation(flueChannels.skill);
28028
- this.subscribeToSessionOperation(flueChannels.task);
28029
- this.subscribeToCompact();
28030
- }
28031
- subscribeToSessionOperation(channel2) {
28032
- const tracingChannel2 = channel2.tracingChannel();
28033
- const states = /* @__PURE__ */ new WeakMap();
28034
- const ensureState2 = (event) => {
28035
- const existing = states.get(event);
28036
- if (existing) {
28037
- return existing;
28038
- }
28039
- const state = this.startOperationState({
28040
- args: event.arguments,
28041
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
28042
- operation: event.operation,
28043
- session: event.session
28044
- });
28045
- states.set(event, state);
28046
- return state;
28047
- };
28048
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
28049
- tracingChannel2,
28050
- ensureState2
28051
- );
28052
- const handlers = {
28053
- start: (event) => {
28054
- ensureState2(event);
28055
- },
28056
- asyncEnd: (event) => {
28057
- this.endOperationState(states.get(event), event.result);
28058
- states.delete(event);
28059
- },
28060
- error: (event) => {
28061
- const state = states.get(event);
28062
- if (state && event.error) {
28063
- safeLog3(state.span, { error: errorToString(event.error) });
28064
- this.finishOperationState(state);
28065
- }
28066
- states.delete(event);
28067
- }
28068
- };
28069
- tracingChannel2.subscribe(handlers);
28070
- this.unsubscribers.push(() => {
28071
- unbindCurrentSpanStore?.();
28072
- tracingChannel2.unsubscribe(handlers);
28073
- });
28074
- }
28075
- subscribeToCompact() {
28076
- const tracingChannel2 = flueChannels.compact.tracingChannel();
28077
- const states = /* @__PURE__ */ new WeakMap();
28078
- const ensureState2 = (event) => {
28079
- const existing = states.get(event);
28080
- if (existing) {
28081
- return existing;
28082
- }
28083
- const state = this.startOperationState({
28084
- args: [],
28085
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
28086
- operation: event.operation,
28087
- session: event.session
28088
- });
28089
- states.set(event, state);
28090
- return state;
28091
- };
28092
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
28093
- tracingChannel2,
28094
- ensureState2
28095
- );
28096
- const handlers = {
28097
- start: (event) => {
28098
- ensureState2(event);
28099
- },
28100
- asyncEnd: (event) => {
28101
- this.endOperationState(states.get(event), void 0);
28102
- states.delete(event);
28103
- },
28104
- error: (event) => {
28105
- const state = states.get(event);
28106
- if (state && event.error) {
28107
- safeLog3(state.span, { error: errorToString(event.error) });
28108
- this.finishOperationState(state);
28109
- }
28110
- states.delete(event);
28111
- }
28112
- };
28113
- tracingChannel2.subscribe(handlers);
28114
- this.unsubscribers.push(() => {
28115
- unbindCurrentSpanStore?.();
28116
- tracingChannel2.unsubscribe(handlers);
28117
- });
28118
- }
28119
- subscribeToContextEvents() {
28120
- const channel2 = flueChannels.contextEvent.tracingChannel();
28121
- const handlers = {
28122
- start: (event) => {
28123
- const flueEvent = event.arguments[0];
28124
- if (!flueEvent) {
28125
- return;
28126
- }
28127
- try {
28128
- this.handleFlueEvent(flueEvent, {
28129
- captureTurnSpans: event.captureTurnSpans !== false
28130
- });
28131
- } catch (error2) {
28132
- logInstrumentationError3("Flue event", error2);
28133
- }
28134
- },
28135
- error: () => {
28136
- }
28137
- };
28138
- channel2.subscribe(handlers);
28139
- this.unsubscribers.push(() => {
28140
- channel2.unsubscribe(handlers);
28141
- });
28142
- }
28143
- bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
28144
- const state = _internalGetGlobalState();
28145
- const startChannel = tracingChannel2.start;
28146
- const contextManager = state?.contextManager;
28147
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
28148
- if (!currentSpanStore || !startChannel) {
28149
- return void 0;
27840
+ toolsByKey = /* @__PURE__ */ new Map();
27841
+ turnsByKey = /* @__PURE__ */ new Map();
27842
+ handle(event, ctx) {
27843
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
27844
+ return;
28150
27845
  }
28151
- startChannel.bindStore(currentSpanStore, (event) => {
28152
- const operationState = ensureState2(event);
28153
- return contextManager.wrapSpanForStore(operationState.span);
28154
- });
28155
- return () => {
28156
- startChannel.unbindStore(currentSpanStore);
28157
- };
28158
- }
28159
- startOperationState(args) {
28160
- const sessionName = getSessionName(args.session);
28161
- const metadata = {
28162
- ...extractOperationInputMetadata(args.operation, args.args),
28163
- ...extractSessionMetadata(args.session),
28164
- "flue.operation": args.operation,
28165
- provider: "flue",
28166
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
28167
- };
28168
- const span = startSpan({
28169
- name: `flue.session.${args.operation}`,
28170
- spanAttributes: { type: "task" /* TASK */ }
28171
- });
28172
- const state = {
28173
- metadata,
28174
- operation: args.operation,
28175
- sessionName,
28176
- span,
28177
- startTime: getCurrentUnixTimestamp()
28178
- };
28179
- safeLog3(span, {
28180
- input: extractOperationInput(args.operation, args.args),
28181
- metadata
28182
- });
28183
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
28184
- state
28185
- );
28186
- addOperationToScope(
28187
- this.activeOperationsByScope,
28188
- sessionName ?? "unknown",
28189
- state
28190
- );
28191
- return state;
28192
- }
28193
- endOperationState(state, result) {
28194
- if (!state) {
27846
+ if (this.seenEvents.has(event)) {
28195
27847
  return;
28196
27848
  }
28197
- const metadata = {
28198
- ...state.metadata,
28199
- ...extractPromptResponseMetadata(result)
28200
- };
28201
- const metrics = {
28202
- ...buildDurationMetrics3(state.startTime),
28203
- ...metricsFromUsage(result?.usage)
28204
- };
28205
- safeLog3(state.span, {
28206
- metadata,
28207
- metrics,
28208
- output: extractOperationOutput(result)
28209
- });
28210
- this.finishCompactionsForOperation(state);
28211
- this.finishOperationState(state);
28212
- }
28213
- finishOperationState(state) {
28214
- removePendingOperation(this.pendingOperationsByKey, state);
28215
- if (state.operationId) {
28216
- this.activeOperationsById.delete(state.operationId);
27849
+ this.seenEvents.add(event);
27850
+ try {
27851
+ this.handleEvent(event, flueContextFromUnknown(ctx));
27852
+ } catch (error2) {
27853
+ logInstrumentationError3("Flue observe", error2);
28217
27854
  }
28218
- removeScopedOperation(this.activeOperationsByScope, state);
28219
- state.span.end();
28220
27855
  }
28221
- handleFlueEvent(event, options) {
27856
+ reset() {
27857
+ this.compactionsByKey.clear();
27858
+ this.operationsById.clear();
27859
+ this.runsById.clear();
27860
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
27861
+ this.tasksById.clear();
27862
+ this.toolsByKey.clear();
27863
+ this.turnsByKey.clear();
27864
+ }
27865
+ handleEvent(event, ctx) {
28222
27866
  switch (event.type) {
27867
+ case "run_start":
27868
+ this.handleRunStart(event, ctx);
27869
+ return;
27870
+ case "run_end":
27871
+ this.handleRunEnd(event);
27872
+ return;
28223
27873
  case "operation_start":
28224
27874
  this.handleOperationStart(event);
28225
27875
  return;
28226
27876
  case "operation":
28227
27877
  this.handleOperation(event);
28228
27878
  return;
28229
- case "text_delta":
28230
- if (!options.captureTurnSpans) {
28231
- return;
28232
- }
28233
- this.ensureTurnState(event).text.push(
28234
- typeof event.text === "string" ? event.text : ""
28235
- );
28236
- return;
28237
- case "thinking_start":
28238
- if (!options.captureTurnSpans) {
28239
- return;
28240
- }
28241
- this.handleThinkingStart(event);
28242
- return;
28243
- case "thinking_delta":
28244
- if (!options.captureTurnSpans) {
28245
- return;
28246
- }
28247
- this.handleThinkingDelta(event);
28248
- return;
28249
- case "thinking_end":
28250
- if (!options.captureTurnSpans) {
28251
- return;
28252
- }
28253
- this.handleThinkingEnd(event);
27879
+ case "turn_request":
27880
+ this.handleTurnRequest(event);
28254
27881
  return;
28255
27882
  case "turn":
28256
- if (!options.captureTurnSpans) {
28257
- return;
28258
- }
28259
27883
  this.handleTurn(event);
28260
27884
  return;
28261
27885
  case "tool_start":
28262
- this.handleToolStart(event, options);
27886
+ this.handleToolStart(event);
28263
27887
  return;
28264
27888
  case "tool_call":
28265
27889
  this.handleToolCall(event);
@@ -28280,203 +27904,216 @@ var FluePlugin = class extends BasePlugin {
28280
27904
  return;
28281
27905
  }
28282
27906
  }
28283
- handleOperationStart(event) {
28284
- if (!isInstrumentedOperation(event.operationKind)) {
27907
+ handleRunStart(event, ctx) {
27908
+ if (!event.runId) {
28285
27909
  return;
28286
27910
  }
28287
- const state = this.takePendingOperationForEvent(event);
28288
- if (!state) {
27911
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
27912
+ const metadata = {
27913
+ ...extractPayloadMetadata(event.payload),
27914
+ ...extractEventMetadata(event, ctx),
27915
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
27916
+ provider: "flue"
27917
+ };
27918
+ const span = startSpan({
27919
+ name: `workflow:${workflowName}`,
27920
+ spanAttributes: { type: "task" /* TASK */ },
27921
+ startTime: eventTime(event.startedAt ?? event.timestamp),
27922
+ event: {
27923
+ input: event.payload,
27924
+ metadata
27925
+ }
27926
+ });
27927
+ this.runsById.set(event.runId, { metadata, span });
27928
+ }
27929
+ handleRunEnd(event) {
27930
+ const state = this.runsById.get(event.runId);
27931
+ this.finishPendingSpansForRun(event);
27932
+ if (state) {
27933
+ safeLog3(state.span, {
27934
+ ...event.isError ? { error: errorToString(event.error) } : {},
27935
+ metadata: {
27936
+ ...state.metadata,
27937
+ ...extractEventMetadata(event),
27938
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
27939
+ },
27940
+ metrics: durationMetrics2(event.durationMs),
27941
+ output: event.result
27942
+ });
27943
+ safeEnd(state.span, eventTime(event.timestamp));
27944
+ this.runsById.delete(event.runId);
27945
+ }
27946
+ void flush().catch((error2) => {
27947
+ logInstrumentationError3("Flue flush", error2);
27948
+ });
27949
+ }
27950
+ handleOperationStart(event) {
27951
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
28289
27952
  return;
28290
27953
  }
28291
- state.operationId = event.operationId;
28292
- this.activeOperationsById.set(event.operationId, state);
28293
- addScopedOperation(this.activeOperationsByScope, event, state);
28294
- state.metadata = {
28295
- ...state.metadata,
27954
+ const metadata = {
28296
27955
  ...extractEventMetadata(event),
28297
- "flue.operation_id": event.operationId
27956
+ "flue.operation": event.operationKind,
27957
+ provider: "flue"
28298
27958
  };
28299
- safeLog3(state.span, { metadata: state.metadata });
27959
+ const parent = this.parentSpanForEvent(event);
27960
+ const span = startFlueSpan(parent, {
27961
+ name: `flue.${event.operationKind}`,
27962
+ spanAttributes: { type: "task" /* TASK */ },
27963
+ startTime: eventTime(event.timestamp),
27964
+ event: { metadata }
27965
+ });
27966
+ this.operationsById.set(event.operationId, { metadata, span });
28300
27967
  }
28301
27968
  handleOperation(event) {
28302
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
28303
- if (!state) {
27969
+ if (!isInstrumentedOperation(event.operationKind)) {
28304
27970
  return;
28305
27971
  }
27972
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
27973
+ const output = operationOutput(event);
28306
27974
  const metadata = {
28307
27975
  ...state.metadata,
28308
27976
  ...extractEventMetadata(event),
28309
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
28310
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
27977
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
27978
+ ...event.usage ? { "flue.usage": event.usage } : {}
28311
27979
  };
28312
- const metrics = metricsFromUsage(event.usage);
27980
+ this.finishPendingChildrenForOperation(event, output);
28313
27981
  safeLog3(state.span, {
28314
- ...event.error ? { error: errorToString(event.error) } : {},
27982
+ ...event.isError ? { error: errorToString(event.error) } : {},
28315
27983
  metadata,
28316
- ...Object.keys(metrics).length ? { metrics } : {}
27984
+ metrics: durationMetrics2(event.durationMs),
27985
+ output
28317
27986
  });
27987
+ safeEnd(state.span, eventTime(event.timestamp));
27988
+ this.operationsById.delete(event.operationId);
28318
27989
  }
28319
- ensureTurnState(event) {
28320
- const scope = scopeKey(event);
28321
- const existing = this.turnsByScope.get(scope);
28322
- if (existing) {
28323
- return existing;
27990
+ handleTurnRequest(event) {
27991
+ const key = turnKey(event);
27992
+ if (!key) {
27993
+ return;
28324
27994
  }
28325
- const parent = this.parentSpanForEvent(event);
28326
27995
  const metadata = {
28327
27996
  ...extractEventMetadata(event),
28328
- provider: "flue"
27997
+ ...event.api ? { "flue.api": event.api } : {},
27998
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
27999
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
28000
+ ...event.provider ? { "flue.provider": event.provider } : {},
28001
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
28002
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
28003
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
28004
+ ...event.input?.tools ? { tools: event.input.tools } : {}
28329
28005
  };
28006
+ const parent = this.parentSpanForTurn(event);
28330
28007
  const span = startFlueSpan(parent, {
28331
- name: "flue.turn",
28332
- spanAttributes: { type: "llm" /* LLM */ }
28008
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
28009
+ spanAttributes: { type: "llm" /* LLM */ },
28010
+ startTime: eventTime(event.timestamp),
28011
+ event: {
28012
+ input: event.input?.messages,
28013
+ metadata
28014
+ }
28333
28015
  });
28334
- const state = {
28335
- metadata,
28336
- span,
28337
- hasThinking: false,
28338
- startTime: getCurrentUnixTimestamp(),
28339
- text: [],
28340
- thinking: [],
28341
- toolCalls: []
28342
- };
28343
- safeLog3(span, { metadata });
28344
- this.turnsByScope.set(scope, state);
28345
- return state;
28016
+ this.logOperationInput(
28017
+ event.operationId,
28018
+ event.input?.messages ?? event.input
28019
+ );
28020
+ this.turnsByKey.set(key, { metadata, span });
28346
28021
  }
28347
28022
  handleTurn(event) {
28348
- const scope = scopeKey(event);
28349
- const state = this.ensureTurnState(event);
28350
- const text = state.text.join("");
28351
- const reasoning = state.finalThinking ?? state.thinking.join("");
28352
- const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
28023
+ const key = turnKey(event);
28024
+ if (!key) {
28025
+ return;
28026
+ }
28027
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
28353
28028
  const metadata = {
28354
28029
  ...state.metadata,
28355
28030
  ...extractEventMetadata(event),
28031
+ ...event.api ? { "flue.api": event.api } : {},
28356
28032
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
28033
+ ...event.provider ? { provider: event.provider } : {},
28034
+ ...event.provider ? { "flue.provider": event.provider } : {},
28035
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
28357
28036
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
28358
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
28359
- provider: "flue"
28037
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28360
28038
  };
28361
28039
  safeLog3(state.span, {
28362
- ...event.error ? { error: errorToString(event.error) } : {},
28040
+ ...event.isError ? { error: errorToString(event.error) } : {},
28363
28041
  metadata,
28364
28042
  metrics: {
28365
- ...durationMsMetrics(event.durationMs),
28043
+ ...durationMetrics2(event.durationMs),
28366
28044
  ...metricsFromUsage(event.usage)
28367
28045
  },
28368
- output: toAssistantOutput(
28369
- text,
28370
- event.stopReason,
28371
- outputReasoning,
28372
- state.toolCalls
28373
- )
28046
+ output: event.output
28374
28047
  });
28375
- state.span.end();
28376
- this.turnsByScope.delete(scope);
28377
- }
28378
- handleThinkingDelta(event) {
28379
- const delta = event.delta;
28380
- if (typeof delta !== "string" || !delta) {
28381
- return;
28382
- }
28383
- const state = this.ensureTurnState(event);
28384
- state.hasThinking = true;
28385
- state.metadata["flue.thinking"] = true;
28386
- state.thinking.push(delta);
28387
- }
28388
- handleThinkingStart(event) {
28389
- const state = this.ensureTurnState(event);
28390
- state.hasThinking = true;
28391
- state.metadata["flue.thinking"] = true;
28392
- }
28393
- handleThinkingEnd(event) {
28394
- const state = this.ensureTurnState(event);
28395
- state.hasThinking = true;
28396
- state.metadata["flue.thinking"] = true;
28397
- if (typeof event.content === "string" && event.content) {
28398
- state.finalThinking = event.content;
28399
- }
28048
+ safeEnd(state.span, eventTime(event.timestamp));
28049
+ this.turnsByKey.delete(key);
28400
28050
  }
28401
- handleToolStart(event, options) {
28402
- const toolCallId = event.toolCallId;
28403
- if (!toolCallId) {
28051
+ handleToolStart(event) {
28052
+ if (!event.toolCallId) {
28404
28053
  return;
28405
28054
  }
28406
- const parent = this.parentSpanForEvent(event);
28407
- const scope = scopeKey(event);
28408
- let turnState = this.turnsByScope.get(scope);
28409
- if (!turnState && parent && options.captureTurnSpans) {
28410
- turnState = this.ensureTurnState(event);
28411
- }
28412
28055
  const metadata = {
28413
28056
  ...extractEventMetadata(event),
28414
28057
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
28415
- "flue.tool_call_id": toolCallId,
28058
+ "flue.tool_call_id": event.toolCallId,
28416
28059
  provider: "flue"
28417
28060
  };
28061
+ const parent = this.parentSpanForTool(event);
28418
28062
  const span = startFlueSpan(parent, {
28419
- name: `tool: ${event.toolName ?? "unknown"}`,
28420
- spanAttributes: { type: "tool" /* TOOL */ }
28421
- });
28422
- if (turnState) {
28423
- turnState.toolCalls.push({
28424
- args: event.args,
28425
- toolCallId,
28426
- toolName: event.toolName
28427
- });
28428
- }
28429
- safeLog3(span, {
28430
- input: event.args,
28431
- metadata
28432
- });
28433
- this.toolsById.set(toolKey(event), {
28434
- metadata,
28435
- span,
28436
- startTime: getCurrentUnixTimestamp()
28063
+ name: `tool:${event.toolName ?? "unknown"}`,
28064
+ spanAttributes: { type: "tool" /* TOOL */ },
28065
+ startTime: eventTime(event.timestamp),
28066
+ event: {
28067
+ input: event.args,
28068
+ metadata
28069
+ }
28437
28070
  });
28071
+ this.toolsByKey.set(toolKey(event), { metadata, span });
28438
28072
  }
28439
28073
  handleToolCall(event) {
28074
+ if (!event.toolCallId) {
28075
+ return;
28076
+ }
28440
28077
  const key = toolKey(event);
28441
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
28078
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
28442
28079
  const metadata = {
28443
28080
  ...state.metadata,
28444
28081
  ...extractEventMetadata(event),
28445
28082
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
28446
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
28083
+ "flue.tool_call_id": event.toolCallId,
28447
28084
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28448
28085
  };
28449
28086
  safeLog3(state.span, {
28450
28087
  ...event.isError ? { error: errorToString(event.result) } : {},
28451
28088
  metadata,
28452
- metrics: durationMsMetrics(event.durationMs),
28089
+ metrics: durationMetrics2(event.durationMs),
28453
28090
  output: event.result
28454
28091
  });
28455
- state.span.end();
28456
- this.toolsById.delete(key);
28092
+ safeEnd(state.span, eventTime(event.timestamp));
28093
+ this.toolsByKey.delete(key);
28457
28094
  }
28458
28095
  handleTaskStart(event) {
28459
- const parent = this.parentSpanForEvent(event);
28096
+ if (!event.taskId) {
28097
+ return;
28098
+ }
28460
28099
  const metadata = {
28461
28100
  ...extractEventMetadata(event),
28462
- ...event.role ? { "flue.role": event.role } : {},
28101
+ ...event.agent ? { "flue.agent": event.agent } : {},
28463
28102
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
28464
28103
  "flue.task_id": event.taskId,
28465
28104
  provider: "flue"
28466
28105
  };
28106
+ const parent = this.parentSpanForEvent(event);
28467
28107
  const span = startFlueSpan(parent, {
28468
- name: "flue.task",
28469
- spanAttributes: { type: "task" /* TASK */ }
28470
- });
28471
- safeLog3(span, {
28472
- input: event.prompt,
28473
- metadata
28474
- });
28475
- this.tasksById.set(event.taskId, {
28476
- metadata,
28477
- span,
28478
- startTime: getCurrentUnixTimestamp()
28108
+ name: event.agent ? `task:${event.agent}` : "flue.task",
28109
+ spanAttributes: { type: "task" /* TASK */ },
28110
+ startTime: eventTime(event.timestamp),
28111
+ event: {
28112
+ input: event.prompt,
28113
+ metadata
28114
+ }
28479
28115
  });
28116
+ this.tasksById.set(event.taskId, { metadata, span });
28480
28117
  }
28481
28118
  handleTask(event) {
28482
28119
  const state = this.tasksById.get(event.taskId);
@@ -28488,426 +28125,372 @@ var FluePlugin = class extends BasePlugin {
28488
28125
  metadata: {
28489
28126
  ...state.metadata,
28490
28127
  ...extractEventMetadata(event),
28128
+ ...event.agent ? { "flue.agent": event.agent } : {},
28491
28129
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28492
28130
  },
28493
- metrics: durationMsMetrics(event.durationMs),
28131
+ metrics: durationMetrics2(event.durationMs),
28494
28132
  output: event.result
28495
28133
  });
28496
- state.span.end();
28134
+ safeEnd(state.span, eventTime(event.timestamp));
28497
28135
  this.tasksById.delete(event.taskId);
28498
28136
  }
28499
28137
  handleCompactionStart(event) {
28500
- const operationState = this.operationStateForEvent(event);
28501
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
28138
+ const key = compactionKey(event);
28139
+ const input = {
28140
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
28141
+ ...event.reason ? { reason: event.reason } : {}
28142
+ };
28502
28143
  const metadata = {
28503
28144
  ...extractEventMetadata(event),
28504
28145
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
28505
28146
  provider: "flue"
28506
28147
  };
28507
- const input = {
28508
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
28509
- ...event.reason ? { reason: event.reason } : {}
28510
- };
28148
+ const parent = this.parentSpanForEvent(event);
28511
28149
  const span = startFlueSpan(parent, {
28512
- name: "flue.compaction",
28513
- spanAttributes: { type: "task" /* TASK */ }
28514
- });
28515
- safeLog3(span, {
28516
- input,
28517
- metadata
28518
- });
28519
- this.compactionsByScope.set(scopeKey(event), {
28520
- input,
28521
- metadata,
28522
- operationState,
28523
- span,
28524
- startTime: getCurrentUnixTimestamp()
28150
+ name: `compaction:${event.reason ?? "unknown"}`,
28151
+ spanAttributes: { type: "task" /* TASK */ },
28152
+ startTime: eventTime(event.timestamp),
28153
+ event: {
28154
+ input,
28155
+ metadata
28156
+ }
28525
28157
  });
28158
+ this.logOperationInput(event.operationId, input);
28159
+ this.compactionsByKey.set(key, { metadata, span });
28526
28160
  }
28527
28161
  handleCompaction(event) {
28528
- const key = scopeKey(event);
28529
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
28530
- if (!state) {
28531
- return;
28532
- }
28162
+ const key = compactionKey(event);
28163
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
28164
+ const metadata = {
28165
+ ...state.metadata,
28166
+ ...extractEventMetadata(event),
28167
+ ...event.usage ? { "flue.usage": event.usage } : {}
28168
+ };
28533
28169
  safeLog3(state.span, {
28534
- metadata: {
28535
- ...state.metadata,
28536
- ...extractEventMetadata(event),
28537
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
28538
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
28539
- },
28170
+ metadata,
28540
28171
  metrics: {
28541
- ...durationMsMetrics(event.durationMs),
28542
- ...metricsFromUsage(event.usage)
28172
+ ...durationMetrics2(event.durationMs),
28173
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
28174
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
28543
28175
  },
28544
28176
  output: {
28545
28177
  messagesAfter: event.messagesAfter,
28546
28178
  messagesBefore: event.messagesBefore
28547
28179
  }
28548
28180
  });
28549
- state.span.end();
28550
- this.deleteCompactionState(state);
28181
+ safeEnd(state.span, eventTime(event.timestamp));
28182
+ this.compactionsByKey.delete(key);
28551
28183
  }
28552
- findCompactionState(event) {
28553
- const operationState = this.operationStateForEvent(event);
28554
- for (const state of this.compactionsByScope.values()) {
28555
- if (operationState && state.operationState === operationState) {
28556
- return state;
28184
+ parentSpanForTurn(event) {
28185
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
28186
+ const compaction = this.compactionsByKey.get(compactionKey(event));
28187
+ if (compaction) {
28188
+ return compaction.span;
28557
28189
  }
28558
28190
  }
28559
- return void 0;
28191
+ return this.parentSpanForEvent(event);
28560
28192
  }
28561
- finishCompactionsForOperation(operationState) {
28562
- for (const state of [...this.compactionsByScope.values()]) {
28563
- if (state.operationState !== operationState) {
28564
- continue;
28193
+ parentSpanForEvent(event) {
28194
+ const turn = turnKey(event);
28195
+ if (turn) {
28196
+ const turnState = this.turnsByKey.get(turn);
28197
+ if (turnState) {
28198
+ return turnState.span;
28565
28199
  }
28566
- safeLog3(state.span, {
28567
- input: state.input,
28568
- metadata: state.metadata,
28569
- metrics: {
28570
- ...buildDurationMetrics3(state.startTime)
28571
- },
28572
- output: { completed: true }
28573
- });
28574
- state.span.end();
28575
- this.deleteCompactionState(state);
28576
28200
  }
28577
- }
28578
- deleteCompactionState(state) {
28579
- for (const [key, candidate] of this.compactionsByScope) {
28580
- if (candidate !== state) {
28581
- continue;
28201
+ if (event.taskId) {
28202
+ const task = this.tasksById.get(event.taskId);
28203
+ if (task) {
28204
+ return task.span;
28582
28205
  }
28583
- this.compactionsByScope.delete(key);
28584
- return;
28585
28206
  }
28586
- }
28587
- startSyntheticToolState(event, toolName) {
28588
- const parent = this.parentSpanForEvent(event);
28589
- const metadata = {
28590
- ...extractEventMetadata(event),
28591
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
28592
- "flue.tool_name": toolName,
28593
- provider: "flue"
28594
- };
28595
- const span = startFlueSpan(parent, {
28596
- name: `tool: ${toolName}`,
28597
- spanAttributes: { type: "tool" /* TOOL */ }
28598
- });
28599
- safeLog3(span, { metadata });
28600
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
28601
- }
28602
- operationStateForEvent(event) {
28603
28207
  if (event.operationId) {
28604
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
28208
+ const operation = this.operationsById.get(event.operationId);
28605
28209
  if (operation) {
28606
- return operation;
28210
+ return operation.span;
28607
28211
  }
28608
28212
  }
28609
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
28213
+ if (event.runId) {
28214
+ return this.runsById.get(event.runId)?.span;
28215
+ }
28216
+ return void 0;
28610
28217
  }
28611
- parentSpanForEvent(event) {
28218
+ parentSpanForTool(event) {
28219
+ if (event.taskId) {
28220
+ const task = this.tasksById.get(event.taskId);
28221
+ if (task) {
28222
+ return task.span;
28223
+ }
28224
+ }
28612
28225
  if (event.operationId) {
28613
- const operation = this.operationStateForEvent(event);
28226
+ const operation = this.operationsById.get(event.operationId);
28614
28227
  if (operation) {
28615
28228
  return operation.span;
28616
28229
  }
28617
28230
  }
28618
- if (event.taskId) {
28619
- return this.tasksById.get(event.taskId)?.span;
28231
+ if (event.runId) {
28232
+ return this.runsById.get(event.runId)?.span;
28620
28233
  }
28621
- return this.operationStateForEvent(event)?.span;
28234
+ return void 0;
28622
28235
  }
28623
- promotePendingOperationForEvent(event) {
28624
- if (!event.operationId) {
28625
- return void 0;
28236
+ logOperationInput(operationId, input) {
28237
+ if (!operationId || input === void 0) {
28238
+ return;
28239
+ }
28240
+ const operation = this.operationsById.get(operationId);
28241
+ if (!operation || operation.loggedInput) {
28242
+ return;
28243
+ }
28244
+ safeLog3(operation.span, { input });
28245
+ operation.loggedInput = true;
28246
+ }
28247
+ startSyntheticOperation(event) {
28248
+ const metadata = {
28249
+ ...extractEventMetadata(event),
28250
+ "flue.operation": event.operationKind,
28251
+ provider: "flue"
28252
+ };
28253
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
28254
+ name: `flue.${event.operationKind}`,
28255
+ spanAttributes: { type: "task" /* TASK */ },
28256
+ startTime: eventTime(event.timestamp),
28257
+ event: { metadata }
28258
+ });
28259
+ return { metadata, span };
28260
+ }
28261
+ startSyntheticTurn(event) {
28262
+ const metadata = {
28263
+ ...extractEventMetadata(event),
28264
+ ...event.api ? { "flue.api": event.api } : {},
28265
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
28266
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
28267
+ ...event.provider ? { "flue.provider": event.provider } : {},
28268
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
28269
+ };
28270
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
28271
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
28272
+ spanAttributes: { type: "llm" /* LLM */ },
28273
+ startTime: eventTime(event.timestamp),
28274
+ event: { metadata }
28275
+ });
28276
+ return { metadata, span };
28277
+ }
28278
+ startSyntheticTool(event) {
28279
+ const metadata = {
28280
+ ...extractEventMetadata(event),
28281
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
28282
+ "flue.tool_call_id": event.toolCallId,
28283
+ provider: "flue"
28284
+ };
28285
+ const span = startFlueSpan(this.parentSpanForTool(event), {
28286
+ name: `tool:${event.toolName ?? "unknown"}`,
28287
+ spanAttributes: { type: "tool" /* TOOL */ },
28288
+ startTime: eventTime(event.timestamp),
28289
+ event: { metadata }
28290
+ });
28291
+ return { metadata, span };
28292
+ }
28293
+ startSyntheticCompaction(event) {
28294
+ const metadata = {
28295
+ ...extractEventMetadata(event),
28296
+ provider: "flue"
28297
+ };
28298
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
28299
+ name: "compaction:unknown",
28300
+ spanAttributes: { type: "task" /* TASK */ },
28301
+ startTime: eventTime(event.timestamp),
28302
+ event: { metadata }
28303
+ });
28304
+ return { metadata, span };
28305
+ }
28306
+ finishPendingChildrenForOperation(event, operationOutput2) {
28307
+ const endTime = eventTime(event.timestamp);
28308
+ const usage = event.usage ?? usageFromOperationResult(event.result);
28309
+ const turnEntries = [...this.turnsByKey].filter(
28310
+ ([, state]) => stateMatchesOperation(state, event.operationId)
28311
+ );
28312
+ turnEntries.forEach(([key, state], index) => {
28313
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
28314
+ safeLog3(state.span, {
28315
+ metadata: state.metadata,
28316
+ metrics: metricsFromUsage(usage),
28317
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
28318
+ });
28319
+ safeEnd(state.span, endTime);
28320
+ this.turnsByKey.delete(key);
28321
+ });
28322
+ for (const [key, state] of this.toolsByKey) {
28323
+ if (!stateMatchesOperation(state, event.operationId)) {
28324
+ continue;
28325
+ }
28326
+ safeEnd(state.span, endTime);
28327
+ this.toolsByKey.delete(key);
28626
28328
  }
28627
- const scopePrefixes = operationScopePrefixes(event);
28628
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28629
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
28329
+ for (const [key, state] of this.tasksById) {
28330
+ if (!stateMatchesOperation(state, event.operationId)) {
28630
28331
  continue;
28631
28332
  }
28632
- const state = candidateQueue.shift();
28633
- if (!state) {
28634
- return void 0;
28333
+ safeEnd(state.span, endTime);
28334
+ this.tasksById.delete(key);
28335
+ }
28336
+ for (const [key, state] of this.compactionsByKey) {
28337
+ if (!stateMatchesOperation(state, event.operationId)) {
28338
+ continue;
28635
28339
  }
28636
- state.operationId = event.operationId;
28637
- this.activeOperationsById.set(event.operationId, state);
28638
- addScopedOperation(this.activeOperationsByScope, event, state);
28639
- state.metadata = {
28640
- ...state.metadata,
28641
- ...extractEventMetadata(event),
28642
- "flue.operation_id": event.operationId
28643
- };
28644
- safeLog3(state.span, { metadata: state.metadata });
28645
- return state;
28340
+ safeLog3(state.span, {
28341
+ metadata: state.metadata,
28342
+ metrics: durationMetrics2(event.durationMs),
28343
+ output: { completed: true }
28344
+ });
28345
+ safeEnd(state.span, eventTime(event.timestamp));
28346
+ this.compactionsByKey.delete(key);
28646
28347
  }
28647
- return void 0;
28648
28348
  }
28649
- activeOperationForEventScope(event) {
28650
- for (const scope of operationScopeNames(event)) {
28651
- const operations = this.activeOperationsByScope.get(scope);
28652
- if (operations?.length) {
28653
- return operations[operations.length - 1];
28349
+ finishPendingSpansForRun(event) {
28350
+ const endTime = eventTime(event.timestamp);
28351
+ for (const [key, state] of this.toolsByKey) {
28352
+ if (!stateMatchesRun(state, event.runId)) {
28353
+ continue;
28654
28354
  }
28355
+ safeEnd(state.span, endTime);
28356
+ this.toolsByKey.delete(key);
28655
28357
  }
28656
- return void 0;
28657
- }
28658
- pendingOperationForEventScope(event) {
28659
- const scopePrefixes = operationScopePrefixes(event);
28660
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28661
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
28358
+ for (const [key, state] of this.turnsByKey) {
28359
+ if (!stateMatchesRun(state, event.runId)) {
28662
28360
  continue;
28663
28361
  }
28664
- return candidateQueue[0];
28362
+ safeEnd(state.span, endTime);
28363
+ this.turnsByKey.delete(key);
28665
28364
  }
28666
- return void 0;
28667
- }
28668
- takePendingOperationForEvent(event) {
28669
- const key = operationKey(event.session, event.operationKind);
28670
- const queue2 = this.pendingOperationsByKey.get(key);
28671
- if (queue2?.length) {
28672
- return queue2.shift();
28365
+ for (const [key, state] of this.tasksById) {
28366
+ if (!stateMatchesRun(state, event.runId)) {
28367
+ continue;
28368
+ }
28369
+ safeEnd(state.span, endTime);
28370
+ this.tasksById.delete(key);
28673
28371
  }
28674
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28675
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
28676
- return candidateQueue.shift();
28372
+ for (const [key, state] of this.compactionsByKey) {
28373
+ if (!stateMatchesRun(state, event.runId)) {
28374
+ continue;
28677
28375
  }
28376
+ safeLog3(state.span, {
28377
+ metadata: state.metadata,
28378
+ output: { completed: true }
28379
+ });
28380
+ safeEnd(state.span, endTime);
28381
+ this.compactionsByKey.delete(key);
28678
28382
  }
28679
- return void 0;
28680
- }
28681
- pendingOperationQueue(key) {
28682
- const existing = this.pendingOperationsByKey.get(key);
28683
- if (existing) {
28684
- return existing;
28383
+ for (const [key, state] of this.operationsById) {
28384
+ if (!stateMatchesRun(state, event.runId)) {
28385
+ continue;
28386
+ }
28387
+ safeLog3(state.span, {
28388
+ metadata: state.metadata,
28389
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
28390
+ });
28391
+ safeEnd(state.span, endTime);
28392
+ this.operationsById.delete(key);
28685
28393
  }
28686
- const queue2 = [];
28687
- this.pendingOperationsByKey.set(key, queue2);
28688
- return queue2;
28689
28394
  }
28690
28395
  };
28691
28396
  function isInstrumentedOperation(operation) {
28692
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
28693
- }
28694
- function getSessionName(session) {
28695
- return typeof session?.name === "string" ? session.name : void 0;
28696
- }
28697
- function operationKey(sessionName, operation) {
28698
- return `${sessionName ?? "unknown"}::${operation}`;
28699
- }
28700
- function operationScopePrefixes(event) {
28701
- const scopes = /* @__PURE__ */ new Set();
28702
- for (const scope of operationScopeNames(event)) {
28703
- scopes.add(`${scope}::`);
28704
- }
28705
- return scopes;
28706
- }
28707
- function operationKeyMatchesScopes(key, scopes) {
28708
- for (const scope of scopes) {
28709
- if (key.startsWith(scope)) {
28710
- return true;
28711
- }
28712
- }
28713
- return false;
28714
- }
28715
- function operationScopeNames(event) {
28716
- const scopes = /* @__PURE__ */ new Set();
28717
- if (event.session) {
28718
- scopes.add(event.session);
28719
- }
28720
- if (event.parentSession) {
28721
- scopes.add(event.parentSession);
28722
- }
28723
- if (!scopes.size) {
28724
- scopes.add("unknown");
28725
- }
28726
- return scopes;
28727
- }
28728
- function addScopedOperation(operationsByScope, event, state) {
28729
- for (const scope of operationScopeNames(event)) {
28730
- addOperationToScope(operationsByScope, scope, state);
28731
- }
28732
- }
28733
- function addOperationToScope(operationsByScope, scope, state) {
28734
- const operations = operationsByScope.get(scope);
28735
- if (operations) {
28736
- if (!operations.includes(state)) {
28737
- operations.push(state);
28738
- }
28739
- } else {
28740
- operationsByScope.set(scope, [state]);
28741
- }
28742
- }
28743
- function removeScopedOperation(operationsByScope, state) {
28744
- for (const [scope, operations] of operationsByScope) {
28745
- const index = operations.indexOf(state);
28746
- if (index === -1) {
28747
- continue;
28748
- }
28749
- operations.splice(index, 1);
28750
- if (operations.length === 0) {
28751
- operationsByScope.delete(scope);
28752
- }
28753
- }
28754
- }
28755
- function removePendingOperation(pendingOperationsByKey, state) {
28756
- for (const [key, queue2] of pendingOperationsByKey) {
28757
- const index = queue2.indexOf(state);
28758
- if (index === -1) {
28759
- continue;
28760
- }
28761
- queue2.splice(index, 1);
28762
- if (queue2.length === 0) {
28763
- pendingOperationsByKey.delete(key);
28764
- }
28765
- return;
28766
- }
28397
+ return operation === "prompt" || operation === "skill" || operation === "compact";
28767
28398
  }
28768
- function extractSessionMetadata(session) {
28769
- const sessionName = getSessionName(session);
28770
- return sessionName ? { "flue.session": sessionName } : {};
28771
- }
28772
- function extractEventMetadata(event) {
28399
+ function extractEventMetadata(event, ctx) {
28773
28400
  return {
28774
28401
  ...event.runId ? { "flue.run_id": event.runId } : {},
28402
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
28403
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
28775
28404
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
28776
28405
  ...event.session ? { "flue.session": event.session } : {},
28777
28406
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
28778
28407
  ...event.harness ? { "flue.harness": event.harness } : {},
28779
28408
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
28780
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
28409
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
28410
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
28411
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
28412
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
28781
28413
  };
28782
28414
  }
28783
- function extractOperationInput(operation, args) {
28784
- switch (operation) {
28785
- case "prompt":
28786
- case "task":
28787
- return args[0];
28788
- case "skill":
28789
- return {
28790
- args: getOptionObject(args[1])?.args,
28791
- name: args[0]
28792
- };
28793
- case "compact":
28794
- return void 0;
28415
+ function extractPayloadMetadata(payload) {
28416
+ if (!isObjectLike(payload)) {
28417
+ return {};
28795
28418
  }
28419
+ const metadata = Reflect.get(payload, "metadata");
28420
+ if (!isObjectLike(metadata)) {
28421
+ return {};
28422
+ }
28423
+ return Object.fromEntries(Object.entries(metadata));
28796
28424
  }
28797
- function extractOperationInputMetadata(operation, args) {
28798
- const options = getOptionObject(args[1]);
28799
- return {
28800
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
28801
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
28802
- ...options?.role ? { "flue.role": options.role } : {},
28803
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
28804
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
28805
- ...Array.isArray(options?.tools) ? {
28806
- "flue.tools_count": options.tools.length,
28807
- tools: summarizeTools(options.tools)
28808
- } : {},
28809
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
28810
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
28811
- };
28812
- }
28813
- function getOptionObject(value) {
28814
- return isObject(value) ? value : void 0;
28815
- }
28816
- function summarizeTools(tools) {
28817
- return tools.flatMap((tool) => {
28818
- if (!isObject(tool)) {
28819
- return [];
28820
- }
28821
- const name = typeof tool.name === "string" ? tool.name : void 0;
28822
- if (!name) {
28823
- return [];
28824
- }
28825
- return [
28826
- {
28827
- function: {
28828
- description: typeof tool.description === "string" ? tool.description : void 0,
28829
- name,
28830
- parameters: tool.parameters
28831
- },
28832
- type: "function"
28833
- }
28834
- ];
28835
- });
28425
+ function operationOutput(event) {
28426
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
28427
+ return llmResultFromOperationResult(event.result);
28428
+ }
28429
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
28836
28430
  }
28837
- function extractPromptResponseMetadata(result) {
28838
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
28839
- return modelId ? {
28840
- model: modelId,
28841
- "flue.model": modelId
28842
- } : {};
28431
+ function llmResultFromOperationResult(result) {
28432
+ if (!isObjectLike(result)) {
28433
+ return result;
28434
+ }
28435
+ const text = Reflect.get(result, "text");
28436
+ return text === void 0 ? result : text;
28843
28437
  }
28844
- function extractOperationOutput(result) {
28845
- if (!result) {
28438
+ function usageFromOperationResult(result) {
28439
+ if (!isObjectLike(result)) {
28846
28440
  return void 0;
28847
28441
  }
28848
- if ("data" in result) {
28849
- return result.data;
28850
- }
28851
- if ("text" in result) {
28852
- return result.text;
28853
- }
28854
- return result;
28442
+ return Reflect.get(result, "usage");
28855
28443
  }
28856
28444
  function metricsFromUsage(usage) {
28445
+ if (!isObjectLike(usage)) {
28446
+ return {};
28447
+ }
28448
+ const cacheRead = Reflect.get(usage, "cacheRead");
28449
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
28450
+ const cost = Reflect.get(usage, "cost");
28451
+ const input = Reflect.get(usage, "input");
28452
+ const output = Reflect.get(usage, "output");
28453
+ const totalTokens = Reflect.get(usage, "totalTokens");
28454
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
28857
28455
  return {
28858
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
28859
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
28860
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
28861
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
28862
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
28863
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
28864
- };
28865
- }
28866
- function buildDurationMetrics3(startTime) {
28867
- return {
28868
- duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
28456
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
28457
+ ...typeof output === "number" ? { completion_tokens: output } : {},
28458
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
28459
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
28460
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
28461
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
28869
28462
  };
28870
28463
  }
28871
- function durationMsMetrics(durationMs) {
28464
+ function durationMetrics2(durationMs) {
28872
28465
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
28873
28466
  }
28874
- function scopeKey(event) {
28875
- if (event.operationId) {
28876
- return `operation:${event.operationId}`;
28877
- }
28878
- if (event.taskId) {
28879
- return `task:${event.taskId}`;
28880
- }
28881
- if (event.session) {
28882
- return `session:${event.session}`;
28467
+ function eventTime(value) {
28468
+ if (typeof value !== "string") {
28469
+ return void 0;
28883
28470
  }
28884
- return "flue:unknown";
28471
+ const timestamp = Date.parse(value);
28472
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
28473
+ }
28474
+ function turnKey(event) {
28475
+ return event.turnId;
28885
28476
  }
28886
28477
  function toolKey(event) {
28887
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
28478
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
28888
28479
  }
28889
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
28480
+ function compactionKey(event) {
28890
28481
  return [
28891
- {
28892
- finish_reason: finishReason ?? "stop",
28893
- index: 0,
28894
- message: {
28895
- content: text,
28896
- ...reasoning ? { reasoning } : {},
28897
- role: "assistant",
28898
- ...toolCalls?.length ? {
28899
- tool_calls: toolCalls.map((toolCall) => ({
28900
- function: {
28901
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
28902
- name: toolCall.toolName ?? "unknown"
28903
- },
28904
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
28905
- type: "function"
28906
- }))
28907
- } : {}
28908
- }
28909
- }
28910
- ];
28482
+ event.instanceId ?? "",
28483
+ event.runId ?? "",
28484
+ event.session ?? "",
28485
+ event.operationId ?? "",
28486
+ event.taskId ?? ""
28487
+ ].join(":");
28488
+ }
28489
+ function stateMatchesOperation(state, operationId) {
28490
+ return state.metadata["flue.operation_id"] === operationId;
28491
+ }
28492
+ function stateMatchesRun(state, runId) {
28493
+ return state.metadata["flue.run_id"] === runId;
28911
28494
  }
28912
28495
  function startFlueSpan(parent, args) {
28913
28496
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -28919,6 +28502,13 @@ function safeLog3(span, event) {
28919
28502
  logInstrumentationError3("Flue span log", error2);
28920
28503
  }
28921
28504
  }
28505
+ function safeEnd(span, endTime) {
28506
+ try {
28507
+ span.end(endTime === void 0 ? void 0 : { endTime });
28508
+ } catch (error2) {
28509
+ logInstrumentationError3("Flue span end", error2);
28510
+ }
28511
+ }
28922
28512
  function errorToString(error2) {
28923
28513
  if (error2 instanceof Error) {
28924
28514
  return error2.message;