braintrust 3.26.0 → 3.28.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 (61) hide show
  1. package/dev/dist/index.d.mts +519 -186
  2. package/dev/dist/index.d.ts +519 -186
  3. package/dev/dist/index.js +3727 -1526
  4. package/dev/dist/index.mjs +2815 -614
  5. package/dist/apply-auto-instrumentation.js +372 -261
  6. package/dist/apply-auto-instrumentation.mjs +171 -60
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +458 -61
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +5 -4
  9. package/dist/auto-instrumentations/bundler/next.cjs +460 -63
  10. package/dist/auto-instrumentations/bundler/next.mjs +6 -5
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +458 -61
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +5 -4
  13. package/dist/auto-instrumentations/bundler/vite.cjs +487 -62
  14. package/dist/auto-instrumentations/bundler/vite.mjs +34 -5
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +444 -61
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +458 -61
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +6 -5
  18. package/dist/auto-instrumentations/{chunk-6E22MYSW.mjs → chunk-26PKVUKB.mjs} +109 -5
  19. package/dist/auto-instrumentations/{chunk-AKKPLXTP.mjs → chunk-2AMDGD65.mjs} +160 -57
  20. package/dist/auto-instrumentations/{chunk-V5LEODRX.mjs → chunk-HD35AM3M.mjs} +1 -1
  21. package/dist/auto-instrumentations/{chunk-XYN63IG5.mjs → chunk-I55G56ZL.mjs} +21 -58
  22. package/dist/auto-instrumentations/{chunk-NRE4QUQR.mjs → chunk-JPUFNW7X.mjs} +140 -0
  23. package/dist/auto-instrumentations/{chunk-XZHHE4Y3.mjs → chunk-NP7V4XB2.mjs} +157 -3
  24. package/dist/auto-instrumentations/hook.mjs +396 -32
  25. package/dist/auto-instrumentations/index.cjs +298 -2
  26. package/dist/auto-instrumentations/index.d.mts +5 -1
  27. package/dist/auto-instrumentations/index.d.ts +5 -1
  28. package/dist/auto-instrumentations/index.mjs +6 -2
  29. package/dist/auto-instrumentations/loader/cjs-patch.cjs +105 -57
  30. package/dist/auto-instrumentations/loader/cjs-patch.mjs +2 -2
  31. package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
  32. package/dist/browser.d.mts +683 -56
  33. package/dist/browser.d.ts +683 -56
  34. package/dist/browser.js +4242 -655
  35. package/dist/browser.mjs +4242 -655
  36. package/dist/{chunk-VYNNEKSA.js → chunk-BBE7SNRV.js} +248 -10
  37. package/dist/{chunk-VRZZQPAA.js → chunk-OBBWQW6K.js} +3351 -1392
  38. package/dist/{chunk-XIZOM2HO.mjs → chunk-UPFNQCGB.mjs} +2419 -460
  39. package/dist/{chunk-PN7EWK66.mjs → chunk-ZHUHZWFY.mjs} +241 -3
  40. package/dist/cli.js +2867 -668
  41. package/dist/edge-light.d.mts +1 -1
  42. package/dist/edge-light.d.ts +1 -1
  43. package/dist/edge-light.js +4242 -655
  44. package/dist/edge-light.mjs +4242 -655
  45. package/dist/index.d.mts +1267 -640
  46. package/dist/index.d.ts +1267 -640
  47. package/dist/index.js +2107 -630
  48. package/dist/index.mjs +1649 -172
  49. package/dist/instrumentation/index.d.mts +198 -6
  50. package/dist/instrumentation/index.d.ts +198 -6
  51. package/dist/instrumentation/index.js +2661 -581
  52. package/dist/instrumentation/index.mjs +2661 -581
  53. package/dist/vitest-evals-reporter.js +45 -43
  54. package/dist/vitest-evals-reporter.mjs +5 -3
  55. package/dist/workerd.d.mts +1 -1
  56. package/dist/workerd.d.ts +1 -1
  57. package/dist/workerd.js +4242 -655
  58. package/dist/workerd.mjs +4242 -655
  59. package/package.json +2 -3
  60. package/util/dist/index.d.mts +1545 -100
  61. package/util/dist/index.d.ts +1545 -100
@@ -3,8 +3,10 @@ var GLOBAL_INSTRUMENTATION_HOOKS_KEY = "__braintrust_instrumentation_hooks";
3
3
  var GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION = 1;
4
4
  var GLOBAL_INSTRUMENTATION_HOOKS_REGISTRY_BRAND = "braintrust.global-instrumentation-hooks.registry";
5
5
  var GLOBAL_INSTRUMENTATION_HOOK_BRAND = "braintrust.global-instrumentation-hooks.hook";
6
+ var GLOBAL_INVOCATION_HOOK_BRAND = "braintrust.global-instrumentation-hooks.invocation-hook";
6
7
  var registryBrand = Symbol.for(GLOBAL_INSTRUMENTATION_HOOKS_REGISTRY_BRAND);
7
8
  var hookBrand = Symbol.for(GLOBAL_INSTRUMENTATION_HOOK_BRAND);
9
+ var invocationHookBrand = Symbol.for(GLOBAL_INVOCATION_HOOK_BRAND);
8
10
  var errorReporter;
