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/index.mjs CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  openRouterChannels,
27
27
  patchTracingChannel,
28
28
  readDisabledInstrumentationEnvConfig
29
- } from "./chunk-NU2GSPHX.mjs";
29
+ } from "./chunk-O4ZIWXO3.mjs";
30
30
 
31
31
  // src/node/config.ts
32
32
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -23598,581 +23598,207 @@ var GitHubCopilotPlugin = class extends BasePlugin {
23598
23598
  }
23599
23599
  };
23600
23600
 
23601
- // src/wrappers/flue.ts
23602
- var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23603
- var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23604
- var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23605
- var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23606
- "braintrust.flue.subscribed-context-events"
23607
- );
23608
- function wrapFlueContext(ctx) {
23609
- if (!isPlausibleFlueContext(ctx)) {
23610
- console.warn("Unsupported Flue context. Not wrapping.");
23611
- return ctx;
23601
+ // src/instrumentation/plugins/flue-plugin.ts
23602
+ var FLUE_AUTO_STATE = /* @__PURE__ */ Symbol.for("braintrust.flue.auto-state");
23603
+ var FLUE_OBSERVE_BRIDGE = /* @__PURE__ */ Symbol.for("braintrust.flue.observe-bridge");
23604
+ var braintrustFlueObserver = (event, ctx) => {
23605
+ getObserveBridge().handle(event, ctx);
23606
+ };
23607
+ var FluePlugin = class extends BasePlugin {
23608
+ onEnable() {
23609
+ this.unsubscribers.push(enableFlueAutoInstrumentation());
23612
23610
  }
23613
- const context = ctx;
23614
- subscribeFlueContextEvents(context, { captureTurnSpans: true });
23615
- return patchFlueContextInPlace(context);
23616
- }
23617
- function patchFlueContextInPlace(ctx) {
23618
- const context = ctx;
23619
- if (context[WRAPPED_FLUE_CONTEXT]) {
23620
- return ctx;
23611
+ onDisable() {
23612
+ for (const unsubscribe of this.unsubscribers) {
23613
+ unsubscribe();
23614
+ }
23615
+ this.unsubscribers = [];
23621
23616
  }
23622
- const originalInit = context.init.bind(context);
23623
- try {
23624
- Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23625
- configurable: false,
23626
- enumerable: false,
23627
- value: true
23628
- });
23629
- Object.defineProperty(context, "init", {
23630
- configurable: true,
23631
- value: async function wrappedFlueInit(options) {
23632
- const harness = await originalInit(options);
23633
- return wrapFlueHarness(harness);
23634
- },
23635
- writable: true
23636
- });
23637
- } catch {
23617
+ };
23618
+ function enableFlueAutoInstrumentation() {
23619
+ const state = getAutoState();
23620
+ state.refCount += 1;
23621
+ if (!state.handlers) {
23622
+ const channel = flueChannels.createContext.tracingChannel();
23623
+ const handlers = {
23624
+ end: (event) => {
23625
+ subscribeToFlueContext(event.result, state);
23626
+ }
23627
+ };
23628
+ channel.subscribe(handlers);
23629
+ state.channel = channel;
23630
+ state.handlers = handlers;
23638
23631
  }
23639
- return ctx;
23632
+ let released = false;
23633
+ return () => {
23634
+ if (released) {
23635
+ return;
23636
+ }
23637
+ released = true;
23638
+ releaseAutoState(state);
23639
+ };
23640
23640
  }
23641
- function wrapFlueSession(session) {
23642
- if (!isPlausibleFlueSession(session)) {
23643
- console.warn("Unsupported Flue session. Not wrapping.");
23644
- return session;
23641
+ function getAutoState() {
23642
+ const existing = Reflect.get(globalThis, FLUE_AUTO_STATE);
23643
+ if (isAutoState(existing)) {
23644
+ return existing;
23645
23645
  }
23646
- return patchFlueSessionInPlace(session);
23646
+ const state = {
23647
+ contexts: /* @__PURE__ */ new WeakSet(),
23648
+ refCount: 0
23649
+ };
23650
+ Reflect.set(globalThis, FLUE_AUTO_STATE, state);
23651
+ return state;
23647
23652
  }
23648
- function subscribeFlueContextEvents(ctx, options = {}) {
23649
- if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23650
- return void 0;
23651
- }
23652
- const context = ctx;
23653
- const captureTurnSpans = options.captureTurnSpans ?? true;
23654
- const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
23655
- if (existingSubscription) {
23656
- if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
23657
- return void 0;
23658
- }
23659
- try {
23660
- existingSubscription.unsubscribe();
23661
- } catch {
23662
- }
23663
- }
23664
- try {
23665
- const unsubscribe = ctx.subscribeEvent((event) => {
23666
- flueChannels.contextEvent.traceSync(() => void 0, {
23667
- arguments: [event],
23668
- captureTurnSpans,
23669
- context: ctx
23670
- });
23671
- });
23672
- if (existingSubscription) {
23673
- existingSubscription.captureTurnSpans = captureTurnSpans;
23674
- existingSubscription.unsubscribe = unsubscribe;
23675
- } else {
23676
- Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
23677
- configurable: false,
23678
- enumerable: false,
23679
- value: {
23680
- captureTurnSpans,
23681
- unsubscribe
23682
- }
23683
- });
23684
- }
23685
- return unsubscribe;
23686
- } catch {
23687
- return void 0;
23653
+ function getObserveBridge() {
23654
+ const existing = Reflect.get(globalThis, FLUE_OBSERVE_BRIDGE);
23655
+ if (isFlueObserveBridge(existing)) {
23656
+ return existing;
23688
23657
  }
23658
+ const bridge = new FlueObserveBridge();
23659
+ Reflect.set(globalThis, FLUE_OBSERVE_BRIDGE, bridge);
23660
+ return bridge;
23689
23661
  }
23690
- function wrapFlueHarness(harness) {
23691
- if (!isPlausibleFlueHarness(harness)) {
23692
- return harness;
23693
- }
23694
- const target = harness;
23695
- if (target[WRAPPED_FLUE_HARNESS]) {
23696
- return harness;
23697
- }
23698
- const originalSession = target.session.bind(target);
23699
- try {
23700
- Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
23701
- configurable: false,
23702
- enumerable: false,
23703
- value: true
23704
- });
23705
- Object.defineProperty(target, "session", {
23706
- configurable: true,
23707
- value: async function wrappedFlueHarnessSession(name, options) {
23708
- const session = await originalSession(name, options);
23709
- return patchFlueSessionInPlace(session);
23710
- },
23711
- writable: true
23712
- });
23713
- const sessions = target.sessions;
23714
- if (sessions && typeof sessions === "object") {
23715
- patchFlueSessionFactory(sessions, "get");
23716
- patchFlueSessionFactory(sessions, "create");
23717
- }
23718
- } catch {
23719
- }
23720
- return harness;
23662
+ function isFlueObserveBridge(value) {
23663
+ return isObjectLike(value) && typeof Reflect.get(value, "handle") === "function" && typeof Reflect.get(value, "reset") === "function";
23721
23664
  }
23722
- function patchFlueSessionInPlace(session) {
23723
- if (session[WRAPPED_FLUE_SESSION]) {
23724
- return session;
23725
- }
23726
- try {
23727
- Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
23728
- configurable: false,
23729
- enumerable: false,
23730
- value: true
23731
- });
23732
- patchCallHandleMethod(session, "prompt", flueChannels.prompt);
23733
- patchCallHandleMethod(session, "skill", flueChannels.skill);
23734
- patchCallHandleMethod(session, "task", flueChannels.task);
23735
- patchCompact(session);
23736
- } catch {
23737
- }
23738
- return session;
23665
+ function isAutoState(value) {
23666
+ return isObjectLike(value) && Reflect.get(value, "contexts") instanceof WeakSet && typeof Reflect.get(value, "refCount") === "number";
23739
23667
  }