9
11
  function setGlobalHookErrorReporter(reporter) {
10
12
  const previousReporter = errorReporter;
@@ -149,12 +151,69 @@ var traceEvents = [
149
151
  "asyncEnd",
150
152
  "error"
151
153
  ];
154
+ function traceInvocation(hook, operator, target, thisArg, args, additional, callbackIndex = -1) {
155
+ const context = {
156
+ ...additional,
157
+ arguments: args,
158
+ self: thisArg
159
+ };
160
+ const invoke = () => hook.invoke(target, thisArg, args, additional);
161
+ if (operator === "traceCallback") {
162
+ return hook.traceCallback(invoke, callbackIndex, context);
163
+ }
164
+ if (operator === "tracePromise") {
165
+ return hook.tracePromise(invoke, context);
166
+ }
167
+ return hook.traceSync(invoke, context);
168
+ }
169
+ var InvocationHook = class {
170
+ interceptors = [];
171
+ get hasInterceptors() {
172
+ return this.interceptors.length > 0;
173
+ }
174
+ intercept(interceptor) {
175
+ if (typeof interceptor !== "function") {
176
+ throw new TypeError("interceptor must be a function");
177
+ }
178
+ this.interceptors = [...this.interceptors, interceptor];
179
+ let active = true;
180
+ return () => {
181
+ if (!active) {
182
+ return;
183
+ }
184
+ active = false;
185
+ const index = this.interceptors.indexOf(interceptor);
186
+ if (index !== -1) {
187
+ this.interceptors = [
188
+ ...this.interceptors.slice(0, index),
189
+ ...this.interceptors.slice(index + 1)
190
+ ];
191
+ }
192
+ };
193
+ }
194
+ invoke(target, thisArg, args, additional) {
195
+ const interceptors = this.interceptors;
196
+ if (interceptors.length === 0) {
197
+ return Reflect.apply(target, thisArg, args);
198
+ }
199
+ let next = target;
200
+ for (let index = interceptors.length - 1; index >= 0; index -= 1) {
201
+ const interceptor = interceptors[index];
202
+ const downstream = next;
203
+ next = function(...nextArgs) {
204
+ return interceptor(downstream, this, nextArgs, additional);
205
+ };
206
+ }
207
+ return Reflect.apply(next, thisArg, args);
208
+ }
209
+ };
152
210
  var TracingHook = class {
153
211
  start;
154
212
  end;
155
213
  asyncStart;
156
214
  asyncEnd;
157
215
  error;
216
+ invocationHook = new InvocationHook();
158
217
  constructor(nameOrChannels) {
159
218
  Object.defineProperty(this, hookBrand, {
160
219
  configurable: false,
@@ -162,6 +221,12 @@ var TracingHook = class {
162
221
  value: GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION,
163
222
  writable: false
164
223
  });
224
+ Object.defineProperty(this, invocationHookBrand, {
225
+ configurable: false,
226
+ enumerable: false,
227
+ value: GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION,
228
+ writable: false
229
+ });
165
230
  if (typeof nameOrChannels === "string") {
166
231
  this.start = new HookChannel(`tracing:${nameOrChannels}:start`);
167
232
  this.end = new HookChannel(`tracing:${nameOrChannels}:end`);
@@ -179,6 +244,26 @@ var TracingHook = class {
179
244
  get hasSubscribers() {
180
245
  return this.start.hasSubscribers || this.end.hasSubscribers || this.asyncStart.hasSubscribers || this.asyncEnd.hasSubscribers || this.error.hasSubscribers;
181
246
  }
247
+ get hasInterceptors() {
248
+ return this.invocationHook.hasInterceptors;
249
+ }
250
+ intercept(interceptor) {
251
+ return this.invocationHook.intercept(interceptor);
252
+ }
253
+ invoke(target, thisArg, args, additional) {
254
+ return this.invocationHook.invoke(target, thisArg, args, additional);
255
+ }
256
+ traceInvocation(operator, target, thisArg, args, additional, callbackIndex = -1) {
257
+ return traceInvocation(
258
+ this,
259
+ operator,
260
+ target,
261
+ thisArg,
262
+ args,
263
+ additional,
264
+ callbackIndex
265
+ );
266
+ }
182
267
  subscribe(handlers) {
183
268
  for (const eventName of traceEvents) {
184
269
  const handler = handlers[eventName];
@@ -400,6 +485,60 @@ function hasTracingHookShape(value) {
400
485
  return false;
401
486
  }
402
487
  }
488
+ function hasInvocationHookShape(value) {
489
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
490
+ return false;
491
+ }
492
+ try {
493
+ const hook = value;
494
+ return value[invocationHookBrand] === GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION && typeof hook.hasInterceptors === "boolean" && typeof hook.intercept === "function" && typeof hook.invoke === "function";
495
+ } catch {
496
+ return false;
497
+ }
498
+ }
499
+ function installInvocationHook(value) {
500
+ const hasInvocationHook = hasInvocationHookShape(value);
501
+ const invocationHook = new InvocationHook();
502
+ try {
503
+ if (!hasInvocationHook) {
504
+ Object.defineProperties(value, {
505
+ [invocationHookBrand]: {
506
+ configurable: false,
507
+ enumerable: false,
508
+ value: GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION,
509
+ writable: false
510
+ },
511
+ hasInterceptors: {
512
+ configurable: false,
513
+ enumerable: false,
514
+ get: () => invocationHook.hasInterceptors
515
+ },
516
+ intercept: {
517
+ configurable: false,
518
+ enumerable: false,
519
+ value: invocationHook.intercept.bind(invocationHook),
520
+ writable: false
521
+ },
522
+ invoke: {
523
+ configurable: false,
524
+ enumerable: false,
525
+ value: invocationHook.invoke.bind(invocationHook),
526
+ writable: false
527
+ }
528
+ });
529
+ }
530
+ if (typeof value.traceInvocation !== "function") {
531
+ Object.defineProperty(value, "traceInvocation", {
532
+ configurable: false,
533
+ enumerable: false,
534
+ value: traceInvocation.bind(void 0, value),
535
+ writable: false
536
+ });
537
+ }
538
+ } catch (error) {
539
+ reportError(error);
540
+ }
541
+ }
403
542
  function isCompatibleTracingHook(value) {
404
543
  try {
405
544
  return value[hookBrand] === GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION && hasTracingHookShape(value);
@@ -486,6 +625,7 @@ function newGlobalTracingChannel(nameOrChannels) {
486
625
  return inertTracingHook;
487
626
  }
488
627
  if (isCompatibleTracingHook(existing)) {
628
+ installInvocationHook(existing);
489
629
  return existing;
490
630
  }
491
631
  if (existing !== void 0) {
@@ -541,6 +681,114 @@ var iso = {
541
681
  };
542
682
  var isomorph_default = iso;
543
683
 
684
+ // src/debug-logger.ts
685
+ var PREFIX = "[braintrust]";
686
+ var DEBUG_LOG_LEVEL_SYMBOL = /* @__PURE__ */ Symbol.for("braintrust-debug-log-level");
687
+ var LOG_LEVEL_PRIORITY = {
688
+ error: 0,
689
+ warn: 1,
690
+ info: 2,
691
+ debug: 3
692
+ };
693
+ var hasWarnedAboutInvalidEnvValue = false;
694
+ var debugLogStateResolver = void 0;
695
+ function warnInvalidEnvValue(value) {
696
+ if (hasWarnedAboutInvalidEnvValue) {
697
+ return;
698
+ }
699
+ hasWarnedAboutInvalidEnvValue = true;
700
+ console.warn(
701
+ PREFIX,
702
+ `Invalid BRAINTRUST_DEBUG_LOG_LEVEL value "${value}". Expected "error", "warn", "info", or "debug".`
703
+ );
704
+ }
705
+ function normalizeDebugLogLevelOption(option) {
706
+ if (option === false) {
707
+ return void 0;
708
+ }
709
+ if (option === "error" || option === "warn" || option === "info" || option === "debug") {
710
+ return option;
711
+ }
712
+ throw new Error(
713
+ `Invalid debugLogLevel value "${option}". Expected false, "error", "warn", "info", or "debug".`
714
+ );
715
+ }
716
+ function parseDebugLogLevelEnv(value) {
717
+ if (!value) {
718
+ return void 0;
719
+ }
720
+ if (value === "error" || value === "warn" || value === "info" || value === "debug") {
721
+ return value;
722
+ }
723
+ warnInvalidEnvValue(value);
724
+ return void 0;
725
+ }
726
+ function getEnvDebugLogLevel() {
727
+ return parseDebugLogLevelEnv(isomorph_default.getEnv("BRAINTRUST_DEBUG_LOG_LEVEL"));
728
+ }
729
+ function setGlobalDebugLogLevel(level) {
730
+ globalThis[DEBUG_LOG_LEVEL_SYMBOL] = level;
731
+ }
732
+ function setDebugLogStateResolver(resolver) {
733
+ debugLogStateResolver = resolver;
734
+ }
735
+ function resolveDebugLogLevel(state) {
736
+ const stateLevel = state?.getDebugLogLevel?.();
737
+ const hasStateOverride = state?.hasDebugLogLevelOverride?.() ?? false;
738
+ if (hasStateOverride) {
739
+ return stateLevel;
740
+ }
741
+ const globalLevel = (
742
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
743
+ globalThis[DEBUG_LOG_LEVEL_SYMBOL]
744
+ );
745
+ if (globalLevel !== void 0) {
746
+ return globalLevel === false ? void 0 : globalLevel;
747
+ }
748
+ return getEnvDebugLogLevel();
749
+ }
750
+ function emit(method, state, args) {
751
+ const level = resolveDebugLogLevel(state);
752
+ if (!level || LOG_LEVEL_PRIORITY[method] > LOG_LEVEL_PRIORITY[level]) {
753
+ return;
754
+ }
755
+ if (method === "info") {
756
+ console.log(PREFIX, ...args);
757
+ } else if (method === "debug") {
758
+ console.debug(PREFIX, ...args);
759
+ } else if (method === "warn") {
760
+ console.warn(PREFIX, ...args);
761
+ } else {
762
+ console.error(PREFIX, ...args);
763
+ }
764
+ }
765
+ function createDebugLogger(state) {
766
+ const resolveState = () => state ?? debugLogStateResolver?.();
767
+ return {
768
+ info(...args) {
769
+ emit("info", resolveState(), args);
770
+ },
771
+ debug(...args) {
772
+ emit("debug", resolveState(), args);
773
+ },
774
+ warn(...args) {
775
+ emit("warn", resolveState(), args);
776
+ },
777
+ error(...args) {
778
+ emit("error", resolveState(), args);
779
+ }
780
+ };
781
+ }
782
+ var debugLogger = {
783
+ ...createDebugLogger(),
784
+ forState(state) {
785
+ return createDebugLogger(state);
786
+ }
787
+ };
788
+ setGlobalHookErrorReporter((error) => {
789
+ debugLogger.error("Global instrumentation hook error:", error);
790
+ });
791
+
544
792
  // src/instrumentation/core/stream-patcher.ts
545
793
  function isAsyncIterable(value) {
546
794
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
@@ -565,112 +813,133 @@ function patchStreamIfNeeded(stream, options) {
565
813
  );
566
814
  return stream;
567
815
  }
568
- if (hasAsyncIteratorMethods(stream) && isSelfAsyncIterator(stream)) {
569
- if ("__braintrust_patched_iterator_methods" in stream) {
570
- return stream;
816
+ const chunks = [];
817
+ let completed = false;
818
+ const notifyCancellation = async () => {
819
+ try {
820
+ await (options.onCancel ?? options.onComplete)(chunks);
821
+ } catch (error) {
822
+ debugLogger.error("Error in stream cancellation handler:", error);
571
823
  }
824
+ };
825
+ const patchAbortIfPresent = () => {
572
826
  try {
573
- const originalNext = stream.next.bind(stream);
574
- const originalReturn = typeof stream.return === "function" ? stream.return.bind(stream) : null;
575
- const originalThrow = typeof stream.throw === "function" ? stream.throw.bind(stream) : null;
576
- const chunks = [];
577
- let completed = false;
578
- stream.next = async (...args) => {
579
- try {
580
- const result = await runNextWithWrapper(
581
- options,
582
- () => originalNext(...args)
583
- );
584
- if (result.done) {
827
+ if ("abort" in stream && typeof stream.abort === "function") {
828
+ const originalAbort = stream.abort.bind(stream);
829
+ stream.abort = (...args) => {
830
+ try {
831
+ return originalAbort(...args);
832
+ } finally {
585
833
  if (!completed) {
586
834
  completed = true;
587
- try {
588
- await options.onComplete(chunks);
589
- } catch (error) {
590
- console.error("Error in stream onComplete handler:", error);
591
- }
592
- }
593
- } else {
594
- const chunk = result.value;
595
- const shouldCollect = options.shouldCollect ? options.shouldCollect(chunk) : true;
596
- if (shouldCollect) {
597
- chunks.push(chunk);
598
- if (options.onChunk) {
599
- try {
600
- await options.onChunk(chunk);
601
- } catch (error) {
602
- console.error("Error in stream onChunk handler:", error);
603
- }
604
- }
835
+ void notifyCancellation();
605
836
  }
606
837
  }
607
- return result;
608
- } catch (error) {
609
- if (!completed) {
610
- completed = true;
611
- if (options.onError) {
612
- try {
613
- await options.onError(
614
- error instanceof Error ? error : new Error(String(error)),
615
- chunks
616
- );
617
- } catch (handlerError) {
618
- console.error("Error in stream onError handler:", handlerError);
619
- }
620
- }
621
- }
622
- throw error;
623
- }
624
- };
625
- if (originalReturn) {
626
- stream.return = async (...args) => {
627
- if (!completed) {
628
- completed = true;
629
- try {
630
- await options.onComplete(chunks);
631
- } catch (error) {
632
- console.error("Error in stream onComplete handler:", error);
633
- }
634
- }
635
- return originalReturn(...args);
636
- };
637
- }
638
- if (originalThrow) {
639
- stream.throw = async (...args) => {
640
- if (!completed) {
641
- completed = true;
642
- const rawError = args[0];
643
- const error = rawError instanceof Error ? rawError : new Error(String(rawError));
644
- if (options.onError) {
645
- try {
646
- await options.onError(error, chunks);
647
- } catch (handlerError) {
648
- console.error("Error in stream onError handler:", handlerError);
649
- }
650
- }
651
- }
652
- return originalThrow(...args);
653
838
  };
654
839
  }
655
- Object.defineProperty(stream, "__braintrust_patched_iterator_methods", {
656
- value: true
657
- });
658
- return stream;
659
840
  } catch (error) {
660
- console.warn("Failed to patch stream iterator methods:", error);
841
+ debugLogger.warn("Failed to patch stream abort method:", error);
661
842
  }
662
- }
663
- const originalIteratorFn = stream[Symbol.asyncIterator];
664
- if ("__braintrust_patched" in originalIteratorFn && originalIteratorFn["__braintrust_patched"]) {
665
- return stream;
666
- }
667
- try {
668
- const patchedIteratorFn = function() {
669
- const iterator = originalIteratorFn.call(this);
670
- const originalNext = iterator.next.bind(iterator);
671
- const chunks = [];
672
- let completed = false;
673
- iterator.next = async function(...args) {
843
+ };
844
+ if (hasAsyncIteratorMethods(stream) && isSelfAsyncIterator(stream)) {
845
+ if ("__braintrust_patched_iterator_methods" in stream) {
846
+ return stream;
847
+ }
848
+ try {
849
+ const originalNext = stream.next.bind(stream);
850
+ const originalReturn = typeof stream.return === "function" ? stream.return.bind(stream) : null;
851
+ const originalThrow = typeof stream.throw === "function" ? stream.throw.bind(stream) : null;
852
+ stream.next = async (...args) => {
853
+ try {
854
+ const result = await runNextWithWrapper(
855
+ options,
856
+ () => originalNext(...args)
857
+ );
858
+ if (result.done) {
859
+ if (!completed) {
860
+ completed = true;
861
+ try {
862
+ await options.onComplete(chunks);
863
+ } catch (error) {
864
+ console.error("Error in stream onComplete handler:", error);
865
+ }
866
+ }
867
+ } else {
868
+ const chunk = result.value;
869
+ const shouldCollect = options.shouldCollect ? options.shouldCollect(chunk) : true;
870
+ if (shouldCollect) {
871
+ chunks.push(chunk);
872
+ if (options.onChunk) {
873
+ try {
874
+ await options.onChunk(chunk);
875
+ } catch (error) {
876
+ console.error("Error in stream onChunk handler:", error);
877
+ }
878
+ }
879
+ }
880
+ }
881
+ return result;
882
+ } catch (error) {
883
+ if (!completed) {
884
+ completed = true;
885
+ if (options.onError) {
886
+ try {
887
+ await options.onError(
888
+ error instanceof Error ? error : new Error(String(error)),
889
+ chunks
890
+ );
891
+ } catch (handlerError) {
892
+ console.error("Error in stream onError handler:", handlerError);
893
+ }
894
+ }
895
+ }
896
+ throw error;
897
+ }
898
+ };
899
+ if (originalReturn) {
900
+ stream.return = async (...args) => {
901
+ if (!completed) {
902
+ completed = true;
903
+ await notifyCancellation();
904
+ }
905
+ return originalReturn(...args);
906
+ };
907
+ }
908
+ if (originalThrow) {
909
+ stream.throw = async (...args) => {
910
+ if (!completed) {
911
+ completed = true;
912
+ const rawError = args[0];
913
+ const error = rawError instanceof Error ? rawError : new Error(String(rawError));
914
+ if (options.onError) {
915
+ try {
916
+ await options.onError(error, chunks);
917
+ } catch (handlerError) {
918
+ console.error("Error in stream onError handler:", handlerError);
919
+ }
920
+ }
921
+ }
922
+ return originalThrow(...args);
923
+ };
924
+ }
925
+ Object.defineProperty(stream, "__braintrust_patched_iterator_methods", {
926
+ value: true
927
+ });
928
+ patchAbortIfPresent();
929
+ return stream;
930
+ } catch (error) {
931
+ console.warn("Failed to patch stream iterator methods:", error);
932
+ }
933
+ }
934
+ const originalIteratorFn = stream[Symbol.asyncIterator];
935
+ if ("__braintrust_patched" in originalIteratorFn && originalIteratorFn["__braintrust_patched"]) {
936
+ return stream;
937
+ }
938
+ try {
939
+ const patchedIteratorFn = function() {
940
+ const iterator = originalIteratorFn.call(this);
941
+ const originalNext = iterator.next.bind(iterator);
942
+ iterator.next = async function(...args) {
674
943
  try {
675
944
  const result = await runNextWithWrapper(
676
945
  options,
@@ -722,11 +991,7 @@ function patchStreamIfNeeded(stream, options) {
722
991
  iterator.return = async function(...args) {
723
992
  if (!completed) {
724
993
  completed = true;
725
- try {
726
- await options.onComplete(chunks);
727
- } catch (error) {
728
- console.error("Error in stream onComplete handler:", error);
729
- }
994
+ await notifyCancellation();
730
995
  }
731
996
  return originalReturn(...args);
732
997
  };
@@ -755,6 +1020,7 @@ function patchStreamIfNeeded(stream, options) {
755
1020
  value: true
756
1021
  });
757
1022
  stream[Symbol.asyncIterator] = patchedIteratorFn;
1023
+ patchAbortIfPresent();
758
1024
  return stream;
759
1025
  } catch (error) {
760
1026
  console.warn("Failed to patch stream:", error);
@@ -768,114 +1034,6 @@ function runNextWithWrapper(options, callback) {
768
1034
  // src/logger.ts
769
1035
  import { v4 as uuidv42 } from "uuid";
770
1036
 
771
- // src/debug-logger.ts
772
- var PREFIX = "[braintrust]";
773
- var DEBUG_LOG_LEVEL_SYMBOL = /* @__PURE__ */ Symbol.for("braintrust-debug-log-level");
774
- var LOG_LEVEL_PRIORITY = {
775
- error: 0,
776
- warn: 1,
777
- info: 2,
778
- debug: 3
779
- };
780
- var hasWarnedAboutInvalidEnvValue = false;
781
- var debugLogStateResolver = void 0;
782
- function warnInvalidEnvValue(value) {
783
- if (hasWarnedAboutInvalidEnvValue) {
784
- return;
785
- }
786
- hasWarnedAboutInvalidEnvValue = true;
787
- console.warn(
788
- PREFIX,
789
- `Invalid BRAINTRUST_DEBUG_LOG_LEVEL value "${value}". Expected "error", "warn", "info", or "debug".`
790
- );
791
- }
792
- function normalizeDebugLogLevelOption(option) {
793
- if (option === false) {
794
- return void 0;
795
- }
796
- if (option === "error" || option === "warn" || option === "info" || option === "debug") {
797
- return option;
798
- }
799
- throw new Error(
800
- `Invalid debugLogLevel value "${option}". Expected false, "error", "warn", "info", or "debug".`
801
- );
802
- }
803
- function parseDebugLogLevelEnv(value) {
804
- if (!value) {
805
- return void 0;
806
- }
807
- if (value === "error" || value === "warn" || value === "info" || value === "debug") {
808
- return value;
809
- }
810
- warnInvalidEnvValue(value);
811
- return void 0;
812
- }
813
- function getEnvDebugLogLevel() {
814
- return parseDebugLogLevelEnv(isomorph_default.getEnv("BRAINTRUST_DEBUG_LOG_LEVEL"));
815
- }
816
- function setGlobalDebugLogLevel(level) {
817
- globalThis[DEBUG_LOG_LEVEL_SYMBOL] = level;
818
- }
819
- function setDebugLogStateResolver(resolver) {
820
- debugLogStateResolver = resolver;
821
- }
822
- function resolveDebugLogLevel(state) {
823
- const stateLevel = state?.getDebugLogLevel?.();
824
- const hasStateOverride = state?.hasDebugLogLevelOverride?.() ?? false;
825
- if (hasStateOverride) {
826
- return stateLevel;
827
- }
828
- const globalLevel = (
829
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
830
- globalThis[DEBUG_LOG_LEVEL_SYMBOL]
831
- );
832
- if (globalLevel !== void 0) {
833
- return globalLevel === false ? void 0 : globalLevel;
834
- }
835
- return getEnvDebugLogLevel();
836
- }
837
- function emit(method, state, args) {
838
- const level = resolveDebugLogLevel(state);
839
- if (!level || LOG_LEVEL_PRIORITY[method] > LOG_LEVEL_PRIORITY[level]) {
840
- return;
841
- }
842
- if (method === "info") {
843
- console.log(PREFIX, ...args);
844
- } else if (method === "debug") {
845
- console.debug(PREFIX, ...args);
846
- } else if (method === "warn") {
847
- console.warn(PREFIX, ...args);
848
- } else {
849
- console.error(PREFIX, ...args);
850
- }
851
- }
852
- function createDebugLogger(state) {
853
- const resolveState = () => state ?? debugLogStateResolver?.();
854
- return {
855
- info(...args) {
856
- emit("info", resolveState(), args);
857
- },
858
- debug(...args) {
859
- emit("debug", resolveState(), args);
860
- },
861
- warn(...args) {
862
- emit("warn", resolveState(), args);
863
- },
864
- error(...args) {
865
- emit("error", resolveState(), args);
866
- }
867
- };
868
- }
869
- var debugLogger = {
870
- ...createDebugLogger(),
871
- forState(state) {
872
- return createDebugLogger(state);
873
- }
874
- };
875
- setGlobalHookErrorReporter((error) => {
876
- debugLogger.error("Global instrumentation hook error:", error);
877
- });
878
-
879
1037
  // src/queue.ts
880
1038
  var DEFAULT_QUEUE_SIZE = 15e3;
881
1039
  var Queue = class {
@@ -2417,7 +2575,8 @@ var AclObjectType = z6.union([
2417
2575
  "org_member",
2418
2576
  "project_log",
2419
2577
  "org_project",
2420
- "org_audit_logs"
2578
+ "org_audit_logs",
2579
+ "project_group"
2421
2580
  ]),
2422
2581
  z6.null()
2423
2582
  ]);
@@ -2546,7 +2705,8 @@ var AsyncScoringState = z6.union([
2546
2705
  token: z6.string(),
2547
2706
  function_ids: z6.array(z6.unknown()),
2548
2707
  skip_logging: z6.union([z6.boolean(), z6.null()]).optional(),
2549
- triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional()
2708
+ triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional(),
2709
+ last_triggered_xact_id: z6.union([z6.string(), z6.number(), z6.null()]).optional()
2550
2710
  }),
2551
2711
  z6.object({ status: z6.literal("disabled") }),
2552
2712
  z6.null(),
@@ -2615,7 +2775,7 @@ var FunctionTypeEnum = z6.enum([
2615
2775
  "parameters",
2616
2776
  "sandbox"
2617
2777
  ]);
2618
- var NullableSavedFunctionId = z6.union([
2778
+ var FacetPreprocessorId = z6.union([
2619
2779
  z6.object({
2620
2780
  type: z6.literal("function"),
2621
2781
  id: z6.string(),
@@ -2626,10 +2786,23 @@ var NullableSavedFunctionId = z6.union([
2626
2786
  name: z6.string(),
2627
2787
  function_type: FunctionTypeEnum.optional().default("scorer")
2628
2788
  }),
2789
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
2629
2790
  z6.null()
2630
2791
  ]);
2792
+ var SavedFunctionId = z6.union([
2793
+ z6.object({
2794
+ type: z6.literal("function"),
2795
+ id: z6.string(),
2796
+ version: z6.string().optional()
2797
+ }),
2798
+ z6.object({
2799
+ type: z6.literal("global"),
2800
+ name: z6.string(),
2801
+ function_type: FunctionTypeEnum.optional().default("scorer")
2802
+ })
2803
+ ]);
2631
2804
  var TopicMapGenerationSettings = z6.object({
2632
- algorithm: z6.enum(["hdbscan", "kmeans"]),
2805
+ algorithm: z6.enum(["hdbscan", "kmeans", "community"]),
2633
2806
  dimension_reduction: z6.enum(["umap", "pca", "none"]),
2634
2807
  sample_size: z6.number().int().gt(0).optional(),
2635
2808
  n_clusters: z6.number().int().gt(0).optional(),
@@ -2641,6 +2814,7 @@ var TopicMapGenerationSettings = z6.object({
2641
2814
  var TopicMapData = z6.object({
2642
2815
  type: z6.literal("topic_map"),
2643
2816
  source_facet: z6.string(),
2817
+ source_facet_function: SavedFunctionId.and(z6.unknown()).optional(),
2644
2818
  embedding_model: z6.string(),
2645
2819
  bundle_key: z6.string().optional(),
2646
2820
  report_key: z6.string().optional(),
@@ -2654,7 +2828,7 @@ var TopicMapData = z6.object({
2654
2828
  });
2655
2829
  var BatchedFacetData = z6.object({
2656
2830
  type: z6.literal("batched_facet"),
2657
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
2831
+ preprocessor: FacetPreprocessorId.optional(),
2658
2832
  facets: z6.array(
2659
2833
  z6.object({
2660
2834
  name: z6.string(),
@@ -2915,18 +3089,6 @@ var ObjectReferenceNullish = z6.union([
2915
3089
  }),
2916
3090
  z6.null()
2917
3091
  ]);
2918
- var SavedFunctionId = z6.union([
2919
- z6.object({
2920
- type: z6.literal("function"),
2921
- id: z6.string(),
2922
- version: z6.string().optional()
2923
- }),
2924
- z6.object({
2925
- type: z6.literal("global"),
2926
- name: z6.string(),
2927
- function_type: FunctionTypeEnum.optional().default("scorer")
2928
- })
2929
- ]);
2930
3092
  var DatasetEvent = z6.object({
2931
3093
  id: z6.string(),
2932
3094
  _xact_id: z6.string(),
@@ -3148,7 +3310,7 @@ var ExtendedSavedFunctionId = z6.union([
3148
3310
  ]);
3149
3311
  var FacetData = z6.object({
3150
3312
  type: z6.literal("facet"),
3151
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
3313
+ preprocessor: FacetPreprocessorId.optional(),
3152
3314
  prompt: z6.string(),
3153
3315
  model: z6.string().optional(),
3154
3316
  embedding_model: z6.string().optional(),
@@ -3653,6 +3815,19 @@ var MessageRole = z6.enum([
3653
3815
  "model",
3654
3816
  "developer"
3655
3817
  ]);
3818
+ var NullableSavedFunctionId = z6.union([
3819
+ z6.object({
3820
+ type: z6.literal("function"),
3821
+ id: z6.string(),
3822
+ version: z6.string().optional()
3823
+ }),
3824
+ z6.object({
3825
+ type: z6.literal("global"),
3826
+ name: z6.string(),
3827
+ function_type: FunctionTypeEnum.optional().default("scorer")
3828
+ }),
3829
+ z6.null()
3830
+ ]);
3656
3831
  var ObjectReference = z6.object({
3657
3832
  object_type: z6.enum([
3658
3833
  "project_logs",
@@ -3674,6 +3849,7 @@ var TraceScope = z6.object({
3674
3849
  });
3675
3850
  var OnlineScoreConfig = z6.union([
3676
3851
  z6.object({
3852
+ status: AutomationStatus.optional(),
3677
3853
  sampling_rate: z6.number().gte(0).lte(1),
3678
3854
  scorers: z6.array(SavedFunctionId),
3679
3855
  btql_filter: z6.union([z6.string(), z6.null()]).optional(),
@@ -3754,6 +3930,72 @@ var Project = z6.object({
3754
3930
  user_id: z6.union([z6.string(), z6.null()]).optional(),
3755
3931
  settings: ProjectSettings.optional()
3756
3932
  });
3933
+ var WindowedAutomationConfig = z6.object({
3934
+ event_type: z6.literal("windowed"),
3935
+ product_origin: z6.union([z6.literal("patterns"), z6.null()]).optional(),
3936
+ status: AutomationStatus.optional(),
3937
+ threshold: z6.object({
3938
+ calculation: z6.object({
3939
+ type: z6.literal("btql"),
3940
+ btql_query: z6.string().min(1),
3941
+ output: z6.object({
3942
+ type: z6.literal("scalar"),
3943
+ value_column: z6.string().min(1)
3944
+ })
3945
+ }),
3946
+ policy: z6.object({
3947
+ condition: z6.object({
3948
+ type: z6.literal("threshold"),
3949
+ operator: z6.enum(["lt", "lte", "gt", "gte", "eq", "neq"]),
3950
+ threshold: z6.number()
3951
+ }),
3952
+ pending_seconds: z6.number().int().gte(0).lte(2592e3),
3953
+ no_data_behavior: z6.enum(["keep_last", "resolve", "alert"]),
3954
+ renotify_interval_seconds: z6.union([z6.number(), z6.null()]).optional(),
3955
+ notify_on_recovery: z6.boolean().optional().default(true)
3956
+ })
3957
+ }).optional(),
3958
+ window: z6.object({
3959
+ window_seconds: z6.number().int().gte(1).lte(2592e3),
3960
+ schedule: z6.union([
3961
+ z6.object({
3962
+ type: z6.literal("interval"),
3963
+ evaluation_interval_seconds: z6.number().int().gte(1).lte(2592e3)
3964
+ }),
3965
+ z6.object({
3966
+ type: z6.literal("cron"),
3967
+ cron_expression: z6.string().min(1),
3968
+ timezone: z6.union([z6.string(), z6.null()]).optional()
3969
+ })
3970
+ ]),
3971
+ evaluation_delay_seconds: z6.number().int().gte(0).lte(2592e3)
3972
+ }),
3973
+ loop: z6.object({
3974
+ prompt: z6.string().min(1).max(1e4),
3975
+ include_trigger_input: z6.boolean().optional().default(false),
3976
+ agent_slug: z6.string().min(1),
3977
+ auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
3978
+ harness: z6.enum(["native", "codex", "claude-code"]).optional(),
3979
+ model: z6.string().min(1).optional(),
3980
+ reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
3981
+ }).optional(),
3982
+ actions: z6.array(
3983
+ z6.union([
3984
+ z6.object({
3985
+ type: z6.literal("webhook"),
3986
+ url: z6.string(),
3987
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3988
+ }),
3989
+ z6.object({
3990
+ type: z6.literal("slack"),
3991
+ workspace_id: z6.string(),
3992
+ channel: z6.string(),
3993
+ message_template: z6.string().optional(),
3994
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3995
+ })
3996
+ ])
3997
+ ).max(20).optional().default([])
3998
+ });
3757
3999
  var TopicAutomationFacetModel = z6.union([
3758
4000
  z6.enum(["brain-facet-latest", "brain-facet-1", "brain-facet-2"]),
3759
4001
  z6.null()
@@ -3795,7 +4037,8 @@ var TopicDigestAutomationConfig = z6.object({
3795
4037
  type: z6.literal("slack"),
3796
4038
  workspace_id: z6.string(),
3797
4039
  channel: z6.string(),
3798
- message_template: z6.string().optional()
4040
+ message_template: z6.string().optional(),
4041
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3799
4042
  }),
3800
4043
  topic_map_function_ids: z6.array(z6.string()).max(10).optional()
3801
4044
  });
@@ -3809,15 +4052,21 @@ var ProjectAutomation = z6.object({
3809
4052
  config: z6.union([
3810
4053
  z6.object({
3811
4054
  event_type: z6.literal("logs"),
4055
+ status: AutomationStatus.optional(),
3812
4056
  btql_filter: z6.string(),
3813
4057
  interval_seconds: z6.number().gte(1).lte(2592e3),
3814
4058
  action: z6.union([
3815
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
4059
+ z6.object({
4060
+ type: z6.literal("webhook"),
4061
+ url: z6.string(),
4062
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4063
+ }),
3816
4064
  z6.object({
3817
4065
  type: z6.literal("slack"),
3818
4066
  workspace_id: z6.string(),
3819
4067
  channel: z6.string(),
3820
- message_template: z6.string().optional()
4068
+ message_template: z6.string().optional(),
4069
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3821
4070
  })
3822
4071
  ])
3823
4072
  }),
@@ -3868,21 +4117,38 @@ var ProjectAutomation = z6.object({
3868
4117
  }),
3869
4118
  z6.object({
3870
4119
  event_type: z6.literal("environment_update"),
4120
+ status: AutomationStatus.optional(),
3871
4121
  environment_filter: z6.array(z6.string()).optional(),
3872
4122
  action: z6.union([
3873
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
4123
+ z6.object({
4124
+ type: z6.literal("webhook"),
4125
+ url: z6.string(),
4126
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4127
+ }),
3874
4128
  z6.object({
3875
4129
  type: z6.literal("slack"),
3876
4130
  workspace_id: z6.string(),
3877
4131
  channel: z6.string(),
3878
- message_template: z6.string().optional()
4132
+ message_template: z6.string().optional(),
4133
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3879
4134
  })
3880
4135
  ])
3881
4136
  }),
4137
+ WindowedAutomationConfig,
3882
4138
  TopicAutomationConfig,
3883
4139
  TopicDigestAutomationConfig
3884
4140
  ])
3885
4141
  });
4142
+ var ProjectGroup = z6.object({
4143
+ id: z6.string().uuid(),
4144
+ org_id: z6.string().uuid(),
4145
+ user_id: z6.union([z6.string(), z6.null()]).optional(),
4146
+ created: z6.union([z6.string(), z6.null()]).optional(),
4147
+ name: z6.string(),
4148
+ description: z6.union([z6.string(), z6.null()]).optional(),
4149
+ deleted_at: z6.union([z6.string(), z6.null()]).optional(),
4150
+ member_projects: z6.array(z6.string().uuid()).max(1e4)
4151
+ });
3886
4152
  var ProjectLogsEvent = z6.object({
3887
4153
  id: z6.string(),
3888
4154
  _xact_id: z6.string(),
@@ -4100,7 +4366,8 @@ var RunEval = z6.object({
4100
4366
  dataset_environment: z6.union([z6.string(), z6.null()]).optional(),
4101
4367
  _internal_btql: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional()
4102
4368
  }),
4103
- z6.object({ data: z6.array(z6.unknown()) })
4369
+ z6.object({ data: z6.array(z6.unknown()) }),
4370
+ z6.object({ experiment_name: z6.string() })
4104
4371
  ]),
4105
4372
  name: z6.string().optional(),
4106
4373
  parameters: z6.object({}).partial().passthrough().optional(),
@@ -4305,7 +4572,9 @@ var View = z6.object({
4305
4572
  "for_review_datasets"
4306
4573
  ]),
4307
4574
  name: z6.string(),
4575
+ description: z6.union([z6.string(), z6.null()]).optional(),
4308
4576
  created: z6.union([z6.string(), z6.null()]).optional(),
4577
+ updated_at: z6.union([z6.string(), z6.null()]).optional(),
4309
4578
  view_data: ViewData.optional(),
4310
4579
  options: ViewOptions.optional(),
4311
4580
  user_id: z6.union([z6.string(), z6.null()]).optional(),
@@ -5382,6 +5651,7 @@ var INSTRUMENTATION_NAMES = {
5382
5651
  CLAUDE_AGENT_SDK: "claude-agent-sdk",
5383
5652
  CLOUDFLARE_AI_CHAT: "cloudflare-ai-chat",
5384
5653
  CLOUDFLARE_AGENTS: "cloudflare-agents",
5654
+ CLOUDFLARE_THINK: "cloudflare-think",
5385
5655
  COHERE: "cohere",
5386
5656
  CURSOR_SDK: "cursor-sdk",
5387
5657
  EVE: "eve",
@@ -5396,18 +5666,20 @@ var INSTRUMENTATION_NAMES = {
5396
5666
  LANGSMITH: "langsmith",
5397
5667
  MASTRA: "mastra",
5398
5668
  MISTRAL: "mistral",
5669
+ OLLAMA: "ollama",
5399
5670
  OPENAI: "openai",
5400
5671
  OPENAI_AGENTS: "openai-agents",
5401
5672
  OPENAI_CODEX: "openai-codex",
5402
5673
  OPENROUTER: "openrouter",
5403
5674
  OPENROUTER_AGENT: "openrouter-agent",
5404
5675
  PI_CODING_AGENT: "pi-coding-agent",
5405
- STRANDS_AGENT_SDK: "strands-agent-sdk"
5676
+ STRANDS_AGENT_SDK: "strands-agent-sdk",
5677
+ VOYAGEAI: "voyageai"
5406
5678
  };
5407
5679
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5408
5680
  "braintrust.spanInstrumentationName"
5409
5681
  );
5410
- var SDK_VERSION = true ? "3.26.0" : "0.0.0";
5682
+ var SDK_VERSION = true ? "3.28.0" : "0.0.0";
5411
5683
  function withSpanInstrumentationName(args, instrumentationName) {
5412
5684
  return {
5413
5685
  ...args,
@@ -5602,6 +5874,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
5602
5874
  var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
5603
5875
  "braintrust.initial-span-write-as-merge"
5604
5876
  );
5877
+ var RESUME_SPAN_WITHOUT_INITIAL_WRITE = /* @__PURE__ */ Symbol(
5878
+ "braintrust.resume-span-without-initial-write"
5879
+ );
5605
5880
  var INTERNAL_SPAN_CONTEXT = /* @__PURE__ */ Symbol("braintrust.internal-span-context");
5606
5881
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
5607
5882
  "braintrust.currentSpanStore"
@@ -8451,7 +8726,7 @@ var ObjectFetcher = class {
8451
8726
  const objectId = await this.id;
8452
8727
  const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
8453
8728
  const internalLimit = getInternalBtqlLimit(this._internal_btql);
8454
- const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
8729
+ let remainingLimit = internalLimit;
8455
8730
  const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
8456
8731
  Object.entries(this._internal_btql ?? {}).filter(
8457
8732
  ([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
@@ -8460,6 +8735,10 @@ var ObjectFetcher = class {
8460
8735
  let cursor = void 0;
8461
8736
  let iterations = 0;
8462
8737
  while (true) {
8738
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
8739
+ return;
8740
+ }
8741
+ const limit = remainingLimit === void 0 ? batchLimit : Math.min(batchLimit, remainingLimit);
8463
8742
  const resp = await state.apiConn().post(
8464
8743
  `btql`,
8465
8744
  {
@@ -8499,7 +8778,14 @@ var ObjectFetcher = class {
8499
8778
  const respJson = await resp.json();
8500
8779
  const mutate = this.mutateRecord;
8501
8780
  for (const record of respJson.data ?? []) {
8502
- yield mutate ? mutate(record) : record;
8781
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
8782
+ return;
8783
+ }
8784
+ const mutatedRecord = mutate ? mutate(record) : record;
8785
+ if (remainingLimit !== void 0) {
8786
+ remainingLimit--;
8787
+ }
8788
+ yield mutatedRecord;
8503
8789
  }
8504
8790
  if (!respJson.cursor) {
8505
8791
  break;
@@ -8976,7 +9262,9 @@ var SpanImpl = class _SpanImpl {
8976
9262
  this._rootSpanId = resolvedIds.rootSpanId;
8977
9263
  this._spanParents = resolvedIds.spanParents;
8978
9264
  this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
8979
- this.logInternal({ event, internalData });
9265
+ if (!args[RESUME_SPAN_WITHOUT_INITIAL_WRITE]) {
9266
+ this.logInternal({ event, internalData });
9267
+ }
8980
9268
  this.isMerge = true;
8981
9269
  }
8982
9270
  getParentInfo() {
@@ -10428,6 +10716,33 @@ function traceStreamingChannel(channel2, config) {
10428
10716
  const { span, startTime } = spanData;
10429
10717
  if (isAsyncIterable(asyncEndEvent.result)) {
10430
10718
  let firstChunkTime;
10719
+ const handleStreamError = (error) => {
10720
+ try {
10721
+ span.log({ error });
10722
+ } catch (loggingError) {
10723
+ debugLogger.error(
10724
+ `Error logging failure for ${channelName}:`,
10725
+ loggingError
10726
+ );
10727
+ }
10728
+ try {
10729
+ span.end();
10730
+ } catch (endingError) {
10731
+ debugLogger.error(
10732
+ `Error ending span for ${channelName}:`,
10733
+ endingError
10734
+ );
10735
+ }
10736
+ states.delete(event);
10737
+ runStreamingErrorHook({
10738
+ channelName,
10739
+ config,
10740
+ error,
10741
+ event: asyncEndEvent,
10742
+ span,
10743
+ startTime
10744
+ });
10745
+ };
10431
10746
  patchStreamIfNeeded(asyncEndEvent.result, {
10432
10747
  onChunk: () => {
10433
10748
  if (firstChunkTime === void 0) {
@@ -10507,33 +10822,12 @@ function traceStreamingChannel(channel2, config) {
10507
10822
  });
10508
10823
  }
10509
10824
  },
10510
- onError: (error) => {
10511
- try {
10512
- span.log({ error });
10513
- } catch (loggingError) {
10514
- debugLogger.error(
10515
- `Error logging failure for ${channelName}:`,
10516
- loggingError
10517
- );
10518
- }
10519
- try {
10520
- span.end();
10521
- } catch (endingError) {
10522
- debugLogger.error(
10523
- `Error ending span for ${channelName}:`,
10524
- endingError
10525
- );
10526
- }
10527
- states.delete(event);
10528
- runStreamingErrorHook({
10529
- channelName,
10530
- config,
10531
- error,
10532
- event: asyncEndEvent,
10533
- span,
10534
- startTime
10535
- });
10536
- }
10825
+ onCancel: () => {
10826
+ const error = new Error("Stream cancelled before completion");
10827
+ error.name = "AbortError";
10828
+ handleStreamError(error);
10829
+ },
10830
+ onError: handleStreamError
10537
10831
  });
10538
10832
  return;
10539
10833
  }
@@ -10849,6 +11143,22 @@ function processInputAttachments(input) {
10849
11143
  };
10850
11144
  }
10851
11145
  }
11146
+ const voyageBase64Key = node.type === "image_base64" ? Object.hasOwn(node, "imageBase64") ? "imageBase64" : "image_base64" : node.type === "video_base64" ? Object.hasOwn(node, "videoBase64") ? "videoBase64" : "video_base64" : void 0;
11147
+ const voyageBase64Value = voyageBase64Key ? node[voyageBase64Key] : void 0;
11148
+ if (voyageBase64Key && typeof voyageBase64Value === "string" && voyageBase64Value.startsWith("data:")) {
11149
+ const mediaType = inferMediaTypeFromDataUrl(
11150
+ voyageBase64Value,
11151
+ node.type === "video_base64" ? "video/mp4" : "image/png"
11152
+ );
11153
+ const filename = `${node.type === "video_base64" ? "video" : "image"}.${getExtensionFromMediaType(mediaType)}`;
11154
+ const attachment = toAttachment(voyageBase64Value, mediaType, filename);
11155
+ if (attachment) {
11156
+ return {
11157
+ ...node,
11158
+ [voyageBase64Key]: attachment
11159
+ };
11160
+ }
11161
+ }
10852
11162
  if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
10853
11163
  const mediaType = inferMediaTypeFromDataUrl(
10854
11164
  node.file.file_data,
@@ -10921,11 +11231,21 @@ function defineChannels(pkg, channels, options) {
10921
11231
  const tracingChannel2 = () => isomorph_default.newTracingChannel(
10922
11232
  fullChannelName
10923
11233
  );
11234
+ const intercept2 = (interceptor) => {
11235
+ const hook = tracingChannel2();
11236
+ return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
11237
+ };
11238
+ };
10924
11239
  return [
10925
11240
  key,
10926
11241
  {
10927
11242
  ...asyncSpec,
10928
11243
  instrumentationName,
11244
+ intercept: intercept2,
11245
+ invoke: (target, thisArg, args, additional) => {
11246
+ const hook = tracingChannel2();
11247
+ return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
11248
+ },
10929
11249
  tracingChannel: tracingChannel2,
10930
11250
  tracePromise: (fn, context) => tracingChannel2().tracePromise(
10931
11251
  fn,
@@ -10939,11 +11259,21 @@ function defineChannels(pkg, channels, options) {
10939
11259
  const tracingChannel = () => isomorph_default.newTracingChannel(
10940
11260
  fullChannelName
10941
11261
  );
11262
+ const intercept = (interceptor) => {
11263
+ const hook = tracingChannel();
11264
+ return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
11265
+ };
11266
+ };
10942
11267
  return [
10943
11268
  key,
10944
11269
  {
10945
11270
  ...syncSpec,
10946
11271
  instrumentationName,
11272
+ intercept,
11273
+ invoke: (target, thisArg, args, additional) => {
11274
+ const hook = tracingChannel();
11275
+ return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
11276
+ },
10947
11277
  tracingChannel,
10948
11278
  traceSync: (fn, context) => tracingChannel().traceSync(
10949
11279
  fn,
@@ -12176,12 +12506,30 @@ function logInstrumentationError(context, error) {
12176
12506
 
12177
12507
  // src/wrappers/anthropic-tokens-util.ts
12178
12508
  function finalizeAnthropicTokens(metrics) {
12179
- const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + (metrics.prompt_cache_creation_tokens || 0);
12180
- return {
12509
+ const hasSplitCacheCreationTokens = metrics.prompt_cache_creation_5m_tokens !== void 0 || metrics.prompt_cache_creation_1h_tokens !== void 0;
12510
+ const splitCacheCreationTokens = (metrics.prompt_cache_creation_5m_tokens || 0) + (metrics.prompt_cache_creation_1h_tokens || 0);
12511
+ const aggregateCacheCreationTokens = metrics.prompt_cache_creation_tokens || 0;
12512
+ const effectiveCacheCreationTokens = Math.max(
12513
+ aggregateCacheCreationTokens,
12514
+ splitCacheCreationTokens
12515
+ );
12516
+ const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + effectiveCacheCreationTokens;
12517
+ const finalized = {
12181
12518
  ...metrics,
12182
12519
  prompt_tokens,
12183
12520
  tokens: prompt_tokens + (metrics.completion_tokens || 0)
12184
12521
  };
12522
+ if (hasSplitCacheCreationTokens && splitCacheCreationTokens >= aggregateCacheCreationTokens) {
12523
+ delete finalized.prompt_cache_creation_tokens;
12524
+ }
12525
+ return finalized;
12526
+ }
12527
+ function toNumericMetrics(metrics) {
12528
+ return Object.fromEntries(
12529
+ Object.entries(metrics).filter(
12530
+ (entry) => entry[1] !== void 0
12531
+ )
12532
+ );
12185
12533
  }
12186
12534
  function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens = 0) {
12187
12535
  const cacheTokens = {};
@@ -12194,6 +12542,12 @@ function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens =
12194
12542
  return cacheTokens;
12195
12543
  }
12196
12544
 
12545
+ // src/wrappers/anthropic-session-collector.ts
12546
+ var sessionStreamCollectors = /* @__PURE__ */ new WeakMap();
12547
+ function registerAnthropicSessionStreamCollector(stream, collector) {
12548
+ sessionStreamCollectors.set(stream, collector);
12549
+ }
12550
+
12197
12551
  // src/instrumentation/plugins/anthropic-channels.ts
12198
12552
  var anthropicChannels = defineChannels(
12199
12553
  "@anthropic-ai/sdk",
@@ -12209,6 +12563,14 @@ var anthropicChannels = defineChannels(
12209
12563
  betaMessagesToolRunner: channel({
12210
12564
  channelName: "beta.messages.toolRunner",
12211
12565
  kind: "sync-stream"
12566
+ }),
12567
+ betaSessionsEventsStream: channel({
12568
+ channelName: "beta.sessions.events.stream",
12569
+ kind: "async"
12570
+ }),
12571
+ betaSessionsThreadsEventsStream: channel({
12572
+ channelName: "beta.sessions.threads.events.stream",
12573
+ kind: "async"
12212
12574
  })
12213
12575
  },
12214
12576
  { instrumentationName: INSTRUMENTATION_NAMES.ANTHROPIC }
@@ -12222,6 +12584,7 @@ var AnthropicPlugin = class extends BasePlugin {
12222
12584
  onEnable() {
12223
12585
  this.subscribeToAnthropicChannels();
12224
12586
  this.subscribeToAnthropicToolRunner();
12587
+ this.subscribeToAnthropicSessionStreams();
12225
12588
  }
12226
12589
  onDisable() {
12227
12590
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
@@ -12339,7 +12702,411 @@ var AnthropicPlugin = class extends BasePlugin {
12339
12702
  tracingChannel.unsubscribe(handlers);
12340
12703
  });
12341
12704
  }
12705
+ subscribeToAnthropicSessionStreams() {
12706
+ this.subscribeToAnthropicSessionStream(
12707
+ anthropicChannels.betaSessionsEventsStream,
12708
+ false
12709
+ );
12710
+ this.subscribeToAnthropicSessionStream(
12711
+ anthropicChannels.betaSessionsThreadsEventsStream,
12712
+ true
12713
+ );
12714
+ }
12715
+ subscribeToAnthropicSessionStream(channel2, isThread) {
12716
+ const tracingChannel = channel2.tracingChannel();
12717
+ const pending = /* @__PURE__ */ new WeakSet();
12718
+ const handlers = {
12719
+ start: (event) => {
12720
+ if (isAutoInstrumentationSuppressed()) {
12721
+ return;
12722
+ }
12723
+ pending.add(event);
12724
+ },
12725
+ asyncEnd: (event) => {
12726
+ if (!pending.delete(event)) {
12727
+ return;
12728
+ }
12729
+ const stream = event.result;
12730
+ if (!isAsyncIterable(stream)) {
12731
+ return;
12732
+ }
12733
+ registerAnthropicSessionStreamCollector(stream, () => {
12734
+ wrapAnthropicSessionEventStream(stream, isThread);
12735
+ });
12736
+ },
12737
+ error: (event) => {
12738
+ pending.delete(event);
12739
+ }
12740
+ };
12741
+ tracingChannel.subscribe(handlers);
12742
+ this.unsubscribers.push(() => tracingChannel.unsubscribe(handlers));
12743
+ }
12342
12744
  };
12745
+ function wrapAnthropicSessionEventStream(stream, isThread) {
12746
+ const state = {
12747
+ history: [],
12748
+ isThread,
12749
+ pendingInput: [],
12750
+ seenEventIds: /* @__PURE__ */ new Set()
12751
+ };
12752
+ patchStreamIfNeeded(stream, {
12753
+ onChunk: (event) => handleAnthropicSessionEvent(state, event),
12754
+ onComplete: () => finalizeAnthropicSessionTurn(state),
12755
+ onError: (error) => finalizeAnthropicSessionTurn(state, error)
12756
+ });
12757
+ return stream;
12758
+ }
12759
+ function handleAnthropicSessionEvent(state, event) {
12760
+ try {
12761
+ if (typeof event.id === "string" && event.type !== "event_delta" && state.seenEventIds.has(event.id)) {
12762
+ return;
12763
+ }
12764
+ if (typeof event.id === "string" && event.type !== "event_delta") {
12765
+ state.seenEventIds.add(event.id);
12766
+ }
12767
+ switch (event.type) {
12768
+ case "user.message":
12769
+ case "system.message":
12770
+ recordAnthropicSessionInput(
12771
+ state,
12772
+ event
12773
+ );
12774
+ break;
12775
+ case "session.status_running":
12776
+ if (!state.isThread) {
12777
+ ensureAnthropicSessionTurn(state);
12778
+ }
12779
+ break;
12780
+ case "session.thread_status_running":
12781
+ if (state.isThread) {
12782
+ ensureAnthropicSessionTurn(state);
12783
+ }
12784
+ break;
12785
+ case "span.model_request_start":
12786
+ if (typeof event.id === "string") {
12787
+ startAnthropicSessionModel(state, event.id);
12788
+ }
12789
+ break;
12790
+ case "event_delta":
12791
+ recordAnthropicSessionFirstToken(state, event);
12792
+ break;
12793
+ case "agent.message":
12794
+ recordAnthropicSessionMessage(
12795
+ state,
12796
+ event
12797
+ );
12798
+ break;
12799
+ case "agent.custom_tool_use":
12800
+ case "agent.mcp_tool_use":
12801
+ case "agent.tool_use":
12802
+ startAnthropicSessionTool(state, event);
12803
+ break;
12804
+ case "user.tool_confirmation":
12805
+ recordAnthropicSessionToolConfirmation(state, event);
12806
+ break;
12807
+ case "agent.mcp_tool_result":
12808
+ case "agent.tool_result":
12809
+ case "user.custom_tool_result":
12810
+ case "user.tool_result":
12811
+ finalizeAnthropicSessionTool(
12812
+ state,
12813
+ event
12814
+ );
12815
+ break;
12816
+ case "span.model_request_end":
12817
+ finalizeAnthropicSessionModel(
12818
+ state,
12819
+ event
12820
+ );
12821
+ break;
12822
+ case "session.status_idle":
12823
+ case "session.thread_status_idle": {
12824
+ if (event.type === "session.status_idle" && state.isThread || event.type === "session.thread_status_idle" && !state.isThread) {
12825
+ break;
12826
+ }
12827
+ const stopReason = isObject(event.stop_reason) ? event.stop_reason.type : void 0;
12828
+ if (stopReason === "end_turn") {
12829
+ finalizeAnthropicSessionTurn(state);
12830
+ } else if (stopReason === "retries_exhausted") {
12831
+ finalizeAnthropicSessionTurn(
12832
+ state,
12833
+ "Anthropic session retries exhausted"
12834
+ );
12835
+ }
12836
+ break;
12837
+ }
12838
+ case "session.error":
12839
+ finalizeAnthropicSessionTurn(state, event.error);
12840
+ break;
12841
+ case "session.deleted":
12842
+ case "session.status_terminated":
12843
+ case "session.thread_status_terminated":
12844
+ if (event.type === "session.deleted" || event.type === "session.status_terminated" && !state.isThread || event.type === "session.thread_status_terminated" && state.isThread) {
12845
+ finalizeAnthropicSessionTurn(state);
12846
+ }
12847
+ break;
12848
+ default:
12849
+ break;
12850
+ }
12851
+ } catch (error) {
12852
+ debugLogger.debug("Error processing Anthropic Sessions event:", error);
12853
+ }
12854
+ }
12855
+ function ensureAnthropicSessionTurn(state) {
12856
+ if (state.activeTurn) {
12857
+ return state.activeTurn;
12858
+ }
12859
+ const input = state.pendingInput;
12860
+ state.pendingInput = [];
12861
+ const span = startSpan(
12862
+ withSpanInstrumentationName(
12863
+ {
12864
+ event: {
12865
+ ...input.length > 0 ? { input } : {},
12866
+ metadata: { provider: "anthropic" }
12867
+ },
12868
+ name: state.isThread ? "anthropic.beta.sessions.thread.turn" : "anthropic.beta.sessions.turn",
12869
+ spanAttributes: { type: "task" /* TASK */ }
12870
+ },
12871
+ INSTRUMENTATION_NAMES.ANTHROPIC
12872
+ )
12873
+ );
12874
+ state.activeTurn = {
12875
+ activeTools: /* @__PURE__ */ new Map(),
12876
+ input: input.slice(),
12877
+ metrics: {},
12878
+ span
12879
+ };
12880
+ return state.activeTurn;
12881
+ }
12882
+ function recordAnthropicSessionInput(state, event) {
12883
+ const content = processAttachmentsInInput(event.content);
12884
+ const message = {
12885
+ role: event.type === "system.message" ? "system" : "user",
12886
+ content
12887
+ };
12888
+ state.history.push(message);
12889
+ if (state.activeTurn) {
12890
+ state.activeTurn.input.push(message);
12891
+ } else {
12892
+ state.pendingInput.push(message);
12893
+ }
12894
+ }
12895
+ function startAnthropicSessionModel(state, startEventId) {
12896
+ const turn = ensureAnthropicSessionTurn(state);
12897
+ if (turn.activeModel) {
12898
+ finalizeAnthropicSessionModelState(state, turn);
12899
+ }
12900
+ const span = withCurrent(
12901
+ turn.span,
12902
+ () => startSpan(
12903
+ withSpanInstrumentationName(
12904
+ {
12905
+ event: {
12906
+ ...state.history.length > 0 ? { input: state.history.slice() } : {},
12907
+ metadata: { provider: "anthropic" }
12908
+ },
12909
+ name: "anthropic.messages.create",
12910
+ spanAttributes: { type: "llm" /* LLM */ }
12911
+ },
12912
+ INSTRUMENTATION_NAMES.ANTHROPIC
12913
+ )
12914
+ )
12915
+ );
12916
+ turn.activeModel = {
12917
+ output: [],
12918
+ span,
12919
+ startEventId,
12920
+ startTime: getCurrentUnixTimestamp()
12921
+ };
12922
+ }
12923
+ function recordAnthropicSessionFirstToken(state, event) {
12924
+ const model = state.activeTurn?.activeModel;
12925
+ if (!model || model.firstTokenTime !== void 0 || !isObject(event.delta) || !isObject(event.delta.content) || typeof event.delta.content.text !== "string") {
12926
+ return;
12927
+ }
12928
+ model.firstTokenTime = getCurrentUnixTimestamp();
12929
+ }
12930
+ function recordAnthropicSessionMessage(state, event) {
12931
+ const turn = ensureAnthropicSessionTurn(state);
12932
+ const content = processAttachmentsInInput(
12933
+ event.content
12934
+ );
12935
+ if (turn.activeModel) {
12936
+ turn.activeModel.output.push(...content);
12937
+ } else {
12938
+ const output = { role: "assistant", content };
12939
+ turn.lastOutput = output;
12940
+ state.history.push(output);
12941
+ }
12942
+ }
12943
+ function startAnthropicSessionTool(state, event) {
12944
+ const turn = ensureAnthropicSessionTurn(state);
12945
+ if (turn.activeModel) {
12946
+ turn.activeModel.output.push({
12947
+ type: "tool_use",
12948
+ id: event.id,
12949
+ name: event.name,
12950
+ input: event.input
12951
+ });
12952
+ }
12953
+ const existing = turn.activeTools.get(event.id);
12954
+ if (existing) {
12955
+ existing.span.end();
12956
+ turn.activeTools.delete(event.id);
12957
+ }
12958
+ const span = withCurrent(
12959
+ turn.span,
12960
+ () => startSpan(
12961
+ withSpanInstrumentationName(
12962
+ {
12963
+ event: { input: event.input },
12964
+ name: event.name,
12965
+ spanAttributes: { type: "tool" /* TOOL */ }
12966
+ },
12967
+ INSTRUMENTATION_NAMES.ANTHROPIC
12968
+ )
12969
+ )
12970
+ );
12971
+ const toolState = {
12972
+ approval: event.evaluated_permission === "allow" ? "approved" : event.evaluated_permission === "deny" ? "denied" : void 0,
12973
+ span
12974
+ };
12975
+ turn.activeTools.set(event.id, toolState);
12976
+ if (toolState.approval === "denied") {
12977
+ finalizeAnthropicSessionToolState(toolState);
12978
+ turn.activeTools.delete(event.id);
12979
+ }
12980
+ }
12981
+ function recordAnthropicSessionToolConfirmation(state, event) {
12982
+ if (typeof event.tool_use_id !== "string" || event.result !== "allow" && event.result !== "deny") {
12983
+ return;
12984
+ }
12985
+ const turn = state.activeTurn;
12986
+ const tool = turn?.activeTools.get(event.tool_use_id);
12987
+ if (!turn || !tool) {
12988
+ return;
12989
+ }
12990
+ tool.approval = event.result === "allow" ? "approved" : "denied";
12991
+ if (tool.approval === "denied") {
12992
+ finalizeAnthropicSessionToolState(tool);
12993
+ turn.activeTools.delete(event.tool_use_id);
12994
+ }
12995
+ }
12996
+ function finalizeAnthropicSessionTool(state, event) {
12997
+ const toolUseId = event.tool_use_id ?? event.mcp_tool_use_id ?? event.custom_tool_use_id;
12998
+ if (!toolUseId) {
12999
+ return;
13000
+ }
13001
+ const content = processAttachmentsInInput(event.content);
13002
+ const turn = state.activeTurn;
13003
+ const tool = turn?.activeTools.get(toolUseId);
13004
+ if (turn && tool) {
13005
+ finalizeAnthropicSessionToolState(tool, event, content);
13006
+ turn.activeTools.delete(toolUseId);
13007
+ }
13008
+ const toolResult = {
13009
+ type: "tool_result",
13010
+ tool_use_id: toolUseId,
13011
+ ...content !== void 0 ? { content } : {},
13012
+ ...event.is_error === true ? { is_error: true } : {}
13013
+ };
13014
+ state.history.push({
13015
+ role: "user",
13016
+ content: [toolResult]
13017
+ });
13018
+ }
13019
+ function finalizeAnthropicSessionToolState(state, event, content = event?.content) {
13020
+ safeAnthropicSessionLog(state.span, {
13021
+ ...event?.is_error === true ? {
13022
+ error: content ?? "Anthropic session tool execution failed"
13023
+ } : {},
13024
+ ...state.approval ? { metadata: { tool_approval: state.approval } } : {},
13025
+ ...content !== void 0 ? { output: content } : {}
13026
+ });
13027
+ state.span.end();
13028
+ }
13029
+ function finalizeAnthropicSessionModel(state, event) {
13030
+ const turn = state.activeTurn;
13031
+ const model = turn?.activeModel;
13032
+ if (!turn || !model || model.startEventId !== event.model_request_start_id) {
13033
+ return;
13034
+ }
13035
+ finalizeAnthropicSessionModelState(state, turn, event);
13036
+ }
13037
+ function finalizeAnthropicSessionModelState(state, turn, event) {
13038
+ const model = turn.activeModel;
13039
+ if (!model) {
13040
+ return;
13041
+ }
13042
+ turn.activeModel = void 0;
13043
+ const metrics = event ? parseAnthropicSessionModelUsage(event.model_usage) : {};
13044
+ if (model.firstTokenTime !== void 0) {
13045
+ metrics.time_to_first_token = model.firstTokenTime - model.startTime;
13046
+ }
13047
+ const output = model.output.length > 0 ? { role: "assistant", content: model.output } : void 0;
13048
+ safeAnthropicSessionLog(model.span, {
13049
+ ...event?.is_error ? { error: "Anthropic session model request failed" } : {},
13050
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
13051
+ ...output ? { output } : {}
13052
+ });
13053
+ model.span.end();
13054
+ if (output) {
13055
+ turn.lastOutput = output;
13056
+ state.history.push(output);
13057
+ }
13058
+ for (const key of [
13059
+ "prompt_tokens",
13060
+ "completion_tokens",
13061
+ "tokens",
13062
+ "prompt_cached_tokens",
13063
+ "prompt_cache_creation_tokens"
13064
+ ]) {
13065
+ const value = metrics[key];
13066
+ if (typeof value === "number") {
13067
+ turn.metrics[key] = (turn.metrics[key] ?? 0) + value;
13068
+ }
13069
+ }
13070
+ }
13071
+ function parseAnthropicSessionModelUsage(usage) {
13072
+ const finalized = finalizeAnthropicTokens({
13073
+ completion_tokens: usage.output_tokens,
13074
+ prompt_cache_creation_tokens: usage.cache_creation_input_tokens,
13075
+ prompt_cached_tokens: usage.cache_read_input_tokens,
13076
+ prompt_tokens: usage.input_tokens
13077
+ });
13078
+ return Object.fromEntries(
13079
+ Object.entries(finalized).filter(
13080
+ (entry) => entry[1] !== void 0
13081
+ )
13082
+ );
13083
+ }
13084
+ function finalizeAnthropicSessionTurn(state, error) {
13085
+ const turn = state.activeTurn;
13086
+ if (!turn) {
13087
+ return;
13088
+ }
13089
+ state.activeTurn = void 0;
13090
+ finalizeAnthropicSessionModelState(state, turn);
13091
+ for (const tool of turn.activeTools.values()) {
13092
+ finalizeAnthropicSessionToolState(tool);
13093
+ }
13094
+ turn.activeTools.clear();
13095
+ safeAnthropicSessionLog(turn.span, {
13096
+ ...error !== void 0 ? { error: error instanceof Error ? error : toLoggedError(error) } : {},
13097
+ ...turn.input.length > 0 ? { input: turn.input } : {},
13098
+ ...turn.lastOutput ? { output: turn.lastOutput } : {},
13099
+ ...Object.keys(turn.metrics).length > 0 ? { metrics: turn.metrics } : {}
13100
+ });
13101
+ turn.span.end();
13102
+ }
13103
+ function safeAnthropicSessionLog(span, event) {
13104
+ try {
13105
+ span.log(event);
13106
+ } catch (error) {
13107
+ debugLogger.debug("Error logging Anthropic Sessions span:", error);
13108
+ }
13109
+ }
12343
13110
  function parseMetricsFromUsage2(usage) {
12344
13111
  if (!usage) {
12345
13112
  return {};
@@ -12355,6 +13122,18 @@ function parseMetricsFromUsage2(usage) {
12355
13122
  saveIfExistsTo("output_tokens", "completion_tokens");
12356
13123
  saveIfExistsTo("cache_read_input_tokens", "prompt_cached_tokens");
12357
13124
  saveIfExistsTo("cache_creation_input_tokens", "prompt_cache_creation_tokens");
13125
+ if (isObject(usage.cache_creation)) {
13126
+ const cacheCreation = usage.cache_creation;
13127
+ for (const [source, target] of [
13128
+ ["ephemeral_5m_input_tokens", "prompt_cache_creation_5m_tokens"],
13129
+ ["ephemeral_1h_input_tokens", "prompt_cache_creation_1h_tokens"]
13130
+ ]) {
13131
+ const value = cacheCreation[source];
13132
+ if (typeof value === "number") {
13133
+ metrics[target] = value;
13134
+ }
13135
+ }
13136
+ }
12358
13137
  if (isObject(usage.server_tool_use)) {
12359
13138
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
12360
13139
  if (typeof value === "number") {
@@ -14213,6 +14992,29 @@ var harnessAgentChannels = defineChannels(
14213
14992
  { instrumentationName: INSTRUMENTATION_NAMES.AI_SDK }
14214
14993
  );
14215
14994
 
14995
+ // src/instrumentation/plugins/cloudflare-think-context.ts
14996
+ var cloudflareThinkSpans = /* @__PURE__ */ new Map();
14997
+ function registerCloudflareThinkSpan(span) {
14998
+ if (span.spanId) {
14999
+ cloudflareThinkSpans.set(span.spanId, span);
15000
+ }
15001
+ }
15002
+ function unregisterCloudflareThinkSpan(span) {
15003
+ if (span.spanId) {
15004
+ cloudflareThinkSpans.delete(span.spanId);
15005
+ }
15006
+ }
15007
+ function currentCloudflareThinkSpan() {
15008
+ const parentSpanIds = _internalGetGlobalState()?.contextManager.getParentSpanIds()?.spanParents ?? [];
15009
+ for (const parentSpanId of parentSpanIds) {
15010
+ const span = cloudflareThinkSpans.get(parentSpanId);
15011
+ if (span) {
15012
+ return span;
15013
+ }
15014
+ }
15015
+ return void 0;
15016
+ }
15017
+
14216
15018
  // src/instrumentation/plugins/ai-sdk-plugin.ts
14217
15019
  var DEFAULT_DENY_OUTPUT_PATHS = [
14218
15020
  // v3
@@ -14319,6 +15121,7 @@ var AISDKPlugin = class extends BasePlugin {
14319
15121
  traceStreamingChannel(aiSDKChannels.streamText, {
14320
15122
  name: "streamText",
14321
15123
  type: "function" /* FUNCTION */,
15124
+ shouldTrace: () => currentCloudflareThinkSpan() === void 0,
14322
15125
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
14323
15126
  extractOutput: (result, endEvent) => processAISDKOutput(
14324
15127
  result,
@@ -14339,6 +15142,7 @@ var AISDKPlugin = class extends BasePlugin {
14339
15142
  traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
14340
15143
  name: "streamText",
14341
15144
  type: "function" /* FUNCTION */,
15145
+ shouldTrace: () => currentCloudflareThinkSpan() === void 0,
14342
15146
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
14343
15147
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
14344
15148
  defaultDenyOutputPaths: denyOutputPaths,
@@ -15324,6 +16128,23 @@ function prepareAISDKWorkflowAgentStreamInput(params, event, span, defaultDenyOu
15324
16128
  metadata
15325
16129
  };
15326
16130
  }
16131
+ function prepareAISDKAgentCallInput(params, event, span, defaultDenyOutputPaths = DEFAULT_DENY_OUTPUT_PATHS) {
16132
+ const { input } = processAISDKWorkflowAgentCallInput(params);
16133
+ const metadata = extractMetadataFromCallParams(params, event.self);
16134
+ const childTracing = prepareAISDKChildTracing(
16135
+ params,
16136
+ event.self,
16137
+ span,
16138
+ defaultDenyOutputPaths,
16139
+ event.aiSDK,
16140
+ { agentOwner: true }
16141
+ );
16142
+ event.modelWrapped = childTracing.modelWrapped;
16143
+ if (childTracing.cleanup) {
16144
+ event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
16145
+ }
16146
+ return { input, metadata };
16147
+ }
15327
16148
  function prepareAISDKEmbedInput(params, self) {
15328
16149
  return {
15329
16150
  input: { ...params },
@@ -15347,6 +16168,18 @@ function extractTopLevelAISDKMetrics(result, event, startTime) {
15347
16168
  }
15348
16169
  return metrics;
15349
16170
  }
16171
+ async function extractResolvedAISDKTokenMetrics(result) {
16172
+ for (const field of ["totalUsage", "usage"]) {
16173
+ try {
16174
+ const usage = await Promise.resolve(result[field]);
16175
+ if (usage !== void 0) {
16176
+ return extractTokenMetrics({ [field]: usage });
16177
+ }
16178
+ } catch {
16179
+ }
16180
+ }
16181
+ return extractTokenMetrics(result);
16182
+ }
15350
16183
  function hasModelChildTracing(event) {
15351
16184
  return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
15352
16185
  }
@@ -16164,13 +16997,15 @@ function patchAISDKStreamingResult(args) {
16164
16997
  const {
16165
16998
  defaultDenyOutputPaths,
16166
16999
  endEvent,
17000
+ forceTopLevelMetrics,
16167
17001
  onComplete,
16168
17002
  onCancel,
16169
17003
  onError,
16170
17004
  result,
16171
17005
  resolvePromiseUsage,
16172
17006
  span,
16173
- startTime
17007
+ startTime,
17008
+ transformOutput
16174
17009
  } = args;
16175
17010
  if (!result || typeof result !== "object") {
16176
17011
  return false;
@@ -16223,8 +17058,8 @@ function patchAISDKStreamingResult(args) {
16223
17058
  }
16224
17059
  outputLogged = true;
16225
17060
  try {
16226
- const metrics = extractTopLevelAISDKMetrics(result, endEvent);
16227
- if (resolvePromiseUsage) {
17061
+ const metrics = forceTopLevelMetrics ? await extractResolvedAISDKTokenMetrics(result) : extractTopLevelAISDKMetrics(result, endEvent);
17062
+ if (resolvePromiseUsage && !forceTopLevelMetrics) {
16228
17063
  try {
16229
17064
  const resultRecord2 = result;
16230
17065
  const pendingUsage = resultRecord2.totalUsage ?? resultRecord2.usage;
@@ -16243,10 +17078,11 @@ function patchAISDKStreamingResult(args) {
16243
17078
  if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
16244
17079
  metrics.time_to_first_token = firstChunkTime - startTime;
16245
17080
  }
16246
- const output = await processAISDKStreamingOutput(
17081
+ const processedOutput = await processAISDKStreamingOutput(
16247
17082
  result,
16248
17083
  resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
16249
17084
  );
17085
+ const output = transformOutput ? transformOutput(processedOutput) : processedOutput;
16250
17086
  const metadata = buildResolvedMetadataPayload(result).metadata;
16251
17087
  try {
16252
17088
  span.log({
@@ -17596,37 +18432,97 @@ function seedTaskToolUseIdMapping(taskIdToToolUseId, message) {
17596
18432
  taskIdToToolUseId.set(message.task_id, message.tool_use_id);
17597
18433
  }
17598
18434
  }
17599
- function extractUsageFromMessage(message) {
17600
- const metrics = {};
17601
- let usage;
17602
- if (message.type === "assistant") {
17603
- usage = message.message?.usage;
17604
- } else if (message.type === "result") {
17605
- usage = message.usage;
17606
- }
18435
+ function tokenCount(value) {
18436
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : void 0;
18437
+ }
18438
+ function copyUsage(usage) {
17607
18439
  if (!usage || typeof usage !== "object") {
17608
- return metrics;
18440
+ return void 0;
18441
+ }
18442
+ const copy = {};
18443
+ for (const key of [
18444
+ "input_tokens",
18445
+ "output_tokens",
18446
+ "cache_read_input_tokens",
18447
+ "cache_creation_input_tokens"
18448
+ ]) {
18449
+ const value = tokenCount(Reflect.get(usage, key));
18450
+ if (value !== void 0) {
18451
+ copy[key] = value;
18452
+ }
18453
+ }
18454
+ const cacheCreation = Reflect.get(usage, "cache_creation");
18455
+ if (cacheCreation && typeof cacheCreation === "object") {
18456
+ const cacheCreationCopy = {};
18457
+ for (const key of [
18458
+ "ephemeral_5m_input_tokens",
18459
+ "ephemeral_1h_input_tokens"
18460
+ ]) {
18461
+ const value = tokenCount(Reflect.get(cacheCreation, key));
18462
+ if (value !== void 0) {
18463
+ cacheCreationCopy[key] = value;
18464
+ }
18465
+ }
18466
+ if (Object.keys(cacheCreationCopy).length > 0) {
18467
+ copy.cache_creation = cacheCreationCopy;
18468
+ }
18469
+ }
18470
+ return Object.keys(copy).length > 0 ? copy : void 0;
18471
+ }
18472
+ function mergeUsage(base, override) {
18473
+ if (!base || !override) {
18474
+ return override ?? base;
18475
+ }
18476
+ const cacheCreation = base.cache_creation || override.cache_creation ? { ...base.cache_creation, ...override.cache_creation } : void 0;
18477
+ return {
18478
+ ...base,
18479
+ ...override,
18480
+ ...cacheCreation && { cache_creation: cacheCreation }
18481
+ };
18482
+ }
18483
+ function extractUsage(usage, includeOutput) {
18484
+ const metrics = {};
18485
+ if (!usage) {
18486
+ return {};
17609
18487
  }
17610
18488
  const inputTokens = getNumberProperty(usage, "input_tokens");
17611
18489
  if (inputTokens !== void 0) {
17612
18490
  metrics.prompt_tokens = inputTokens;
17613
18491
  }
17614
- const outputTokens = getNumberProperty(usage, "output_tokens");
17615
- if (outputTokens !== void 0) {
17616
- metrics.completion_tokens = outputTokens;
18492
+ if (includeOutput) {
18493
+ const outputTokens = getNumberProperty(usage, "output_tokens");
18494
+ if (outputTokens !== void 0) {
18495
+ metrics.completion_tokens = outputTokens;
18496
+ }
17617
18497
  }
17618
18498
  const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
17619
18499
  const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
17620
- if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
17621
- Object.assign(
17622
- metrics,
17623
- extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
17624
- );
18500
+ Object.assign(
18501
+ metrics,
18502
+ extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
18503
+ );
18504
+ const cacheCreation5mTokens = getNumberProperty(
18505
+ usage.cache_creation,
18506
+ "ephemeral_5m_input_tokens"
18507
+ );
18508
+ const cacheCreation1hTokens = getNumberProperty(
18509
+ usage.cache_creation,
18510
+ "ephemeral_1h_input_tokens"
18511
+ );
18512
+ if (cacheCreation5mTokens !== void 0) {
18513
+ metrics.prompt_cache_creation_5m_tokens = cacheCreation5mTokens;
17625
18514
  }
17626
- if (Object.keys(metrics).length > 0) {
17627
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
18515
+ if (cacheCreation1hTokens !== void 0) {
18516
+ metrics.prompt_cache_creation_1h_tokens = cacheCreation1hTokens;
17628
18517
  }
17629
- return metrics;
18518
+ if (Object.keys(metrics).length === 0) {
18519
+ return {};
18520
+ }
18521
+ const finalized = finalizeAnthropicTokens(metrics);
18522
+ if (metrics.completion_tokens === void 0) {
18523
+ delete finalized.tokens;
18524
+ }
18525
+ return toNumericMetrics(finalized);
17630
18526
  }
17631
18527
  function buildLLMInput(promptMessages, conversationHistory) {
17632
18528
  const inputParts = [...promptMessages, ...conversationHistory];
@@ -17660,16 +18556,16 @@ function buildRootPromptMessages(prompt, capturedPromptMessages) {
17660
18556
  function formatCapturedMessages(messages) {
17661
18557
  return messages.length > 0 ? messages : [];
17662
18558
  }
17663
- async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
18559
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, usage, hasFinalOutputUsage, existingSpan) {
17664
18560
  if (messages.length === 0) {
17665
18561
  return void 0;
17666
18562
  }
17667
18563
  const lastMessage = messages[messages.length - 1];
17668
- if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
18564
+ if (lastMessage.type !== "assistant") {
17669
18565
  return void 0;
17670
18566
  }
17671
- const model = lastMessage.message.model || options.model;
17672
- const usage = extractUsageFromMessage(lastMessage);
18567
+ const model = lastMessage.message?.model || options.model;
18568
+ const metrics = options.includePartialMessages ? extractUsage(usage, hasFinalOutputUsage) : {};
17673
18569
  const input = buildLLMInput(promptMessages, conversationHistory);
17674
18570
  const outputs = messages.map(
17675
18571
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
@@ -17691,8 +18587,8 @@ async function createLLMSpanForMessages(messages, promptMessages, conversationHi
17691
18587
  );
17692
18588
  span.log({
17693
18589
  input,
17694
- metadata: model ? { model } : void 0,
17695
- metrics: usage,
18590
+ metadata: { ...model && { model }, provider: "anthropic" },
18591
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
17696
18592
  output: outputs
17697
18593
  });
17698
18594
  const spanExport = await span.export();
@@ -17782,11 +18678,17 @@ function prepareLocalToolHandlersInMcpServers(mcpServers) {
17782
18678
  }
17783
18679
  return { hasLocalToolHandlers, localToolHookNames };
17784
18680
  }
17785
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
18681
+ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
17786
18682
  const preToolUse = async (input, toolUseID) => {
17787
18683
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
17788
18684
  return {};
17789
18685
  }
18686
+ if (!toolUseToParent.has(toolUseID) && input.agent_id) {
18687
+ const parentToolUseId = taskIdToToolUseId.get(input.agent_id);
18688
+ if (parentToolUseId) {
18689
+ toolUseToParent.set(toolUseID, parentToolUseId);
18690
+ }
18691
+ }
17790
18692
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
17791
18693
  return {};
17792
18694
  }
@@ -17982,9 +18884,6 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
17982
18884
  }
17983
18885
  const metadata = {
17984
18886
  ...subAgentDetailsToMetadata(details),
17985
- ...input.agent_transcript_path && {
17986
- "claude_agent_sdk.agent_transcript_path": input.agent_transcript_path
17987
- },
17988
18887
  "claude_agent_sdk.stop_hook_active": input.stop_hook_active
17989
18888
  };
17990
18889
  try {
@@ -18006,7 +18905,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
18006
18905
  subagentStop
18007
18906
  };
18008
18907
  }
18009
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
18908
+ function injectTracingHooks(options, resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
18010
18909
  const {
18011
18910
  preToolUse,
18012
18911
  postToolUse,
@@ -18015,6 +18914,8 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
18015
18914
  subagentStop
18016
18915
  } = createToolTracingHooks(
18017
18916
  resolveParentSpan,
18917
+ taskIdToToolUseId,
18918
+ toolUseToParent,
18018
18919
  activeToolSpans,
18019
18920
  options.mcpServers,
18020
18921
  localToolHookNames,
@@ -18096,6 +18997,13 @@ async function finalizeCurrentMessageGroup(state) {
18096
18997
  }
18097
18998
  }
18098
18999
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
19000
+ const lastMessage = state.currentMessages[state.currentMessages.length - 1];
19001
+ const messageId = lastMessage?.message?.id;
19002
+ const usage = state.options.includePartialMessages ? mergeUsage(
19003
+ copyUsage(lastMessage?.message?.usage),
19004
+ messageId ? state.usageByMessageId.get(messageId) : void 0
19005
+ ) : void 0;
19006
+ const hasFinalOutputUsage = messageId !== void 0 && state.finalOutputUsageMessageIds.has(messageId);
18099
19007
  const llmSpanResult = await createLLMSpanForMessages(
18100
19008
  state.currentMessages,
18101
19009
  promptMessages,
@@ -18103,6 +19011,8 @@ async function finalizeCurrentMessageGroup(state) {
18103
19011
  state.options,
18104
19012
  state.currentMessageStartTime,
18105
19013
  parentSpan,
19014
+ usage,
19015
+ hasFinalOutputUsage,
18106
19016
  existingLlmSpan
18107
19017
  );
18108
19018
  if (llmSpanResult) {
@@ -18120,9 +19030,17 @@ async function finalizeCurrentMessageGroup(state) {
18120
19030
  }
18121
19031
  }
18122
19032
  state.activeLlmSpansByParentToolUse.delete(parentKey);
18123
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
18124
- if (lastMessage?.message?.usage) {
18125
- state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
19033
+ if (messageId) {
19034
+ state.usageByMessageId.delete(messageId);
19035
+ state.finalOutputUsageMessageIds.delete(messageId);
19036
+ for (const [
19037
+ parent,
19038
+ activeMessageId
19039
+ ] of state.activePartialMessageIdByParentKey) {
19040
+ if (activeMessageId === messageId) {
19041
+ state.activePartialMessageIdByParentKey.delete(parent);
19042
+ }
19043
+ }
18126
19044
  }
18127
19045
  state.currentMessages.length = 0;
18128
19046
  }
@@ -18213,6 +19131,10 @@ async function ensureActiveLlmSpanForParentToolUse(rootSpan, activeLlmSpansByPar
18213
19131
  );
18214
19132
  llmParentSpan = await subAgentSpan.export();
18215
19133
  }
19134
+ const racedLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
19135
+ if (racedLlmSpan) {
19136
+ return racedLlmSpan;
19137
+ }
18216
19138
  const llmSpan = startSpan(
18217
19139
  withSpanInstrumentationName(
18218
19140
  {
@@ -18332,7 +19254,49 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
18332
19254
  }
18333
19255
  return true;
18334
19256
  }
19257
+ function handlePartialUsageMessage(state, message) {
19258
+ if (message.type !== "stream_event") {
19259
+ return false;
19260
+ }
19261
+ const event = message.event;
19262
+ if (!event || typeof event !== "object") {
19263
+ return true;
19264
+ }
19265
+ const parentKey = llmParentKey(message.parent_tool_use_id ?? null);
19266
+ if (event.type === "message_start") {
19267
+ const messageId2 = event.message?.id;
19268
+ const usage = copyUsage(event.message?.usage);
19269
+ if (messageId2) {
19270
+ state.activePartialMessageIdByParentKey.set(parentKey, messageId2);
19271
+ if (usage) {
19272
+ state.usageByMessageId.set(messageId2, usage);
19273
+ }
19274
+ }
19275
+ return true;
19276
+ }
19277
+ const messageId = state.activePartialMessageIdByParentKey.get(parentKey);
19278
+ if (!messageId) {
19279
+ return true;
19280
+ }
19281
+ if (event.type === "message_delta") {
19282
+ const update = copyUsage(event.usage);
19283
+ if (update) {
19284
+ const usage = state.usageByMessageId.get(messageId) ?? {};
19285
+ Object.assign(usage, update);
19286
+ state.usageByMessageId.set(messageId, usage);
19287
+ if (update.output_tokens !== void 0) {
19288
+ state.finalOutputUsageMessageIds.add(messageId);
19289
+ }
19290
+ }
19291
+ } else if (event.type === "message_stop") {
19292
+ state.activePartialMessageIdByParentKey.delete(parentKey);
19293
+ }
19294
+ return true;
19295
+ }
18335
19296
  async function handleStreamMessage(state, message) {
19297
+ if (handlePartialUsageMessage(state, message)) {
19298
+ return;
19299
+ }
18336
19300
  maybeTrackToolUseContext(state, message);
18337
19301
  if (await maybeHandleTaskLifecycleMessage(state, message)) {
18338
19302
  return;
@@ -18379,36 +19343,9 @@ async function handleStreamMessage(state, message) {
18379
19343
  );
18380
19344
  state.currentMessages.push(message);
18381
19345
  }
18382
- if (message.type !== "result" || !message.usage) {
19346
+ if (message.type !== "result") {
18383
19347
  return;
18384
19348
  }
18385
- const finalUsageMetrics = extractUsageFromMessage(message);
18386
- if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
18387
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
18388
- if (lastMessage?.message?.usage) {
18389
- const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
18390
- if (adjustedTokens >= 0) {
18391
- lastMessage.message.usage.output_tokens = adjustedTokens;
18392
- }
18393
- const resultUsage = message.usage;
18394
- if (resultUsage && typeof resultUsage === "object") {
18395
- const cacheReadTokens = getNumberProperty(
18396
- resultUsage,
18397
- "cache_read_input_tokens"
18398
- );
18399
- if (cacheReadTokens !== void 0) {
18400
- lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
18401
- }
18402
- const cacheCreationTokens = getNumberProperty(
18403
- resultUsage,
18404
- "cache_creation_input_tokens"
18405
- );
18406
- if (cacheCreationTokens !== void 0) {
18407
- lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
18408
- }
18409
- }
18410
- }
18411
- }
18412
19349
  const metadata = {};
18413
19350
  if (message.num_turns !== void 0) {
18414
19351
  metadata.num_turns = message.num_turns;
@@ -18416,8 +19353,12 @@ async function handleStreamMessage(state, message) {
18416
19353
  if (message.session_id !== void 0) {
18417
19354
  metadata.session_id = message.session_id;
18418
19355
  }
18419
- if (Object.keys(metadata).length > 0) {
18420
- state.span.log({ metadata });
19356
+ const metrics = state.options.includePartialMessages ? {} : extractUsage(copyUsage(message.usage), true);
19357
+ if (Object.keys(metadata).length > 0 || Object.keys(metrics).length > 0) {
19358
+ state.span.log({
19359
+ ...Object.keys(metadata).length > 0 ? { metadata } : {},
19360
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
19361
+ });
18421
19362
  }
18422
19363
  }
18423
19364
  async function finalizeQuerySpan(state) {
@@ -18441,6 +19382,9 @@ async function finalizeQuerySpan(state) {
18441
19382
  llmSpan.end();
18442
19383
  }
18443
19384
  state.activeLlmSpansByParentToolUse.clear();
19385
+ state.activePartialMessageIdByParentKey.clear();
19386
+ state.finalOutputUsageMessageIds.clear();
19387
+ state.usageByMessageId.clear();
18444
19388
  for (const toolSpan of state.activeToolSpans.values()) {
18445
19389
  toolSpan.end();
18446
19390
  }
@@ -18565,6 +19509,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
18565
19509
  const optionsWithHooks = injectTracingHooks(
18566
19510
  options,
18567
19511
  resolveToolUseParentSpan,
19512
+ taskIdToToolUseId,
19513
+ toolUseToParent,
18568
19514
  activeToolSpans,
18569
19515
  localToolHookNames,
18570
19516
  skipLocalToolHooks,
@@ -18575,8 +19521,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
18575
19521
  params.options = optionsWithHooks;
18576
19522
  event.arguments[0] = params;
18577
19523
  spans.set(event, {
18578
- accumulatedOutputTokens: 0,
18579
19524
  activeLlmSpansByParentToolUse,
19525
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
18580
19526
  activeToolSpans,
18581
19527
  conversationHistoryByParentKey,
18582
19528
  capturedPromptMessages,
@@ -18584,6 +19530,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
18584
19530
  currentMessageStartTime: startTime,
18585
19531
  currentMessages: [],
18586
19532
  endedSubAgentSpans,
19533
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
18587
19534
  finalResults: [],
18588
19535
  options: optionsWithHooks,
18589
19536
  originalPrompt,
@@ -18599,6 +19546,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
18599
19546
  latestLlmParentBySubAgentToolUse,
18600
19547
  latestRootLlmParentRef,
18601
19548
  toolUseToParent,
19549
+ usageByMessageId: /* @__PURE__ */ new Map(),
18602
19550
  localToolContext
18603
19551
  });
18604
19552
  },
@@ -18668,6 +19616,295 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
18668
19616
  }
18669
19617
  };
18670
19618
 
19619
+ // src/instrumentation/plugins/cloudflare-think-channels.ts
19620
+ var cloudflareThinkChannels = defineChannels(
19621
+ "@cloudflare/think",
19622
+ {
19623
+ runInferenceLoop: channel({
19624
+ channelName: "Think.runInferenceLoop",
19625
+ kind: "async"
19626
+ })
19627
+ },
19628
+ { instrumentationName: INSTRUMENTATION_NAMES.CLOUDFLARE_THINK }
19629
+ );
19630
+
19631
+ // src/instrumentation/plugins/cloudflare-think-plugin.ts
19632
+ var THINK_STATE_ID = /* @__PURE__ */ Symbol.for("braintrust.cloudflare-think.state-id");
19633
+ var CloudflareThinkPlugin = class extends BasePlugin {
19634
+ statesBySpanId = /* @__PURE__ */ new Map();
19635
+ onEnable() {
19636
+ this.subscribeToThinkRuns();
19637
+ this.subscribeToAISDKStreamTextSync();
19638
+ this.subscribeToAISDKStreamTextAsync();
19639
+ }
19640
+ onDisable() {
19641
+ for (const unsubscribe of this.unsubscribers) {
19642
+ unsubscribe();
19643
+ }
19644
+ this.unsubscribers = [];
19645
+ for (const state of this.statesBySpanId.values()) {
19646
+ this.finishState(state);
19647
+ }
19648
+ this.statesBySpanId.clear();
19649
+ }
19650
+ subscribeToThinkRuns() {
19651
+ const channel2 = cloudflareThinkChannels.runInferenceLoop.tracingChannel();
19652
+ const states = /* @__PURE__ */ new WeakMap();
19653
+ const state = _internalGetGlobalState();
19654
+ const contextManager = state?.contextManager;
19655
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
19656
+ const ensureState2 = (event) => {
19657
+ if (isAutoInstrumentationSuppressed()) {
19658
+ return void 0;
19659
+ }
19660
+ const existing = states.get(event);
19661
+ if (existing) {
19662
+ return existing;
19663
+ }
19664
+ const span = startSpan(
19665
+ withSpanInstrumentationName(
19666
+ {
19667
+ name: "Think.runTurn",
19668
+ spanAttributes: { type: "task" /* TASK */ }
19669
+ },
19670
+ INSTRUMENTATION_NAMES.CLOUDFLARE_THINK
19671
+ )
19672
+ );
19673
+ const runState = {
19674
+ aiResultPatched: false,
19675
+ fallbackInput: extractFallbackInput(event.self?.messages),
19676
+ finalized: false,
19677
+ inputLogged: false,
19678
+ span,
19679
+ startTime: getCurrentUnixTimestamp()
19680
+ };
19681
+ const metadata = {
19682
+ braintrust: {
19683
+ integration_name: "cloudflare-think",
19684
+ sdk_language: "typescript"
19685
+ }
19686
+ };
19687
+ if (typeof event.moduleVersion === "string") {
19688
+ metadata["cloudflare_think.version"] = event.moduleVersion;
19689
+ }
19690
+ span.log({ metadata });
19691
+ states.set(event, runState);
19692
+ if (span.spanId) {
19693
+ this.statesBySpanId.set(span.spanId, runState);
19694
+ }
19695
+ registerCloudflareThinkSpan(span);
19696
+ return runState;
19697
+ };
19698
+ if (contextManager && currentSpanStore && channel2.start) {
19699
+ channel2.start.bindStore(currentSpanStore, (event) => {
19700
+ const runState = ensureState2(event);
19701
+ return runState ? contextManager.wrapSpanForStore(runState.span) : currentSpanStore.getStore();
19702
+ });
19703
+ this.unsubscribers.push(
19704
+ () => channel2.start?.unbindStore(currentSpanStore)
19705
+ );
19706
+ }
19707
+ const handlers = {
19708
+ start: (event) => {
19709
+ ensureState2(event);
19710
+ },
19711
+ asyncEnd: (event) => {
19712
+ const runState = states.get(event);
19713
+ states.delete(event);
19714
+ if (!runState || runState.finalized || runState.aiResultPatched) {
19715
+ return;
19716
+ }
19717
+ this.finishState(runState, void 0, event.result);
19718
+ },
19719
+ error: (event) => {
19720
+ const runState = states.get(event);
19721
+ states.delete(event);
19722
+ if (runState) {
19723
+ this.finishState(runState, event.error);
19724
+ }
19725
+ }
19726
+ };
19727
+ channel2.subscribe(handlers);
19728
+ this.unsubscribers.push(() => channel2.unsubscribe(handlers));
19729
+ }
19730
+ subscribeToAISDKStreamTextSync() {
19731
+ const channel2 = aiSDKChannels.streamTextSync.tracingChannel();
19732
+ const handlers = {
19733
+ start: (event) => {
19734
+ this.startAISDKStream(event);
19735
+ },
19736
+ end: (event) => {
19737
+ this.endAISDKStream(event);
19738
+ },
19739
+ error: (event) => {
19740
+ this.errorAISDKStream(event);
19741
+ }
19742
+ };
19743
+ channel2.subscribe(handlers);
19744
+ this.unsubscribers.push(() => channel2.unsubscribe(handlers));
19745
+ }
19746
+ subscribeToAISDKStreamTextAsync() {
19747
+ const channel2 = aiSDKChannels.streamText.tracingChannel();
19748
+ const handlers = {
19749
+ start: (event) => {
19750
+ this.startAISDKStream(event);
19751
+ },
19752
+ asyncEnd: (event) => {
19753
+ this.endAISDKStream(event);
19754
+ },
19755
+ error: (event) => {
19756
+ this.errorAISDKStream(event);
19757
+ }
19758
+ };
19759
+ channel2.subscribe(handlers);
19760
+ this.unsubscribers.push(() => channel2.unsubscribe(handlers));
19761
+ }
19762
+ startAISDKStream(event) {
19763
+ const runState = this.currentState();
19764
+ if (!runState || runState.finalized) {
19765
+ return;
19766
+ }
19767
+ try {
19768
+ const prepared = prepareAISDKAgentCallInput(
19769
+ event.arguments[0],
19770
+ event,
19771
+ runState.span
19772
+ );
19773
+ runState.span.log({
19774
+ input: extractThinkTaskInput(prepared.input),
19775
+ metadata: {
19776
+ ...prepared.metadata,
19777
+ braintrust: {
19778
+ integration_name: "cloudflare-think",
19779
+ sdk_language: "typescript"
19780
+ }
19781
+ }
19782
+ });
19783
+ runState.inputLogged = true;
19784
+ runState.aiEvent = event;
19785
+ Reflect.set(event, THINK_STATE_ID, runState.span.spanId);
19786
+ } catch (error) {
19787
+ debugLogger.error(
19788
+ "Error preparing @cloudflare/think AI SDK tracing:",
19789
+ error
19790
+ );
19791
+ }
19792
+ }
19793
+ endAISDKStream(event) {
19794
+ const runState = this.stateForAISDKEvent(event);
19795
+ if (!runState || runState.finalized) {
19796
+ return;
19797
+ }
19798
+ const patched = patchAISDKStreamingResult({
19799
+ defaultDenyOutputPaths: DEFAULT_DENY_OUTPUT_PATHS,
19800
+ endEvent: event,
19801
+ forceTopLevelMetrics: true,
19802
+ onComplete: () => this.releaseState(runState),
19803
+ result: event.result,
19804
+ span: runState.span,
19805
+ startTime: runState.startTime,
19806
+ transformOutput: extractThinkTaskOutput
19807
+ });
19808
+ runState.aiResultPatched = patched;
19809
+ if (!patched) {
19810
+ this.finishState(runState, void 0, event.result);
19811
+ }
19812
+ }
19813
+ errorAISDKStream(event) {
19814
+ const runState = this.stateForAISDKEvent(event);
19815
+ if (runState) {
19816
+ this.finishState(runState, event.error);
19817
+ }
19818
+ }
19819
+ currentState() {
19820
+ const parentIds = _internalGetGlobalState()?.contextManager.getParentSpanIds()?.spanParents ?? [];
19821
+ for (const parentId of parentIds) {
19822
+ const state = this.statesBySpanId.get(parentId);
19823
+ if (state) {
19824
+ return state;
19825
+ }
19826
+ }
19827
+ return void 0;
19828
+ }
19829
+ stateForAISDKEvent(event) {
19830
+ const spanId = Reflect.get(event, THINK_STATE_ID);
19831
+ return typeof spanId === "string" ? this.statesBySpanId.get(spanId) : void 0;
19832
+ }
19833
+ finishState(state, error, output) {
19834
+ if (state.finalized) {
19835
+ return;
19836
+ }
19837
+ state.finalized = true;
19838
+ try {
19839
+ if (!state.inputLogged && state.fallbackInput !== void 0) {
19840
+ state.span.log({ input: state.fallbackInput });
19841
+ }
19842
+ if (error !== void 0) {
19843
+ state.span.log({ error });
19844
+ } else if (output !== void 0) {
19845
+ state.span.log({ output: extractThinkTaskOutput(output) });
19846
+ }
19847
+ finalizeAISDKChildTracing(state.aiEvent);
19848
+ state.span.end();
19849
+ } finally {
19850
+ this.releaseState(state);
19851
+ }
19852
+ }
19853
+ releaseState(state) {
19854
+ state.finalized = true;
19855
+ unregisterCloudflareThinkSpan(state.span);
19856
+ if (state.span.spanId) {
19857
+ this.statesBySpanId.delete(state.span.spanId);
19858
+ }
19859
+ }
19860
+ };
19861
+ function extractFallbackInput(messages) {
19862
+ if (!Array.isArray(messages) || messages.length === 0) {
19863
+ return void 0;
19864
+ }
19865
+ let latestUserIndex = -1;
19866
+ for (let index = messages.length - 1; index >= 0; index--) {
19867
+ if (messages[index]?.role === "user") {
19868
+ latestUserIndex = index;
19869
+ break;
19870
+ }
19871
+ }
19872
+ const selected = latestUserIndex >= 0 ? messages.slice(latestUserIndex) : [];
19873
+ return selected.map((message) => ({
19874
+ role: message.role,
19875
+ content: message.content ?? message.parts
19876
+ }));
19877
+ }
19878
+ function extractThinkTaskOutput(output) {
19879
+ if (!isObject(output)) {
19880
+ return output;
19881
+ }
19882
+ if (typeof output.text === "string") {
19883
+ return { role: "assistant", content: output.text };
19884
+ }
19885
+ if (output.object !== void 0) {
19886
+ return output.object;
19887
+ }
19888
+ return output;
19889
+ }
19890
+ function extractThinkTaskInput(input) {
19891
+ if (!isObject(input)) {
19892
+ return input;
19893
+ }
19894
+ const system = input.instructions ?? input.system;
19895
+ if (Array.isArray(input.messages)) {
19896
+ return system === void 0 ? input.messages : [{ role: "system", content: system }, ...input.messages];
19897
+ }
19898
+ if (Array.isArray(input.prompt)) {
19899
+ return system === void 0 ? input.prompt : [{ role: "system", content: system }, ...input.prompt];
19900
+ }
19901
+ if (typeof input.prompt === "string") {
19902
+ const messages = [{ role: "user", content: input.prompt }];
19903
+ return system === void 0 ? messages : [{ role: "system", content: system }, ...messages];
19904
+ }
19905
+ return input;
19906
+ }
19907
+
18671
19908
  // src/instrumentation/plugins/cursor-sdk-channels.ts
18672
19909
  var cursorSDKChannels = defineChannels(
18673
19910
  "@cursor/sdk",
@@ -20784,9 +22021,9 @@ function extractEmbedPromptTokenCount(response) {
20784
22021
  let sawAny = false;
20785
22022
  for (const embedding of embeddings) {
20786
22023
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
20787
- const tokenCount = embeddingStats?.tokenCount;
20788
- if (typeof tokenCount === "number" && Number.isFinite(tokenCount)) {
20789
- total += tokenCount;
22024
+ const tokenCount2 = embeddingStats?.tokenCount;
22025
+ if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
22026
+ total += tokenCount2;
20790
22027
  sawAny = true;
20791
22028
  }
20792
22029
  }
@@ -24433,6 +25670,470 @@ function aggregateMistralStreamChunks(chunks) {
24433
25670
  };
24434
25671
  }
24435
25672
 
25673
+ // src/instrumentation/plugins/ollama-channels.ts
25674
+ var ollamaChannels = defineChannels(
25675
+ "ollama",
25676
+ {
25677
+ chat: channel({
25678
+ channelName: "chat",
25679
+ kind: "async"
25680
+ }),
25681
+ generate: channel({
25682
+ channelName: "generate",
25683
+ kind: "async"
25684
+ }),
25685
+ embed: channel({
25686
+ channelName: "embed",
25687
+ kind: "async"
25688
+ })
25689
+ },
25690
+ { instrumentationName: INSTRUMENTATION_NAMES.OLLAMA }
25691
+ );
25692
+
25693
+ // src/instrumentation/plugins/ollama-plugin.ts
25694
+ var OllamaPlugin = class extends BasePlugin {
25695
+ onEnable() {
25696
+ this.unsubscribers.push(
25697
+ traceStreamingChannel(ollamaChannels.chat, {
25698
+ name: "ollama.chat",
25699
+ type: "llm" /* LLM */,
25700
+ extractInput: extractOllamaChatInput,
25701
+ extractOutput: (result, event) => extractOllamaChatOutput(
25702
+ result,
25703
+ countOllamaToolCalls(event?.arguments?.[0]?.messages)
25704
+ ),
25705
+ extractMetadata: extractOllamaResponseMetadata,
25706
+ extractMetrics: extractOllamaMetrics,
25707
+ aggregateChunks: aggregateOllamaChatChunks
25708
+ }),
25709
+ traceStreamingChannel(ollamaChannels.generate, {
25710
+ name: "ollama.generate",
25711
+ type: "llm" /* LLM */,
25712
+ extractInput: extractOllamaGenerateInput,
25713
+ extractOutput: extractOllamaGenerateOutput,
25714
+ extractMetadata: extractOllamaResponseMetadata,
25715
+ extractMetrics: extractOllamaMetrics,
25716
+ aggregateChunks: aggregateOllamaGenerateChunks
25717
+ }),
25718
+ traceAsyncChannel(ollamaChannels.embed, {
25719
+ name: "ollama.embed",
25720
+ type: "llm" /* LLM */,
25721
+ extractInput: extractOllamaEmbedInput,
25722
+ extractOutput: extractOllamaEmbedOutput,
25723
+ extractMetadata: extractOllamaResponseMetadata,
25724
+ extractMetrics: extractOllamaMetrics
25725
+ })
25726
+ );
25727
+ }
25728
+ onDisable() {
25729
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
25730
+ }
25731
+ };
25732
+ function isNonNegativeNumber(value) {
25733
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
25734
+ }
25735
+ function normalizeFinishReason(response, hasToolCalls = false) {
25736
+ if (hasToolCalls) {
25737
+ return "tool_calls";
25738
+ }
25739
+ return response?.done_reason || "stop";
25740
+ }
25741
+ function stringifyArguments(value) {
25742
+ if (typeof value === "string") {
25743
+ return value;
25744
+ }
25745
+ try {
25746
+ return JSON.stringify(value ?? {});
25747
+ } catch {
25748
+ return String(value);
25749
+ }
25750
+ }
25751
+ function syntheticToolCallId(name, index) {
25752
+ const normalizedName = name.replace(/[^a-zA-Z0-9_-]/g, "_") || "tool";
25753
+ return `ollama_call_${normalizedName}_${index}`;
25754
+ }
25755
+ function normalizeToolCall(toolCall, index) {
25756
+ const name = toolCall.function?.name;
25757
+ if (typeof name !== "string" || name.length === 0) {
25758
+ return void 0;
25759
+ }
25760
+ return {
25761
+ id: typeof toolCall.id === "string" && toolCall.id.length > 0 ? toolCall.id : syntheticToolCallId(name, index),
25762
+ type: "function",
25763
+ function: {
25764
+ name,
25765
+ arguments: stringifyArguments(toolCall.function?.arguments)
25766
+ }
25767
+ };
25768
+ }
25769
+ function normalizeToolCalls(toolCalls, syntheticIdOffset = 0) {
25770
+ if (!Array.isArray(toolCalls)) {
25771
+ return [];
25772
+ }
25773
+ return toolCalls.flatMap((toolCall, index) => {
25774
+ const normalized = normalizeToolCall(toolCall, syntheticIdOffset + index);
25775
+ return normalized ? [normalized] : [];
25776
+ });
25777
+ }
25778
+ function countOllamaToolCalls(messages) {
25779
+ if (!Array.isArray(messages)) {
25780
+ return 0;
25781
+ }
25782
+ return messages.reduce(
25783
+ (count, message) => count + (isObject(message) && Array.isArray(message.tool_calls) ? message.tool_calls.length : 0),
25784
+ 0
25785
+ );
25786
+ }
25787
+ function imageBytes(value) {
25788
+ if (value instanceof Uint8Array) {
25789
+ return value;
25790
+ }
25791
+ if (value instanceof ArrayBuffer) {
25792
+ return new Uint8Array(value);
25793
+ }
25794
+ if (typeof value !== "string" || value.startsWith("data:")) {
25795
+ return void 0;
25796
+ }
25797
+ try {
25798
+ const decoded = atob(value.slice(0, 24));
25799
+ return Uint8Array.from(decoded, (character) => character.charCodeAt(0));
25800
+ } catch {
25801
+ return void 0;
25802
+ }
25803
+ }
25804
+ function inferImageMediaType(value) {
25805
+ if (typeof value === "string") {
25806
+ const dataUrlType = value.match(/^data:(image\/[^;]+);base64,/i)?.[1];
25807
+ if (dataUrlType) {
25808
+ return dataUrlType;
25809
+ }
25810
+ }
25811
+ const bytes = imageBytes(value);
25812
+ if (!bytes) {
25813
+ return void 0;
25814
+ }
25815
+ if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
25816
+ return "image/png";
25817
+ }
25818
+ if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
25819
+ return "image/jpeg";
25820
+ }
25821
+ const signature = String.fromCharCode(...bytes.slice(0, 12));
25822
+ if (signature.startsWith("GIF87a") || signature.startsWith("GIF89a")) {
25823
+ return "image/gif";
25824
+ }
25825
+ if (signature.startsWith("RIFF") && signature.slice(8, 12) === "WEBP") {
25826
+ return "image/webp";
25827
+ }
25828
+ return void 0;
25829
+ }
25830
+ function normalizeTextAndImages(content, images) {
25831
+ if (!images || images.length === 0) {
25832
+ return { content };
25833
+ }
25834
+ const imageParts = [];
25835
+ const unrecognizedImages = [];
25836
+ for (const image of images) {
25837
+ let localImagePath;
25838
+ let localPathMediaType;
25839
+ if (typeof image === "string" && !/^data:/i.test(image) && !/^https?:\/\//i.test(image)) {
25840
+ const extension = image.match(/\.([a-z0-9]+)$/i)?.[1]?.toLowerCase();
25841
+ const extensionMediaType = {
25842
+ png: "image/png",
25843
+ jpg: "image/jpeg",
25844
+ jpeg: "image/jpeg",
25845
+ gif: "image/gif",
25846
+ webp: "image/webp"
25847
+ }[extension ?? ""];
25848
+ if (extensionMediaType && isomorph_default.statSync) {
25849
+ try {
25850
+ if (isomorph_default.statSync(image).isFile()) {
25851
+ localImagePath = image;
25852
+ localPathMediaType = extensionMediaType;
25853
+ }
25854
+ } catch {
25855
+ }
25856
+ }
25857
+ }
25858
+ const mediaType = localPathMediaType ?? inferImageMediaType(image);
25859
+ if (!mediaType) {
25860
+ unrecognizedImages.push(image);
25861
+ continue;
25862
+ }
25863
+ const processedImage = localImagePath ? new Attachment({
25864
+ data: localImagePath,
25865
+ filename: localImagePath.split(/[\\/]/).at(-1) ?? "image",
25866
+ contentType: mediaType
25867
+ }) : processInputAttachments({
25868
+ type: "image",
25869
+ image,
25870
+ mediaType
25871
+ }).image;
25872
+ imageParts.push({
25873
+ type: "image_url",
25874
+ image_url: { url: processedImage }
25875
+ });
25876
+ }
25877
+ return {
25878
+ content: imageParts.length > 0 ? [...content ? [{ type: "text", text: content }] : [], ...imageParts] : content,
25879
+ ...unrecognizedImages.length > 0 ? { unrecognizedImages } : {}
25880
+ };
25881
+ }
25882
+ function normalizeMessage(message, toolCallId, syntheticToolCallIdOffset = 0) {
25883
+ if (typeof message.role !== "string") {
25884
+ return void 0;
25885
+ }
25886
+ const toolCalls = normalizeToolCalls(
25887
+ message.tool_calls,
25888
+ syntheticToolCallIdOffset
25889
+ );
25890
+ if (message.role === "tool") {
25891
+ const toolName = typeof message.tool_name === "string" && message.tool_name.length > 0 ? message.tool_name : "tool";
25892
+ return {
25893
+ role: "tool",
25894
+ tool_call_id: toolCallId ?? syntheticToolCallId(toolName, 0),
25895
+ content: typeof message.content === "string" ? message.content : ""
25896
+ };
25897
+ }
25898
+ const normalizedContent = normalizeTextAndImages(
25899
+ typeof message.content === "string" ? message.content || (toolCalls.length > 0 ? null : "") : toolCalls.length > 0 ? null : "",
25900
+ message.images
25901
+ );
25902
+ return {
25903
+ role: message.role,
25904
+ content: normalizedContent.content,
25905
+ ...typeof message.thinking === "string" && message.thinking.length > 0 ? { reasoning: message.thinking } : {},
25906
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
25907
+ ...normalizedContent.unrecognizedImages ? { images: normalizedContent.unrecognizedImages } : {}
25908
+ };
25909
+ }
25910
+ function normalizeMessages(messages) {
25911
+ if (!Array.isArray(messages)) {
25912
+ return [];
25913
+ }
25914
+ const pendingToolCallIds = /* @__PURE__ */ new Map();
25915
+ let syntheticToolCallIdOffset = 0;
25916
+ return messages.flatMap((message) => {
25917
+ if (!isObject(message)) {
25918
+ return [];
25919
+ }
25920
+ const ollamaMessage = message;
25921
+ let toolCallId;
25922
+ if (ollamaMessage.role === "tool") {
25923
+ const toolName = ollamaMessage.tool_name;
25924
+ if (typeof toolName === "string") {
25925
+ toolCallId = pendingToolCallIds.get(toolName)?.shift();
25926
+ }
25927
+ }
25928
+ const normalized = normalizeMessage(
25929
+ ollamaMessage,
25930
+ toolCallId,
25931
+ syntheticToolCallIdOffset
25932
+ );
25933
+ if (Array.isArray(ollamaMessage.tool_calls)) {
25934
+ syntheticToolCallIdOffset += ollamaMessage.tool_calls.length;
25935
+ }
25936
+ if (ollamaMessage.role === "assistant" && normalized) {
25937
+ const toolCalls = Array.isArray(normalized.tool_calls) ? normalized.tool_calls : [];
25938
+ for (const toolCall of toolCalls) {
25939
+ if (!isObject(toolCall) || !isObject(toolCall.function)) {
25940
+ continue;
25941
+ }
25942
+ const name = toolCall.function.name;
25943
+ const id = toolCall.id;
25944
+ if (typeof name === "string" && typeof id === "string") {
25945
+ const ids = pendingToolCallIds.get(name) ?? [];
25946
+ ids.push(id);
25947
+ pendingToolCallIds.set(name, ids);
25948
+ }
25949
+ }
25950
+ }
25951
+ return normalized ? [normalized] : [];
25952
+ });
25953
+ }
25954
+ function normalizeToolDefinition(tool) {
25955
+ const fn = tool.function;
25956
+ if (!fn || typeof fn.name !== "string" || fn.name.length === 0) {
25957
+ return void 0;
25958
+ }
25959
+ return {
25960
+ type: "function",
25961
+ function: {
25962
+ name: fn.name,
25963
+ ...typeof fn.description === "string" ? { description: fn.description } : {},
25964
+ ...isObject(fn.parameters) ? { parameters: fn.parameters } : {}
25965
+ }
25966
+ };
25967
+ }
25968
+ function extractToolsMetadata(tools) {
25969
+ if (!Array.isArray(tools)) {
25970
+ return {};
25971
+ }
25972
+ const normalized = tools.flatMap((tool) => {
25973
+ if (!isObject(tool)) {
25974
+ return [];
25975
+ }
25976
+ const definition = normalizeToolDefinition(tool);
25977
+ return definition ? [definition] : [];
25978
+ });
25979
+ return normalized.length > 0 ? { tools: normalized } : {};
25980
+ }
25981
+ function extractOptionsMetadata(options) {
25982
+ if (!isObject(options)) {
25983
+ return {};
25984
+ }
25985
+ const metadata = {};
25986
+ const mappings = [
25987
+ ["temperature", "temperature"],
25988
+ ["top_p", "top_p"],
25989
+ ["num_predict", "max_tokens"],
25990
+ ["frequency_penalty", "frequency_penalty"],
25991
+ ["presence_penalty", "presence_penalty"],
25992
+ ["stop", "stop"]
25993
+ ];
25994
+ for (const [source, target] of mappings) {
25995
+ if (options[source] !== void 0) {
25996
+ metadata[target] = options[source];
25997
+ }
25998
+ }
25999
+ return metadata;
26000
+ }
26001
+ function extractRequestMetadata(request) {
26002
+ return {
26003
+ provider: "ollama",
26004
+ ...typeof request?.model === "string" ? { model: request.model } : {},
26005
+ ...extractOptionsMetadata(request?.options),
26006
+ ...request?.format !== void 0 ? { response_format: request.format } : {}
26007
+ };
26008
+ }
26009
+ function extractOllamaChatInput([request]) {
26010
+ return {
26011
+ input: normalizeMessages(request.messages),
26012
+ metadata: {
26013
+ ...extractRequestMetadata(request),
26014
+ ...extractToolsMetadata(request.tools)
26015
+ }
26016
+ };
26017
+ }
26018
+ function extractOllamaGenerateInput([request]) {
26019
+ const normalizedPrompt = normalizeTextAndImages(
26020
+ typeof request.prompt === "string" ? request.prompt : "",
26021
+ Array.isArray(request.images) ? request.images : void 0
26022
+ );
26023
+ const input = [
26024
+ ...typeof request.system === "string" ? [{ role: "system", content: request.system }] : [],
26025
+ {
26026
+ role: "user",
26027
+ content: normalizedPrompt.content,
26028
+ ...typeof request.suffix === "string" ? { suffix: request.suffix } : {},
26029
+ ...normalizedPrompt.unrecognizedImages ? { images: normalizedPrompt.unrecognizedImages } : {}
26030
+ }
26031
+ ];
26032
+ return {
26033
+ input,
26034
+ metadata: extractRequestMetadata(request)
26035
+ };
26036
+ }
26037
+ function extractOllamaEmbedInput([request]) {
26038
+ return {
26039
+ input: request.input,
26040
+ metadata: extractRequestMetadata(request)
26041
+ };
26042
+ }
26043
+ function extractOllamaChatOutput(result, syntheticToolCallIdOffset = 0) {
26044
+ if (!isObject(result) || !isObject(result.message)) {
26045
+ return void 0;
26046
+ }
26047
+ const message = normalizeMessage(
26048
+ result.message,
26049
+ void 0,
26050
+ syntheticToolCallIdOffset
26051
+ );
26052
+ if (!message) {
26053
+ return void 0;
26054
+ }
26055
+ const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
26056
+ return [
26057
+ {
26058
+ index: 0,
26059
+ finish_reason: normalizeFinishReason(result, toolCalls.length > 0),
26060
+ message
26061
+ }
26062
+ ];
26063
+ }
26064
+ function extractOllamaGenerateOutput(result) {
26065
+ if (!isObject(result) || typeof result.response !== "string") {
26066
+ return void 0;
26067
+ }
26068
+ return [
26069
+ {
26070
+ index: 0,
26071
+ finish_reason: normalizeFinishReason(result),
26072
+ message: {
26073
+ role: "assistant",
26074
+ content: result.response,
26075
+ ...typeof result.thinking === "string" && result.thinking.length > 0 ? { reasoning: result.thinking } : {}
26076
+ }
26077
+ }
26078
+ ];
26079
+ }
26080
+ function extractOllamaEmbedOutput(result) {
26081
+ const embedding = Array.isArray(result?.embeddings) ? result.embeddings[0] : void 0;
26082
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
26083
+ }
26084
+ function extractOllamaResponseMetadata(result) {
26085
+ return typeof result?.model === "string" ? { model: result.model } : void 0;
26086
+ }
26087
+ function extractOllamaMetrics(result) {
26088
+ const metrics = {};
26089
+ const promptTokens = result?.prompt_eval_count;
26090
+ const completionTokens = result?.eval_count;
26091
+ if (isNonNegativeNumber(promptTokens)) {
26092
+ metrics.prompt_tokens = promptTokens;
26093
+ }
26094
+ if (isNonNegativeNumber(completionTokens)) {
26095
+ metrics.completion_tokens = completionTokens;
26096
+ }
26097
+ if (isNonNegativeNumber(promptTokens) || isNonNegativeNumber(completionTokens)) {
26098
+ metrics.tokens = (isNonNegativeNumber(promptTokens) ? promptTokens : 0) + (isNonNegativeNumber(completionTokens) ? completionTokens : 0);
26099
+ }
26100
+ return metrics;
26101
+ }
26102
+ function aggregateOllamaChatChunks(chunks, _result, event, _startTime) {
26103
+ const last = chunks.at(-1);
26104
+ const message = {
26105
+ role: "assistant",
26106
+ content: chunks.map((chunk) => chunk.message?.content ?? "").join(""),
26107
+ thinking: chunks.map((chunk) => chunk.message?.thinking ?? "").join(""),
26108
+ tool_calls: chunks.flatMap((chunk) => chunk.message?.tool_calls ?? [])
26109
+ };
26110
+ const response = {
26111
+ ...last,
26112
+ message
26113
+ };
26114
+ return {
26115
+ output: extractOllamaChatOutput(
26116
+ response,
26117
+ countOllamaToolCalls(event?.arguments?.[0]?.messages)
26118
+ ),
26119
+ metrics: extractOllamaMetrics(last ?? {}),
26120
+ metadata: extractOllamaResponseMetadata(last ?? {})
26121
+ };
26122
+ }
26123
+ function aggregateOllamaGenerateChunks(chunks, _result, _event, _startTime) {
26124
+ const last = chunks.at(-1);
26125
+ const response = {
26126
+ ...last,
26127
+ response: chunks.map((chunk) => chunk.response ?? "").join(""),
26128
+ thinking: chunks.map((chunk) => chunk.thinking ?? "").join("")
26129
+ };
26130
+ return {
26131
+ output: extractOllamaGenerateOutput(response),
26132
+ metrics: extractOllamaMetrics(last ?? {}),
26133
+ metadata: extractOllamaResponseMetadata(last ?? {})
26134
+ };
26135
+ }
26136
+
24436
26137
  // src/instrumentation/plugins/google-adk-channels.ts
24437
26138
  var googleADKChannels = defineChannels(
24438
26139
  "@google/adk",
@@ -27217,7 +28918,7 @@ function getStringProperty2(obj, key) {
27217
28918
  return typeof value === "string" ? value : void 0;
27218
28919
  }
27219
28920
  function extractMetricsFromUsage(usage) {
27220
- const metrics = {
28921
+ const rawMetrics = {
27221
28922
  prompt_tokens: usage.inputTokens,
27222
28923
  completion_tokens: usage.outputTokens,
27223
28924
  ...extractAnthropicCacheTokens(
@@ -27226,10 +28927,10 @@ function extractMetricsFromUsage(usage) {
27226
28927
  )
27227
28928
  };
27228
28929
  if (usage.reasoningTokens !== void 0) {
27229
- metrics.completion_reasoning_tokens = usage.reasoningTokens;
27230
- metrics.reasoning_tokens = usage.reasoningTokens;
28930
+ rawMetrics.completion_reasoning_tokens = usage.reasoningTokens;
28931
+ rawMetrics.reasoning_tokens = usage.reasoningTokens;
27231
28932
  }
27232
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
28933
+ const metrics = finalizeAnthropicTokens(rawMetrics);
27233
28934
  const metadata = {
27234
28935
  model: usage.model
27235
28936
  };
@@ -28168,17 +29869,20 @@ var FlueObserveBridge = class {
28168
29869
  return;
28169
29870
  }
28170
29871
  const metadata = {
29872
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
28171
29873
  ...extractEventMetadata(event),
28172
29874
  "flue.operation": event.operationKind,
28173
29875
  provider: "flue"
28174
29876
  };
28175
29877
  const parent = this.parentSpanForEvent(event);
28176
- const span = startFlueSpan(parent, {
29878
+ const args = {
28177
29879
  name: `flue.${event.operationKind}`,
28178
29880
  spanAttributes: { type: "task" /* TASK */ },
28179
29881
  startTime: eventTime(event.timestamp),
28180
29882
  event: { metadata }
28181
- });
29883
+ };
29884
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
29885
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
28182
29886
  this.operationsById.set(event.operationId, { metadata, span });
28183
29887
  }
28184
29888
  handleOperation(event) {
@@ -28186,16 +29890,21 @@ var FlueObserveBridge = class {
28186
29890
  return;
28187
29891
  }
28188
29892
  const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
28189
- const output = operationOutput(event);
29893
+ const output = operationOutput(event) ?? outputFromAgentTurn(state.latestAgentOutput);
28190
29894
  const metadata = {
28191
29895
  ...state.metadata,
28192
29896
  ...extractEventMetadata(event),
28193
29897
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
28194
29898
  ...event.usage ? { "flue.usage": event.usage } : {}
28195
29899
  };
29900
+ const input = flueOperationInput(event);
29901
+ if (!state.loggedInput && input !== void 0) {
29902
+ safeLog3(state.span, { input });
29903
+ state.loggedInput = true;
29904
+ }
28196
29905
  this.finishPendingChildrenForOperation(event, output);
28197
29906
  safeLog3(state.span, {
28198
- ...event.isError ? { error: toLoggedError(event.error) } : {},
29907
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
28199
29908
  metadata,
28200
29909
  metrics: durationMetrics2(event.durationMs),
28201
29910
  output
@@ -28209,6 +29918,8 @@ var FlueObserveBridge = class {
28209
29918
  return;
28210
29919
  }
28211
29920
  const input = flueTurnRequestInput(event);
29921
+ const operation = event.operationId ? this.operationsById.get(event.operationId) : void 0;
29922
+ const turnInput = prepareFlueTurnInput(event, input, operation);
28212
29923
  const model = flueTurnRequestModel(event);
28213
29924
  const provider = flueTurnRequestProvider(event);
28214
29925
  const api = flueTurnRequestApi(event);
@@ -28221,20 +29932,22 @@ var FlueObserveBridge = class {
28221
29932
  ...provider ? { "flue.provider": provider } : {},
28222
29933
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
28223
29934
  ...reasoning ? { reasoning } : {},
28224
- ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
28225
- ...input?.tools ? { tools: input.tools } : {}
29935
+ ...turnInput.metadata
28226
29936
  };
28227
29937
  const parent = this.parentSpanForTurn(event);
28228
29938
  const span = startFlueSpan(parent, {
28229
- name: `llm:${model ?? event.purpose ?? "unknown"}`,
29939
+ name: "flue.turn",
28230
29940
  spanAttributes: { type: "llm" /* LLM */ },
28231
29941
  startTime: eventTime(event.timestamp),
28232
29942
  event: {
28233
- input: input?.messages,
29943
+ input: turnInput.messages,
28234
29944
  metadata
28235
29945
  }
28236
29946
  });
28237
- this.logOperationInput(event.operationId, input?.messages ?? input);
29947
+ this.logOperationInput(
29948
+ event.operationId,
29949
+ latestUserMessageInput(input?.messages)
29950
+ );
28238
29951
  this.turnsByKey.set(key, { metadata, span });
28239
29952
  }
28240
29953
  handleTurn(event) {
@@ -28270,6 +29983,12 @@ var FlueObserveBridge = class {
28270
29983
  },
28271
29984
  output
28272
29985
  });
29986
+ if (event.purpose === "agent" && event.operationId) {
29987
+ const operation = this.operationsById.get(event.operationId);
29988
+ if (operation) {
29989
+ operation.latestAgentOutput = output;
29990
+ }
29991
+ }
28273
29992
  safeEnd(state.span, eventTime(event.timestamp));
28274
29993
  this.turnsByKey.delete(key);
28275
29994
  }
@@ -28349,7 +30068,7 @@ var FlueObserveBridge = class {
28349
30068
  return;
28350
30069
  }
28351
30070
  safeLog3(state.span, {
28352
- ...event.isError ? { error: toLoggedError(event.result) } : {},
30071
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.result) } : {},
28353
30072
  metadata: {
28354
30073
  ...state.metadata,
28355
30074
  ...extractEventMetadata(event),
@@ -28395,6 +30114,7 @@ var FlueObserveBridge = class {
28395
30114
  ...event.usage ? { "flue.usage": event.usage } : {}
28396
30115
  };
28397
30116
  safeLog3(state.span, {
30117
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
28398
30118
  metadata,
28399
30119
  metrics: {
28400
30120
  ...durationMetrics2(event.durationMs),
@@ -28474,16 +30194,20 @@ var FlueObserveBridge = class {
28474
30194
  }
28475
30195
  startSyntheticOperation(event) {
28476
30196
  const metadata = {
30197
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
28477
30198
  ...extractEventMetadata(event),
28478
30199
  "flue.operation": event.operationKind,
28479
30200
  provider: "flue"
28480
30201
  };
28481
- const span = startFlueSpan(this.parentSpanForEvent(event), {
30202
+ const args = {
28482
30203
  name: `flue.${event.operationKind}`,
28483
30204
  spanAttributes: { type: "task" /* TASK */ },
28484
30205
  startTime: eventTime(event.timestamp),
28485
30206
  event: { metadata }
28486
- });
30207
+ };
30208
+ const parent = this.parentSpanForEvent(event);
30209
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
30210
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
28487
30211
  return { metadata, span };
28488
30212
  }
28489
30213
  startSyntheticTurn(event) {
@@ -28499,7 +30223,7 @@ var FlueObserveBridge = class {
28499
30223
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
28500
30224
  };
28501
30225
  const span = startFlueSpan(this.parentSpanForEvent(event), {
28502
- name: `llm:${model ?? event.purpose ?? "unknown"}`,
30226
+ name: "flue.turn",
28503
30227
  spanAttributes: { type: "llm" /* LLM */ },
28504
30228
  startTime: eventTime(event.timestamp),
28505
30229
  event: { metadata }
@@ -28631,7 +30355,10 @@ function extractEventMetadata(event, ctx) {
28631
30355
  return {
28632
30356
  ...event.runId ? { "flue.run_id": event.runId } : {},
28633
30357
  ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
30358
+ ...event.submissionId ? { "flue.submission_id": event.submissionId } : {},
28634
30359
  ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
30360
+ ...event.agentName ? { "flue.agent_name": event.agentName } : {},
30361
+ ...event.conversationId ? { "flue.conversation_id": event.conversationId } : {},
28635
30362
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
28636
30363
  ...event.session ? { "flue.session": event.session } : {},
28637
30364
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
@@ -28659,8 +30386,73 @@ function flueRunInput(event) {
28659
30386
  function flueTurnRequestInput(event) {
28660
30387
  return event.request?.input ?? event.input;
28661
30388
  }
30389
+ function prepareFlueTurnInput(event, input, operation) {
30390
+ const messages = input?.messages;
30391
+ const tracksUserTurn = event.purpose === "agent" && operation?.metadata["flue.operation"] === "prompt" && Array.isArray(messages);
30392
+ if (!tracksUserTurn) {
30393
+ return {
30394
+ messages,
30395
+ metadata: {
30396
+ ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
30397
+ ...input?.tools ? { tools: input.tools } : {}
30398
+ }
30399
+ };
30400
+ }
30401
+ const previous = operation.turnInputState;
30402
+ const previousMessageCount = previous?.messageCount ?? 0;
30403
+ const boundaryFingerprint = messages.length > 0 ? fingerprintJsonValue(messages[messages.length - 1]) : void 0;
30404
+ const continuesPreviousInput = previous !== void 0 && messages.length >= previousMessageCount && (previousMessageCount === 0 || previous.boundaryFingerprint !== void 0 && previous.boundaryFingerprint === fingerprintJsonValue(messages[previousMessageCount - 1]));
30405
+ const inputMode = previous === void 0 ? "full" : continuesPreviousInput ? "delta" : "reset";
30406
+ const systemPromptFingerprint = fingerprintJsonValue(input?.systemPrompt);
30407
+ const toolsFingerprint = fingerprintJsonValue(input?.tools);
30408
+ operation.turnInputState = {
30409
+ ...boundaryFingerprint !== void 0 ? { boundaryFingerprint } : {},
30410
+ messageCount: messages.length,
30411
+ ...systemPromptFingerprint !== void 0 ? { systemPromptFingerprint } : {},
30412
+ ...toolsFingerprint !== void 0 ? { toolsFingerprint } : {}
30413
+ };
30414
+ return {
30415
+ messages: continuesPreviousInput ? messages.slice(previousMessageCount) : messages,
30416
+ metadata: {
30417
+ "flue.input_mode": inputMode,
30418
+ ...continuesPreviousInput ? { "flue.input_message_offset": previousMessageCount } : {},
30419
+ ...input?.systemPrompt && (!continuesPreviousInput || systemPromptFingerprint !== previous?.systemPromptFingerprint) ? { "flue.system_prompt": input.systemPrompt } : {},
30420
+ ...input?.tools && (!continuesPreviousInput || toolsFingerprint !== previous?.toolsFingerprint) ? { tools: input.tools } : {}
30421
+ }
30422
+ };
30423
+ }
30424
+ function fingerprintJsonValue(value) {
30425
+ try {
30426
+ const serialized = JSON.stringify(value);
30427
+ if (serialized === void 0) {
30428
+ return void 0;
30429
+ }
30430
+ let hash = 2166136261;
30431
+ for (let i = 0; i < serialized.length; i++) {
30432
+ hash = Math.imul(hash ^ serialized.charCodeAt(i), 16777619);
30433
+ }
30434
+ return `${serialized.length}:${hash >>> 0}`;
30435
+ } catch {
30436
+ return void 0;
30437
+ }
30438
+ }
30439
+ function latestUserMessageInput(messages) {
30440
+ if (!messages) {
30441
+ return void 0;
30442
+ }
30443
+ for (let i = messages.length - 1; i >= 0; i--) {
30444
+ const message = messages[i];
30445
+ if (isObjectLike(message) && Reflect.get(message, "role") === "user") {
30446
+ return [message];
30447
+ }
30448
+ }
30449
+ return void 0;
30450
+ }
30451
+ function flueOperationInput(event) {
30452
+ return typeof event.agentInput?.text === "string" ? [{ content: event.agentInput.text, role: "user" }] : void 0;
30453
+ }
28662
30454
  function flueTurnRequestModel(event) {
28663
- return event.request?.model ?? event.model;
30455
+ return event.request?.requestedModel ?? event.request?.model ?? event.model;
28664
30456
  }
28665
30457
  function flueTurnRequestProvider(event) {
28666
30458
  return event.request?.providerName ?? event.provider ?? event.request?.providerId;
@@ -28669,10 +30461,10 @@ function flueTurnRequestApi(event) {
28669
30461
  return event.request?.api ?? event.api;
28670
30462
  }
28671
30463
  function flueTurnRequestReasoning(event) {
28672
- return event.request?.reasoning ?? event.reasoning;
30464
+ return event.request?.reasoningLevel ?? event.request?.reasoning ?? event.reasoning;
28673
30465
  }
28674
30466
  function flueTurnModel(event) {
28675
- return event.request?.model ?? event.model;
30467
+ return event.response?.responseModel ?? event.request?.requestedModel ?? event.request?.model ?? event.model;
28676
30468
  }
28677
30469
  function flueTurnProvider(event) {
28678
30470
  return event.request?.providerName ?? event.provider ?? event.request?.providerId;
@@ -28687,7 +30479,7 @@ function flueTurnOutput(event) {
28687
30479
  return event.response?.output ?? event.output;
28688
30480
  }
28689
30481
  function flueTurnStopReason(event) {
28690
- return event.response?.stopReason ?? event.stopReason;
30482
+ return event.response?.finishReason ?? event.response?.stopReason ?? event.stopReason;
28691
30483
  }
28692
30484
  function flueTurnError(event) {
28693
30485
  return event.response?.error ?? event.response?.errorInfo?.message ?? event.error;
@@ -28702,6 +30494,9 @@ function flueToolInput(event) {
28702
30494
  return event.input;
28703
30495
  }
28704
30496
  function flueToolOutput(event) {
30497
+ if (Object.hasOwn(event, "effectiveResult")) {
30498
+ return event.effectiveResult;
30499
+ }
28705
30500
  return event.output !== void 0 ? event.output : event.result;
28706
30501
  }
28707
30502
  function flueToolError(event) {
@@ -28709,10 +30504,36 @@ function flueToolError(event) {
28709
30504
  }
28710
30505
  function operationOutput(event) {
28711
30506
  if (event.operationKind === "prompt" || event.operationKind === "skill") {
28712
- return llmResultFromOperationResult(event.result);
30507
+ return outputFromAgentInvocation(event.agentOutput) ?? llmResultFromOperationResult(event.result);
28713
30508
  }
28714
30509
  return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
28715
30510
  }
30511
+ function outputFromAgentInvocation(output) {
30512
+ if (output?.type === "text") {
30513
+ return output.text;
30514
+ }
30515
+ if (output?.type === "data") {
30516
+ return output.data;
30517
+ }
30518
+ return void 0;
30519
+ }
30520
+ function outputFromAgentTurn(output) {
30521
+ if (!isObjectLike(output)) {
30522
+ return output;
30523
+ }
30524
+ const content = Reflect.get(output, "content");
30525
+ if (!Array.isArray(content)) {
30526
+ return output;
30527
+ }
30528
+ const text = content.flatMap((part) => {
30529
+ if (!isObjectLike(part) || Reflect.get(part, "type") !== "text") {
30530
+ return [];
30531
+ }
30532
+ const value = Reflect.get(part, "text");
30533
+ return typeof value === "string" ? [value] : [];
30534
+ });
30535
+ return text.length > 0 ? text.join("") : output;
30536
+ }
28716
30537
  function llmResultFromOperationResult(result) {
28717
30538
  if (!isObjectLike(result)) {
28718
30539
  return result;
@@ -28787,6 +30608,21 @@ function startFlueSpan(parent, args) {
28787
30608
  withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE)
28788
30609
  );
28789
30610
  }
30611
+ function startFlueRootSpan(args) {
30612
+ const state = _internalGetGlobalState();
30613
+ const spanId = state.idGenerator.getSpanId();
30614
+ const rootSpanId = state.idGenerator.shareRootSpanId() ? spanId : state.idGenerator.getTraceId();
30615
+ return withCurrent(
30616
+ NOOP_SPAN,
30617
+ () => startSpan({
30618
+ ...withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE),
30619
+ parentSpanIds: { parentSpanIds: [], rootSpanId },
30620
+ spanId,
30621
+ state
30622
+ }),
30623
+ state
30624
+ );
30625
+ }
28790
30626
  function runWithCurrentSpanStore(span, next) {
28791
30627
  const state = _internalGetGlobalState();
28792
30628
  const contextManager = state?.contextManager;
@@ -28811,7 +30647,7 @@ function safeEnd(span, endTime) {
28811
30647
  }
28812
30648
  }
28813
30649
  function logInstrumentationError3(label, error) {
28814
- console.error(`Error in ${label} instrumentation:`, error);
30650
+ debugLogger.debug(`Error in ${label} instrumentation:`, error);
28815
30651
  }
28816
30652
 
28817
30653
  // src/wrappers/langchain/callback-handler.ts
@@ -29740,12 +31576,13 @@ var piCodingAgentChannels = defineChannels(
29740
31576
  );
29741
31577
 
29742
31578
  // src/instrumentation/plugins/pi-coding-agent-plugin.ts
29743
- var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
31579
+ var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
31580
+ var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
29744
31581
  var piPromptContextStore;
29745
31582
  var PiCodingAgentPlugin = class extends BasePlugin {
29746
31583
  activePromptStates = /* @__PURE__ */ new Set();
29747
31584
  onEnable() {
29748
- this.subscribeToPrompt();
31585
+ this.interceptPrompt();
29749
31586
  }
29750
31587
  onDisable() {
29751
31588
  for (const unsubscribe of this.unsubscribers) {
@@ -29753,65 +31590,74 @@ var PiCodingAgentPlugin = class extends BasePlugin {
29753
31590
  }
29754
31591
  this.unsubscribers = [];
29755
31592
  for (const state of [...this.activePromptStates]) {
29756
- void finalizePiPromptRun(state).catch((error) => {
29757
- logInstrumentationError4("Pi Coding Agent disable cleanup", error);
29758
- });
31593
+ finishPiPromptRun(state);
29759
31594
  }
29760
31595
  }
29761
- subscribeToPrompt() {
29762
- const channel2 = piCodingAgentChannels.prompt.tracingChannel();
29763
- const states = /* @__PURE__ */ new WeakMap();
29764
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
29765
- const handlers = {
29766
- start: (event) => {
29767
- const state = startPiPromptRun(event, (state2) => {
29768
- this.activePromptStates.delete(state2);
29769
- });
29770
- if (state) {
29771
- this.activePromptStates.add(state);
29772
- states.set(event, state);
29773
- }
29774
- },
29775
- asyncEnd: async (event) => {
29776
- const state = states.get(event);
29777
- if (!state) {
29778
- return;
29779
- }
29780
- states.delete(event);
29781
- state.promptCallEnded = true;
29782
- if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
29783
- if (!state.sawStreamFn) {
29784
- state.queued = true;
29785
- if (!state.streamPatchState.queuedPromptStates.includes(state)) {
29786
- state.streamPatchState.queuedPromptStates.push(state);
29787
- }
31596
+ interceptPrompt() {
31597
+ this.unsubscribers.push(
31598
+ piCodingAgentChannels.prompt.intercept(
31599
+ (target, thisArg, args, additional) => {
31600
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
31601
+ let state;
31602
+ try {
31603
+ state = startPiPromptRun(
31604
+ {
31605
+ ...additional,
31606
+ arguments: args,
31607
+ self: thisArg
31608
+ },
31609
+ (finalizedState) => {
31610
+ this.activePromptStates.delete(finalizedState);
31611
+ }
31612
+ );
31613
+ } catch (error) {
31614
+ logInstrumentationError4("Pi Coding Agent prompt start", error);
29788
31615
  }
29789
- return;
29790
- }
29791
- await finalizePiPromptRun(state);
29792
- },
29793
- error: async (event) => {
29794
- const state = states.get(event);
29795
- if (!state) {
29796
- return;
31616
+ if (!state) {
31617
+ return runWithAutoInstrumentationSuppressed(invokeTarget);
31618
+ }
31619
+ this.activePromptStates.add(state);
31620
+ return promptContextStore().run(
31621
+ state,
31622
+ () => runWithAutoInstrumentationSuppressed(() => {
31623
+ let result;
31624
+ try {
31625
+ result = invokeTarget();
31626
+ } catch (error) {
31627
+ finishPiPromptRun(state, error);
31628
+ throw error;
31629
+ }
31630
+ return Promise.resolve(result).then(
31631
+ (value) => {
31632
+ finishPiPromptCall(state);
31633
+ return value;
31634
+ },
31635
+ (error) => {
31636
+ finishPiPromptRun(state, error);
31637
+ throw error;
31638
+ }
31639
+ );
31640
+ })
31641
+ );
29797
31642
  }
29798
- states.delete(event);
29799
- await finalizePiPromptRun(state, event.error);
29800
- }
29801
- };
29802
- channel2.subscribe(handlers);
29803
- this.unsubscribers.push(() => {
29804
- unbindAutoInstrumentationSuppression?.();
29805
- channel2.unsubscribe(handlers);
29806
- });
31643
+ )
31644
+ );
29807
31645
  }
29808
31646
  };
31647
+ function finishPiPromptCall(state) {
31648
+ state.promptCallEnded = true;
31649
+ if (state.deferCompletionUntilTurnEnd && !state.turnEnded) {
31650
+ return;
31651
+ }
31652
+ finishPiPromptRun(state);
31653
+ }
29809
31654
  function startPiPromptRun(event, onFinalize) {
29810
31655
  const session = extractSession(event);
29811
31656
  const agent = session?.agent;
29812
31657
  if (!session || !isPiAgent(agent)) {
29813
31658
  return void 0;
29814
31659
  }
31660
+ installPiAgentInstrumentation(agent);
29815
31661
  const metadata = {
29816
31662
  ...extractSessionMetadata(session),
29817
31663
  ...extractPromptOptionsMetadata(event.arguments[1]),
@@ -29833,9 +31679,7 @@ function startPiPromptRun(event, onFinalize) {
29833
31679
  INSTRUMENTATION_NAMES.PI_CODING_AGENT
29834
31680
  )
29835
31681
  );
29836
- const streamPatchState = installPiStreamPatch(agent);
29837
31682
  const options = event.arguments[1];
29838
- const promptText = event.arguments[0];
29839
31683
  const state = {
29840
31684
  activeLlmSpans: /* @__PURE__ */ new Set(),
29841
31685
  activeToolSpans: /* @__PURE__ */ new Map(),
@@ -29847,29 +31691,10 @@ function startPiPromptRun(event, onFinalize) {
29847
31691
  metrics: {},
29848
31692
  onFinalize,
29849
31693
  promptCallEnded: false,
29850
- ...typeof promptText === "string" ? { promptText } : {},
29851
- queued: false,
29852
31694
  span,
29853
- sawStreamFn: false,
29854
31695
  startTime: getCurrentUnixTimestamp(),
29855
- streamPatchState,
29856
31696
  turnEnded: false
29857
31697
  };
29858
- state.restorePromptContext = enterPiPromptContext(state);
29859
- streamPatchState.activePromptStates.add(state);
29860
- try {
29861
- state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
29862
- try {
29863
- await runWithAutoInstrumentationSuppressed(
29864
- () => handlePiAgentEvent(state, agentEvent)
29865
- );
29866
- } catch (error) {
29867
- logInstrumentationError4("Pi Coding Agent event", error);
29868
- }
29869
- });
29870
- } catch (error) {
29871
- logInstrumentationError4("Pi Coding Agent event subscription", error);
29872
- }
29873
31698
  return state;
29874
31699
  }
29875
31700
  function extractSession(event) {
@@ -29883,111 +31708,55 @@ function promptContextStore() {
29883
31708
  piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
29884
31709
  return piPromptContextStore;
29885
31710
  }
29886
- function currentPromptContextFrames() {
29887
- return promptContextStore().getStore()?.frames ?? [];
29888
- }
29889
31711
  function currentPiPromptState() {
29890
- const frames = currentPromptContextFrames();
29891
- return frames[frames.length - 1]?.state;
29892
- }
29893
- function enterPiPromptContext(state) {
29894
- const frame = {
29895
- id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
29896
- state
29897
- };
29898
- promptContextStore().enterWith({
29899
- frames: [...currentPromptContextFrames(), frame]
29900
- });
29901
- return () => {
29902
- const frames = currentPromptContextFrames().filter(
29903
- (candidate) => candidate.id !== frame.id
29904
- );
29905
- promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
29906
- };
29907
- }
29908
- function installPiStreamPatch(agent) {
29909
- const existing = piStreamPatchStates.get(agent);
29910
- if (existing) {
29911
- if (agent.streamFn !== existing.wrappedStreamFn) {
29912
- debugLogger.debug(
29913
- "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
29914
- );
29915
- }
29916
- return existing;
29917
- }
29918
- const patchState = {
29919
- activePromptStates: /* @__PURE__ */ new Set(),
29920
- agent,
29921
- originalStreamFn: agent.streamFn,
29922
- queuedPromptStates: [],
29923
- wrappedStreamFn: agent.streamFn
29924
- };
29925
- patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
29926
- agent.streamFn = patchState.wrappedStreamFn;
29927
- piStreamPatchStates.set(agent, patchState);
29928
- return patchState;
29929
- }
29930
- function resolveStreamPromptState(patchState, context) {
29931
- let lastUserText;
29932
- if (Array.isArray(context.messages)) {
29933
- for (let i = context.messages.length - 1; i >= 0; i--) {
29934
- const message = context.messages[i];
29935
- if (isPiUserMessage(message)) {
29936
- if (typeof message.content === "string") {
29937
- lastUserText = message.content;
29938
- } else {
29939
- lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
29940
- }
29941
- break;
29942
- }
29943
- }
29944
- }
29945
- if (lastUserText !== void 0) {
29946
- const queuedMatch = patchState.queuedPromptStates.find(
29947
- (state) => state.promptText === lastUserText
29948
- );
29949
- if (queuedMatch) {
29950
- return queuedMatch;
29951
- }
29952
- const matches = [...patchState.activePromptStates].filter(
29953
- (state) => state.promptText === lastUserText
31712
+ return promptContextStore().getStore();
31713
+ }
31714
+ function installPiAgentInstrumentation(agent) {
31715
+ const existing = piAgentPatchStates.get(agent);
31716
+ if (!existing || agent.streamFn !== existing.wrappedStreamFn) {
31717
+ const patchState = {
31718
+ originalStreamFn: agent.streamFn,
31719
+ wrappedStreamFn: agent.streamFn
31720
+ };
31721
+ patchState.wrappedStreamFn = makeInstrumentedStreamFn(
31722
+ agent,
31723
+ patchState.originalStreamFn
29954
31724
  );
29955
- if (matches.length === 1) {
29956
- return matches[0];
29957
- }
31725
+ agent.streamFn = patchState.wrappedStreamFn;
31726
+ piAgentPatchStates.set(agent, patchState);
29958
31727
  }
29959
- const contextState = currentPiPromptState();
29960
- if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
29961
- return contextState;
31728
+ if (piAgentEventSubscriptions.has(agent)) {
31729
+ return;
29962
31730
  }
29963
- if (patchState.activePromptStates.size === 1) {
29964
- return [...patchState.activePromptStates][0];
31731
+ try {
31732
+ agent.subscribe(async (event) => {
31733
+ const state = currentPiPromptState();
31734
+ if (!state || state.agent !== agent || state.finalized) {
31735
+ return;
31736
+ }
31737
+ try {
31738
+ await runWithAutoInstrumentationSuppressed(
31739
+ () => handlePiAgentEvent(state, event)
31740
+ );
31741
+ } catch (error) {
31742
+ logInstrumentationError4("Pi Coding Agent event", error);
31743
+ }
31744
+ });
31745
+ piAgentEventSubscriptions.add(agent);
31746
+ } catch (error) {
31747
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
29965
31748
  }
29966
- return void 0;
29967
31749
  }
29968
- function makeSharedInstrumentedStreamFn(patchState) {
31750
+ function makeInstrumentedStreamFn(agent, originalStreamFn) {
29969
31751
  return async function instrumentedPiStreamFn(model, context, options) {
29970
- const state = resolveStreamPromptState(patchState, context);
29971
- if (!state) {
29972
- const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
29973
- model,
29974
- context,
29975
- options
29976
- ]);
29977
- return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
31752
+ const invokeOriginal = () => Reflect.apply(originalStreamFn, this, [model, context, options]);
31753
+ const state = currentPiPromptState();
31754
+ if (!state || state.agent !== agent || state.finalized) {
31755
+ return invokeOriginal();
29978
31756
  }
29979
- state.sawStreamFn = true;
29980
- removeQueuedPromptState(state);
29981
- state.streamPatchState.eventPromptState = state;
29982
31757
  const llmState = await startPiLlmSpan(state, model, context, options);
29983
31758
  try {
29984
- const stream = await runWithAutoInstrumentationSuppressed(
29985
- () => Reflect.apply(patchState.originalStreamFn, this, [
29986
- model,
29987
- context,
29988
- options
29989
- ])
29990
- );
31759
+ const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
29991
31760
  return patchAssistantMessageStream(stream, state, llmState);
29992
31761
  } catch (error) {
29993
31762
  finishPiLlmSpan(state, llmState, void 0, error);
@@ -30134,13 +31903,6 @@ async function handlePiAgentEvent(state, event) {
30134
31903
  if (state.finalized) {
30135
31904
  return;
30136
31905
  }
30137
- const eventPromptState = state.streamPatchState.eventPromptState;
30138
- if (eventPromptState && eventPromptState !== state) {
30139
- return;
30140
- }
30141
- if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
30142
- return;
30143
- }
30144
31906
  switch (event.type) {
30145
31907
  case "message_end":
30146
31908
  if (isPiAssistantMessage(event.message)) {
@@ -30155,11 +31917,8 @@ async function handlePiAgentEvent(state, event) {
30155
31917
  addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
30156
31918
  }
30157
31919
  }
30158
- if (state.streamPatchState.eventPromptState === state) {
30159
- state.streamPatchState.eventPromptState = void 0;
30160
- }
30161
31920
  if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
30162
- await finalizePiPromptRun(state);
31921
+ finishPiPromptRun(state);
30163
31922
  }
30164
31923
  return;
30165
31924
  case "tool_execution_start":
@@ -30232,19 +31991,13 @@ function finishPiToolSpan(state, event) {
30232
31991
  }
30233
31992
  }
30234
31993
  }
30235
- async function finalizePiPromptRun(state, error) {
31994
+ function finishPiPromptRun(state, error) {
30236
31995
  if (state.finalized) {
30237
31996
  return;
30238
31997
  }
30239
31998
  state.finalized = true;
30240
31999
  state.onFinalize?.(state);
30241
- restorePiStreamFn(state);
30242
- try {
30243
- state.unsubscribeAgent?.();
30244
- } catch (unsubscribeError) {
30245
- logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
30246
- }
30247
- await finishOpenLlmSpans(state, error);
32000
+ finishOpenLlmSpans(state, error);
30248
32001
  finishOpenToolSpans(state, error);
30249
32002
  const metadata = {
30250
32003
  ...state.metadata,
@@ -30261,34 +32014,14 @@ async function finalizePiPromptRun(state, error) {
30261
32014
  output: state.output
30262
32015
  });
30263
32016
  } finally {
30264
- state.span.end();
30265
- }
30266
- }
30267
- function restorePiStreamFn(state) {
30268
- const patchState = state.streamPatchState;
30269
- patchState.activePromptStates.delete(state);
30270
- removeQueuedPromptState(state);
30271
- if (patchState.eventPromptState === state) {
30272
- patchState.eventPromptState = void 0;
30273
- }
30274
- state.restorePromptContext?.();
30275
- if (patchState.activePromptStates.size > 0) {
30276
- return;
30277
- }
30278
- if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
30279
- patchState.agent.streamFn = patchState.originalStreamFn;
30280
- }
30281
- piStreamPatchStates.delete(patchState.agent);
30282
- }
30283
- function removeQueuedPromptState(state) {
30284
- state.queued = false;
30285
- const queuedPromptStates = state.streamPatchState.queuedPromptStates;
30286
- const index = queuedPromptStates.indexOf(state);
30287
- if (index >= 0) {
30288
- queuedPromptStates.splice(index, 1);
32017
+ try {
32018
+ state.span.end();
32019
+ } catch (endError) {
32020
+ logInstrumentationError4("Pi Coding Agent prompt end", endError);
32021
+ }
30289
32022
  }
30290
32023
  }
30291
- async function finishOpenLlmSpans(state, error) {
32024
+ function finishOpenLlmSpans(state, error) {
30292
32025
  for (const llmState of [...state.activeLlmSpans]) {
30293
32026
  finishPiLlmSpan(state, llmState, void 0, error);
30294
32027
  }
@@ -30369,7 +32102,7 @@ function normalizeAssistantMessage(message) {
30369
32102
  (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
30370
32103
  ).join("");
30371
32104
  const toolCalls = message.content.flatMap(
30372
- (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
32105
+ (part) => part.type === "toolCall" ? [normalizeToolCall2(part)] : []
30373
32106
  );
30374
32107
  return {
30375
32108
  role: "assistant",
@@ -30404,13 +32137,13 @@ function normalizeUserContent(content) {
30404
32137
  return part;
30405
32138
  });
30406
32139
  }
30407
- function normalizeToolCall(toolCall) {
32140
+ function normalizeToolCall2(toolCall) {
30408
32141
  return {
30409
32142
  id: toolCall.id,
30410
32143
  type: "function",
30411
32144
  function: {
30412
32145
  name: toolCall.name,
30413
- arguments: stringifyArguments(toolCall.arguments)
32146
+ arguments: stringifyArguments2(toolCall.arguments)
30414
32147
  }
30415
32148
  };
30416
32149
  }
@@ -30593,7 +32326,7 @@ function cleanMetrics5(metrics) {
30593
32326
  }
30594
32327
  return cleaned;
30595
32328
  }
30596
- function stringifyArguments(value) {
32329
+ function stringifyArguments2(value) {
30597
32330
  if (typeof value === "string") {
30598
32331
  return value;
30599
32332
  }
@@ -30789,8 +32522,7 @@ function startAgentStream(event, activeChildParents) {
30789
32522
  ...extractAgentMetadata2(agent),
30790
32523
  ...extractModelMetadata3(model),
30791
32524
  "strands.operation": "Agent.stream",
30792
- provider: extractProvider(model),
30793
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
32525
+ provider: extractProvider(model)
30794
32526
  };
30795
32527
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
30796
32528
  const attachmentCache = createStrandsAttachmentCache();
@@ -30840,8 +32572,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
30840
32572
  const metadata = {
30841
32573
  "strands.operation": operation,
30842
32574
  provider: "strands",
30843
- ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {},
30844
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
32575
+ ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
30845
32576
  };
30846
32577
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
30847
32578
  const input = processStrandsInputAttachments(event.arguments[0]);
@@ -31627,6 +33358,320 @@ function logInstrumentationError5(context, error) {
31627
33358
  debugLogger.debug(`${context}:`, error);
31628
33359
  }
31629
33360
 
33361
+ // src/instrumentation/plugins/voyageai-channels.ts
33362
+ var voyageAIChannels = defineChannels(
33363
+ "voyageai",
33364
+ {
33365
+ embed: channel({
33366
+ channelName: "embed",
33367
+ kind: "async"
33368
+ }),
33369
+ multimodalEmbed: channel({
33370
+ channelName: "multimodalEmbed",
33371
+ kind: "async"
33372
+ }),
33373
+ rerank: channel({
33374
+ channelName: "rerank",
33375
+ kind: "async"
33376
+ }),
33377
+ contextualizedEmbed: channel({
33378
+ channelName: "contextualizedEmbed",
33379
+ kind: "async"
33380
+ })
33381
+ },
33382
+ { instrumentationName: INSTRUMENTATION_NAMES.VOYAGEAI }
33383
+ );
33384
+
33385
+ // src/instrumentation/plugins/voyageai-plugin.ts
33386
+ var RERANK_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
33387
+ "model",
33388
+ "returnDocuments",
33389
+ "topK",
33390
+ "truncation"
33391
+ ]);
33392
+ var VoyageAIPlugin = class extends BasePlugin {
33393
+ onEnable() {
33394
+ this.unsubscribers.push(
33395
+ interceptVoyageAICall(
33396
+ voyageAIChannels.embed,
33397
+ "voyageai.embed",
33398
+ extractTextEmbeddingInput,
33399
+ summarizeEmbeddingOutput,
33400
+ extractEmbeddingUsageMetrics
33401
+ ),
33402
+ interceptVoyageAICall(
33403
+ voyageAIChannels.multimodalEmbed,
33404
+ "voyageai.multimodalEmbed",
33405
+ extractMultimodalEmbeddingInput,
33406
+ summarizeEmbeddingOutput,
33407
+ extractEmbeddingUsageMetrics
33408
+ ),
33409
+ interceptVoyageAICall(
33410
+ voyageAIChannels.rerank,
33411
+ "voyageai.rerank",
33412
+ extractRerankInput,
33413
+ summarizeRerankOutput
33414
+ ),
33415
+ interceptVoyageAICall(
33416
+ voyageAIChannels.contextualizedEmbed,
33417
+ "voyageai.contextualizedEmbed",
33418
+ extractContextualizedEmbeddingInput,
33419
+ summarizeContextualizedEmbeddingOutput,
33420
+ extractEmbeddingUsageMetrics
33421
+ )
33422
+ );
33423
+ }
33424
+ onDisable() {
33425
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
33426
+ }
33427
+ };
33428
+ function interceptVoyageAICall(channel2, name, extractInput2, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
33429
+ return channel2.intercept((target, thisArg, args) => {
33430
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
33431
+ if (isAutoInstrumentationSuppressed()) {
33432
+ return invokeTarget();
33433
+ }
33434
+ let span;
33435
+ try {
33436
+ const { input, metadata } = extractInput2(args);
33437
+ span = startSpan(
33438
+ withSpanInstrumentationName(
33439
+ {
33440
+ event: { input, metadata },
33441
+ name,
33442
+ spanAttributes: { type: "llm" /* LLM */ }
33443
+ },
33444
+ INSTRUMENTATION_NAMES.VOYAGEAI
33445
+ )
33446
+ );
33447
+ } catch (error) {
33448
+ debugLogger.error(`Error starting span for ${name}:`, error);
33449
+ return invokeTarget();
33450
+ }
33451
+ let result;
33452
+ try {
33453
+ result = withCurrent(
33454
+ span,
33455
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
33456
+ );
33457
+ } catch (error) {
33458
+ finishVoyageAISpan(span, name, () => span.log({ error }));
33459
+ throw error;
33460
+ }
33461
+ void Promise.resolve(result).then(
33462
+ (value) => finishVoyageAISpan(span, name, () => {
33463
+ const metadata = extractResponseMetadata3(value);
33464
+ span.log({
33465
+ output: extractOutput2(value),
33466
+ ...metadata ? { metadata } : {},
33467
+ metrics: extractMetrics2(value)
33468
+ });
33469
+ }),
33470
+ (error) => finishVoyageAISpan(span, name, () => span.log({ error }))
33471
+ );
33472
+ return result;
33473
+ });
33474
+ }
33475
+ function finishVoyageAISpan(span, name, log) {
33476
+ try {
33477
+ log();
33478
+ } catch (error) {
33479
+ debugLogger.error(`Error logging span for ${name}:`, error);
33480
+ }
33481
+ try {
33482
+ span.end();
33483
+ } catch (error) {
33484
+ debugLogger.error(`Error ending span for ${name}:`, error);
33485
+ }
33486
+ }
33487
+ function getRequestArg2(args) {
33488
+ if (Array.isArray(args)) {
33489
+ return isObject(args[0]) ? args[0] : void 0;
33490
+ }
33491
+ if (!isObject(args)) {
33492
+ return void 0;
33493
+ }
33494
+ const firstArg = Reflect.get(args, "0");
33495
+ return isObject(firstArg) ? firstArg : void 0;
33496
+ }
33497
+ function pickMetadata(request, allowlist) {
33498
+ const metadata = {};
33499
+ if (request) {
33500
+ for (const key of allowlist) {
33501
+ if (!Object.hasOwn(request, key)) {
33502
+ continue;
33503
+ }
33504
+ const value = request[key];
33505
+ if (value !== void 0) {
33506
+ metadata[key] = value;
33507
+ }
33508
+ }
33509
+ }
33510
+ return {
33511
+ ...metadata,
33512
+ provider: "voyage"
33513
+ };
33514
+ }
33515
+ function buildEmbeddingInput(inputs, request) {
33516
+ const outputDimensions = request?.outputDimension;
33517
+ return {
33518
+ inputs,
33519
+ ...typeof outputDimensions === "number" && Number.isFinite(outputDimensions) ? { output_dimensions: outputDimensions } : {}
33520
+ };
33521
+ }
33522
+ function embeddingMetadata(request) {
33523
+ return {
33524
+ ...typeof request?.model === "string" ? { model: request.model } : {},
33525
+ provider: "voyage"
33526
+ };
33527
+ }
33528
+ function extractTextEmbeddingInput(args) {
33529
+ const request = getRequestArg2(args);
33530
+ const rawInput = request?.input;
33531
+ const values = Array.isArray(rawInput) ? rawInput : [rawInput];
33532
+ return {
33533
+ input: buildEmbeddingInput(
33534
+ values.flatMap(
33535
+ (value) => typeof value === "string" ? [{ content: value }] : []
33536
+ ),
33537
+ request
33538
+ ),
33539
+ metadata: embeddingMetadata(request)
33540
+ };
33541
+ }
33542
+ function extractContextualizedEmbeddingInput(args) {
33543
+ const request = getRequestArg2(args);
33544
+ const rawInputs = request?.inputs;
33545
+ const values = Array.isArray(rawInputs) ? rawInputs.flatMap((value) => Array.isArray(value) ? value : [value]) : [];
33546
+ return {
33547
+ input: buildEmbeddingInput(
33548
+ values.flatMap(
33549
+ (value) => typeof value === "string" ? [{ content: value }] : []
33550
+ ),
33551
+ request
33552
+ ),
33553
+ metadata: embeddingMetadata(request)
33554
+ };
33555
+ }
33556
+ function extractMultimodalEmbeddingInput(args) {
33557
+ const request = getRequestArg2(args);
33558
+ const rawInputs = request?.inputs;
33559
+ const inputs = Array.isArray(rawInputs) ? rawInputs.map((rawInput) => {
33560
+ const rawContent = isObject(rawInput) ? rawInput.content : void 0;
33561
+ return {
33562
+ content: Array.isArray(rawContent) ? rawContent.flatMap(normalizeMultimodalContentPart) : []
33563
+ };
33564
+ }) : [];
33565
+ const input = buildEmbeddingInput(inputs, request);
33566
+ const processedInput = processInputAttachments(input);
33567
+ return {
33568
+ input: hasInlineEmbeddingMedia(processedInput) ? input : processedInput,
33569
+ metadata: embeddingMetadata(request)
33570
+ };
33571
+ }
33572
+ function normalizeMultimodalContentPart(part) {
33573
+ if (!isObject(part) || typeof part.type !== "string") {
33574
+ return [];
33575
+ }
33576
+ if (part.type === "text") {
33577
+ return typeof part.text === "string" ? [{ type: "text", text: part.text }] : [];
33578
+ }
33579
+ const camelCaseField = {
33580
+ image_base64: "imageBase64",
33581
+ image_url: "imageUrl",
33582
+ video_base64: "videoBase64",
33583
+ video_url: "videoUrl"
33584
+ };
33585
+ const field = camelCaseField[part.type];
33586
+ if (!field) {
33587
+ return [];
33588
+ }
33589
+ const data = typeof part[field] === "string" ? part[field] : part[part.type];
33590
+ if (typeof data !== "string") {
33591
+ return [];
33592
+ }
33593
+ return part.type.startsWith("image_") ? [{ type: "image_url", image_url: { url: data } }] : [{ type: "file", file: { file_data: data } }];
33594
+ }
33595
+ function hasInlineEmbeddingMedia(input) {
33596
+ return input.inputs.some(
33597
+ ({ content }) => Array.isArray(content) ? content.some((part) => {
33598
+ const value = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
33599
+ return typeof value === "string" && value.startsWith("data:");
33600
+ }) : false
33601
+ );
33602
+ }
33603
+ function extractRerankInput(args) {
33604
+ const request = getRequestArg2(args);
33605
+ const documents = request?.documents;
33606
+ return {
33607
+ input: {
33608
+ documents,
33609
+ query: request?.query
33610
+ },
33611
+ metadata: {
33612
+ ...pickMetadata(request, RERANK_METADATA_ALLOWLIST),
33613
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
33614
+ }
33615
+ };
33616
+ }
33617
+ function extractResponseMetadata3(result) {
33618
+ if (!isObject(result)) {
33619
+ return void 0;
33620
+ }
33621
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
33622
+ const model = typeof result.model === "string" ? result.model : typeof rawResponse?.model === "string" ? rawResponse.model : void 0;
33623
+ return model ? { model } : void 0;
33624
+ }
33625
+ function summarizeEmbeddingOutput(result) {
33626
+ return {
33627
+ count: isObject(result) && Array.isArray(result.data) ? result.data.length : 0
33628
+ };
33629
+ }
33630
+ function summarizeRerankOutput(result) {
33631
+ if (!isObject(result) || !Array.isArray(result.data)) {
33632
+ return void 0;
33633
+ }
33634
+ return result.data.slice(0, 100).map((item) => ({
33635
+ index: isObject(item) ? item.index : void 0,
33636
+ relevance_score: isObject(item) ? (typeof item.relevanceScore === "number" ? item.relevanceScore : item.relevance_score) ?? null : null
33637
+ }));
33638
+ }
33639
+ function summarizeContextualizedEmbeddingOutput(result) {
33640
+ if (!isObject(result)) {
33641
+ return { count: 0 };
33642
+ }
33643
+ if (Array.isArray(result.results)) {
33644
+ return {
33645
+ count: result.results.reduce(
33646
+ (count, item) => count + (isObject(item) && Array.isArray(item.embeddings) ? item.embeddings.length : 0),
33647
+ 0
33648
+ )
33649
+ };
33650
+ }
33651
+ if (!Array.isArray(result.data)) {
33652
+ return { count: 0 };
33653
+ }
33654
+ return {
33655
+ count: result.data.reduce(
33656
+ (count, item) => count + (isObject(item) && Array.isArray(item.data) ? item.data.length : 0),
33657
+ 0
33658
+ )
33659
+ };
33660
+ }
33661
+ function extractEmbeddingUsageMetrics(result) {
33662
+ const metrics = extractUsageMetrics3(result);
33663
+ return typeof metrics.tokens === "number" ? { prompt_tokens: metrics.tokens, tokens: metrics.tokens } : {};
33664
+ }
33665
+ function extractUsageMetrics3(result) {
33666
+ if (!isObject(result)) {
33667
+ return {};
33668
+ }
33669
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
33670
+ const usage = isObject(result.usage) ? result.usage : isObject(rawResponse?.usage) ? rawResponse.usage : void 0;
33671
+ const tokens = typeof result.totalTokens === "number" ? result.totalTokens : usage?.totalTokens ?? usage?.total_tokens;
33672
+ return typeof tokens === "number" && Number.isFinite(tokens) && tokens >= 0 ? { tokens } : {};
33673
+ }
33674
+
31630
33675
  // src/instrumentation/plugins/cloudflare-ai-chat-channels.ts
31631
33676
  var cloudflareAIChatChannels = defineChannels(
31632
33677
  "@cloudflare/ai-chat",
@@ -32161,6 +34206,7 @@ var BraintrustPlugin = class extends BasePlugin {
32161
34206
  anthropicPlugin = null;
32162
34207
  aiSDKPlugin = null;
32163
34208
  claudeAgentSDKPlugin = null;
34209
+ cloudflareThinkPlugin = null;
32164
34210
  cursorSDKPlugin = null;
32165
34211
  openAIAgentsPlugin = null;
32166
34212
  googleGenAIPlugin = null;
@@ -32169,6 +34215,7 @@ var BraintrustPlugin = class extends BasePlugin {
32169
34215
  openRouterPlugin = null;
32170
34216
  openRouterAgentPlugin = null;
32171
34217
  mistralPlugin = null;
34218
+ ollamaPlugin = null;
32172
34219
  googleADKPlugin = null;
32173
34220
  coherePlugin = null;
32174
34221
  groqPlugin = null;
@@ -32180,6 +34227,7 @@ var BraintrustPlugin = class extends BasePlugin {
32180
34227
  langSmithPlugin = null;
32181
34228
  piCodingAgentPlugin = null;
32182
34229
  strandsAgentSDKPlugin = null;
34230
+ voyageAIPlugin = null;
32183
34231
  cloudflareAIChatPlugin = null;
32184
34232
  cloudflareAgentsPlugin = null;
32185
34233
  constructor(config = {}) {
@@ -32208,6 +34256,10 @@ var BraintrustPlugin = class extends BasePlugin {
32208
34256
  this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
32209
34257
  this.claudeAgentSDKPlugin.enable();
32210
34258
  }
34259
+ if (integrations.cloudflareThink !== false) {
34260
+ this.cloudflareThinkPlugin = new CloudflareThinkPlugin();
34261
+ this.cloudflareThinkPlugin.enable();
34262
+ }
32211
34263
  if (integrations.cursorSDK !== false && integrations.cursor !== false) {
32212
34264
  this.cursorSDKPlugin = new CursorSDKPlugin();
32213
34265
  this.cursorSDKPlugin.enable();
@@ -32238,6 +34290,10 @@ var BraintrustPlugin = class extends BasePlugin {
32238
34290
  this.mistralPlugin = new MistralPlugin();
32239
34291
  this.mistralPlugin.enable();
32240
34292
  }
34293
+ if (integrations.ollama !== false) {
34294
+ this.ollamaPlugin = new OllamaPlugin();
34295
+ this.ollamaPlugin.enable();
34296
+ }
32241
34297
  if (integrations.googleADK !== false) {
32242
34298
  this.googleADKPlugin = new GoogleADKPlugin();
32243
34299
  this.googleADKPlugin.enable();
@@ -32246,6 +34302,10 @@ var BraintrustPlugin = class extends BasePlugin {
32246
34302
  this.coherePlugin = new CoherePlugin();
32247
34303
  this.coherePlugin.enable();
32248
34304
  }
34305
+ if (integrations.voyageai !== false) {
34306
+ this.voyageAIPlugin = new VoyageAIPlugin();
34307
+ this.voyageAIPlugin.enable();
34308
+ }
32249
34309
  if (integrations.groq !== false) {
32250
34310
  this.groqPlugin = new GroqPlugin();
32251
34311
  this.groqPlugin.enable();
@@ -32314,6 +34374,10 @@ var BraintrustPlugin = class extends BasePlugin {
32314
34374
  this.claudeAgentSDKPlugin.disable();
32315
34375
  this.claudeAgentSDKPlugin = null;
32316
34376
  }
34377
+ if (this.cloudflareThinkPlugin) {
34378
+ this.cloudflareThinkPlugin.disable();
34379
+ this.cloudflareThinkPlugin = null;
34380
+ }
32317
34381
  if (this.cursorSDKPlugin) {
32318
34382
  this.cursorSDKPlugin.disable();
32319
34383
  this.cursorSDKPlugin = null;
@@ -32346,6 +34410,10 @@ var BraintrustPlugin = class extends BasePlugin {
32346
34410
  this.mistralPlugin.disable();
32347
34411
  this.mistralPlugin = null;
32348
34412
  }
34413
+ if (this.ollamaPlugin) {
34414
+ this.ollamaPlugin.disable();
34415
+ this.ollamaPlugin = null;
34416
+ }
32349
34417
  if (this.googleADKPlugin) {
32350
34418
  this.googleADKPlugin.disable();
32351
34419
  this.googleADKPlugin = null;
@@ -32354,6 +34422,10 @@ var BraintrustPlugin = class extends BasePlugin {
32354
34422
  this.coherePlugin.disable();
32355
34423
  this.coherePlugin = null;
32356
34424
  }
34425
+ if (this.voyageAIPlugin) {
34426
+ this.voyageAIPlugin.disable();
34427
+ this.voyageAIPlugin = null;
34428
+ }
32357
34429
  if (this.groqPlugin) {
32358
34430
  this.groqPlugin.disable();
32359
34431
  this.groqPlugin = null;
@@ -34082,6 +36154,7 @@ var envIntegrationAliases = {
34082
36154
  cloudflareaichat: "cloudflareAIChat",
34083
36155
  "cloudflare-ai-chat": "cloudflareAIChat",
34084
36156
  "@cloudflare/ai-chat": "cloudflareAIChat",
36157
+ cloudflarethink: "cloudflareThink",
34085
36158
  cursor: "cursor",
34086
36159
  "cursor-sdk": "cursorSDK",
34087
36160
  cursorsdk: "cursorSDK",
@@ -34102,6 +36175,7 @@ var envIntegrationAliases = {
34102
36175
  openrouteragent: "openrouterAgent",
34103
36176
  "openrouter-agent": "openrouterAgent",
34104
36177
  mistral: "mistral",
36178
+ ollama: "ollama",
34105
36179
  googleadk: "googleADK",
34106
36180
  "google-adk": "googleADK",
34107
36181
  cohere: "cohere",
@@ -34122,7 +36196,10 @@ var envIntegrationAliases = {
34122
36196
  "langchain-js": "langchain",
34123
36197
  "@langchain": "langchain",
34124
36198
  langgraph: "langgraph",
34125
- langsmith: "langsmith"
36199
+ langsmith: "langsmith",
36200
+ voyage: "voyageai",
36201
+ "voyage-ai": "voyageai",
36202
+ voyageai: "voyageai"
34126
36203
  };
34127
36204
  function getDefaultInstrumentationIntegrations() {
34128
36205
  return {
@@ -34137,6 +36214,7 @@ function getDefaultInstrumentationIntegrations() {
34137
36214
  huggingface: true,
34138
36215
  claudeAgentSDK: true,
34139
36216
  cloudflareAIChat: true,
36217
+ cloudflareThink: true,
34140
36218
  cursor: true,
34141
36219
  cursorSDK: true,
34142
36220
  flue: true,
@@ -34145,6 +36223,7 @@ function getDefaultInstrumentationIntegrations() {
34145
36223
  openrouter: true,
34146
36224
  openrouterAgent: true,
34147
36225
  mistral: true,
36226
+ ollama: true,
34148
36227
  cohere: true,
34149
36228
  groq: true,
34150
36229
  bedrock: true,
@@ -34155,6 +36234,7 @@ function getDefaultInstrumentationIntegrations() {
34155
36234
  langchain: true,
34156
36235
  langgraph: true,
34157
36236
  langsmith: true,
36237
+ voyageai: true,
34158
36238
  piCodingAgent: true,
34159
36239
  strandsAgentSDK: true,
34160
36240
  cloudflareAgents: true