23740
- function patchFlueSessionFactory(sessions, method) {
23741
- const original = sessions[method];
23742
- if (typeof original !== "function") {
23668
+ function releaseAutoState(state) {
23669
+ state.refCount -= 1;
23670
+ if (state.refCount > 0) {
23743
23671
  return;
23744
23672
  }
23745
- const bound = original.bind(sessions);
23746
- Object.defineProperty(sessions, method, {
23747
- configurable: true,
23748
- value: async function wrappedFlueSessionFactory(name, options) {
23749
- const session = await bound(name, options);
23750
- return patchFlueSessionInPlace(session);
23751
- },
23752
- writable: true
23753
- });
23754
- }
23755
- function patchCallHandleMethod(session, method, channel) {
23756
- const original = session[method];
23757
- if (typeof original !== "function") {
23758
- return;
23673
+ try {
23674
+ if (state.channel && state.handlers) {
23675
+ state.channel.unsubscribe(state.handlers);
23676
+ }
23677
+ } finally {
23678
+ Reflect.deleteProperty(globalThis, FLUE_AUTO_STATE);
23759
23679
  }
23760
- const bound = original.bind(session);
23761
- Object.defineProperty(session, method, {
23762
- configurable: true,
23763
- value(input, options) {
23764
- const args = [input, options];
23765
- const { originalResult, traced: traced2 } = traceFlueOperation(channel, {
23766
- context: {
23767
- arguments: args,
23768
- operation: method,
23769
- session
23770
- },
23771
- run: () => bound(input, options)
23772
- });
23773
- return preserveCallHandle(originalResult, traced2);
23774
- },
23775
- writable: true
23776
- });
23777
23680
  }
23778
- function patchCompact(session) {
23779
- const original = session.compact;
23780
- if (typeof original !== "function") {
23681
+ function subscribeToFlueContext(value, state) {
23682
+ if (!isObservableFlueContext(value) || state.contexts.has(value)) {
23781
23683
  return;
23782
23684
  }
23783
- const bound = original.bind(session);
23784
- Object.defineProperty(session, "compact", {
23785
- configurable: true,
23786
- value() {
23787
- const context = {
23788
- arguments: [],
23789
- operation: "compact",
23790
- session
23791
- };
23792
- return flueChannels.compact.tracePromise(() => bound(), context);
23793
- },
23794
- writable: true
23795
- });
23796
- }
23797
- function traceFlueOperation(channel, args) {
23798
- const tracingChannel2 = channel.tracingChannel();
23799
- const context = args.context;
23800
- let originalResult;
23801
- let traced2;
23802
- const run = () => {
23685
+ const ctx = flueContextFromUnknown(value);
23686
+ let released = false;
23687
+ let unsubscribe;
23688
+ const release = () => {
23689
+ if (released) {
23690
+ return;
23691
+ }
23692
+ released = true;
23803
23693
  try {
23804
- originalResult = args.run();
23805
- tracingChannel2.end?.publish(context);
23694
+ unsubscribe?.();
23806
23695
  } catch (error) {
23807
- context.error = normalizeError3(error);
23808
- tracingChannel2.error?.publish(context);
23809
- tracingChannel2.end?.publish(context);
23810
- throw error;
23696
+ logInstrumentationError3("Flue context unsubscribe", error);
23811
23697
  }
23812
- traced2 = Promise.resolve(originalResult).then(
23813
- (result) => {
23814
- context.result = result;
23815
- tracingChannel2.asyncStart?.publish(context);
23816
- tracingChannel2.asyncEnd?.publish(context);
23817
- return result;
23818
- },
23819
- (error) => {
23820
- context.error = normalizeError3(error);
23821
- tracingChannel2.error?.publish(context);
23822
- tracingChannel2.asyncStart?.publish(context);
23823
- tracingChannel2.asyncEnd?.publish(context);
23824
- throw error;
23825
- }
23826
- );
23827
23698
  };
23828
- if (tracingChannel2.start?.runStores) {
23829
- tracingChannel2.start.runStores(context, run);
23830
- } else {
23831
- tracingChannel2.start?.publish(context);
23832
- run();
23699
+ try {
23700
+ unsubscribe = value.subscribeEvent((event) => {
23701
+ if (state.refCount <= 0) {
23702
+ release();
23703
+ return;
23704
+ }
23705
+ braintrustFlueObserver(event, ctx);
23706
+ if (isAutoContextTerminalEvent(event, ctx)) {
23707
+ release();
23708
+ }
23709
+ });
23710
+ state.contexts.add(value);
23711
+ } catch (error) {
23712
+ logInstrumentationError3("Flue context subscription", error);
23833
23713
  }
23834
- return { originalResult, traced: traced2 };
23835
- }
23836
- function normalizeError3(error) {
23837
- return error instanceof Error ? error : new Error(String(error));
23838
23714
  }
23839
- function preserveCallHandle(originalHandle, traced2) {
23840
- if (!isFlueCallHandle(originalHandle)) {
23841
- return traced2;
23715
+ function isAutoContextTerminalEvent(event, ctx) {
23716
+ if (!isObjectLike(event)) {
23717
+ return false;
23842
23718
  }
23843
- const handle = originalHandle;
23844
- const wrapped = {
23845
- get signal() {
23846
- return handle.signal;
23847
- },
23848
- abort(reason) {
23849
- return handle.abort(reason);
23850
- },
23851
- then(onfulfilled, onrejected) {
23852
- return traced2.then(onfulfilled, onrejected);
23853
- }
23854
- };
23855
- return wrapped;
23719
+ const type = Reflect.get(event, "type");
23720
+ if (type === "run_end") {
23721
+ return true;
23722
+ }
23723
+ if (type !== "operation") {
23724
+ return false;
23725
+ }
23726
+ return !ctx?.runId && typeof Reflect.get(event, "runId") !== "string";
23856
23727
  }
23857
- function isPlausibleFlueContext(value) {
23858
- return !!value && typeof value === "object" && typeof value.init === "function";
23728
+ function isObservableFlueContext(value) {
23729
+ return isObjectLike(value) && typeof Reflect.get(value, "subscribeEvent") === "function";
23859
23730
  }
23860
- function isPlausibleFlueHarness(value) {
23861
- return !!value && typeof value === "object" && typeof value.session === "function";
23731
+ function isFlueEvent(event) {
23732
+ const type = Reflect.get(event, "type");
23733
+ 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";
23862
23734
  }
23863
- function isPlausibleFlueSession(value) {
23864
- return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
23735
+ function flueContextFromUnknown(ctx) {
23736
+ if (!isObjectLike(ctx)) {
23737
+ return void 0;
23738
+ }
23739
+ const id = Reflect.get(ctx, "id");
23740
+ const runId = Reflect.get(ctx, "runId");
23741
+ return {
23742
+ ...typeof id === "string" ? { id } : {},
23743
+ ...typeof runId === "string" ? { runId } : {}
23744
+ };
23865
23745
  }
23866
- function isFlueCallHandle(value) {
23867
- return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
23746
+ function isObjectLike(value) {
23747
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23868
23748
  }
23869
-
23870
- // src/instrumentation/plugins/flue-plugin.ts
23871
- var FluePlugin = class extends BasePlugin {
23872
- activeOperationsById = /* @__PURE__ */ new Map();
23873
- activeOperationsByScope = /* @__PURE__ */ new Map();
23874
- compactionsByScope = /* @__PURE__ */ new Map();
23875
- pendingOperationsByKey = /* @__PURE__ */ new Map();
23749
+ var FlueObserveBridge = class {
23750
+ compactionsByKey = /* @__PURE__ */ new Map();
23751
+ operationsById = /* @__PURE__ */ new Map();
23752
+ runsById = /* @__PURE__ */ new Map();
23753
+ seenEvents = /* @__PURE__ */ new WeakSet();
23876
23754
  tasksById = /* @__PURE__ */ new Map();
23877
- toolsById = /* @__PURE__ */ new Map();
23878
- turnsByScope = /* @__PURE__ */ new Map();
23879
- onEnable() {
23880
- this.subscribeToContextCreation();
23881
- this.subscribeToSessionCreation();
23882
- this.subscribeToContextEvents();
23883
- this.subscribeToSessionOperations();
23884
- }
23885
- onDisable() {
23886
- for (const unsubscribe of this.unsubscribers) {
23887
- unsubscribe();
23888
- }
23889
- this.unsubscribers = [];
23890
- this.activeOperationsById.clear();
23891
- this.activeOperationsByScope.clear();
23892
- this.compactionsByScope.clear();
23893
- this.pendingOperationsByKey.clear();
23894
- this.tasksById.clear();
23895
- this.toolsById.clear();
23896
- this.turnsByScope.clear();
23897
- }
23898
- subscribeToContextCreation() {
23899
- const channel = flueChannels.createContext.tracingChannel();
23900
- const handlers = {
23901
- end: (event) => {
23902
- const ctx = event.result;
23903
- if (!ctx) {
23904
- return;
23905
- }
23906
- subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
23907
- patchFlueContextInPlace(ctx);
23908
- },
23909
- error: () => {
23910
- }
23911
- };
23912
- channel.subscribe(handlers);
23913
- this.unsubscribers.push(() => {
23914
- channel.unsubscribe(handlers);
23915
- });
23916
- }
23917
- subscribeToSessionCreation() {
23918
- const channel = flueChannels.openSession.tracingChannel();
23919
- const handlers = {
23920
- asyncEnd: (event) => {
23921
- if (event.result) {
23922
- patchFlueSessionInPlace(
23923
- event.result
23924
- );
23925
- }
23926
- if (event.harness) {
23927
- wrapFlueHarness(event.harness);
23928
- }
23929
- },
23930
- error: () => {
23931
- }
23932
- };
23933
- channel.subscribe(handlers);
23934
- this.unsubscribers.push(() => {
23935
- channel.unsubscribe(handlers);
23936
- });
23937
- }
23938
- subscribeToSessionOperations() {
23939
- this.subscribeToSessionOperation(flueChannels.prompt);
23940
- this.subscribeToSessionOperation(flueChannels.skill);
23941
- this.subscribeToSessionOperation(flueChannels.task);
23942
- this.subscribeToCompact();
23943
- }
23944
- subscribeToSessionOperation(channel) {
23945
- const tracingChannel2 = channel.tracingChannel();
23946
- const states = /* @__PURE__ */ new WeakMap();
23947
- const ensureState2 = (event) => {
23948
- const existing = states.get(event);
23949
- if (existing) {
23950
- return existing;
23951
- }
23952
- const state = this.startOperationState({
23953
- args: event.arguments,
23954
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23955
- operation: event.operation,
23956
- session: event.session
23957
- });
23958
- states.set(event, state);
23959
- return state;
23960
- };
23961
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23962
- tracingChannel2,
23963
- ensureState2
23964
- );
23965
- const handlers = {
23966
- start: (event) => {
23967
- ensureState2(event);
23968
- },
23969
- asyncEnd: (event) => {
23970
- this.endOperationState(states.get(event), event.result);
23971
- states.delete(event);
23972
- },
23973
- error: (event) => {
23974
- const state = states.get(event);
23975
- if (state && event.error) {
23976
- safeLog3(state.span, { error: errorToString(event.error) });
23977
- this.finishOperationState(state);
23978
- }
23979
- states.delete(event);
23980
- }
23981
- };
23982
- tracingChannel2.subscribe(handlers);
23983
- this.unsubscribers.push(() => {
23984
- unbindCurrentSpanStore?.();
23985
- tracingChannel2.unsubscribe(handlers);
23986
- });
23987
- }
23988
- subscribeToCompact() {
23989
- const tracingChannel2 = flueChannels.compact.tracingChannel();
23990
- const states = /* @__PURE__ */ new WeakMap();
23991
- const ensureState2 = (event) => {
23992
- const existing = states.get(event);
23993
- if (existing) {
23994
- return existing;
23995
- }
23996
- const state = this.startOperationState({
23997
- args: [],
23998
- moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23999
- operation: event.operation,
24000
- session: event.session
24001
- });
24002
- states.set(event, state);
24003
- return state;
24004
- };
24005
- const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24006
- tracingChannel2,
24007
- ensureState2
24008
- );
24009
- const handlers = {
24010
- start: (event) => {
24011
- ensureState2(event);
24012
- },
24013
- asyncEnd: (event) => {
24014
- this.endOperationState(states.get(event), void 0);
24015
- states.delete(event);
24016
- },
24017
- error: (event) => {
24018
- const state = states.get(event);
24019
- if (state && event.error) {
24020
- safeLog3(state.span, { error: errorToString(event.error) });
24021
- this.finishOperationState(state);
24022
- }
24023
- states.delete(event);
24024
- }
24025
- };
24026
- tracingChannel2.subscribe(handlers);
24027
- this.unsubscribers.push(() => {
24028
- unbindCurrentSpanStore?.();
24029
- tracingChannel2.unsubscribe(handlers);
24030
- });
24031
- }
24032
- subscribeToContextEvents() {
24033
- const channel = flueChannels.contextEvent.tracingChannel();
24034
- const handlers = {
24035
- start: (event) => {
24036
- const flueEvent = event.arguments[0];
24037
- if (!flueEvent) {
24038
- return;
24039
- }
24040
- try {
24041
- this.handleFlueEvent(flueEvent, {
24042
- captureTurnSpans: event.captureTurnSpans !== false
24043
- });
24044
- } catch (error) {
24045
- logInstrumentationError3("Flue event", error);
24046
- }
24047
- },
24048
- error: () => {
24049
- }
24050
- };
24051
- channel.subscribe(handlers);
24052
- this.unsubscribers.push(() => {
24053
- channel.unsubscribe(handlers);
24054
- });
24055
- }
24056
- bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
24057
- const state = _internalGetGlobalState();
24058
- const startChannel = tracingChannel2.start;
24059
- const contextManager = state?.contextManager;
24060
- const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
24061
- if (!currentSpanStore || !startChannel) {
24062
- return void 0;
23755
+ toolsByKey = /* @__PURE__ */ new Map();
23756
+ turnsByKey = /* @__PURE__ */ new Map();
23757
+ handle(event, ctx) {
23758
+ if (!isObjectLike(event) || !isFlueEvent(event)) {
23759
+ return;
24063
23760
  }
24064
- startChannel.bindStore(currentSpanStore, (event) => {
24065
- const operationState = ensureState2(event);
24066
- return contextManager.wrapSpanForStore(operationState.span);
24067
- });
24068
- return () => {
24069
- startChannel.unbindStore(currentSpanStore);
24070
- };
24071
- }
24072
- startOperationState(args) {
24073
- const sessionName = getSessionName(args.session);
24074
- const metadata = {
24075
- ...extractOperationInputMetadata(args.operation, args.args),
24076
- ...extractSessionMetadata(args.session),
24077
- "flue.operation": args.operation,
24078
- provider: "flue",
24079
- ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24080
- };
24081
- const span = startSpan({
24082
- name: `flue.session.${args.operation}`,
24083
- spanAttributes: { type: "task" /* TASK */ }
24084
- });
24085
- const state = {
24086
- metadata,
24087
- operation: args.operation,
24088
- sessionName,
24089
- span,
24090
- startTime: getCurrentUnixTimestamp()
24091
- };
24092
- safeLog3(span, {
24093
- input: extractOperationInput(args.operation, args.args),
24094
- metadata
24095
- });
24096
- this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24097
- state
24098
- );
24099
- addOperationToScope(
24100
- this.activeOperationsByScope,
24101
- sessionName ?? "unknown",
24102
- state
24103
- );
24104
- return state;
24105
- }
24106
- endOperationState(state, result) {
24107
- if (!state) {
23761
+ if (this.seenEvents.has(event)) {
24108
23762
  return;
24109
23763
  }
24110
- const metadata = {
24111
- ...state.metadata,
24112
- ...extractPromptResponseMetadata(result)
24113
- };
24114
- const metrics = {
24115
- ...buildDurationMetrics3(state.startTime),
24116
- ...metricsFromUsage(result?.usage)
24117
- };
24118
- safeLog3(state.span, {
24119
- metadata,
24120
- metrics,
24121
- output: extractOperationOutput(result)
24122
- });
24123
- this.finishCompactionsForOperation(state);
24124
- this.finishOperationState(state);
24125
- }
24126
- finishOperationState(state) {
24127
- removePendingOperation(this.pendingOperationsByKey, state);
24128
- if (state.operationId) {
24129
- this.activeOperationsById.delete(state.operationId);
23764
+ this.seenEvents.add(event);
23765
+ try {
23766
+ this.handleEvent(event, flueContextFromUnknown(ctx));
23767
+ } catch (error) {
23768
+ logInstrumentationError3("Flue observe", error);
24130
23769
  }
24131
- removeScopedOperation(this.activeOperationsByScope, state);
24132
- state.span.end();
24133
23770
  }
24134
- handleFlueEvent(event, options) {
23771
+ reset() {
23772
+ this.compactionsByKey.clear();
23773
+ this.operationsById.clear();
23774
+ this.runsById.clear();
23775
+ this.seenEvents = /* @__PURE__ */ new WeakSet();
23776
+ this.tasksById.clear();
23777
+ this.toolsByKey.clear();
23778
+ this.turnsByKey.clear();
23779
+ }
23780
+ handleEvent(event, ctx) {
24135
23781
  switch (event.type) {
23782
+ case "run_start":
23783
+ this.handleRunStart(event, ctx);
23784
+ return;
23785
+ case "run_end":
23786
+ this.handleRunEnd(event);
23787
+ return;
24136
23788
  case "operation_start":
24137
23789
  this.handleOperationStart(event);
24138
23790
  return;
24139
23791
  case "operation":
24140
23792
  this.handleOperation(event);
24141
23793
  return;
24142
- case "text_delta":
24143
- if (!options.captureTurnSpans) {
24144
- return;
24145
- }
24146
- this.ensureTurnState(event).text.push(
24147
- typeof event.text === "string" ? event.text : ""
24148
- );
24149
- return;
24150
- case "thinking_start":
24151
- if (!options.captureTurnSpans) {
24152
- return;
24153
- }
24154
- this.handleThinkingStart(event);
24155
- return;
24156
- case "thinking_delta":
24157
- if (!options.captureTurnSpans) {
24158
- return;
24159
- }
24160
- this.handleThinkingDelta(event);
24161
- return;
24162
- case "thinking_end":
24163
- if (!options.captureTurnSpans) {
24164
- return;
24165
- }
24166
- this.handleThinkingEnd(event);
23794
+ case "turn_request":
23795
+ this.handleTurnRequest(event);
24167
23796
  return;
24168
23797
  case "turn":
24169
- if (!options.captureTurnSpans) {
24170
- return;
24171
- }
24172
23798
  this.handleTurn(event);
24173
23799
  return;
24174
23800
  case "tool_start":
24175
- this.handleToolStart(event, options);
23801
+ this.handleToolStart(event);
24176
23802
  return;
24177
23803
  case "tool_call":
24178
23804
  this.handleToolCall(event);
@@ -24193,203 +23819,216 @@ var FluePlugin = class extends BasePlugin {
24193
23819
  return;
24194
23820
  }
24195
23821
  }
24196
- handleOperationStart(event) {
24197
- if (!isInstrumentedOperation(event.operationKind)) {
23822
+ handleRunStart(event, ctx) {
23823
+ if (!event.runId) {
24198
23824
  return;
24199
23825
  }
24200
- const state = this.takePendingOperationForEvent(event);
24201
- if (!state) {
23826
+ const workflowName = event.workflowName ?? event.owner?.workflowName ?? (typeof ctx?.id === "string" ? ctx.id : "unknown");
23827
+ const metadata = {
23828
+ ...extractPayloadMetadata(event.payload),
23829
+ ...extractEventMetadata(event, ctx),
23830
+ ...workflowName ? { "flue.workflow_name": workflowName } : {},
23831
+ provider: "flue"
23832
+ };
23833
+ const span = startSpan({
23834
+ name: `workflow:${workflowName}`,
23835
+ spanAttributes: { type: "task" /* TASK */ },
23836
+ startTime: eventTime(event.startedAt ?? event.timestamp),
23837
+ event: {
23838
+ input: event.payload,
23839
+ metadata
23840
+ }
23841
+ });
23842
+ this.runsById.set(event.runId, { metadata, span });
23843
+ }
23844
+ handleRunEnd(event) {
23845
+ const state = this.runsById.get(event.runId);
23846
+ this.finishPendingSpansForRun(event);
23847
+ if (state) {
23848
+ safeLog3(state.span, {
23849
+ ...event.isError ? { error: errorToString(event.error) } : {},
23850
+ metadata: {
23851
+ ...state.metadata,
23852
+ ...extractEventMetadata(event),
23853
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
23854
+ },
23855
+ metrics: durationMetrics2(event.durationMs),
23856
+ output: event.result
23857
+ });
23858
+ safeEnd(state.span, eventTime(event.timestamp));
23859
+ this.runsById.delete(event.runId);
23860
+ }
23861
+ void flush().catch((error) => {
23862
+ logInstrumentationError3("Flue flush", error);
23863
+ });
23864
+ }
23865
+ handleOperationStart(event) {
23866
+ if (!event.operationId || !isInstrumentedOperation(event.operationKind)) {
24202
23867
  return;
24203
23868
  }
24204
- state.operationId = event.operationId;
24205
- this.activeOperationsById.set(event.operationId, state);
24206
- addScopedOperation(this.activeOperationsByScope, event, state);
24207
- state.metadata = {
24208
- ...state.metadata,
23869
+ const metadata = {
24209
23870
  ...extractEventMetadata(event),
24210
- "flue.operation_id": event.operationId
23871
+ "flue.operation": event.operationKind,
23872
+ provider: "flue"
24211
23873
  };
24212
- safeLog3(state.span, { metadata: state.metadata });
23874
+ const parent = this.parentSpanForEvent(event);
23875
+ const span = startFlueSpan(parent, {
23876
+ name: `flue.${event.operationKind}`,
23877
+ spanAttributes: { type: "task" /* TASK */ },
23878
+ startTime: eventTime(event.timestamp),
23879
+ event: { metadata }
23880
+ });
23881
+ this.operationsById.set(event.operationId, { metadata, span });
24213
23882
  }
24214
23883
  handleOperation(event) {
24215
- const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24216
- if (!state) {
23884
+ if (!isInstrumentedOperation(event.operationKind)) {
24217
23885
  return;
24218
23886
  }
23887
+ const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
23888
+ const output = operationOutput(event);
24219
23889
  const metadata = {
24220
23890
  ...state.metadata,
24221
23891
  ...extractEventMetadata(event),
24222
- ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24223
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
23892
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
23893
+ ...event.usage ? { "flue.usage": event.usage } : {}
24224
23894
  };
24225
- const metrics = metricsFromUsage(event.usage);
23895
+ this.finishPendingChildrenForOperation(event, output);
24226
23896
  safeLog3(state.span, {
24227
- ...event.error ? { error: errorToString(event.error) } : {},
23897
+ ...event.isError ? { error: errorToString(event.error) } : {},
24228
23898
  metadata,
24229
- ...Object.keys(metrics).length ? { metrics } : {}
23899
+ metrics: durationMetrics2(event.durationMs),
23900
+ output
24230
23901
  });
23902
+ safeEnd(state.span, eventTime(event.timestamp));
23903
+ this.operationsById.delete(event.operationId);
24231
23904
  }
24232
- ensureTurnState(event) {
24233
- const scope = scopeKey(event);
24234
- const existing = this.turnsByScope.get(scope);
24235
- if (existing) {
24236
- return existing;
23905
+ handleTurnRequest(event) {
23906
+ const key = turnKey(event);
23907
+ if (!key) {
23908
+ return;
24237
23909
  }
24238
- const parent = this.parentSpanForEvent(event);
24239
23910
  const metadata = {
24240
23911
  ...extractEventMetadata(event),
24241
- provider: "flue"
23912
+ ...event.api ? { "flue.api": event.api } : {},
23913
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
23914
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
23915
+ ...event.provider ? { "flue.provider": event.provider } : {},
23916
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
23917
+ ...event.reasoning ? { reasoning: event.reasoning } : {},
23918
+ ...event.input?.systemPrompt ? { "flue.system_prompt": event.input.systemPrompt } : {},
23919
+ ...event.input?.tools ? { tools: event.input.tools } : {}
24242
23920
  };
23921
+ const parent = this.parentSpanForTurn(event);
24243
23922
  const span = startFlueSpan(parent, {
24244
- name: "flue.turn",
24245
- spanAttributes: { type: "llm" /* LLM */ }
23923
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
23924
+ spanAttributes: { type: "llm" /* LLM */ },
23925
+ startTime: eventTime(event.timestamp),
23926
+ event: {
23927
+ input: event.input?.messages,
23928
+ metadata
23929
+ }
24246
23930
  });
24247
- const state = {
24248
- metadata,
24249
- span,
24250
- hasThinking: false,
24251
- startTime: getCurrentUnixTimestamp(),
24252
- text: [],
24253
- thinking: [],
24254
- toolCalls: []
24255
- };
24256
- safeLog3(span, { metadata });
24257
- this.turnsByScope.set(scope, state);
24258
- return state;
23931
+ this.logOperationInput(
23932
+ event.operationId,
23933
+ event.input?.messages ?? event.input
23934
+ );
23935
+ this.turnsByKey.set(key, { metadata, span });
24259
23936
  }
24260
23937
  handleTurn(event) {
24261
- const scope = scopeKey(event);
24262
- const state = this.ensureTurnState(event);
24263
- const text = state.text.join("");
24264
- const reasoning = state.finalThinking ?? state.thinking.join("");
24265
- const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
23938
+ const key = turnKey(event);
23939
+ if (!key) {
23940
+ return;
23941
+ }
23942
+ const state = this.turnsByKey.get(key) ?? this.startSyntheticTurn(event);
24266
23943
  const metadata = {
24267
23944
  ...state.metadata,
24268
23945
  ...extractEventMetadata(event),
23946
+ ...event.api ? { "flue.api": event.api } : {},
24269
23947
  ...event.model ? { model: event.model, "flue.model": event.model } : {},
23948
+ ...event.provider ? { provider: event.provider } : {},
23949
+ ...event.provider ? { "flue.provider": event.provider } : {},
23950
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
24270
23951
  ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24271
- ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24272
- provider: "flue"
23952
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24273
23953
  };
24274
23954
  safeLog3(state.span, {
24275
- ...event.error ? { error: errorToString(event.error) } : {},
23955
+ ...event.isError ? { error: errorToString(event.error) } : {},
24276
23956
  metadata,
24277
23957
  metrics: {
24278
- ...durationMsMetrics(event.durationMs),
24279
- ...metricsFromUsage(event.usage)
24280
- },
24281
- output: toAssistantOutput(
24282
- text,
24283
- event.stopReason,
24284
- outputReasoning,
24285
- state.toolCalls
24286
- )
24287
- });
24288
- state.span.end();
24289
- this.turnsByScope.delete(scope);
24290
- }
24291
- handleThinkingDelta(event) {
24292
- const delta = event.delta;
24293
- if (typeof delta !== "string" || !delta) {
24294
- return;
24295
- }
24296
- const state = this.ensureTurnState(event);
24297
- state.hasThinking = true;
24298
- state.metadata["flue.thinking"] = true;
24299
- state.thinking.push(delta);
24300
- }
24301
- handleThinkingStart(event) {
24302
- const state = this.ensureTurnState(event);
24303
- state.hasThinking = true;
24304
- state.metadata["flue.thinking"] = true;
24305
- }
24306
- handleThinkingEnd(event) {
24307
- const state = this.ensureTurnState(event);
24308
- state.hasThinking = true;
24309
- state.metadata["flue.thinking"] = true;
24310
- if (typeof event.content === "string" && event.content) {
24311
- state.finalThinking = event.content;
24312
- }
23958
+ ...durationMetrics2(event.durationMs),
23959
+ ...metricsFromUsage(event.usage)
23960
+ },
23961
+ output: event.output
23962
+ });
23963
+ safeEnd(state.span, eventTime(event.timestamp));
23964
+ this.turnsByKey.delete(key);
24313
23965
  }
24314
- handleToolStart(event, options) {
24315
- const toolCallId = event.toolCallId;
24316
- if (!toolCallId) {
23966
+ handleToolStart(event) {
23967
+ if (!event.toolCallId) {
24317
23968
  return;
24318
23969
  }
24319
- const parent = this.parentSpanForEvent(event);
24320
- const scope = scopeKey(event);
24321
- let turnState = this.turnsByScope.get(scope);
24322
- if (!turnState && parent && options.captureTurnSpans) {
24323
- turnState = this.ensureTurnState(event);
24324
- }
24325
23970
  const metadata = {
24326
23971
  ...extractEventMetadata(event),
24327
23972
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24328
- "flue.tool_call_id": toolCallId,
23973
+ "flue.tool_call_id": event.toolCallId,
24329
23974
  provider: "flue"
24330
23975
  };
23976
+ const parent = this.parentSpanForTool(event);
24331
23977
  const span = startFlueSpan(parent, {
24332
- name: `tool: ${event.toolName ?? "unknown"}`,
24333
- spanAttributes: { type: "tool" /* TOOL */ }
24334
- });
24335
- if (turnState) {
24336
- turnState.toolCalls.push({
24337
- args: event.args,
24338
- toolCallId,
24339
- toolName: event.toolName
24340
- });
24341
- }
24342
- safeLog3(span, {
24343
- input: event.args,
24344
- metadata
24345
- });
24346
- this.toolsById.set(toolKey(event), {
24347
- metadata,
24348
- span,
24349
- startTime: getCurrentUnixTimestamp()
23978
+ name: `tool:${event.toolName ?? "unknown"}`,
23979
+ spanAttributes: { type: "tool" /* TOOL */ },
23980
+ startTime: eventTime(event.timestamp),
23981
+ event: {
23982
+ input: event.args,
23983
+ metadata
23984
+ }
24350
23985
  });
23986
+ this.toolsByKey.set(toolKey(event), { metadata, span });
24351
23987
  }
24352
23988
  handleToolCall(event) {
23989
+ if (!event.toolCallId) {
23990
+ return;
23991
+ }
24353
23992
  const key = toolKey(event);
24354
- const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
23993
+ const state = this.toolsByKey.get(key) ?? this.startSyntheticTool(event);
24355
23994
  const metadata = {
24356
23995
  ...state.metadata,
24357
23996
  ...extractEventMetadata(event),
24358
23997
  ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24359
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
23998
+ "flue.tool_call_id": event.toolCallId,
24360
23999
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24361
24000
  };
24362
24001
  safeLog3(state.span, {
24363
24002
  ...event.isError ? { error: errorToString(event.result) } : {},
24364
24003
  metadata,
24365
- metrics: durationMsMetrics(event.durationMs),
24004
+ metrics: durationMetrics2(event.durationMs),
24366
24005
  output: event.result
24367
24006
  });
24368
- state.span.end();
24369
- this.toolsById.delete(key);
24007
+ safeEnd(state.span, eventTime(event.timestamp));
24008
+ this.toolsByKey.delete(key);
24370
24009
  }
24371
24010
  handleTaskStart(event) {
24372
- const parent = this.parentSpanForEvent(event);
24011
+ if (!event.taskId) {
24012
+ return;
24013
+ }
24373
24014
  const metadata = {
24374
24015
  ...extractEventMetadata(event),
24375
- ...event.role ? { "flue.role": event.role } : {},
24016
+ ...event.agent ? { "flue.agent": event.agent } : {},
24376
24017
  ...event.cwd ? { "flue.cwd": event.cwd } : {},
24377
24018
  "flue.task_id": event.taskId,
24378
24019
  provider: "flue"
24379
24020
  };
24021
+ const parent = this.parentSpanForEvent(event);
24380
24022
  const span = startFlueSpan(parent, {
24381
- name: "flue.task",
24382
- spanAttributes: { type: "task" /* TASK */ }
24383
- });
24384
- safeLog3(span, {
24385
- input: event.prompt,
24386
- metadata
24387
- });
24388
- this.tasksById.set(event.taskId, {
24389
- metadata,
24390
- span,
24391
- startTime: getCurrentUnixTimestamp()
24023
+ name: event.agent ? `task:${event.agent}` : "flue.task",
24024
+ spanAttributes: { type: "task" /* TASK */ },
24025
+ startTime: eventTime(event.timestamp),
24026
+ event: {
24027
+ input: event.prompt,
24028
+ metadata
24029
+ }
24392
24030
  });
24031
+ this.tasksById.set(event.taskId, { metadata, span });
24393
24032
  }
24394
24033
  handleTask(event) {
24395
24034
  const state = this.tasksById.get(event.taskId);
@@ -24401,426 +24040,372 @@ var FluePlugin = class extends BasePlugin {
24401
24040
  metadata: {
24402
24041
  ...state.metadata,
24403
24042
  ...extractEventMetadata(event),
24043
+ ...event.agent ? { "flue.agent": event.agent } : {},
24404
24044
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24405
24045
  },
24406
- metrics: durationMsMetrics(event.durationMs),
24046
+ metrics: durationMetrics2(event.durationMs),
24407
24047
  output: event.result
24408
24048
  });
24409
- state.span.end();
24049
+ safeEnd(state.span, eventTime(event.timestamp));
24410
24050
  this.tasksById.delete(event.taskId);
24411
24051
  }
24412
24052
  handleCompactionStart(event) {
24413
- const operationState = this.operationStateForEvent(event);
24414
- const parent = operationState?.span ?? this.parentSpanForEvent(event);
24053
+ const key = compactionKey(event);
24054
+ const input = {
24055
+ ...event.estimatedTokens !== void 0 ? { estimatedTokens: event.estimatedTokens } : {},
24056
+ ...event.reason ? { reason: event.reason } : {}
24057
+ };
24415
24058
  const metadata = {
24416
24059
  ...extractEventMetadata(event),
24417
24060
  ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24418
24061
  provider: "flue"
24419
24062
  };
24420
- const input = {
24421
- ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24422
- ...event.reason ? { reason: event.reason } : {}
24423
- };
24063
+ const parent = this.parentSpanForEvent(event);
24424
24064
  const span = startFlueSpan(parent, {
24425
- name: "flue.compaction",
24426
- spanAttributes: { type: "task" /* TASK */ }
24427
- });
24428
- safeLog3(span, {
24429
- input,
24430
- metadata
24431
- });
24432
- this.compactionsByScope.set(scopeKey(event), {
24433
- input,
24434
- metadata,
24435
- operationState,
24436
- span,
24437
- startTime: getCurrentUnixTimestamp()
24065
+ name: `compaction:${event.reason ?? "unknown"}`,
24066
+ spanAttributes: { type: "task" /* TASK */ },
24067
+ startTime: eventTime(event.timestamp),
24068
+ event: {
24069
+ input,
24070
+ metadata
24071
+ }
24438
24072
  });
24073
+ this.logOperationInput(event.operationId, input);
24074
+ this.compactionsByKey.set(key, { metadata, span });
24439
24075
  }
24440
24076
  handleCompaction(event) {
24441
- const key = scopeKey(event);
24442
- const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24443
- if (!state) {
24444
- return;
24445
- }
24077
+ const key = compactionKey(event);
24078
+ const state = this.compactionsByKey.get(key) ?? this.startSyntheticCompaction(event);
24079
+ const metadata = {
24080
+ ...state.metadata,
24081
+ ...extractEventMetadata(event),
24082
+ ...event.usage ? { "flue.usage": event.usage } : {}
24083
+ };
24446
24084
  safeLog3(state.span, {
24447
- metadata: {
24448
- ...state.metadata,
24449
- ...extractEventMetadata(event),
24450
- ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24451
- ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24452
- },
24085
+ metadata,
24453
24086
  metrics: {
24454
- ...durationMsMetrics(event.durationMs),
24455
- ...metricsFromUsage(event.usage)
24087
+ ...durationMetrics2(event.durationMs),
24088
+ ...typeof event.messagesBefore === "number" ? { messages_before: event.messagesBefore } : {},
24089
+ ...typeof event.messagesAfter === "number" ? { messages_after: event.messagesAfter } : {}
24456
24090
  },
24457
24091
  output: {
24458
24092
  messagesAfter: event.messagesAfter,
24459
24093
  messagesBefore: event.messagesBefore
24460
24094
  }
24461
24095
  });
24462
- state.span.end();
24463
- this.deleteCompactionState(state);
24096
+ safeEnd(state.span, eventTime(event.timestamp));
24097
+ this.compactionsByKey.delete(key);
24464
24098
  }
24465
- findCompactionState(event) {
24466
- const operationState = this.operationStateForEvent(event);
24467
- for (const state of this.compactionsByScope.values()) {
24468
- if (operationState && state.operationState === operationState) {
24469
- return state;
24099
+ parentSpanForTurn(event) {
24100
+ if (event.purpose === "compaction" || event.purpose === "compaction_prefix") {
24101
+ const compaction = this.compactionsByKey.get(compactionKey(event));
24102
+ if (compaction) {
24103
+ return compaction.span;
24470
24104
  }
24471
24105
  }
24472
- return void 0;
24106
+ return this.parentSpanForEvent(event);
24473
24107
  }
24474
- finishCompactionsForOperation(operationState) {
24475
- for (const state of [...this.compactionsByScope.values()]) {
24476
- if (state.operationState !== operationState) {
24477
- continue;
24108
+ parentSpanForEvent(event) {
24109
+ const turn = turnKey(event);
24110
+ if (turn) {
24111
+ const turnState = this.turnsByKey.get(turn);
24112
+ if (turnState) {
24113
+ return turnState.span;
24478
24114
  }
24479
- safeLog3(state.span, {
24480
- input: state.input,
24481
- metadata: state.metadata,
24482
- metrics: {
24483
- ...buildDurationMetrics3(state.startTime)
24484
- },
24485
- output: { completed: true }
24486
- });
24487
- state.span.end();
24488
- this.deleteCompactionState(state);
24489
24115
  }
24490
- }
24491
- deleteCompactionState(state) {
24492
- for (const [key, candidate] of this.compactionsByScope) {
24493
- if (candidate !== state) {
24494
- continue;
24116
+ if (event.taskId) {
24117
+ const task = this.tasksById.get(event.taskId);
24118
+ if (task) {
24119
+ return task.span;
24495
24120
  }
24496
- this.compactionsByScope.delete(key);
24497
- return;
24498
24121
  }
24499
- }
24500
- startSyntheticToolState(event, toolName) {
24501
- const parent = this.parentSpanForEvent(event);
24502
- const metadata = {
24503
- ...extractEventMetadata(event),
24504
- ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24505
- "flue.tool_name": toolName,
24506
- provider: "flue"
24507
- };
24508
- const span = startFlueSpan(parent, {
24509
- name: `tool: ${toolName}`,
24510
- spanAttributes: { type: "tool" /* TOOL */ }
24511
- });
24512
- safeLog3(span, { metadata });
24513
- return { metadata, span, startTime: getCurrentUnixTimestamp() };
24514
- }
24515
- operationStateForEvent(event) {
24516
24122
  if (event.operationId) {
24517
- const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24123
+ const operation = this.operationsById.get(event.operationId);
24518
24124
  if (operation) {
24519
- return operation;
24125
+ return operation.span;
24520
24126
  }
24521
24127
  }
24522
- return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24128
+ if (event.runId) {
24129
+ return this.runsById.get(event.runId)?.span;
24130
+ }
24131
+ return void 0;
24523
24132
  }
24524
- parentSpanForEvent(event) {
24133
+ parentSpanForTool(event) {
24134
+ if (event.taskId) {
24135
+ const task = this.tasksById.get(event.taskId);
24136
+ if (task) {
24137
+ return task.span;
24138
+ }
24139
+ }
24525
24140
  if (event.operationId) {
24526
- const operation = this.operationStateForEvent(event);
24141
+ const operation = this.operationsById.get(event.operationId);
24527
24142
  if (operation) {
24528
24143
  return operation.span;
24529
24144
  }
24530
24145
  }
24531
- if (event.taskId) {
24532
- return this.tasksById.get(event.taskId)?.span;
24146
+ if (event.runId) {
24147
+ return this.runsById.get(event.runId)?.span;
24533
24148
  }
24534
- return this.operationStateForEvent(event)?.span;
24149
+ return void 0;
24535
24150
  }
24536
- promotePendingOperationForEvent(event) {
24537
- if (!event.operationId) {
24538
- return void 0;
24151
+ logOperationInput(operationId, input) {
24152
+ if (!operationId || input === void 0) {
24153
+ return;
24154
+ }
24155
+ const operation = this.operationsById.get(operationId);
24156
+ if (!operation || operation.loggedInput) {
24157
+ return;
24158
+ }
24159
+ safeLog3(operation.span, { input });
24160
+ operation.loggedInput = true;
24161
+ }
24162
+ startSyntheticOperation(event) {
24163
+ const metadata = {
24164
+ ...extractEventMetadata(event),
24165
+ "flue.operation": event.operationKind,
24166
+ provider: "flue"
24167
+ };
24168
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24169
+ name: `flue.${event.operationKind}`,
24170
+ spanAttributes: { type: "task" /* TASK */ },
24171
+ startTime: eventTime(event.timestamp),
24172
+ event: { metadata }
24173
+ });
24174
+ return { metadata, span };
24175
+ }
24176
+ startSyntheticTurn(event) {
24177
+ const metadata = {
24178
+ ...extractEventMetadata(event),
24179
+ ...event.api ? { "flue.api": event.api } : {},
24180
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24181
+ ...event.provider ? { provider: event.provider } : { provider: "flue" },
24182
+ ...event.provider ? { "flue.provider": event.provider } : {},
24183
+ ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
24184
+ };
24185
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24186
+ name: `llm:${event.model ?? event.purpose ?? "unknown"}`,
24187
+ spanAttributes: { type: "llm" /* LLM */ },
24188
+ startTime: eventTime(event.timestamp),
24189
+ event: { metadata }
24190
+ });
24191
+ return { metadata, span };
24192
+ }
24193
+ startSyntheticTool(event) {
24194
+ const metadata = {
24195
+ ...extractEventMetadata(event),
24196
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24197
+ "flue.tool_call_id": event.toolCallId,
24198
+ provider: "flue"
24199
+ };
24200
+ const span = startFlueSpan(this.parentSpanForTool(event), {
24201
+ name: `tool:${event.toolName ?? "unknown"}`,
24202
+ spanAttributes: { type: "tool" /* TOOL */ },
24203
+ startTime: eventTime(event.timestamp),
24204
+ event: { metadata }
24205
+ });
24206
+ return { metadata, span };
24207
+ }
24208
+ startSyntheticCompaction(event) {
24209
+ const metadata = {
24210
+ ...extractEventMetadata(event),
24211
+ provider: "flue"
24212
+ };
24213
+ const span = startFlueSpan(this.parentSpanForEvent(event), {
24214
+ name: "compaction:unknown",
24215
+ spanAttributes: { type: "task" /* TASK */ },
24216
+ startTime: eventTime(event.timestamp),
24217
+ event: { metadata }
24218
+ });
24219
+ return { metadata, span };
24220
+ }
24221
+ finishPendingChildrenForOperation(event, operationOutput2) {
24222
+ const endTime = eventTime(event.timestamp);
24223
+ const usage = event.usage ?? usageFromOperationResult(event.result);
24224
+ const turnEntries = [...this.turnsByKey].filter(
24225
+ ([, state]) => stateMatchesOperation(state, event.operationId)
24226
+ );
24227
+ turnEntries.forEach(([key, state], index) => {
24228
+ const shouldLogOperationOutput = (event.operationKind === "prompt" || event.operationKind === "skill") && index === turnEntries.length - 1 && operationOutput2 !== void 0;
24229
+ safeLog3(state.span, {
24230
+ metadata: state.metadata,
24231
+ metrics: metricsFromUsage(usage),
24232
+ ...shouldLogOperationOutput ? { output: operationOutput2 } : {}
24233
+ });
24234
+ safeEnd(state.span, endTime);
24235
+ this.turnsByKey.delete(key);
24236
+ });
24237
+ for (const [key, state] of this.toolsByKey) {
24238
+ if (!stateMatchesOperation(state, event.operationId)) {
24239
+ continue;
24240
+ }
24241
+ safeEnd(state.span, endTime);
24242
+ this.toolsByKey.delete(key);
24539
24243
  }
24540
- const scopePrefixes = operationScopePrefixes(event);
24541
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24542
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24244
+ for (const [key, state] of this.tasksById) {
24245
+ if (!stateMatchesOperation(state, event.operationId)) {
24543
24246
  continue;
24544
24247
  }
24545
- const state = candidateQueue.shift();
24546
- if (!state) {
24547
- return void 0;
24248
+ safeEnd(state.span, endTime);
24249
+ this.tasksById.delete(key);
24250
+ }
24251
+ for (const [key, state] of this.compactionsByKey) {
24252
+ if (!stateMatchesOperation(state, event.operationId)) {
24253
+ continue;
24548
24254
  }
24549
- state.operationId = event.operationId;
24550
- this.activeOperationsById.set(event.operationId, state);
24551
- addScopedOperation(this.activeOperationsByScope, event, state);
24552
- state.metadata = {
24553
- ...state.metadata,
24554
- ...extractEventMetadata(event),
24555
- "flue.operation_id": event.operationId
24556
- };
24557
- safeLog3(state.span, { metadata: state.metadata });
24558
- return state;
24255
+ safeLog3(state.span, {
24256
+ metadata: state.metadata,
24257
+ metrics: durationMetrics2(event.durationMs),
24258
+ output: { completed: true }
24259
+ });
24260
+ safeEnd(state.span, eventTime(event.timestamp));
24261
+ this.compactionsByKey.delete(key);
24559
24262
  }
24560
- return void 0;
24561
24263
  }
24562
- activeOperationForEventScope(event) {
24563
- for (const scope of operationScopeNames(event)) {
24564
- const operations = this.activeOperationsByScope.get(scope);
24565
- if (operations?.length) {
24566
- return operations[operations.length - 1];
24264
+ finishPendingSpansForRun(event) {
24265
+ const endTime = eventTime(event.timestamp);
24266
+ for (const [key, state] of this.toolsByKey) {
24267
+ if (!stateMatchesRun(state, event.runId)) {
24268
+ continue;
24567
24269
  }
24270
+ safeEnd(state.span, endTime);
24271
+ this.toolsByKey.delete(key);
24568
24272
  }
24569
- return void 0;
24570
- }
24571
- pendingOperationForEventScope(event) {
24572
- const scopePrefixes = operationScopePrefixes(event);
24573
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24574
- if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24273
+ for (const [key, state] of this.turnsByKey) {
24274
+ if (!stateMatchesRun(state, event.runId)) {
24575
24275
  continue;
24576
24276
  }
24577
- return candidateQueue[0];
24277
+ safeEnd(state.span, endTime);
24278
+ this.turnsByKey.delete(key);
24578
24279
  }
24579
- return void 0;
24580
- }
24581
- takePendingOperationForEvent(event) {
24582
- const key = operationKey(event.session, event.operationKind);
24583
- const queue2 = this.pendingOperationsByKey.get(key);
24584
- if (queue2?.length) {
24585
- return queue2.shift();
24280
+ for (const [key, state] of this.tasksById) {
24281
+ if (!stateMatchesRun(state, event.runId)) {
24282
+ continue;
24283
+ }
24284
+ safeEnd(state.span, endTime);
24285
+ this.tasksById.delete(key);
24586
24286
  }
24587
- for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24588
- if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24589
- return candidateQueue.shift();
24287
+ for (const [key, state] of this.compactionsByKey) {
24288
+ if (!stateMatchesRun(state, event.runId)) {
24289
+ continue;
24590
24290
  }
24291
+ safeLog3(state.span, {
24292
+ metadata: state.metadata,
24293
+ output: { completed: true }
24294
+ });
24295
+ safeEnd(state.span, endTime);
24296
+ this.compactionsByKey.delete(key);
24591
24297
  }
24592
- return void 0;
24593
- }
24594
- pendingOperationQueue(key) {
24595
- const existing = this.pendingOperationsByKey.get(key);
24596
- if (existing) {
24597
- return existing;
24298
+ for (const [key, state] of this.operationsById) {
24299
+ if (!stateMatchesRun(state, event.runId)) {
24300
+ continue;
24301
+ }
24302
+ safeLog3(state.span, {
24303
+ metadata: state.metadata,
24304
+ ...state.metadata["flue.operation"] === "compact" ? { output: { completed: true } } : {}
24305
+ });
24306
+ safeEnd(state.span, endTime);
24307
+ this.operationsById.delete(key);
24598
24308
  }
24599
- const queue2 = [];
24600
- this.pendingOperationsByKey.set(key, queue2);
24601
- return queue2;
24602
24309
  }
24603
24310
  };
24604
24311
  function isInstrumentedOperation(operation) {
24605
- return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24606
- }
24607
- function getSessionName(session) {
24608
- return typeof session?.name === "string" ? session.name : void 0;
24609
- }
24610
- function operationKey(sessionName, operation) {
24611
- return `${sessionName ?? "unknown"}::${operation}`;
24612
- }
24613
- function operationScopePrefixes(event) {
24614
- const scopes = /* @__PURE__ */ new Set();
24615
- for (const scope of operationScopeNames(event)) {
24616
- scopes.add(`${scope}::`);
24617
- }
24618
- return scopes;
24619
- }
24620
- function operationKeyMatchesScopes(key, scopes) {
24621
- for (const scope of scopes) {
24622
- if (key.startsWith(scope)) {
24623
- return true;
24624
- }
24625
- }
24626
- return false;
24627
- }
24628
- function operationScopeNames(event) {
24629
- const scopes = /* @__PURE__ */ new Set();
24630
- if (event.session) {
24631
- scopes.add(event.session);
24632
- }
24633
- if (event.parentSession) {
24634
- scopes.add(event.parentSession);
24635
- }
24636
- if (!scopes.size) {
24637
- scopes.add("unknown");
24638
- }
24639
- return scopes;
24640
- }
24641
- function addScopedOperation(operationsByScope, event, state) {
24642
- for (const scope of operationScopeNames(event)) {
24643
- addOperationToScope(operationsByScope, scope, state);
24644
- }
24645
- }
24646
- function addOperationToScope(operationsByScope, scope, state) {
24647
- const operations = operationsByScope.get(scope);
24648
- if (operations) {
24649
- if (!operations.includes(state)) {
24650
- operations.push(state);
24651
- }
24652
- } else {
24653
- operationsByScope.set(scope, [state]);
24654
- }
24655
- }
24656
- function removeScopedOperation(operationsByScope, state) {
24657
- for (const [scope, operations] of operationsByScope) {
24658
- const index = operations.indexOf(state);
24659
- if (index === -1) {
24660
- continue;
24661
- }
24662
- operations.splice(index, 1);
24663
- if (operations.length === 0) {
24664
- operationsByScope.delete(scope);
24665
- }
24666
- }
24667
- }
24668
- function removePendingOperation(pendingOperationsByKey, state) {
24669
- for (const [key, queue2] of pendingOperationsByKey) {
24670
- const index = queue2.indexOf(state);
24671
- if (index === -1) {
24672
- continue;
24673
- }
24674
- queue2.splice(index, 1);
24675
- if (queue2.length === 0) {
24676
- pendingOperationsByKey.delete(key);
24677
- }
24678
- return;
24679
- }
24680
- }
24681
- function extractSessionMetadata(session) {
24682
- const sessionName = getSessionName(session);
24683
- return sessionName ? { "flue.session": sessionName } : {};
24312
+ return operation === "prompt" || operation === "skill" || operation === "compact";
24684
24313
  }
24685
- function extractEventMetadata(event) {
24314
+ function extractEventMetadata(event, ctx) {
24686
24315
  return {
24687
24316
  ...event.runId ? { "flue.run_id": event.runId } : {},
24317
+ ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
24318
+ ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
24688
24319
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
24689
24320
  ...event.session ? { "flue.session": event.session } : {},
24690
24321
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
24691
24322
  ...event.harness ? { "flue.harness": event.harness } : {},
24692
24323
  ...event.taskId ? { "flue.task_id": event.taskId } : {},
24693
- ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24324
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {},
24325
+ ...event.turnId ? { "flue.turn_id": event.turnId } : {},
24326
+ ...typeof ctx?.id === "string" ? { "flue.context_id": ctx.id } : {},
24327
+ ...typeof ctx?.runId === "string" ? { "flue.context_run_id": ctx.runId } : {}
24694
24328
  };
24695
24329
  }
24696
- function extractOperationInput(operation, args) {
24697
- switch (operation) {
24698
- case "prompt":
24699
- case "task":
24700
- return args[0];
24701
- case "skill":
24702
- return {
24703
- args: getOptionObject(args[1])?.args,
24704
- name: args[0]
24705
- };
24706
- case "compact":
24707
- return void 0;
24330
+ function extractPayloadMetadata(payload) {
24331
+ if (!isObjectLike(payload)) {
24332
+ return {};
24708
24333
  }
24334
+ const metadata = Reflect.get(payload, "metadata");
24335
+ if (!isObjectLike(metadata)) {
24336
+ return {};
24337
+ }
24338
+ return Object.fromEntries(Object.entries(metadata));
24709
24339
  }
24710
- function extractOperationInputMetadata(operation, args) {
24711
- const options = getOptionObject(args[1]);
24712
- return {
24713
- ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
24714
- ...options?.model ? { model: options.model, "flue.model": options.model } : {},
24715
- ...options?.role ? { "flue.role": options.role } : {},
24716
- ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
24717
- ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
24718
- ...Array.isArray(options?.tools) ? {
24719
- "flue.tools_count": options.tools.length,
24720
- tools: summarizeTools(options.tools)
24721
- } : {},
24722
- ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
24723
- ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
24724
- };
24725
- }
24726
- function getOptionObject(value) {
24727
- return isObject(value) ? value : void 0;
24728
- }
24729
- function summarizeTools(tools) {
24730
- return tools.flatMap((tool) => {
24731
- if (!isObject(tool)) {
24732
- return [];
24733
- }
24734
- const name = typeof tool.name === "string" ? tool.name : void 0;
24735
- if (!name) {
24736
- return [];
24737
- }
24738
- return [
24739
- {
24740
- function: {
24741
- description: typeof tool.description === "string" ? tool.description : void 0,
24742
- name,
24743
- parameters: tool.parameters
24744
- },
24745
- type: "function"
24746
- }
24747
- ];
24748
- });
24340
+ function operationOutput(event) {
24341
+ if (event.operationKind === "prompt" || event.operationKind === "skill") {
24342
+ return llmResultFromOperationResult(event.result);
24343
+ }
24344
+ return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
24749
24345
  }
24750
- function extractPromptResponseMetadata(result) {
24751
- const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
24752
- return modelId ? {
24753
- model: modelId,
24754
- "flue.model": modelId
24755
- } : {};
24346
+ function llmResultFromOperationResult(result) {
24347
+ if (!isObjectLike(result)) {
24348
+ return result;
24349
+ }
24350
+ const text = Reflect.get(result, "text");
24351
+ return text === void 0 ? result : text;
24756
24352
  }
24757
- function extractOperationOutput(result) {
24758
- if (!result) {
24353
+ function usageFromOperationResult(result) {
24354
+ if (!isObjectLike(result)) {
24759
24355
  return void 0;
24760
24356
  }
24761
- if ("data" in result) {
24762
- return result.data;
24763
- }
24764
- if ("text" in result) {
24765
- return result.text;
24766
- }
24767
- return result;
24357
+ return Reflect.get(result, "usage");
24768
24358
  }
24769
24359
  function metricsFromUsage(usage) {
24360
+ if (!isObjectLike(usage)) {
24361
+ return {};
24362
+ }
24363
+ const cacheRead = Reflect.get(usage, "cacheRead");
24364
+ const cacheWrite = Reflect.get(usage, "cacheWrite");
24365
+ const cost = Reflect.get(usage, "cost");
24366
+ const input = Reflect.get(usage, "input");
24367
+ const output = Reflect.get(usage, "output");
24368
+ const totalTokens = Reflect.get(usage, "totalTokens");
24369
+ const totalCost = isObjectLike(cost) ? Reflect.get(cost, "total") : void 0;
24770
24370
  return {
24771
- ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
24772
- ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
24773
- ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
24774
- ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
24775
- ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
24776
- ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
24777
- };
24778
- }
24779
- function buildDurationMetrics3(startTime) {
24780
- return {
24781
- duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
24371
+ ...typeof input === "number" ? { prompt_tokens: input } : {},
24372
+ ...typeof output === "number" ? { completion_tokens: output } : {},
24373
+ ...typeof cacheRead === "number" ? { prompt_cached_tokens: cacheRead } : {},
24374
+ ...typeof cacheWrite === "number" ? { prompt_cache_creation_tokens: cacheWrite } : {},
24375
+ ...typeof totalTokens === "number" ? { tokens: totalTokens } : {},
24376
+ ...typeof totalCost === "number" ? { estimated_cost: totalCost } : {}
24782
24377
  };
24783
24378
  }
24784
- function durationMsMetrics(durationMs) {
24379
+ function durationMetrics2(durationMs) {
24785
24380
  return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
24786
24381
  }
24787
- function scopeKey(event) {
24788
- if (event.operationId) {
24789
- return `operation:${event.operationId}`;
24790
- }
24791
- if (event.taskId) {
24792
- return `task:${event.taskId}`;
24793
- }
24794
- if (event.session) {
24795
- return `session:${event.session}`;
24382
+ function eventTime(value) {
24383
+ if (typeof value !== "string") {
24384
+ return void 0;
24796
24385
  }
24797
- return "flue:unknown";
24386
+ const timestamp = Date.parse(value);
24387
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
24388
+ }
24389
+ function turnKey(event) {
24390
+ return event.turnId;
24798
24391
  }
24799
24392
  function toolKey(event) {
24800
- return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24393
+ return `${event.turnId ?? event.operationId ?? event.taskId ?? event.runId ?? "unknown"}:${event.toolCallId ?? "unknown"}`;
24801
24394
  }
24802
- function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24395
+ function compactionKey(event) {
24803
24396
  return [
24804
- {
24805
- finish_reason: finishReason ?? "stop",
24806
- index: 0,
24807
- message: {
24808
- content: text,
24809
- ...reasoning ? { reasoning } : {},
24810
- role: "assistant",
24811
- ...toolCalls?.length ? {
24812
- tool_calls: toolCalls.map((toolCall) => ({
24813
- function: {
24814
- arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
24815
- name: toolCall.toolName ?? "unknown"
24816
- },
24817
- ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
24818
- type: "function"
24819
- }))
24820
- } : {}
24821
- }
24822
- }
24823
- ];
24397
+ event.instanceId ?? "",
24398
+ event.runId ?? "",
24399
+ event.session ?? "",
24400
+ event.operationId ?? "",
24401
+ event.taskId ?? ""
24402
+ ].join(":");
24403
+ }
24404
+ function stateMatchesOperation(state, operationId) {
24405
+ return state.metadata["flue.operation_id"] === operationId;
24406
+ }
24407
+ function stateMatchesRun(state, runId) {
24408
+ return state.metadata["flue.run_id"] === runId;
24824
24409
  }
24825
24410
  function startFlueSpan(parent, args) {
24826
24411
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
@@ -24832,6 +24417,13 @@ function safeLog3(span, event) {
24832
24417
  logInstrumentationError3("Flue span log", error);
24833
24418
  }
24834
24419
  }
24420
+ function safeEnd(span, endTime) {
24421
+ try {
24422
+ span.end(endTime === void 0 ? void 0 : { endTime });
24423
+ } catch (error) {
24424
+ logInstrumentationError3("Flue span end", error);
24425
+ }
24426
+ }
24835
24427
  function errorToString(error) {
24836
24428
  if (error instanceof Error) {
24837
24429
  return error.message;
@@ -25913,6 +25505,7 @@ __export(exports_exports, {
25913
25505
  _internalIso: () => isomorph_default,
25914
25506
  _internalSetInitialState: () => _internalSetInitialState,
25915
25507
  addAzureBlobHeaders: () => addAzureBlobHeaders,
25508
+ braintrustFlueObserver: () => braintrustFlueObserver,
25916
25509
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
25917
25510
  buildLocalSummary: () => buildLocalSummary,
25918
25511
  configureInstrumentation: () => configureInstrumentation,
@@ -25992,8 +25585,6 @@ __export(exports_exports, {
25992
25585
  wrapCohere: () => wrapCohere,
25993
25586
  wrapCopilotClient: () => wrapCopilotClient,
25994
25587
  wrapCursorSDK: () => wrapCursorSDK,
25995
- wrapFlueContext: () => wrapFlueContext,
25996
- wrapFlueSession: () => wrapFlueSession,
25997
25588
  wrapGenkit: () => wrapGenkit,
25998
25589
  wrapGoogleADK: () => wrapGoogleADK,
25999
25590
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -33023,6 +32614,7 @@ export {
33023
32614
  isomorph_default as _internalIso,
33024
32615
  _internalSetInitialState,
33025
32616
  addAzureBlobHeaders,
32617
+ braintrustFlueObserver,
33026
32618
  braintrustStreamChunkSchema,
33027
32619
  buildLocalSummary,
33028
32620
  configureInstrumentation,
@@ -33103,8 +32695,6 @@ export {
33103
32695
  wrapCohere,
33104
32696
  wrapCopilotClient,
33105
32697
  wrapCursorSDK,
33106
- wrapFlueContext,
33107
- wrapFlueSession,
33108
32698
  wrapGenkit,
33109
32699
  wrapGoogleADK,
33110
32700
  wrapGoogleGenAI,