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
@@ -1,6 +1,6 @@
1
1
  // src/node/config.ts
2
2
  import { AsyncLocalStorage } from "node:async_hooks";
3
- import * as path from "node:path";
3
+ import * as path2 from "node:path";
4
4
  import * as fs from "node:fs/promises";
5
5
  import * as os from "node:os";
6
6
  import * as fsSync from "node:fs";
@@ -14,8 +14,10 @@ var GLOBAL_INSTRUMENTATION_HOOKS_KEY = "__braintrust_instrumentation_hooks";
14
14
  var GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION = 1;
15
15
  var GLOBAL_INSTRUMENTATION_HOOKS_REGISTRY_BRAND = "braintrust.global-instrumentation-hooks.registry";
16
16
  var GLOBAL_INSTRUMENTATION_HOOK_BRAND = "braintrust.global-instrumentation-hooks.hook";
17
+ var GLOBAL_INVOCATION_HOOK_BRAND = "braintrust.global-instrumentation-hooks.invocation-hook";
17
18
  var registryBrand = Symbol.for(GLOBAL_INSTRUMENTATION_HOOKS_REGISTRY_BRAND);
18
19
  var hookBrand = Symbol.for(GLOBAL_INSTRUMENTATION_HOOK_BRAND);
20
+ var invocationHookBrand = Symbol.for(GLOBAL_INVOCATION_HOOK_BRAND);
19
21
  var errorReporter;
20
22
  function setGlobalHookErrorReporter(reporter) {
21
23
  const previousReporter = errorReporter;
@@ -160,12 +162,69 @@ var traceEvents = [
160
162
  "asyncEnd",
161
163
  "error"
162
164
  ];
165
+ function traceInvocation(hook, operator, target, thisArg, args, additional, callbackIndex = -1) {
166
+ const context = {
167
+ ...additional,
168
+ arguments: args,
169
+ self: thisArg
170
+ };
171
+ const invoke2 = () => hook.invoke(target, thisArg, args, additional);
172
+ if (operator === "traceCallback") {
173
+ return hook.traceCallback(invoke2, callbackIndex, context);
174
+ }
175
+ if (operator === "tracePromise") {
176
+ return hook.tracePromise(invoke2, context);
177
+ }
178
+ return hook.traceSync(invoke2, context);
179
+ }
180
+ var InvocationHook = class {
181
+ interceptors = [];
182
+ get hasInterceptors() {
183
+ return this.interceptors.length > 0;
184
+ }
185
+ intercept(interceptor) {
186
+ if (typeof interceptor !== "function") {
187
+ throw new TypeError("interceptor must be a function");
188
+ }
189
+ this.interceptors = [...this.interceptors, interceptor];
190
+ let active = true;
191
+ return () => {
192
+ if (!active) {
193
+ return;
194
+ }
195
+ active = false;
196
+ const index = this.interceptors.indexOf(interceptor);
197
+ if (index !== -1) {
198
+ this.interceptors = [
199
+ ...this.interceptors.slice(0, index),
200
+ ...this.interceptors.slice(index + 1)
201
+ ];
202
+ }
203
+ };
204
+ }
205
+ invoke(target, thisArg, args, additional) {
206
+ const interceptors = this.interceptors;
207
+ if (interceptors.length === 0) {
208
+ return Reflect.apply(target, thisArg, args);
209
+ }
210
+ let next = target;
211
+ for (let index = interceptors.length - 1; index >= 0; index -= 1) {
212
+ const interceptor = interceptors[index];
213
+ const downstream = next;
214
+ next = function(...nextArgs) {
215
+ return interceptor(downstream, this, nextArgs, additional);
216
+ };
217
+ }
218
+ return Reflect.apply(next, thisArg, args);
219
+ }
220
+ };
163
221
  var TracingHook = class {
164
222
  start;
165
223
  end;
166
224
  asyncStart;
167
225
  asyncEnd;
168
226
  error;
227
+ invocationHook = new InvocationHook();
169
228
  constructor(nameOrChannels) {
170
229
  Object.defineProperty(this, hookBrand, {
171
230
  configurable: false,
@@ -173,6 +232,12 @@ var TracingHook = class {
173
232
  value: GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION,
174
233
  writable: false
175
234
  });
235
+ Object.defineProperty(this, invocationHookBrand, {
236
+ configurable: false,
237
+ enumerable: false,
238
+ value: GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION,
239
+ writable: false
240
+ });
176
241
  if (typeof nameOrChannels === "string") {
177
242
  this.start = new HookChannel(`tracing:${nameOrChannels}:start`);
178
243
  this.end = new HookChannel(`tracing:${nameOrChannels}:end`);
@@ -190,6 +255,26 @@ var TracingHook = class {
190
255
  get hasSubscribers() {
191
256
  return this.start.hasSubscribers || this.end.hasSubscribers || this.asyncStart.hasSubscribers || this.asyncEnd.hasSubscribers || this.error.hasSubscribers;
192
257
  }
258
+ get hasInterceptors() {
259
+ return this.invocationHook.hasInterceptors;
260
+ }
261
+ intercept(interceptor) {
262
+ return this.invocationHook.intercept(interceptor);
263
+ }
264
+ invoke(target, thisArg, args, additional) {
265
+ return this.invocationHook.invoke(target, thisArg, args, additional);
266
+ }
267
+ traceInvocation(operator, target, thisArg, args, additional, callbackIndex = -1) {
268
+ return traceInvocation(
269
+ this,
270
+ operator,
271
+ target,
272
+ thisArg,
273
+ args,
274
+ additional,
275
+ callbackIndex
276
+ );
277
+ }
193
278
  subscribe(handlers) {
194
279
  for (const eventName of traceEvents) {
195
280
  const handler = handlers[eventName];
@@ -411,6 +496,60 @@ function hasTracingHookShape(value) {
411
496
  return false;
412
497
  }
413
498
  }
499
+ function hasInvocationHookShape(value) {
500
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
501
+ return false;
502
+ }
503
+ try {
504
+ const hook = value;
505
+ return value[invocationHookBrand] === GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION && typeof hook.hasInterceptors === "boolean" && typeof hook.intercept === "function" && typeof hook.invoke === "function";
506
+ } catch {
507
+ return false;
508
+ }
509
+ }
510
+ function installInvocationHook(value) {
511
+ const hasInvocationHook = hasInvocationHookShape(value);
512
+ const invocationHook = new InvocationHook();
513
+ try {
514
+ if (!hasInvocationHook) {
515
+ Object.defineProperties(value, {
516
+ [invocationHookBrand]: {
517
+ configurable: false,
518
+ enumerable: false,
519
+ value: GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION,
520
+ writable: false
521
+ },
522
+ hasInterceptors: {
523
+ configurable: false,
524
+ enumerable: false,
525
+ get: () => invocationHook.hasInterceptors
526
+ },
527
+ intercept: {
528
+ configurable: false,
529
+ enumerable: false,
530
+ value: invocationHook.intercept.bind(invocationHook),
531
+ writable: false
532
+ },
533
+ invoke: {
534
+ configurable: false,
535
+ enumerable: false,
536
+ value: invocationHook.invoke.bind(invocationHook),
537
+ writable: false
538
+ }
539
+ });
540
+ }
541
+ if (typeof value.traceInvocation !== "function") {
542
+ Object.defineProperty(value, "traceInvocation", {
543
+ configurable: false,
544
+ enumerable: false,
545
+ value: traceInvocation.bind(void 0, value),
546
+ writable: false
547
+ });
548
+ }
549
+ } catch (error) {
550
+ reportError(error);
551
+ }
552
+ }
414
553
  function isCompatibleTracingHook(value) {
415
554
  try {
416
555
  return value[hookBrand] === GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION && hasTracingHookShape(value);
@@ -497,6 +636,7 @@ function newGlobalTracingChannel(nameOrChannels) {
497
636
  return inertTracingHook;
498
637
  }
499
638
  if (isCompatibleTracingHook(existing)) {
639
+ installInvocationHook(existing);
500
640
  return existing;
501
641
  }
502
642
  if (existing !== void 0) {
@@ -660,34 +800,93 @@ setGlobalHookErrorReporter((error) => {
660
800
  debugLogger.error("Global instrumentation hook error:", error);
661
801
  });
662
802
 
663
- // src/gitutil.ts
664
- import { simpleGit } from "simple-git";
665
- var COMMON_BASE_BRANCHES = ["main", "master", "develop"];
666
- async function currentRepo() {
667
- try {
668
- const git = simpleGit();
669
- if (await git.checkIsRepo()) {
670
- return git;
671
- } else {
672
- return null;
803
+ // src/git-command.ts
804
+ import { execFile } from "node:child_process";
805
+ import { constants } from "node:fs";
806
+ import { access } from "node:fs/promises";
807
+ import * as path from "node:path";
808
+ var GIT_EXECUTABLE_NAMES = process.platform === "win32" ? ["git.exe", "git"] : ["git"];
809
+ var GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
810
+ var gitExecutablePromise;
811
+ function executableSearchPath() {
812
+ return Object.entries(process.env).find(
813
+ ([name]) => name.toUpperCase() === "PATH"
814
+ )?.[1];
815
+ }
816
+ async function findGitExecutable(searchPath = executableSearchPath()) {
817
+ if (!searchPath) {
818
+ return void 0;
819
+ }
820
+ for (const rawSearchDir of searchPath.split(path.delimiter)) {
821
+ const searchDir = rawSearchDir.trim().replace(/^"(.*)"$/, "$1");
822
+ if (!path.isAbsolute(searchDir)) {
823
+ continue;
673
824
  }
674
- } catch {
675
- return null;
825
+ for (const executableName of GIT_EXECUTABLE_NAMES) {
826
+ const candidate = path.join(searchDir, executableName);
827
+ try {
828
+ await access(
829
+ candidate,
830
+ process.platform === "win32" ? constants.F_OK : constants.X_OK
831
+ );
832
+ return candidate;
833
+ } catch {
834
+ }
835
+ }
836
+ }
837
+ return void 0;
838
+ }
839
+ async function resolveGitExecutable() {
840
+ gitExecutablePromise ??= findGitExecutable();
841
+ return await gitExecutablePromise;
842
+ }
843
+ async function runGitCommand(args, options = {}) {
844
+ const executable = await resolveGitExecutable();
845
+ if (!executable) {
846
+ throw new Error("Could not find a git executable on PATH");
676
847
  }
848
+ return await new Promise((resolve, reject2) => {
849
+ execFile(
850
+ executable,
851
+ args,
852
+ {
853
+ cwd: options.cwd,
854
+ encoding: "utf8",
855
+ maxBuffer: GIT_MAX_BUFFER_BYTES
856
+ },
857
+ (error, stdout) => {
858
+ if (error) {
859
+ reject2(error);
860
+ } else {
861
+ resolve(stdout);
862
+ }
863
+ }
864
+ );
865
+ });
677
866
  }
867
+
868
+ // src/gitutil.ts
869
+ var COMMON_BASE_BRANCHES = ["main", "master", "develop"];
678
870
  var _baseBranch = null;
679
871
  async function getBaseBranch(remote = void 0) {
680
872
  if (_baseBranch === null) {
681
- const git = await currentRepo();
682
- if (git === null) {
873
+ const repoPath = await currentRepoPath();
874
+ if (!repoPath) {
683
875
  throw new Error("Not in a git repo");
684
876
  }
685
- const remoteName = remote ?? (await git.getRemotes())[0]?.name;
877
+ const runGit = async (args) => await runGitCommand(args, { cwd: repoPath });
878
+ const remoteName = remote ?? (await runGit(["remote"])).trim().split(/\r?\n/)[0];
686
879
  if (!remoteName) {
687
880
  throw new Error("No remote found");
688
881
  }
689
882
  let branch = null;
690
- const repoBranches = new Set((await git.branchLocal()).all);
883
+ const repoBranches = new Set(
884
+ (await runGit([
885
+ "for-each-ref",
886
+ "--format=%(refname:short)",
887
+ "refs/heads/"
888
+ ])).trim().split(/\r?\n/)
889
+ );
691
890
  const matchingBaseBranches = COMMON_BASE_BRANCHES.filter(
692
891
  (b) => repoBranches.has(b)
693
892
  );
@@ -695,7 +894,7 @@ async function getBaseBranch(remote = void 0) {
695
894
  branch = matchingBaseBranches[0];
696
895
  } else {
697
896
  try {
698
- const remoteInfo = await git.remote(["show", remoteName]);
897
+ const remoteInfo = await runGit(["remote", "show", remoteName]);
699
898
  if (!remoteInfo) {
700
899
  throw new Error(`Could not find remote ${remoteName}`);
701
900
  }
@@ -713,27 +912,28 @@ async function getBaseBranch(remote = void 0) {
713
912
  return _baseBranch;
714
913
  }
715
914
  async function getBaseBranchAncestor(remote = void 0) {
716
- const git = await currentRepo();
717
- if (git === null) {
915
+ const repoPath = await currentRepoPath();
916
+ if (!repoPath) {
718
917
  throw new Error("Not in a git repo");
719
918
  }
720
919
  const { remote: remoteName, branch: baseBranch } = await getBaseBranch(remote);
721
- const isDirty = (await git.diffSummary()).files.length > 0;
920
+ const isDirty = (await runGitCommand(["diff", "--name-only"], {
921
+ cwd: repoPath
922
+ })).trim().length > 0;
722
923
  const head = isDirty ? "HEAD" : "HEAD^";
723
924
  try {
724
- const ancestor = await git.raw([
725
- "merge-base",
726
- head,
727
- `${remoteName}/${baseBranch}`
728
- ]);
925
+ const ancestor = await runGitCommand(
926
+ ["merge-base", head, `${remoteName}/${baseBranch}`],
927
+ { cwd: repoPath }
928
+ );
729
929
  return ancestor.trim();
730
930
  } catch {
731
931
  return void 0;
732
932
  }
733
933
  }
734
934
  async function getPastNAncestors(n = 1e3, remote = void 0) {
735
- const git = await currentRepo();
736
- if (git === null) {
935
+ const repoPath = await currentRepoPath();
936
+ if (!repoPath) {
737
937
  return [];
738
938
  }
739
939
  let ancestor = void 0;
@@ -748,8 +948,10 @@ async function getPastNAncestors(n = 1e3, remote = void 0) {
748
948
  if (!ancestor) {
749
949
  return [];
750
950
  }
751
- const commits = await git.log({ from: ancestor, to: "HEAD", maxCount: n });
752
- return commits.all.slice(0, n).map((c) => c.hash);
951
+ const commits = (await runGitCommand(["rev-list", `--max-count=${n}`, `${ancestor}..HEAD`], {
952
+ cwd: repoPath
953
+ })).trim();
954
+ return commits ? commits.split(/\r?\n/).slice(0, n) : [];
753
955
  }
754
956
  async function attempt(fn) {
755
957
  try {
@@ -780,9 +982,14 @@ async function getRepoInfo(settings) {
780
982
  });
781
983
  return sanitized;
782
984
  }
985
+ async function currentRepoPath() {
986
+ return await attempt(
987
+ async () => (await runGitCommand(["rev-parse", "--show-toplevel"])).trim()
988
+ );
989
+ }
783
990
  async function repoInfo() {
784
- const git = await currentRepo();
785
- if (git === null) {
991
+ const repoPath = await currentRepoPath();
992
+ if (!repoPath) {
786
993
  return void 0;
787
994
  }
788
995
  let commit = void 0;
@@ -793,29 +1000,32 @@ async function repoInfo() {
793
1000
  let tag = void 0;
794
1001
  let branch = void 0;
795
1002
  let git_diff = void 0;
796
- const dirty = (await git.diffSummary()).files.length > 0;
797
- commit = await attempt(async () => await git.revparse(["HEAD"]));
1003
+ const runGit = async (args) => await runGitCommand(args, { cwd: repoPath });
1004
+ const dirty = (await runGit(["diff", "--name-only"])).trim().length > 0;
1005
+ commit = await attempt(
1006
+ async () => (await runGit(["rev-parse", "HEAD"])).trim()
1007
+ );
798
1008
  commit_message = await attempt(
799
- async () => (await git.raw(["log", "-1", "--pretty=%B"])).trim()
1009
+ async () => (await runGit(["log", "-1", "--pretty=%B"])).trim()
800
1010
  );
801
1011
  commit_time = await attempt(
802
- async () => (await git.raw(["log", "-1", "--pretty=%cI"])).trim()
1012
+ async () => (await runGit(["log", "-1", "--pretty=%cI"])).trim()
803
1013
  );
804
1014
  author_name = await attempt(
805
- async () => (await git.raw(["log", "-1", "--pretty=%aN"])).trim()
1015
+ async () => (await runGit(["log", "-1", "--pretty=%aN"])).trim()
806
1016
  );
807
1017
  author_email = await attempt(
808
- async () => (await git.raw(["log", "-1", "--pretty=%aE"])).trim()
1018
+ async () => (await runGit(["log", "-1", "--pretty=%aE"])).trim()
809
1019
  );
810
1020
  tag = await attempt(
811
- async () => (await git.raw(["describe", "--tags", "--exact-match", "--always"])).trim()
1021
+ async () => (await runGit(["describe", "--tags", "--exact-match", "--always"])).trim()
812
1022
  );
813
1023
  branch = await attempt(
814
- async () => (await git.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim()
1024
+ async () => (await runGit(["rev-parse", "--abbrev-ref", "HEAD"])).trim()
815
1025
  );
816
1026
  if (dirty) {
817
1027
  git_diff = await attempt(
818
- async () => truncateToByteLimit(await git.raw(["--no-ext-diff", "diff", "HEAD"]))
1028
+ async () => truncateToByteLimit(await runGit(["diff", "--no-ext-diff", "HEAD"]))
819
1029
  );
820
1030
  }
821
1031
  return {
@@ -1896,15 +2106,15 @@ function mergeDictsWithPaths({
1896
2106
  function mergeDictsWithPathsHelper({
1897
2107
  mergeInto,
1898
2108
  mergeFrom,
1899
- path: path2,
2109
+ path: path3,
1900
2110
  mergePaths
1901
2111
  }) {
1902
2112
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
1903
2113
  if (FORBIDDEN_MERGE_KEYS.has(k)) return;
1904
- const fullPath = path2.concat([k]);
2114
+ const fullPath = path3.concat([k]);
1905
2115
  const fullPathSerialized = JSON.stringify(fullPath);
1906
2116
  const mergeIntoV = recordFind(mergeInto, k);
1907
- const isSetUnionField = path2.length === 0 && SET_UNION_FIELDS.has(k) && !mergePaths.has(fullPathSerialized);
2117
+ const isSetUnionField = path3.length === 0 && SET_UNION_FIELDS.has(k) && !mergePaths.has(fullPathSerialized);
1908
2118
  if (isSetUnionField && isArray(mergeIntoV) && isArray(mergeFromV)) {
1909
2119
  const seen = /* @__PURE__ */ new Set();
1910
2120
  const combined = [];
@@ -1937,9 +2147,9 @@ function mergeDicts(mergeInto, mergeFrom) {
1937
2147
  function recordFind(m, k) {
1938
2148
  return m[k];
1939
2149
  }
1940
- function getObjValueByPath(row, path2) {
2150
+ function getObjValueByPath(row, path3) {
1941
2151
  let curr = row;
1942
- for (const p of path2) {
2152
+ for (const p of path3) {
1943
2153
  if (!isObjectOrArray(curr)) {
1944
2154
  return null;
1945
2155
  }
@@ -2566,7 +2776,8 @@ var AclObjectType = z6.union([
2566
2776
  "org_member",
2567
2777
  "project_log",
2568
2778
  "org_project",
2569
- "org_audit_logs"
2779
+ "org_audit_logs",
2780
+ "project_group"
2570
2781
  ]),
2571
2782
  z6.null()
2572
2783
  ]);
@@ -2695,7 +2906,8 @@ var AsyncScoringState = z6.union([
2695
2906
  token: z6.string(),
2696
2907
  function_ids: z6.array(z6.unknown()),
2697
2908
  skip_logging: z6.union([z6.boolean(), z6.null()]).optional(),
2698
- triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional()
2909
+ triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional(),
2910
+ last_triggered_xact_id: z6.union([z6.string(), z6.number(), z6.null()]).optional()
2699
2911
  }),
2700
2912
  z6.object({ status: z6.literal("disabled") }),
2701
2913
  z6.null(),
@@ -2764,7 +2976,7 @@ var FunctionTypeEnum = z6.enum([
2764
2976
  "parameters",
2765
2977
  "sandbox"
2766
2978
  ]);
2767
- var NullableSavedFunctionId = z6.union([
2979
+ var FacetPreprocessorId = z6.union([
2768
2980
  z6.object({
2769
2981
  type: z6.literal("function"),
2770
2982
  id: z6.string(),
@@ -2775,10 +2987,23 @@ var NullableSavedFunctionId = z6.union([
2775
2987
  name: z6.string(),
2776
2988
  function_type: FunctionTypeEnum.optional().default("scorer")
2777
2989
  }),
2990
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
2778
2991
  z6.null()
2779
2992
  ]);
2993
+ var SavedFunctionId = z6.union([
2994
+ z6.object({
2995
+ type: z6.literal("function"),
2996
+ id: z6.string(),
2997
+ version: z6.string().optional()
2998
+ }),
2999
+ z6.object({
3000
+ type: z6.literal("global"),
3001
+ name: z6.string(),
3002
+ function_type: FunctionTypeEnum.optional().default("scorer")
3003
+ })
3004
+ ]);
2780
3005
  var TopicMapGenerationSettings = z6.object({
2781
- algorithm: z6.enum(["hdbscan", "kmeans"]),
3006
+ algorithm: z6.enum(["hdbscan", "kmeans", "community"]),
2782
3007
  dimension_reduction: z6.enum(["umap", "pca", "none"]),
2783
3008
  sample_size: z6.number().int().gt(0).optional(),
2784
3009
  n_clusters: z6.number().int().gt(0).optional(),
@@ -2790,6 +3015,7 @@ var TopicMapGenerationSettings = z6.object({
2790
3015
  var TopicMapData = z6.object({
2791
3016
  type: z6.literal("topic_map"),
2792
3017
  source_facet: z6.string(),
3018
+ source_facet_function: SavedFunctionId.and(z6.unknown()).optional(),
2793
3019
  embedding_model: z6.string(),
2794
3020
  bundle_key: z6.string().optional(),
2795
3021
  report_key: z6.string().optional(),
@@ -2803,7 +3029,7 @@ var TopicMapData = z6.object({
2803
3029
  });
2804
3030
  var BatchedFacetData = z6.object({
2805
3031
  type: z6.literal("batched_facet"),
2806
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
3032
+ preprocessor: FacetPreprocessorId.optional(),
2807
3033
  facets: z6.array(
2808
3034
  z6.object({
2809
3035
  name: z6.string(),
@@ -3064,18 +3290,6 @@ var ObjectReferenceNullish = z6.union([
3064
3290
  }),
3065
3291
  z6.null()
3066
3292
  ]);
3067
- var SavedFunctionId = z6.union([
3068
- z6.object({
3069
- type: z6.literal("function"),
3070
- id: z6.string(),
3071
- version: z6.string().optional()
3072
- }),
3073
- z6.object({
3074
- type: z6.literal("global"),
3075
- name: z6.string(),
3076
- function_type: FunctionTypeEnum.optional().default("scorer")
3077
- })
3078
- ]);
3079
3293
  var DatasetEvent = z6.object({
3080
3294
  id: z6.string(),
3081
3295
  _xact_id: z6.string(),
@@ -3297,7 +3511,7 @@ var ExtendedSavedFunctionId = z6.union([
3297
3511
  ]);
3298
3512
  var FacetData = z6.object({
3299
3513
  type: z6.literal("facet"),
3300
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
3514
+ preprocessor: FacetPreprocessorId.optional(),
3301
3515
  prompt: z6.string(),
3302
3516
  model: z6.string().optional(),
3303
3517
  embedding_model: z6.string().optional(),
@@ -3802,6 +4016,19 @@ var MessageRole = z6.enum([
3802
4016
  "model",
3803
4017
  "developer"
3804
4018
  ]);
4019
+ var NullableSavedFunctionId = z6.union([
4020
+ z6.object({
4021
+ type: z6.literal("function"),
4022
+ id: z6.string(),
4023
+ version: z6.string().optional()
4024
+ }),
4025
+ z6.object({
4026
+ type: z6.literal("global"),
4027
+ name: z6.string(),
4028
+ function_type: FunctionTypeEnum.optional().default("scorer")
4029
+ }),
4030
+ z6.null()
4031
+ ]);
3805
4032
  var ObjectReference = z6.object({
3806
4033
  object_type: z6.enum([
3807
4034
  "project_logs",
@@ -3823,6 +4050,7 @@ var TraceScope = z6.object({
3823
4050
  });
3824
4051
  var OnlineScoreConfig = z6.union([
3825
4052
  z6.object({
4053
+ status: AutomationStatus.optional(),
3826
4054
  sampling_rate: z6.number().gte(0).lte(1),
3827
4055
  scorers: z6.array(SavedFunctionId),
3828
4056
  btql_filter: z6.union([z6.string(), z6.null()]).optional(),
@@ -3903,6 +4131,72 @@ var Project = z6.object({
3903
4131
  user_id: z6.union([z6.string(), z6.null()]).optional(),
3904
4132
  settings: ProjectSettings.optional()
3905
4133
  });
4134
+ var WindowedAutomationConfig = z6.object({
4135
+ event_type: z6.literal("windowed"),
4136
+ product_origin: z6.union([z6.literal("patterns"), z6.null()]).optional(),
4137
+ status: AutomationStatus.optional(),
4138
+ threshold: z6.object({
4139
+ calculation: z6.object({
4140
+ type: z6.literal("btql"),
4141
+ btql_query: z6.string().min(1),
4142
+ output: z6.object({
4143
+ type: z6.literal("scalar"),
4144
+ value_column: z6.string().min(1)
4145
+ })
4146
+ }),
4147
+ policy: z6.object({
4148
+ condition: z6.object({
4149
+ type: z6.literal("threshold"),
4150
+ operator: z6.enum(["lt", "lte", "gt", "gte", "eq", "neq"]),
4151
+ threshold: z6.number()
4152
+ }),
4153
+ pending_seconds: z6.number().int().gte(0).lte(2592e3),
4154
+ no_data_behavior: z6.enum(["keep_last", "resolve", "alert"]),
4155
+ renotify_interval_seconds: z6.union([z6.number(), z6.null()]).optional(),
4156
+ notify_on_recovery: z6.boolean().optional().default(true)
4157
+ })
4158
+ }).optional(),
4159
+ window: z6.object({
4160
+ window_seconds: z6.number().int().gte(1).lte(2592e3),
4161
+ schedule: z6.union([
4162
+ z6.object({
4163
+ type: z6.literal("interval"),
4164
+ evaluation_interval_seconds: z6.number().int().gte(1).lte(2592e3)
4165
+ }),
4166
+ z6.object({
4167
+ type: z6.literal("cron"),
4168
+ cron_expression: z6.string().min(1),
4169
+ timezone: z6.union([z6.string(), z6.null()]).optional()
4170
+ })
4171
+ ]),
4172
+ evaluation_delay_seconds: z6.number().int().gte(0).lte(2592e3)
4173
+ }),
4174
+ loop: z6.object({
4175
+ prompt: z6.string().min(1).max(1e4),
4176
+ include_trigger_input: z6.boolean().optional().default(false),
4177
+ agent_slug: z6.string().min(1),
4178
+ auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
4179
+ harness: z6.enum(["native", "codex", "claude-code"]).optional(),
4180
+ model: z6.string().min(1).optional(),
4181
+ reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
4182
+ }).optional(),
4183
+ actions: z6.array(
4184
+ z6.union([
4185
+ z6.object({
4186
+ type: z6.literal("webhook"),
4187
+ url: z6.string(),
4188
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4189
+ }),
4190
+ z6.object({
4191
+ type: z6.literal("slack"),
4192
+ workspace_id: z6.string(),
4193
+ channel: z6.string(),
4194
+ message_template: z6.string().optional(),
4195
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4196
+ })
4197
+ ])
4198
+ ).max(20).optional().default([])
4199
+ });
3906
4200
  var TopicAutomationFacetModel = z6.union([
3907
4201
  z6.enum(["brain-facet-latest", "brain-facet-1", "brain-facet-2"]),
3908
4202
  z6.null()
@@ -3944,7 +4238,8 @@ var TopicDigestAutomationConfig = z6.object({
3944
4238
  type: z6.literal("slack"),
3945
4239
  workspace_id: z6.string(),
3946
4240
  channel: z6.string(),
3947
- message_template: z6.string().optional()
4241
+ message_template: z6.string().optional(),
4242
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3948
4243
  }),
3949
4244
  topic_map_function_ids: z6.array(z6.string()).max(10).optional()
3950
4245
  });
@@ -3958,15 +4253,21 @@ var ProjectAutomation = z6.object({
3958
4253
  config: z6.union([
3959
4254
  z6.object({
3960
4255
  event_type: z6.literal("logs"),
4256
+ status: AutomationStatus.optional(),
3961
4257
  btql_filter: z6.string(),
3962
4258
  interval_seconds: z6.number().gte(1).lte(2592e3),
3963
4259
  action: z6.union([
3964
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
4260
+ z6.object({
4261
+ type: z6.literal("webhook"),
4262
+ url: z6.string(),
4263
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4264
+ }),
3965
4265
  z6.object({
3966
4266
  type: z6.literal("slack"),
3967
4267
  workspace_id: z6.string(),
3968
4268
  channel: z6.string(),
3969
- message_template: z6.string().optional()
4269
+ message_template: z6.string().optional(),
4270
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3970
4271
  })
3971
4272
  ])
3972
4273
  }),
@@ -4017,21 +4318,38 @@ var ProjectAutomation = z6.object({
4017
4318
  }),
4018
4319
  z6.object({
4019
4320
  event_type: z6.literal("environment_update"),
4321
+ status: AutomationStatus.optional(),
4020
4322
  environment_filter: z6.array(z6.string()).optional(),
4021
4323
  action: z6.union([
4022
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
4324
+ z6.object({
4325
+ type: z6.literal("webhook"),
4326
+ url: z6.string(),
4327
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4328
+ }),
4023
4329
  z6.object({
4024
4330
  type: z6.literal("slack"),
4025
4331
  workspace_id: z6.string(),
4026
4332
  channel: z6.string(),
4027
- message_template: z6.string().optional()
4333
+ message_template: z6.string().optional(),
4334
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4028
4335
  })
4029
4336
  ])
4030
4337
  }),
4338
+ WindowedAutomationConfig,
4031
4339
  TopicAutomationConfig,
4032
4340
  TopicDigestAutomationConfig
4033
4341
  ])
4034
4342
  });
4343
+ var ProjectGroup = z6.object({
4344
+ id: z6.string().uuid(),
4345
+ org_id: z6.string().uuid(),
4346
+ user_id: z6.union([z6.string(), z6.null()]).optional(),
4347
+ created: z6.union([z6.string(), z6.null()]).optional(),
4348
+ name: z6.string(),
4349
+ description: z6.union([z6.string(), z6.null()]).optional(),
4350
+ deleted_at: z6.union([z6.string(), z6.null()]).optional(),
4351
+ member_projects: z6.array(z6.string().uuid()).max(1e4)
4352
+ });
4035
4353
  var ProjectLogsEvent = z6.object({
4036
4354
  id: z6.string(),
4037
4355
  _xact_id: z6.string(),
@@ -4249,7 +4567,8 @@ var RunEval = z6.object({
4249
4567
  dataset_environment: z6.union([z6.string(), z6.null()]).optional(),
4250
4568
  _internal_btql: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional()
4251
4569
  }),
4252
- z6.object({ data: z6.array(z6.unknown()) })
4570
+ z6.object({ data: z6.array(z6.unknown()) }),
4571
+ z6.object({ experiment_name: z6.string() })
4253
4572
  ]),
4254
4573
  name: z6.string().optional(),
4255
4574
  parameters: z6.object({}).partial().passthrough().optional(),
@@ -4454,7 +4773,9 @@ var View = z6.object({
4454
4773
  "for_review_datasets"
4455
4774
  ]),
4456
4775
  name: z6.string(),
4776
+ description: z6.union([z6.string(), z6.null()]).optional(),
4457
4777
  created: z6.union([z6.string(), z6.null()]).optional(),
4778
+ updated_at: z6.union([z6.string(), z6.null()]).optional(),
4458
4779
  view_data: ViewData.optional(),
4459
4780
  options: ViewOptions.optional(),
4460
4781
  user_id: z6.union([z6.string(), z6.null()]).optional(),
@@ -4981,10 +5302,10 @@ var DiskCache = class {
4981
5302
  return;
4982
5303
  }
4983
5304
  const stats = await Promise.all(
4984
- paths.map(async (path2) => {
4985
- const stat2 = await isomorph_default.stat(path2);
5305
+ paths.map(async (path3) => {
5306
+ const stat2 = await isomorph_default.stat(path3);
4986
5307
  return {
4987
- path: path2,
5308
+ path: path3,
4988
5309
  mtime: stat2.mtime.getTime()
4989
5310
  };
4990
5311
  })
@@ -5559,6 +5880,7 @@ var INSTRUMENTATION_NAMES = {
5559
5880
  CLAUDE_AGENT_SDK: "claude-agent-sdk",
5560
5881
  CLOUDFLARE_AI_CHAT: "cloudflare-ai-chat",
5561
5882
  CLOUDFLARE_AGENTS: "cloudflare-agents",
5883
+ CLOUDFLARE_THINK: "cloudflare-think",
5562
5884
  COHERE: "cohere",
5563
5885
  CURSOR_SDK: "cursor-sdk",
5564
5886
  EVE: "eve",
@@ -5573,18 +5895,20 @@ var INSTRUMENTATION_NAMES = {
5573
5895
  LANGSMITH: "langsmith",
5574
5896
  MASTRA: "mastra",
5575
5897
  MISTRAL: "mistral",
5898
+ OLLAMA: "ollama",
5576
5899
  OPENAI: "openai",
5577
5900
  OPENAI_AGENTS: "openai-agents",
5578
5901
  OPENAI_CODEX: "openai-codex",
5579
5902
  OPENROUTER: "openrouter",
5580
5903
  OPENROUTER_AGENT: "openrouter-agent",
5581
5904
  PI_CODING_AGENT: "pi-coding-agent",
5582
- STRANDS_AGENT_SDK: "strands-agent-sdk"
5905
+ STRANDS_AGENT_SDK: "strands-agent-sdk",
5906
+ VOYAGEAI: "voyageai"
5583
5907
  };
5584
5908
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5585
5909
  "braintrust.spanInstrumentationName"
5586
5910
  );
5587
- var SDK_VERSION = true ? "3.26.0" : "0.0.0";
5911
+ var SDK_VERSION = true ? "3.28.0" : "0.0.0";
5588
5912
  function withSpanInstrumentationName(args, instrumentationName) {
5589
5913
  return {
5590
5914
  ...args,
@@ -5779,6 +6103,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
5779
6103
  var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
5780
6104
  "braintrust.initial-span-write-as-merge"
5781
6105
  );
6106
+ var RESUME_SPAN_WITHOUT_INITIAL_WRITE = /* @__PURE__ */ Symbol(
6107
+ "braintrust.resume-span-without-initial-write"
6108
+ );
5782
6109
  var INTERNAL_SPAN_CONTEXT = /* @__PURE__ */ Symbol("braintrust.internal-span-context");
5783
6110
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
5784
6111
  "braintrust.currentSpanStore"
@@ -6344,9 +6671,9 @@ var HTTPConnection = class _HTTPConnection {
6344
6671
  this.headers["Authorization"] = `Bearer ${this.token}`;
6345
6672
  }
6346
6673
  }
6347
- async get(path2, params = void 0, config) {
6674
+ async get(path3, params = void 0, config) {
6348
6675
  const { headers, ...rest } = config || {};
6349
- const url = new URL(_urljoin(this.base_url, path2));
6676
+ const url = new URL(_urljoin(this.base_url, path3));
6350
6677
  url.search = new URLSearchParams(
6351
6678
  params ? Object.entries(params).filter(([_, v]) => v !== void 0).flatMap(
6352
6679
  ([k, v]) => v !== void 0 ? typeof v === "string" ? [[k, v]] : v.map((x) => [k, x]) : []
@@ -6367,7 +6694,7 @@ var HTTPConnection = class _HTTPConnection {
6367
6694
  })
6368
6695
  );
6369
6696
  }
6370
- async post(path2, params, config, retries = 0) {
6697
+ async post(path3, params, config, retries = 0) {
6371
6698
  const { headers, ...rest } = config || {};
6372
6699
  const this_fetch = this.fetch;
6373
6700
  const this_base_url = this.base_url;
@@ -6376,7 +6703,7 @@ var HTTPConnection = class _HTTPConnection {
6376
6703
  for (let i = 0; i < tries; i++) {
6377
6704
  try {
6378
6705
  return await checkResponse(
6379
- await this_fetch(_urljoin(this_base_url, path2), {
6706
+ await this_fetch(_urljoin(this_base_url, path3), {
6380
6707
  method: "POST",
6381
6708
  headers: {
6382
6709
  Accept: "application/json",
@@ -6397,7 +6724,7 @@ var HTTPConnection = class _HTTPConnection {
6397
6724
  throw error;
6398
6725
  }
6399
6726
  debugLogger.debug(
6400
- `Retrying API request ${path2} after ${formatHTTPError(error)}`
6727
+ `Retrying API request ${path3} after ${formatHTTPError(error)}`
6401
6728
  );
6402
6729
  const sleepTimeMs = HTTP_RETRY_BASE_SLEEP_TIME_S * 1e3 * 2 ** i + Math.random() * HTTP_RETRY_JITTER_MS;
6403
6730
  debugLogger.info(
@@ -9162,7 +9489,7 @@ var ObjectFetcher = class {
9162
9489
  const objectId = await this.id;
9163
9490
  const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
9164
9491
  const internalLimit = getInternalBtqlLimit(this._internal_btql);
9165
- const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
9492
+ let remainingLimit = internalLimit;
9166
9493
  const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
9167
9494
  Object.entries(this._internal_btql ?? {}).filter(
9168
9495
  ([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
@@ -9171,6 +9498,10 @@ var ObjectFetcher = class {
9171
9498
  let cursor = void 0;
9172
9499
  let iterations = 0;
9173
9500
  while (true) {
9501
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9502
+ return;
9503
+ }
9504
+ const limit = remainingLimit === void 0 ? batchLimit : Math.min(batchLimit, remainingLimit);
9174
9505
  const resp = await state.apiConn().post(
9175
9506
  `btql`,
9176
9507
  {
@@ -9210,7 +9541,14 @@ var ObjectFetcher = class {
9210
9541
  const respJson = await resp.json();
9211
9542
  const mutate = this.mutateRecord;
9212
9543
  for (const record of respJson.data ?? []) {
9213
- yield mutate ? mutate(record) : record;
9544
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9545
+ return;
9546
+ }
9547
+ const mutatedRecord = mutate ? mutate(record) : record;
9548
+ if (remainingLimit !== void 0) {
9549
+ remainingLimit--;
9550
+ }
9551
+ yield mutatedRecord;
9214
9552
  }
9215
9553
  if (!respJson.cursor) {
9216
9554
  break;
@@ -9730,7 +10068,9 @@ var SpanImpl = class _SpanImpl {
9730
10068
  this._rootSpanId = resolvedIds.rootSpanId;
9731
10069
  this._spanParents = resolvedIds.spanParents;
9732
10070
  this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
9733
- this.logInternal({ event, internalData });
10071
+ if (!args[RESUME_SPAN_WITHOUT_INITIAL_WRITE]) {
10072
+ this.logInternal({ event, internalData });
10073
+ }
9734
10074
  this.isMerge = true;
9735
10075
  }
9736
10076
  getParentInfo() {
@@ -10905,6 +11245,34 @@ function patchStreamIfNeeded(stream, options) {
10905
11245
  );
10906
11246
  return stream;
10907
11247
  }
11248
+ const chunks = [];
11249
+ let completed = false;
11250
+ const notifyCancellation = async () => {
11251
+ try {
11252
+ await (options.onCancel ?? options.onComplete)(chunks);
11253
+ } catch (error) {
11254
+ debugLogger.error("Error in stream cancellation handler:", error);
11255
+ }
11256
+ };
11257
+ const patchAbortIfPresent = () => {
11258
+ try {
11259
+ if ("abort" in stream && typeof stream.abort === "function") {
11260
+ const originalAbort = stream.abort.bind(stream);
11261
+ stream.abort = (...args) => {
11262
+ try {
11263
+ return originalAbort(...args);
11264
+ } finally {
11265
+ if (!completed) {
11266
+ completed = true;
11267
+ void notifyCancellation();
11268
+ }
11269
+ }
11270
+ };
11271
+ }
11272
+ } catch (error) {
11273
+ debugLogger.warn("Failed to patch stream abort method:", error);
11274
+ }
11275
+ };
10908
11276
  if (hasAsyncIteratorMethods(stream) && isSelfAsyncIterator(stream)) {
10909
11277
  if ("__braintrust_patched_iterator_methods" in stream) {
10910
11278
  return stream;
@@ -10913,8 +11281,6 @@ function patchStreamIfNeeded(stream, options) {
10913
11281
  const originalNext = stream.next.bind(stream);
10914
11282
  const originalReturn = typeof stream.return === "function" ? stream.return.bind(stream) : null;
10915
11283
  const originalThrow = typeof stream.throw === "function" ? stream.throw.bind(stream) : null;
10916
- const chunks = [];
10917
- let completed = false;
10918
11284
  stream.next = async (...args) => {
10919
11285
  try {
10920
11286
  const result = await runNextWithWrapper(
@@ -10966,11 +11332,7 @@ function patchStreamIfNeeded(stream, options) {
10966
11332
  stream.return = async (...args) => {
10967
11333
  if (!completed) {
10968
11334
  completed = true;
10969
- try {
10970
- await options.onComplete(chunks);
10971
- } catch (error) {
10972
- console.error("Error in stream onComplete handler:", error);
10973
- }
11335
+ await notifyCancellation();
10974
11336
  }
10975
11337
  return originalReturn(...args);
10976
11338
  };
@@ -10995,6 +11357,7 @@ function patchStreamIfNeeded(stream, options) {
10995
11357
  Object.defineProperty(stream, "__braintrust_patched_iterator_methods", {
10996
11358
  value: true
10997
11359
  });
11360
+ patchAbortIfPresent();
10998
11361
  return stream;
10999
11362
  } catch (error) {
11000
11363
  console.warn("Failed to patch stream iterator methods:", error);
@@ -11008,8 +11371,6 @@ function patchStreamIfNeeded(stream, options) {
11008
11371
  const patchedIteratorFn = function() {
11009
11372
  const iterator = originalIteratorFn.call(this);
11010
11373
  const originalNext = iterator.next.bind(iterator);
11011
- const chunks = [];
11012
- let completed = false;
11013
11374
  iterator.next = async function(...args) {
11014
11375
  try {
11015
11376
  const result = await runNextWithWrapper(
@@ -11062,11 +11423,7 @@ function patchStreamIfNeeded(stream, options) {
11062
11423
  iterator.return = async function(...args) {
11063
11424
  if (!completed) {
11064
11425
  completed = true;
11065
- try {
11066
- await options.onComplete(chunks);
11067
- } catch (error) {
11068
- console.error("Error in stream onComplete handler:", error);
11069
- }
11426
+ await notifyCancellation();
11070
11427
  }
11071
11428
  return originalReturn(...args);
11072
11429
  };
@@ -11095,6 +11452,7 @@ function patchStreamIfNeeded(stream, options) {
11095
11452
  value: true
11096
11453
  });
11097
11454
  stream[Symbol.asyncIterator] = patchedIteratorFn;
11455
+ patchAbortIfPresent();
11098
11456
  return stream;
11099
11457
  } catch (error) {
11100
11458
  console.warn("Failed to patch stream:", error);
@@ -11843,6 +12201,33 @@ function traceStreamingChannel(channel2, config) {
11843
12201
  const { span, startTime } = spanData;
11844
12202
  if (isAsyncIterable(asyncEndEvent.result)) {
11845
12203
  let firstChunkTime;
12204
+ const handleStreamError = (error) => {
12205
+ try {
12206
+ span.log({ error });
12207
+ } catch (loggingError) {
12208
+ debugLogger.error(
12209
+ `Error logging failure for ${channelName}:`,
12210
+ loggingError
12211
+ );
12212
+ }
12213
+ try {
12214
+ span.end();
12215
+ } catch (endingError) {
12216
+ debugLogger.error(
12217
+ `Error ending span for ${channelName}:`,
12218
+ endingError
12219
+ );
12220
+ }
12221
+ states.delete(event);
12222
+ runStreamingErrorHook({
12223
+ channelName,
12224
+ config,
12225
+ error,
12226
+ event: asyncEndEvent,
12227
+ span,
12228
+ startTime
12229
+ });
12230
+ };
11846
12231
  patchStreamIfNeeded(asyncEndEvent.result, {
11847
12232
  onChunk: () => {
11848
12233
  if (firstChunkTime === void 0) {
@@ -11922,33 +12307,12 @@ function traceStreamingChannel(channel2, config) {
11922
12307
  });
11923
12308
  }
11924
12309
  },
11925
- onError: (error) => {
11926
- try {
11927
- span.log({ error });
11928
- } catch (loggingError) {
11929
- debugLogger.error(
11930
- `Error logging failure for ${channelName}:`,
11931
- loggingError
11932
- );
11933
- }
11934
- try {
11935
- span.end();
11936
- } catch (endingError) {
11937
- debugLogger.error(
11938
- `Error ending span for ${channelName}:`,
11939
- endingError
11940
- );
11941
- }
11942
- states.delete(event);
11943
- runStreamingErrorHook({
11944
- channelName,
11945
- config,
11946
- error,
11947
- event: asyncEndEvent,
11948
- span,
11949
- startTime
11950
- });
11951
- }
12310
+ onCancel: () => {
12311
+ const error = new Error("Stream cancelled before completion");
12312
+ error.name = "AbortError";
12313
+ handleStreamError(error);
12314
+ },
12315
+ onError: handleStreamError
11952
12316
  });
11953
12317
  return;
11954
12318
  }
@@ -12264,6 +12628,22 @@ function processInputAttachments(input) {
12264
12628
  };
12265
12629
  }
12266
12630
  }
12631
+ 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;
12632
+ const voyageBase64Value = voyageBase64Key ? node[voyageBase64Key] : void 0;
12633
+ if (voyageBase64Key && typeof voyageBase64Value === "string" && voyageBase64Value.startsWith("data:")) {
12634
+ const mediaType = inferMediaTypeFromDataUrl(
12635
+ voyageBase64Value,
12636
+ node.type === "video_base64" ? "video/mp4" : "image/png"
12637
+ );
12638
+ const filename = `${node.type === "video_base64" ? "video" : "image"}.${getExtensionFromMediaType(mediaType)}`;
12639
+ const attachment = toAttachment(voyageBase64Value, mediaType, filename);
12640
+ if (attachment) {
12641
+ return {
12642
+ ...node,
12643
+ [voyageBase64Key]: attachment
12644
+ };
12645
+ }
12646
+ }
12267
12647
  if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
12268
12648
  const mediaType = inferMediaTypeFromDataUrl(
12269
12649
  node.file.file_data,
@@ -12336,11 +12716,21 @@ function defineChannels(pkg, channels, options) {
12336
12716
  const tracingChannel2 = () => isomorph_default.newTracingChannel(
12337
12717
  fullChannelName
12338
12718
  );
12719
+ const intercept2 = (interceptor) => {
12720
+ const hook = tracingChannel2();
12721
+ return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
12722
+ };
12723
+ };
12339
12724
  return [
12340
12725
  key,
12341
12726
  {
12342
12727
  ...asyncSpec,
12343
12728
  instrumentationName,
12729
+ intercept: intercept2,
12730
+ invoke: (target, thisArg, args, additional) => {
12731
+ const hook = tracingChannel2();
12732
+ return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
12733
+ },
12344
12734
  tracingChannel: tracingChannel2,
12345
12735
  tracePromise: (fn, context) => tracingChannel2().tracePromise(
12346
12736
  fn,
@@ -12354,11 +12744,21 @@ function defineChannels(pkg, channels, options) {
12354
12744
  const tracingChannel = () => isomorph_default.newTracingChannel(
12355
12745
  fullChannelName
12356
12746
  );
12747
+ const intercept = (interceptor) => {
12748
+ const hook = tracingChannel();
12749
+ return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
12750
+ };
12751
+ };
12357
12752
  return [
12358
12753
  key,
12359
12754
  {
12360
12755
  ...syncSpec,
12361
12756
  instrumentationName,
12757
+ intercept,
12758
+ invoke: (target, thisArg, args, additional) => {
12759
+ const hook = tracingChannel();
12760
+ return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
12761
+ },
12362
12762
  tracingChannel,
12363
12763
  traceSync: (fn, context) => tracingChannel().traceSync(
12364
12764
  fn,
@@ -13591,12 +13991,30 @@ function logInstrumentationError(context, error) {
13591
13991
 
13592
13992
  // src/wrappers/anthropic-tokens-util.ts
13593
13993
  function finalizeAnthropicTokens(metrics) {
13594
- const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + (metrics.prompt_cache_creation_tokens || 0);
13595
- return {
13994
+ const hasSplitCacheCreationTokens = metrics.prompt_cache_creation_5m_tokens !== void 0 || metrics.prompt_cache_creation_1h_tokens !== void 0;
13995
+ const splitCacheCreationTokens = (metrics.prompt_cache_creation_5m_tokens || 0) + (metrics.prompt_cache_creation_1h_tokens || 0);
13996
+ const aggregateCacheCreationTokens = metrics.prompt_cache_creation_tokens || 0;
13997
+ const effectiveCacheCreationTokens = Math.max(
13998
+ aggregateCacheCreationTokens,
13999
+ splitCacheCreationTokens
14000
+ );
14001
+ const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + effectiveCacheCreationTokens;
14002
+ const finalized = {
13596
14003
  ...metrics,
13597
14004
  prompt_tokens,
13598
14005
  tokens: prompt_tokens + (metrics.completion_tokens || 0)
13599
14006
  };
14007
+ if (hasSplitCacheCreationTokens && splitCacheCreationTokens >= aggregateCacheCreationTokens) {
14008
+ delete finalized.prompt_cache_creation_tokens;
14009
+ }
14010
+ return finalized;
14011
+ }
14012
+ function toNumericMetrics(metrics) {
14013
+ return Object.fromEntries(
14014
+ Object.entries(metrics).filter(
14015
+ (entry) => entry[1] !== void 0
14016
+ )
14017
+ );
13600
14018
  }
13601
14019
  function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens = 0) {
13602
14020
  const cacheTokens = {};
@@ -13609,6 +14027,12 @@ function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens =
13609
14027
  return cacheTokens;
13610
14028
  }
13611
14029
 
14030
+ // src/wrappers/anthropic-session-collector.ts
14031
+ var sessionStreamCollectors = /* @__PURE__ */ new WeakMap();
14032
+ function registerAnthropicSessionStreamCollector(stream, collector) {
14033
+ sessionStreamCollectors.set(stream, collector);
14034
+ }
14035
+
13612
14036
  // src/instrumentation/plugins/anthropic-channels.ts
13613
14037
  var anthropicChannels = defineChannels(
13614
14038
  "@anthropic-ai/sdk",
@@ -13624,6 +14048,14 @@ var anthropicChannels = defineChannels(
13624
14048
  betaMessagesToolRunner: channel({
13625
14049
  channelName: "beta.messages.toolRunner",
13626
14050
  kind: "sync-stream"
14051
+ }),
14052
+ betaSessionsEventsStream: channel({
14053
+ channelName: "beta.sessions.events.stream",
14054
+ kind: "async"
14055
+ }),
14056
+ betaSessionsThreadsEventsStream: channel({
14057
+ channelName: "beta.sessions.threads.events.stream",
14058
+ kind: "async"
13627
14059
  })
13628
14060
  },
13629
14061
  { instrumentationName: INSTRUMENTATION_NAMES.ANTHROPIC }
@@ -13637,6 +14069,7 @@ var AnthropicPlugin = class extends BasePlugin {
13637
14069
  onEnable() {
13638
14070
  this.subscribeToAnthropicChannels();
13639
14071
  this.subscribeToAnthropicToolRunner();
14072
+ this.subscribeToAnthropicSessionStreams();
13640
14073
  }
13641
14074
  onDisable() {
13642
14075
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
@@ -13754,7 +14187,411 @@ var AnthropicPlugin = class extends BasePlugin {
13754
14187
  tracingChannel.unsubscribe(handlers);
13755
14188
  });
13756
14189
  }
14190
+ subscribeToAnthropicSessionStreams() {
14191
+ this.subscribeToAnthropicSessionStream(
14192
+ anthropicChannels.betaSessionsEventsStream,
14193
+ false
14194
+ );
14195
+ this.subscribeToAnthropicSessionStream(
14196
+ anthropicChannels.betaSessionsThreadsEventsStream,
14197
+ true
14198
+ );
14199
+ }
14200
+ subscribeToAnthropicSessionStream(channel2, isThread) {
14201
+ const tracingChannel = channel2.tracingChannel();
14202
+ const pending = /* @__PURE__ */ new WeakSet();
14203
+ const handlers = {
14204
+ start: (event) => {
14205
+ if (isAutoInstrumentationSuppressed()) {
14206
+ return;
14207
+ }
14208
+ pending.add(event);
14209
+ },
14210
+ asyncEnd: (event) => {
14211
+ if (!pending.delete(event)) {
14212
+ return;
14213
+ }
14214
+ const stream = event.result;
14215
+ if (!isAsyncIterable(stream)) {
14216
+ return;
14217
+ }
14218
+ registerAnthropicSessionStreamCollector(stream, () => {
14219
+ wrapAnthropicSessionEventStream(stream, isThread);
14220
+ });
14221
+ },
14222
+ error: (event) => {
14223
+ pending.delete(event);
14224
+ }
14225
+ };
14226
+ tracingChannel.subscribe(handlers);
14227
+ this.unsubscribers.push(() => tracingChannel.unsubscribe(handlers));
14228
+ }
13757
14229
  };
14230
+ function wrapAnthropicSessionEventStream(stream, isThread) {
14231
+ const state = {
14232
+ history: [],
14233
+ isThread,
14234
+ pendingInput: [],
14235
+ seenEventIds: /* @__PURE__ */ new Set()
14236
+ };
14237
+ patchStreamIfNeeded(stream, {
14238
+ onChunk: (event) => handleAnthropicSessionEvent(state, event),
14239
+ onComplete: () => finalizeAnthropicSessionTurn(state),
14240
+ onError: (error) => finalizeAnthropicSessionTurn(state, error)
14241
+ });
14242
+ return stream;
14243
+ }
14244
+ function handleAnthropicSessionEvent(state, event) {
14245
+ try {
14246
+ if (typeof event.id === "string" && event.type !== "event_delta" && state.seenEventIds.has(event.id)) {
14247
+ return;
14248
+ }
14249
+ if (typeof event.id === "string" && event.type !== "event_delta") {
14250
+ state.seenEventIds.add(event.id);
14251
+ }
14252
+ switch (event.type) {
14253
+ case "user.message":
14254
+ case "system.message":
14255
+ recordAnthropicSessionInput(
14256
+ state,
14257
+ event
14258
+ );
14259
+ break;
14260
+ case "session.status_running":
14261
+ if (!state.isThread) {
14262
+ ensureAnthropicSessionTurn(state);
14263
+ }
14264
+ break;
14265
+ case "session.thread_status_running":
14266
+ if (state.isThread) {
14267
+ ensureAnthropicSessionTurn(state);
14268
+ }
14269
+ break;
14270
+ case "span.model_request_start":
14271
+ if (typeof event.id === "string") {
14272
+ startAnthropicSessionModel(state, event.id);
14273
+ }
14274
+ break;
14275
+ case "event_delta":
14276
+ recordAnthropicSessionFirstToken(state, event);
14277
+ break;
14278
+ case "agent.message":
14279
+ recordAnthropicSessionMessage(
14280
+ state,
14281
+ event
14282
+ );
14283
+ break;
14284
+ case "agent.custom_tool_use":
14285
+ case "agent.mcp_tool_use":
14286
+ case "agent.tool_use":
14287
+ startAnthropicSessionTool(state, event);
14288
+ break;
14289
+ case "user.tool_confirmation":
14290
+ recordAnthropicSessionToolConfirmation(state, event);
14291
+ break;
14292
+ case "agent.mcp_tool_result":
14293
+ case "agent.tool_result":
14294
+ case "user.custom_tool_result":
14295
+ case "user.tool_result":
14296
+ finalizeAnthropicSessionTool(
14297
+ state,
14298
+ event
14299
+ );
14300
+ break;
14301
+ case "span.model_request_end":
14302
+ finalizeAnthropicSessionModel(
14303
+ state,
14304
+ event
14305
+ );
14306
+ break;
14307
+ case "session.status_idle":
14308
+ case "session.thread_status_idle": {
14309
+ if (event.type === "session.status_idle" && state.isThread || event.type === "session.thread_status_idle" && !state.isThread) {
14310
+ break;
14311
+ }
14312
+ const stopReason = isObject(event.stop_reason) ? event.stop_reason.type : void 0;
14313
+ if (stopReason === "end_turn") {
14314
+ finalizeAnthropicSessionTurn(state);
14315
+ } else if (stopReason === "retries_exhausted") {
14316
+ finalizeAnthropicSessionTurn(
14317
+ state,
14318
+ "Anthropic session retries exhausted"
14319
+ );
14320
+ }
14321
+ break;
14322
+ }
14323
+ case "session.error":
14324
+ finalizeAnthropicSessionTurn(state, event.error);
14325
+ break;
14326
+ case "session.deleted":
14327
+ case "session.status_terminated":
14328
+ case "session.thread_status_terminated":
14329
+ if (event.type === "session.deleted" || event.type === "session.status_terminated" && !state.isThread || event.type === "session.thread_status_terminated" && state.isThread) {
14330
+ finalizeAnthropicSessionTurn(state);
14331
+ }
14332
+ break;
14333
+ default:
14334
+ break;
14335
+ }
14336
+ } catch (error) {
14337
+ debugLogger.debug("Error processing Anthropic Sessions event:", error);
14338
+ }
14339
+ }
14340
+ function ensureAnthropicSessionTurn(state) {
14341
+ if (state.activeTurn) {
14342
+ return state.activeTurn;
14343
+ }
14344
+ const input = state.pendingInput;
14345
+ state.pendingInput = [];
14346
+ const span = startSpan(
14347
+ withSpanInstrumentationName(
14348
+ {
14349
+ event: {
14350
+ ...input.length > 0 ? { input } : {},
14351
+ metadata: { provider: "anthropic" }
14352
+ },
14353
+ name: state.isThread ? "anthropic.beta.sessions.thread.turn" : "anthropic.beta.sessions.turn",
14354
+ spanAttributes: { type: "task" /* TASK */ }
14355
+ },
14356
+ INSTRUMENTATION_NAMES.ANTHROPIC
14357
+ )
14358
+ );
14359
+ state.activeTurn = {
14360
+ activeTools: /* @__PURE__ */ new Map(),
14361
+ input: input.slice(),
14362
+ metrics: {},
14363
+ span
14364
+ };
14365
+ return state.activeTurn;
14366
+ }
14367
+ function recordAnthropicSessionInput(state, event) {
14368
+ const content = processAttachmentsInInput(event.content);
14369
+ const message = {
14370
+ role: event.type === "system.message" ? "system" : "user",
14371
+ content
14372
+ };
14373
+ state.history.push(message);
14374
+ if (state.activeTurn) {
14375
+ state.activeTurn.input.push(message);
14376
+ } else {
14377
+ state.pendingInput.push(message);
14378
+ }
14379
+ }
14380
+ function startAnthropicSessionModel(state, startEventId) {
14381
+ const turn = ensureAnthropicSessionTurn(state);
14382
+ if (turn.activeModel) {
14383
+ finalizeAnthropicSessionModelState(state, turn);
14384
+ }
14385
+ const span = withCurrent(
14386
+ turn.span,
14387
+ () => startSpan(
14388
+ withSpanInstrumentationName(
14389
+ {
14390
+ event: {
14391
+ ...state.history.length > 0 ? { input: state.history.slice() } : {},
14392
+ metadata: { provider: "anthropic" }
14393
+ },
14394
+ name: "anthropic.messages.create",
14395
+ spanAttributes: { type: "llm" /* LLM */ }
14396
+ },
14397
+ INSTRUMENTATION_NAMES.ANTHROPIC
14398
+ )
14399
+ )
14400
+ );
14401
+ turn.activeModel = {
14402
+ output: [],
14403
+ span,
14404
+ startEventId,
14405
+ startTime: getCurrentUnixTimestamp()
14406
+ };
14407
+ }
14408
+ function recordAnthropicSessionFirstToken(state, event) {
14409
+ const model = state.activeTurn?.activeModel;
14410
+ if (!model || model.firstTokenTime !== void 0 || !isObject(event.delta) || !isObject(event.delta.content) || typeof event.delta.content.text !== "string") {
14411
+ return;
14412
+ }
14413
+ model.firstTokenTime = getCurrentUnixTimestamp();
14414
+ }
14415
+ function recordAnthropicSessionMessage(state, event) {
14416
+ const turn = ensureAnthropicSessionTurn(state);
14417
+ const content = processAttachmentsInInput(
14418
+ event.content
14419
+ );
14420
+ if (turn.activeModel) {
14421
+ turn.activeModel.output.push(...content);
14422
+ } else {
14423
+ const output = { role: "assistant", content };
14424
+ turn.lastOutput = output;
14425
+ state.history.push(output);
14426
+ }
14427
+ }
14428
+ function startAnthropicSessionTool(state, event) {
14429
+ const turn = ensureAnthropicSessionTurn(state);
14430
+ if (turn.activeModel) {
14431
+ turn.activeModel.output.push({
14432
+ type: "tool_use",
14433
+ id: event.id,
14434
+ name: event.name,
14435
+ input: event.input
14436
+ });
14437
+ }
14438
+ const existing = turn.activeTools.get(event.id);
14439
+ if (existing) {
14440
+ existing.span.end();
14441
+ turn.activeTools.delete(event.id);
14442
+ }
14443
+ const span = withCurrent(
14444
+ turn.span,
14445
+ () => startSpan(
14446
+ withSpanInstrumentationName(
14447
+ {
14448
+ event: { input: event.input },
14449
+ name: event.name,
14450
+ spanAttributes: { type: "tool" /* TOOL */ }
14451
+ },
14452
+ INSTRUMENTATION_NAMES.ANTHROPIC
14453
+ )
14454
+ )
14455
+ );
14456
+ const toolState = {
14457
+ approval: event.evaluated_permission === "allow" ? "approved" : event.evaluated_permission === "deny" ? "denied" : void 0,
14458
+ span
14459
+ };
14460
+ turn.activeTools.set(event.id, toolState);
14461
+ if (toolState.approval === "denied") {
14462
+ finalizeAnthropicSessionToolState(toolState);
14463
+ turn.activeTools.delete(event.id);
14464
+ }
14465
+ }
14466
+ function recordAnthropicSessionToolConfirmation(state, event) {
14467
+ if (typeof event.tool_use_id !== "string" || event.result !== "allow" && event.result !== "deny") {
14468
+ return;
14469
+ }
14470
+ const turn = state.activeTurn;
14471
+ const tool = turn?.activeTools.get(event.tool_use_id);
14472
+ if (!turn || !tool) {
14473
+ return;
14474
+ }
14475
+ tool.approval = event.result === "allow" ? "approved" : "denied";
14476
+ if (tool.approval === "denied") {
14477
+ finalizeAnthropicSessionToolState(tool);
14478
+ turn.activeTools.delete(event.tool_use_id);
14479
+ }
14480
+ }
14481
+ function finalizeAnthropicSessionTool(state, event) {
14482
+ const toolUseId = event.tool_use_id ?? event.mcp_tool_use_id ?? event.custom_tool_use_id;
14483
+ if (!toolUseId) {
14484
+ return;
14485
+ }
14486
+ const content = processAttachmentsInInput(event.content);
14487
+ const turn = state.activeTurn;
14488
+ const tool = turn?.activeTools.get(toolUseId);
14489
+ if (turn && tool) {
14490
+ finalizeAnthropicSessionToolState(tool, event, content);
14491
+ turn.activeTools.delete(toolUseId);
14492
+ }
14493
+ const toolResult = {
14494
+ type: "tool_result",
14495
+ tool_use_id: toolUseId,
14496
+ ...content !== void 0 ? { content } : {},
14497
+ ...event.is_error === true ? { is_error: true } : {}
14498
+ };
14499
+ state.history.push({
14500
+ role: "user",
14501
+ content: [toolResult]
14502
+ });
14503
+ }
14504
+ function finalizeAnthropicSessionToolState(state, event, content = event?.content) {
14505
+ safeAnthropicSessionLog(state.span, {
14506
+ ...event?.is_error === true ? {
14507
+ error: content ?? "Anthropic session tool execution failed"
14508
+ } : {},
14509
+ ...state.approval ? { metadata: { tool_approval: state.approval } } : {},
14510
+ ...content !== void 0 ? { output: content } : {}
14511
+ });
14512
+ state.span.end();
14513
+ }
14514
+ function finalizeAnthropicSessionModel(state, event) {
14515
+ const turn = state.activeTurn;
14516
+ const model = turn?.activeModel;
14517
+ if (!turn || !model || model.startEventId !== event.model_request_start_id) {
14518
+ return;
14519
+ }
14520
+ finalizeAnthropicSessionModelState(state, turn, event);
14521
+ }
14522
+ function finalizeAnthropicSessionModelState(state, turn, event) {
14523
+ const model = turn.activeModel;
14524
+ if (!model) {
14525
+ return;
14526
+ }
14527
+ turn.activeModel = void 0;
14528
+ const metrics = event ? parseAnthropicSessionModelUsage(event.model_usage) : {};
14529
+ if (model.firstTokenTime !== void 0) {
14530
+ metrics.time_to_first_token = model.firstTokenTime - model.startTime;
14531
+ }
14532
+ const output = model.output.length > 0 ? { role: "assistant", content: model.output } : void 0;
14533
+ safeAnthropicSessionLog(model.span, {
14534
+ ...event?.is_error ? { error: "Anthropic session model request failed" } : {},
14535
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
14536
+ ...output ? { output } : {}
14537
+ });
14538
+ model.span.end();
14539
+ if (output) {
14540
+ turn.lastOutput = output;
14541
+ state.history.push(output);
14542
+ }
14543
+ for (const key of [
14544
+ "prompt_tokens",
14545
+ "completion_tokens",
14546
+ "tokens",
14547
+ "prompt_cached_tokens",
14548
+ "prompt_cache_creation_tokens"
14549
+ ]) {
14550
+ const value = metrics[key];
14551
+ if (typeof value === "number") {
14552
+ turn.metrics[key] = (turn.metrics[key] ?? 0) + value;
14553
+ }
14554
+ }
14555
+ }
14556
+ function parseAnthropicSessionModelUsage(usage) {
14557
+ const finalized = finalizeAnthropicTokens({
14558
+ completion_tokens: usage.output_tokens,
14559
+ prompt_cache_creation_tokens: usage.cache_creation_input_tokens,
14560
+ prompt_cached_tokens: usage.cache_read_input_tokens,
14561
+ prompt_tokens: usage.input_tokens
14562
+ });
14563
+ return Object.fromEntries(
14564
+ Object.entries(finalized).filter(
14565
+ (entry) => entry[1] !== void 0
14566
+ )
14567
+ );
14568
+ }
14569
+ function finalizeAnthropicSessionTurn(state, error) {
14570
+ const turn = state.activeTurn;
14571
+ if (!turn) {
14572
+ return;
14573
+ }
14574
+ state.activeTurn = void 0;
14575
+ finalizeAnthropicSessionModelState(state, turn);
14576
+ for (const tool of turn.activeTools.values()) {
14577
+ finalizeAnthropicSessionToolState(tool);
14578
+ }
14579
+ turn.activeTools.clear();
14580
+ safeAnthropicSessionLog(turn.span, {
14581
+ ...error !== void 0 ? { error: error instanceof Error ? error : toLoggedError(error) } : {},
14582
+ ...turn.input.length > 0 ? { input: turn.input } : {},
14583
+ ...turn.lastOutput ? { output: turn.lastOutput } : {},
14584
+ ...Object.keys(turn.metrics).length > 0 ? { metrics: turn.metrics } : {}
14585
+ });
14586
+ turn.span.end();
14587
+ }
14588
+ function safeAnthropicSessionLog(span, event) {
14589
+ try {
14590
+ span.log(event);
14591
+ } catch (error) {
14592
+ debugLogger.debug("Error logging Anthropic Sessions span:", error);
14593
+ }
14594
+ }
13758
14595
  function parseMetricsFromUsage2(usage) {
13759
14596
  if (!usage) {
13760
14597
  return {};
@@ -13770,6 +14607,18 @@ function parseMetricsFromUsage2(usage) {
13770
14607
  saveIfExistsTo("output_tokens", "completion_tokens");
13771
14608
  saveIfExistsTo("cache_read_input_tokens", "prompt_cached_tokens");
13772
14609
  saveIfExistsTo("cache_creation_input_tokens", "prompt_cache_creation_tokens");
14610
+ if (isObject(usage.cache_creation)) {
14611
+ const cacheCreation = usage.cache_creation;
14612
+ for (const [source, target] of [
14613
+ ["ephemeral_5m_input_tokens", "prompt_cache_creation_5m_tokens"],
14614
+ ["ephemeral_1h_input_tokens", "prompt_cache_creation_1h_tokens"]
14615
+ ]) {
14616
+ const value = cacheCreation[source];
14617
+ if (typeof value === "number") {
14618
+ metrics[target] = value;
14619
+ }
14620
+ }
14621
+ }
13773
14622
  if (isObject(usage.server_tool_use)) {
13774
14623
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
13775
14624
  if (typeof value === "number") {
@@ -15628,6 +16477,29 @@ var harnessAgentChannels = defineChannels(
15628
16477
  { instrumentationName: INSTRUMENTATION_NAMES.AI_SDK }
15629
16478
  );
15630
16479
 
16480
+ // src/instrumentation/plugins/cloudflare-think-context.ts
16481
+ var cloudflareThinkSpans = /* @__PURE__ */ new Map();
16482
+ function registerCloudflareThinkSpan(span) {
16483
+ if (span.spanId) {
16484
+ cloudflareThinkSpans.set(span.spanId, span);
16485
+ }
16486
+ }
16487
+ function unregisterCloudflareThinkSpan(span) {
16488
+ if (span.spanId) {
16489
+ cloudflareThinkSpans.delete(span.spanId);
16490
+ }
16491
+ }
16492
+ function currentCloudflareThinkSpan() {
16493
+ const parentSpanIds = _internalGetGlobalState()?.contextManager.getParentSpanIds()?.spanParents ?? [];
16494
+ for (const parentSpanId of parentSpanIds) {
16495
+ const span = cloudflareThinkSpans.get(parentSpanId);
16496
+ if (span) {
16497
+ return span;
16498
+ }
16499
+ }
16500
+ return void 0;
16501
+ }
16502
+
15631
16503
  // src/instrumentation/plugins/ai-sdk-plugin.ts
15632
16504
  var DEFAULT_DENY_OUTPUT_PATHS = [
15633
16505
  // v3
@@ -15734,6 +16606,7 @@ var AISDKPlugin = class extends BasePlugin {
15734
16606
  traceStreamingChannel(aiSDKChannels.streamText, {
15735
16607
  name: "streamText",
15736
16608
  type: "function" /* FUNCTION */,
16609
+ shouldTrace: () => currentCloudflareThinkSpan() === void 0,
15737
16610
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15738
16611
  extractOutput: (result, endEvent) => processAISDKOutput(
15739
16612
  result,
@@ -15754,6 +16627,7 @@ var AISDKPlugin = class extends BasePlugin {
15754
16627
  traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
15755
16628
  name: "streamText",
15756
16629
  type: "function" /* FUNCTION */,
16630
+ shouldTrace: () => currentCloudflareThinkSpan() === void 0,
15757
16631
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15758
16632
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
15759
16633
  defaultDenyOutputPaths: denyOutputPaths,
@@ -16336,7 +17210,7 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
16336
17210
  return defaultDenyOutputPaths;
16337
17211
  }
16338
17212
  const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
16339
- if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path2) => typeof path2 === "string")) {
17213
+ if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path3) => typeof path3 === "string")) {
16340
17214
  return runtimeDenyOutputPaths;
16341
17215
  }
16342
17216
  return defaultDenyOutputPaths;
@@ -16739,6 +17613,23 @@ function prepareAISDKWorkflowAgentStreamInput(params, event, span, defaultDenyOu
16739
17613
  metadata
16740
17614
  };
16741
17615
  }
17616
+ function prepareAISDKAgentCallInput(params, event, span, defaultDenyOutputPaths = DEFAULT_DENY_OUTPUT_PATHS) {
17617
+ const { input } = processAISDKWorkflowAgentCallInput(params);
17618
+ const metadata = extractMetadataFromCallParams(params, event.self);
17619
+ const childTracing = prepareAISDKChildTracing(
17620
+ params,
17621
+ event.self,
17622
+ span,
17623
+ defaultDenyOutputPaths,
17624
+ event.aiSDK,
17625
+ { agentOwner: true }
17626
+ );
17627
+ event.modelWrapped = childTracing.modelWrapped;
17628
+ if (childTracing.cleanup) {
17629
+ event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
17630
+ }
17631
+ return { input, metadata };
17632
+ }
16742
17633
  function prepareAISDKEmbedInput(params, self) {
16743
17634
  return {
16744
17635
  input: { ...params },
@@ -16762,6 +17653,18 @@ function extractTopLevelAISDKMetrics(result, event, startTime) {
16762
17653
  }
16763
17654
  return metrics;
16764
17655
  }
17656
+ async function extractResolvedAISDKTokenMetrics(result) {
17657
+ for (const field of ["totalUsage", "usage"]) {
17658
+ try {
17659
+ const usage = await Promise.resolve(result[field]);
17660
+ if (usage !== void 0) {
17661
+ return extractTokenMetrics({ [field]: usage });
17662
+ }
17663
+ } catch {
17664
+ }
17665
+ }
17666
+ return extractTokenMetrics(result);
17667
+ }
16765
17668
  function hasModelChildTracing(event) {
16766
17669
  return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
16767
17670
  }
@@ -17579,13 +18482,15 @@ function patchAISDKStreamingResult(args) {
17579
18482
  const {
17580
18483
  defaultDenyOutputPaths,
17581
18484
  endEvent,
18485
+ forceTopLevelMetrics,
17582
18486
  onComplete,
17583
18487
  onCancel,
17584
18488
  onError,
17585
18489
  result,
17586
18490
  resolvePromiseUsage,
17587
18491
  span,
17588
- startTime
18492
+ startTime,
18493
+ transformOutput
17589
18494
  } = args;
17590
18495
  if (!result || typeof result !== "object") {
17591
18496
  return false;
@@ -17638,8 +18543,8 @@ function patchAISDKStreamingResult(args) {
17638
18543
  }
17639
18544
  outputLogged = true;
17640
18545
  try {
17641
- const metrics = extractTopLevelAISDKMetrics(result, endEvent);
17642
- if (resolvePromiseUsage) {
18546
+ const metrics = forceTopLevelMetrics ? await extractResolvedAISDKTokenMetrics(result) : extractTopLevelAISDKMetrics(result, endEvent);
18547
+ if (resolvePromiseUsage && !forceTopLevelMetrics) {
17643
18548
  try {
17644
18549
  const resultRecord2 = result;
17645
18550
  const pendingUsage = resultRecord2.totalUsage ?? resultRecord2.usage;
@@ -17658,10 +18563,11 @@ function patchAISDKStreamingResult(args) {
17658
18563
  if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
17659
18564
  metrics.time_to_first_token = firstChunkTime - startTime;
17660
18565
  }
17661
- const output = await processAISDKStreamingOutput(
18566
+ const processedOutput = await processAISDKStreamingOutput(
17662
18567
  result,
17663
18568
  resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
17664
18569
  );
18570
+ const output = transformOutput ? transformOutput(processedOutput) : processedOutput;
17665
18571
  const metadata = buildResolvedMetadataPayload(result).metadata;
17666
18572
  try {
17667
18573
  span.log({
@@ -18066,11 +18972,11 @@ function processAISDKOutput(output, denyOutputPaths) {
18066
18972
  if (!output) return output;
18067
18973
  const merged = extractSerializableOutputFields(output);
18068
18974
  const deleteOutputPaths = denyOutputPaths.filter(
18069
- (path2) => path2.toLowerCase().endsWith("headers")
18975
+ (path3) => path3.toLowerCase().endsWith("headers")
18070
18976
  );
18071
18977
  const sanitized = omit(merged, denyOutputPaths, deleteOutputPaths);
18072
- for (const path2 of TRANSPORT_PAYLOAD_ROOT_PATHS) {
18073
- const stack = [{ obj: sanitized, keys: parsePath(path2) }];
18978
+ for (const path3 of TRANSPORT_PAYLOAD_ROOT_PATHS) {
18979
+ const stack = [{ obj: sanitized, keys: parsePath(path3) }];
18074
18980
  while (stack.length > 0) {
18075
18981
  const entry = stack.pop();
18076
18982
  if (!entry || entry.keys.length === 0) {
@@ -18509,11 +19415,11 @@ function firstNumber2(...values) {
18509
19415
  function deepCopy(obj) {
18510
19416
  return JSON.parse(JSON.stringify(obj));
18511
19417
  }
18512
- function parsePath(path2) {
19418
+ function parsePath(path3) {
18513
19419
  const keys = [];
18514
19420
  let current = "";
18515
- for (let i = 0; i < path2.length; i++) {
18516
- const char = path2[i];
19421
+ for (let i = 0; i < path3.length; i++) {
19422
+ const char = path3[i];
18517
19423
  if (char === ".") {
18518
19424
  if (current) {
18519
19425
  keys.push(current);
@@ -18526,8 +19432,8 @@ function parsePath(path2) {
18526
19432
  }
18527
19433
  let bracketContent = "";
18528
19434
  i++;
18529
- while (i < path2.length && path2[i] !== "]") {
18530
- bracketContent += path2[i];
19435
+ while (i < path3.length && path3[i] !== "]") {
19436
+ bracketContent += path3[i];
18531
19437
  i++;
18532
19438
  }
18533
19439
  if (bracketContent === "") {
@@ -18582,9 +19488,9 @@ function omitAtPath(obj, keys, deleteLeaf = false) {
18582
19488
  function omit(obj, paths, deletePaths = []) {
18583
19489
  const result = deepCopy(obj);
18584
19490
  const deletePathSet = new Set(deletePaths);
18585
- for (const path2 of paths) {
18586
- const keys = parsePath(path2);
18587
- omitAtPath(result, keys, deletePathSet.has(path2));
19491
+ for (const path3 of paths) {
19492
+ const keys = parsePath(path3);
19493
+ omitAtPath(result, keys, deletePathSet.has(path3));
18588
19494
  }
18589
19495
  return result;
18590
19496
  }
@@ -19011,37 +19917,97 @@ function seedTaskToolUseIdMapping(taskIdToToolUseId, message) {
19011
19917
  taskIdToToolUseId.set(message.task_id, message.tool_use_id);
19012
19918
  }
19013
19919
  }
19014
- function extractUsageFromMessage(message) {
19015
- const metrics = {};
19016
- let usage;
19017
- if (message.type === "assistant") {
19018
- usage = message.message?.usage;
19019
- } else if (message.type === "result") {
19020
- usage = message.usage;
19021
- }
19920
+ function tokenCount(value) {
19921
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : void 0;
19922
+ }
19923
+ function copyUsage(usage) {
19022
19924
  if (!usage || typeof usage !== "object") {
19023
- return metrics;
19925
+ return void 0;
19926
+ }
19927
+ const copy = {};
19928
+ for (const key of [
19929
+ "input_tokens",
19930
+ "output_tokens",
19931
+ "cache_read_input_tokens",
19932
+ "cache_creation_input_tokens"
19933
+ ]) {
19934
+ const value = tokenCount(Reflect.get(usage, key));
19935
+ if (value !== void 0) {
19936
+ copy[key] = value;
19937
+ }
19938
+ }
19939
+ const cacheCreation = Reflect.get(usage, "cache_creation");
19940
+ if (cacheCreation && typeof cacheCreation === "object") {
19941
+ const cacheCreationCopy = {};
19942
+ for (const key of [
19943
+ "ephemeral_5m_input_tokens",
19944
+ "ephemeral_1h_input_tokens"
19945
+ ]) {
19946
+ const value = tokenCount(Reflect.get(cacheCreation, key));
19947
+ if (value !== void 0) {
19948
+ cacheCreationCopy[key] = value;
19949
+ }
19950
+ }
19951
+ if (Object.keys(cacheCreationCopy).length > 0) {
19952
+ copy.cache_creation = cacheCreationCopy;
19953
+ }
19954
+ }
19955
+ return Object.keys(copy).length > 0 ? copy : void 0;
19956
+ }
19957
+ function mergeUsage(base, override) {
19958
+ if (!base || !override) {
19959
+ return override ?? base;
19960
+ }
19961
+ const cacheCreation = base.cache_creation || override.cache_creation ? { ...base.cache_creation, ...override.cache_creation } : void 0;
19962
+ return {
19963
+ ...base,
19964
+ ...override,
19965
+ ...cacheCreation && { cache_creation: cacheCreation }
19966
+ };
19967
+ }
19968
+ function extractUsage(usage, includeOutput) {
19969
+ const metrics = {};
19970
+ if (!usage) {
19971
+ return {};
19024
19972
  }
19025
19973
  const inputTokens = getNumberProperty(usage, "input_tokens");
19026
19974
  if (inputTokens !== void 0) {
19027
19975
  metrics.prompt_tokens = inputTokens;
19028
19976
  }
19029
- const outputTokens = getNumberProperty(usage, "output_tokens");
19030
- if (outputTokens !== void 0) {
19031
- metrics.completion_tokens = outputTokens;
19977
+ if (includeOutput) {
19978
+ const outputTokens = getNumberProperty(usage, "output_tokens");
19979
+ if (outputTokens !== void 0) {
19980
+ metrics.completion_tokens = outputTokens;
19981
+ }
19032
19982
  }
19033
19983
  const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
19034
19984
  const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
19035
- if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
19036
- Object.assign(
19037
- metrics,
19038
- extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
19039
- );
19985
+ Object.assign(
19986
+ metrics,
19987
+ extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
19988
+ );
19989
+ const cacheCreation5mTokens = getNumberProperty(
19990
+ usage.cache_creation,
19991
+ "ephemeral_5m_input_tokens"
19992
+ );
19993
+ const cacheCreation1hTokens = getNumberProperty(
19994
+ usage.cache_creation,
19995
+ "ephemeral_1h_input_tokens"
19996
+ );
19997
+ if (cacheCreation5mTokens !== void 0) {
19998
+ metrics.prompt_cache_creation_5m_tokens = cacheCreation5mTokens;
19040
19999
  }
19041
- if (Object.keys(metrics).length > 0) {
19042
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
20000
+ if (cacheCreation1hTokens !== void 0) {
20001
+ metrics.prompt_cache_creation_1h_tokens = cacheCreation1hTokens;
19043
20002
  }
19044
- return metrics;
20003
+ if (Object.keys(metrics).length === 0) {
20004
+ return {};
20005
+ }
20006
+ const finalized = finalizeAnthropicTokens(metrics);
20007
+ if (metrics.completion_tokens === void 0) {
20008
+ delete finalized.tokens;
20009
+ }
20010
+ return toNumericMetrics(finalized);
19045
20011
  }
19046
20012
  function buildLLMInput(promptMessages, conversationHistory) {
19047
20013
  const inputParts = [...promptMessages, ...conversationHistory];
@@ -19075,16 +20041,16 @@ function buildRootPromptMessages(prompt, capturedPromptMessages) {
19075
20041
  function formatCapturedMessages(messages) {
19076
20042
  return messages.length > 0 ? messages : [];
19077
20043
  }
19078
- async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
20044
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, usage, hasFinalOutputUsage, existingSpan) {
19079
20045
  if (messages.length === 0) {
19080
20046
  return void 0;
19081
20047
  }
19082
20048
  const lastMessage = messages[messages.length - 1];
19083
- if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
20049
+ if (lastMessage.type !== "assistant") {
19084
20050
  return void 0;
19085
20051
  }
19086
- const model = lastMessage.message.model || options.model;
19087
- const usage = extractUsageFromMessage(lastMessage);
20052
+ const model = lastMessage.message?.model || options.model;
20053
+ const metrics = options.includePartialMessages ? extractUsage(usage, hasFinalOutputUsage) : {};
19088
20054
  const input = buildLLMInput(promptMessages, conversationHistory);
19089
20055
  const outputs = messages.map(
19090
20056
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
@@ -19106,8 +20072,8 @@ async function createLLMSpanForMessages(messages, promptMessages, conversationHi
19106
20072
  );
19107
20073
  span.log({
19108
20074
  input,
19109
- metadata: model ? { model } : void 0,
19110
- metrics: usage,
20075
+ metadata: { ...model && { model }, provider: "anthropic" },
20076
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
19111
20077
  output: outputs
19112
20078
  });
19113
20079
  const spanExport = await span.export();
@@ -19197,11 +20163,17 @@ function prepareLocalToolHandlersInMcpServers(mcpServers) {
19197
20163
  }
19198
20164
  return { hasLocalToolHandlers, localToolHookNames };
19199
20165
  }
19200
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20166
+ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
19201
20167
  const preToolUse = async (input, toolUseID) => {
19202
20168
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
19203
20169
  return {};
19204
20170
  }
20171
+ if (!toolUseToParent.has(toolUseID) && input.agent_id) {
20172
+ const parentToolUseId = taskIdToToolUseId.get(input.agent_id);
20173
+ if (parentToolUseId) {
20174
+ toolUseToParent.set(toolUseID, parentToolUseId);
20175
+ }
20176
+ }
19205
20177
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
19206
20178
  return {};
19207
20179
  }
@@ -19397,9 +20369,6 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
19397
20369
  }
19398
20370
  const metadata = {
19399
20371
  ...subAgentDetailsToMetadata(details),
19400
- ...input.agent_transcript_path && {
19401
- "claude_agent_sdk.agent_transcript_path": input.agent_transcript_path
19402
- },
19403
20372
  "claude_agent_sdk.stop_hook_active": input.stop_hook_active
19404
20373
  };
19405
20374
  try {
@@ -19421,7 +20390,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
19421
20390
  subagentStop
19422
20391
  };
19423
20392
  }
19424
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20393
+ function injectTracingHooks(options, resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
19425
20394
  const {
19426
20395
  preToolUse,
19427
20396
  postToolUse,
@@ -19430,6 +20399,8 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
19430
20399
  subagentStop
19431
20400
  } = createToolTracingHooks(
19432
20401
  resolveParentSpan,
20402
+ taskIdToToolUseId,
20403
+ toolUseToParent,
19433
20404
  activeToolSpans,
19434
20405
  options.mcpServers,
19435
20406
  localToolHookNames,
@@ -19511,6 +20482,13 @@ async function finalizeCurrentMessageGroup(state) {
19511
20482
  }
19512
20483
  }
19513
20484
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
20485
+ const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20486
+ const messageId = lastMessage?.message?.id;
20487
+ const usage = state.options.includePartialMessages ? mergeUsage(
20488
+ copyUsage(lastMessage?.message?.usage),
20489
+ messageId ? state.usageByMessageId.get(messageId) : void 0
20490
+ ) : void 0;
20491
+ const hasFinalOutputUsage = messageId !== void 0 && state.finalOutputUsageMessageIds.has(messageId);
19514
20492
  const llmSpanResult = await createLLMSpanForMessages(
19515
20493
  state.currentMessages,
19516
20494
  promptMessages,
@@ -19518,6 +20496,8 @@ async function finalizeCurrentMessageGroup(state) {
19518
20496
  state.options,
19519
20497
  state.currentMessageStartTime,
19520
20498
  parentSpan,
20499
+ usage,
20500
+ hasFinalOutputUsage,
19521
20501
  existingLlmSpan
19522
20502
  );
19523
20503
  if (llmSpanResult) {
@@ -19535,9 +20515,17 @@ async function finalizeCurrentMessageGroup(state) {
19535
20515
  }
19536
20516
  }
19537
20517
  state.activeLlmSpansByParentToolUse.delete(parentKey);
19538
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
19539
- if (lastMessage?.message?.usage) {
19540
- state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
20518
+ if (messageId) {
20519
+ state.usageByMessageId.delete(messageId);
20520
+ state.finalOutputUsageMessageIds.delete(messageId);
20521
+ for (const [
20522
+ parent,
20523
+ activeMessageId
20524
+ ] of state.activePartialMessageIdByParentKey) {
20525
+ if (activeMessageId === messageId) {
20526
+ state.activePartialMessageIdByParentKey.delete(parent);
20527
+ }
20528
+ }
19541
20529
  }
19542
20530
  state.currentMessages.length = 0;
19543
20531
  }
@@ -19628,6 +20616,10 @@ async function ensureActiveLlmSpanForParentToolUse(rootSpan, activeLlmSpansByPar
19628
20616
  );
19629
20617
  llmParentSpan = await subAgentSpan.export();
19630
20618
  }
20619
+ const racedLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
20620
+ if (racedLlmSpan) {
20621
+ return racedLlmSpan;
20622
+ }
19631
20623
  const llmSpan = startSpan(
19632
20624
  withSpanInstrumentationName(
19633
20625
  {
@@ -19747,7 +20739,49 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
19747
20739
  }
19748
20740
  return true;
19749
20741
  }
20742
+ function handlePartialUsageMessage(state, message) {
20743
+ if (message.type !== "stream_event") {
20744
+ return false;
20745
+ }
20746
+ const event = message.event;
20747
+ if (!event || typeof event !== "object") {
20748
+ return true;
20749
+ }
20750
+ const parentKey = llmParentKey(message.parent_tool_use_id ?? null);
20751
+ if (event.type === "message_start") {
20752
+ const messageId2 = event.message?.id;
20753
+ const usage = copyUsage(event.message?.usage);
20754
+ if (messageId2) {
20755
+ state.activePartialMessageIdByParentKey.set(parentKey, messageId2);
20756
+ if (usage) {
20757
+ state.usageByMessageId.set(messageId2, usage);
20758
+ }
20759
+ }
20760
+ return true;
20761
+ }
20762
+ const messageId = state.activePartialMessageIdByParentKey.get(parentKey);
20763
+ if (!messageId) {
20764
+ return true;
20765
+ }
20766
+ if (event.type === "message_delta") {
20767
+ const update = copyUsage(event.usage);
20768
+ if (update) {
20769
+ const usage = state.usageByMessageId.get(messageId) ?? {};
20770
+ Object.assign(usage, update);
20771
+ state.usageByMessageId.set(messageId, usage);
20772
+ if (update.output_tokens !== void 0) {
20773
+ state.finalOutputUsageMessageIds.add(messageId);
20774
+ }
20775
+ }
20776
+ } else if (event.type === "message_stop") {
20777
+ state.activePartialMessageIdByParentKey.delete(parentKey);
20778
+ }
20779
+ return true;
20780
+ }
19750
20781
  async function handleStreamMessage(state, message) {
20782
+ if (handlePartialUsageMessage(state, message)) {
20783
+ return;
20784
+ }
19751
20785
  maybeTrackToolUseContext(state, message);
19752
20786
  if (await maybeHandleTaskLifecycleMessage(state, message)) {
19753
20787
  return;
@@ -19794,36 +20828,9 @@ async function handleStreamMessage(state, message) {
19794
20828
  );
19795
20829
  state.currentMessages.push(message);
19796
20830
  }
19797
- if (message.type !== "result" || !message.usage) {
20831
+ if (message.type !== "result") {
19798
20832
  return;
19799
20833
  }
19800
- const finalUsageMetrics = extractUsageFromMessage(message);
19801
- if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
19802
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
19803
- if (lastMessage?.message?.usage) {
19804
- const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
19805
- if (adjustedTokens >= 0) {
19806
- lastMessage.message.usage.output_tokens = adjustedTokens;
19807
- }
19808
- const resultUsage = message.usage;
19809
- if (resultUsage && typeof resultUsage === "object") {
19810
- const cacheReadTokens = getNumberProperty(
19811
- resultUsage,
19812
- "cache_read_input_tokens"
19813
- );
19814
- if (cacheReadTokens !== void 0) {
19815
- lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
19816
- }
19817
- const cacheCreationTokens = getNumberProperty(
19818
- resultUsage,
19819
- "cache_creation_input_tokens"
19820
- );
19821
- if (cacheCreationTokens !== void 0) {
19822
- lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
19823
- }
19824
- }
19825
- }
19826
- }
19827
20834
  const metadata = {};
19828
20835
  if (message.num_turns !== void 0) {
19829
20836
  metadata.num_turns = message.num_turns;
@@ -19831,8 +20838,12 @@ async function handleStreamMessage(state, message) {
19831
20838
  if (message.session_id !== void 0) {
19832
20839
  metadata.session_id = message.session_id;
19833
20840
  }
19834
- if (Object.keys(metadata).length > 0) {
19835
- state.span.log({ metadata });
20841
+ const metrics = state.options.includePartialMessages ? {} : extractUsage(copyUsage(message.usage), true);
20842
+ if (Object.keys(metadata).length > 0 || Object.keys(metrics).length > 0) {
20843
+ state.span.log({
20844
+ ...Object.keys(metadata).length > 0 ? { metadata } : {},
20845
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
20846
+ });
19836
20847
  }
19837
20848
  }
19838
20849
  async function finalizeQuerySpan(state) {
@@ -19856,6 +20867,9 @@ async function finalizeQuerySpan(state) {
19856
20867
  llmSpan.end();
19857
20868
  }
19858
20869
  state.activeLlmSpansByParentToolUse.clear();
20870
+ state.activePartialMessageIdByParentKey.clear();
20871
+ state.finalOutputUsageMessageIds.clear();
20872
+ state.usageByMessageId.clear();
19859
20873
  for (const toolSpan of state.activeToolSpans.values()) {
19860
20874
  toolSpan.end();
19861
20875
  }
@@ -19980,6 +20994,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19980
20994
  const optionsWithHooks = injectTracingHooks(
19981
20995
  options,
19982
20996
  resolveToolUseParentSpan,
20997
+ taskIdToToolUseId,
20998
+ toolUseToParent,
19983
20999
  activeToolSpans,
19984
21000
  localToolHookNames,
19985
21001
  skipLocalToolHooks,
@@ -19990,8 +21006,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19990
21006
  params.options = optionsWithHooks;
19991
21007
  event.arguments[0] = params;
19992
21008
  spans.set(event, {
19993
- accumulatedOutputTokens: 0,
19994
21009
  activeLlmSpansByParentToolUse,
21010
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
19995
21011
  activeToolSpans,
19996
21012
  conversationHistoryByParentKey,
19997
21013
  capturedPromptMessages,
@@ -19999,6 +21015,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19999
21015
  currentMessageStartTime: startTime,
20000
21016
  currentMessages: [],
20001
21017
  endedSubAgentSpans,
21018
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
20002
21019
  finalResults: [],
20003
21020
  options: optionsWithHooks,
20004
21021
  originalPrompt,
@@ -20014,6 +21031,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
20014
21031
  latestLlmParentBySubAgentToolUse,
20015
21032
  latestRootLlmParentRef,
20016
21033
  toolUseToParent,
21034
+ usageByMessageId: /* @__PURE__ */ new Map(),
20017
21035
  localToolContext
20018
21036
  });
20019
21037
  },
@@ -20083,6 +21101,295 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
20083
21101
  }
20084
21102
  };
20085
21103
 
21104
+ // src/instrumentation/plugins/cloudflare-think-channels.ts
21105
+ var cloudflareThinkChannels = defineChannels(
21106
+ "@cloudflare/think",
21107
+ {
21108
+ runInferenceLoop: channel({
21109
+ channelName: "Think.runInferenceLoop",
21110
+ kind: "async"
21111
+ })
21112
+ },
21113
+ { instrumentationName: INSTRUMENTATION_NAMES.CLOUDFLARE_THINK }
21114
+ );
21115
+
21116
+ // src/instrumentation/plugins/cloudflare-think-plugin.ts
21117
+ var THINK_STATE_ID = /* @__PURE__ */ Symbol.for("braintrust.cloudflare-think.state-id");
21118
+ var CloudflareThinkPlugin = class extends BasePlugin {
21119
+ statesBySpanId = /* @__PURE__ */ new Map();
21120
+ onEnable() {
21121
+ this.subscribeToThinkRuns();
21122
+ this.subscribeToAISDKStreamTextSync();
21123
+ this.subscribeToAISDKStreamTextAsync();
21124
+ }
21125
+ onDisable() {
21126
+ for (const unsubscribe of this.unsubscribers) {
21127
+ unsubscribe();
21128
+ }
21129
+ this.unsubscribers = [];
21130
+ for (const state of this.statesBySpanId.values()) {
21131
+ this.finishState(state);
21132
+ }
21133
+ this.statesBySpanId.clear();
21134
+ }
21135
+ subscribeToThinkRuns() {
21136
+ const channel2 = cloudflareThinkChannels.runInferenceLoop.tracingChannel();
21137
+ const states = /* @__PURE__ */ new WeakMap();
21138
+ const state = _internalGetGlobalState();
21139
+ const contextManager = state?.contextManager;
21140
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
21141
+ const ensureState2 = (event) => {
21142
+ if (isAutoInstrumentationSuppressed()) {
21143
+ return void 0;
21144
+ }
21145
+ const existing = states.get(event);
21146
+ if (existing) {
21147
+ return existing;
21148
+ }
21149
+ const span = startSpan(
21150
+ withSpanInstrumentationName(
21151
+ {
21152
+ name: "Think.runTurn",
21153
+ spanAttributes: { type: "task" /* TASK */ }
21154
+ },
21155
+ INSTRUMENTATION_NAMES.CLOUDFLARE_THINK
21156
+ )
21157
+ );
21158
+ const runState = {
21159
+ aiResultPatched: false,
21160
+ fallbackInput: extractFallbackInput(event.self?.messages),
21161
+ finalized: false,
21162
+ inputLogged: false,
21163
+ span,
21164
+ startTime: getCurrentUnixTimestamp()
21165
+ };
21166
+ const metadata = {
21167
+ braintrust: {
21168
+ integration_name: "cloudflare-think",
21169
+ sdk_language: "typescript"
21170
+ }
21171
+ };
21172
+ if (typeof event.moduleVersion === "string") {
21173
+ metadata["cloudflare_think.version"] = event.moduleVersion;
21174
+ }
21175
+ span.log({ metadata });
21176
+ states.set(event, runState);
21177
+ if (span.spanId) {
21178
+ this.statesBySpanId.set(span.spanId, runState);
21179
+ }
21180
+ registerCloudflareThinkSpan(span);
21181
+ return runState;
21182
+ };
21183
+ if (contextManager && currentSpanStore && channel2.start) {
21184
+ channel2.start.bindStore(currentSpanStore, (event) => {
21185
+ const runState = ensureState2(event);
21186
+ return runState ? contextManager.wrapSpanForStore(runState.span) : currentSpanStore.getStore();
21187
+ });
21188
+ this.unsubscribers.push(
21189
+ () => channel2.start?.unbindStore(currentSpanStore)
21190
+ );
21191
+ }
21192
+ const handlers = {
21193
+ start: (event) => {
21194
+ ensureState2(event);
21195
+ },
21196
+ asyncEnd: (event) => {
21197
+ const runState = states.get(event);
21198
+ states.delete(event);
21199
+ if (!runState || runState.finalized || runState.aiResultPatched) {
21200
+ return;
21201
+ }
21202
+ this.finishState(runState, void 0, event.result);
21203
+ },
21204
+ error: (event) => {
21205
+ const runState = states.get(event);
21206
+ states.delete(event);
21207
+ if (runState) {
21208
+ this.finishState(runState, event.error);
21209
+ }
21210
+ }
21211
+ };
21212
+ channel2.subscribe(handlers);
21213
+ this.unsubscribers.push(() => channel2.unsubscribe(handlers));
21214
+ }
21215
+ subscribeToAISDKStreamTextSync() {
21216
+ const channel2 = aiSDKChannels.streamTextSync.tracingChannel();
21217
+ const handlers = {
21218
+ start: (event) => {
21219
+ this.startAISDKStream(event);
21220
+ },
21221
+ end: (event) => {
21222
+ this.endAISDKStream(event);
21223
+ },
21224
+ error: (event) => {
21225
+ this.errorAISDKStream(event);
21226
+ }
21227
+ };
21228
+ channel2.subscribe(handlers);
21229
+ this.unsubscribers.push(() => channel2.unsubscribe(handlers));
21230
+ }
21231
+ subscribeToAISDKStreamTextAsync() {
21232
+ const channel2 = aiSDKChannels.streamText.tracingChannel();
21233
+ const handlers = {
21234
+ start: (event) => {
21235
+ this.startAISDKStream(event);
21236
+ },
21237
+ asyncEnd: (event) => {
21238
+ this.endAISDKStream(event);
21239
+ },
21240
+ error: (event) => {
21241
+ this.errorAISDKStream(event);
21242
+ }
21243
+ };
21244
+ channel2.subscribe(handlers);
21245
+ this.unsubscribers.push(() => channel2.unsubscribe(handlers));
21246
+ }
21247
+ startAISDKStream(event) {
21248
+ const runState = this.currentState();
21249
+ if (!runState || runState.finalized) {
21250
+ return;
21251
+ }
21252
+ try {
21253
+ const prepared = prepareAISDKAgentCallInput(
21254
+ event.arguments[0],
21255
+ event,
21256
+ runState.span
21257
+ );
21258
+ runState.span.log({
21259
+ input: extractThinkTaskInput(prepared.input),
21260
+ metadata: {
21261
+ ...prepared.metadata,
21262
+ braintrust: {
21263
+ integration_name: "cloudflare-think",
21264
+ sdk_language: "typescript"
21265
+ }
21266
+ }
21267
+ });
21268
+ runState.inputLogged = true;
21269
+ runState.aiEvent = event;
21270
+ Reflect.set(event, THINK_STATE_ID, runState.span.spanId);
21271
+ } catch (error) {
21272
+ debugLogger.error(
21273
+ "Error preparing @cloudflare/think AI SDK tracing:",
21274
+ error
21275
+ );
21276
+ }
21277
+ }
21278
+ endAISDKStream(event) {
21279
+ const runState = this.stateForAISDKEvent(event);
21280
+ if (!runState || runState.finalized) {
21281
+ return;
21282
+ }
21283
+ const patched = patchAISDKStreamingResult({
21284
+ defaultDenyOutputPaths: DEFAULT_DENY_OUTPUT_PATHS,
21285
+ endEvent: event,
21286
+ forceTopLevelMetrics: true,
21287
+ onComplete: () => this.releaseState(runState),
21288
+ result: event.result,
21289
+ span: runState.span,
21290
+ startTime: runState.startTime,
21291
+ transformOutput: extractThinkTaskOutput
21292
+ });
21293
+ runState.aiResultPatched = patched;
21294
+ if (!patched) {
21295
+ this.finishState(runState, void 0, event.result);
21296
+ }
21297
+ }
21298
+ errorAISDKStream(event) {
21299
+ const runState = this.stateForAISDKEvent(event);
21300
+ if (runState) {
21301
+ this.finishState(runState, event.error);
21302
+ }
21303
+ }
21304
+ currentState() {
21305
+ const parentIds = _internalGetGlobalState()?.contextManager.getParentSpanIds()?.spanParents ?? [];
21306
+ for (const parentId of parentIds) {
21307
+ const state = this.statesBySpanId.get(parentId);
21308
+ if (state) {
21309
+ return state;
21310
+ }
21311
+ }
21312
+ return void 0;
21313
+ }
21314
+ stateForAISDKEvent(event) {
21315
+ const spanId = Reflect.get(event, THINK_STATE_ID);
21316
+ return typeof spanId === "string" ? this.statesBySpanId.get(spanId) : void 0;
21317
+ }
21318
+ finishState(state, error, output) {
21319
+ if (state.finalized) {
21320
+ return;
21321
+ }
21322
+ state.finalized = true;
21323
+ try {
21324
+ if (!state.inputLogged && state.fallbackInput !== void 0) {
21325
+ state.span.log({ input: state.fallbackInput });
21326
+ }
21327
+ if (error !== void 0) {
21328
+ state.span.log({ error });
21329
+ } else if (output !== void 0) {
21330
+ state.span.log({ output: extractThinkTaskOutput(output) });
21331
+ }
21332
+ finalizeAISDKChildTracing(state.aiEvent);
21333
+ state.span.end();
21334
+ } finally {
21335
+ this.releaseState(state);
21336
+ }
21337
+ }
21338
+ releaseState(state) {
21339
+ state.finalized = true;
21340
+ unregisterCloudflareThinkSpan(state.span);
21341
+ if (state.span.spanId) {
21342
+ this.statesBySpanId.delete(state.span.spanId);
21343
+ }
21344
+ }
21345
+ };
21346
+ function extractFallbackInput(messages) {
21347
+ if (!Array.isArray(messages) || messages.length === 0) {
21348
+ return void 0;
21349
+ }
21350
+ let latestUserIndex = -1;
21351
+ for (let index = messages.length - 1; index >= 0; index--) {
21352
+ if (messages[index]?.role === "user") {
21353
+ latestUserIndex = index;
21354
+ break;
21355
+ }
21356
+ }
21357
+ const selected = latestUserIndex >= 0 ? messages.slice(latestUserIndex) : [];
21358
+ return selected.map((message) => ({
21359
+ role: message.role,
21360
+ content: message.content ?? message.parts
21361
+ }));
21362
+ }
21363
+ function extractThinkTaskOutput(output) {
21364
+ if (!isObject(output)) {
21365
+ return output;
21366
+ }
21367
+ if (typeof output.text === "string") {
21368
+ return { role: "assistant", content: output.text };
21369
+ }
21370
+ if (output.object !== void 0) {
21371
+ return output.object;
21372
+ }
21373
+ return output;
21374
+ }
21375
+ function extractThinkTaskInput(input) {
21376
+ if (!isObject(input)) {
21377
+ return input;
21378
+ }
21379
+ const system = input.instructions ?? input.system;
21380
+ if (Array.isArray(input.messages)) {
21381
+ return system === void 0 ? input.messages : [{ role: "system", content: system }, ...input.messages];
21382
+ }
21383
+ if (Array.isArray(input.prompt)) {
21384
+ return system === void 0 ? input.prompt : [{ role: "system", content: system }, ...input.prompt];
21385
+ }
21386
+ if (typeof input.prompt === "string") {
21387
+ const messages = [{ role: "user", content: input.prompt }];
21388
+ return system === void 0 ? messages : [{ role: "system", content: system }, ...messages];
21389
+ }
21390
+ return input;
21391
+ }
21392
+
20086
21393
  // src/instrumentation/plugins/cursor-sdk-channels.ts
20087
21394
  var cursorSDKChannels = defineChannels(
20088
21395
  "@cursor/sdk",
@@ -22199,9 +23506,9 @@ function extractEmbedPromptTokenCount(response) {
22199
23506
  let sawAny = false;
22200
23507
  for (const embedding of embeddings) {
22201
23508
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
22202
- const tokenCount = embeddingStats?.tokenCount;
22203
- if (typeof tokenCount === "number" && Number.isFinite(tokenCount)) {
22204
- total += tokenCount;
23509
+ const tokenCount2 = embeddingStats?.tokenCount;
23510
+ if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
23511
+ total += tokenCount2;
22205
23512
  sawAny = true;
22206
23513
  }
22207
23514
  }
@@ -25848,6 +27155,470 @@ function aggregateMistralStreamChunks(chunks) {
25848
27155
  };
25849
27156
  }
25850
27157
 
27158
+ // src/instrumentation/plugins/ollama-channels.ts
27159
+ var ollamaChannels = defineChannels(
27160
+ "ollama",
27161
+ {
27162
+ chat: channel({
27163
+ channelName: "chat",
27164
+ kind: "async"
27165
+ }),
27166
+ generate: channel({
27167
+ channelName: "generate",
27168
+ kind: "async"
27169
+ }),
27170
+ embed: channel({
27171
+ channelName: "embed",
27172
+ kind: "async"
27173
+ })
27174
+ },
27175
+ { instrumentationName: INSTRUMENTATION_NAMES.OLLAMA }
27176
+ );
27177
+
27178
+ // src/instrumentation/plugins/ollama-plugin.ts
27179
+ var OllamaPlugin = class extends BasePlugin {
27180
+ onEnable() {
27181
+ this.unsubscribers.push(
27182
+ traceStreamingChannel(ollamaChannels.chat, {
27183
+ name: "ollama.chat",
27184
+ type: "llm" /* LLM */,
27185
+ extractInput: extractOllamaChatInput,
27186
+ extractOutput: (result, event) => extractOllamaChatOutput(
27187
+ result,
27188
+ countOllamaToolCalls(event?.arguments?.[0]?.messages)
27189
+ ),
27190
+ extractMetadata: extractOllamaResponseMetadata,
27191
+ extractMetrics: extractOllamaMetrics,
27192
+ aggregateChunks: aggregateOllamaChatChunks
27193
+ }),
27194
+ traceStreamingChannel(ollamaChannels.generate, {
27195
+ name: "ollama.generate",
27196
+ type: "llm" /* LLM */,
27197
+ extractInput: extractOllamaGenerateInput,
27198
+ extractOutput: extractOllamaGenerateOutput,
27199
+ extractMetadata: extractOllamaResponseMetadata,
27200
+ extractMetrics: extractOllamaMetrics,
27201
+ aggregateChunks: aggregateOllamaGenerateChunks
27202
+ }),
27203
+ traceAsyncChannel(ollamaChannels.embed, {
27204
+ name: "ollama.embed",
27205
+ type: "llm" /* LLM */,
27206
+ extractInput: extractOllamaEmbedInput,
27207
+ extractOutput: extractOllamaEmbedOutput,
27208
+ extractMetadata: extractOllamaResponseMetadata,
27209
+ extractMetrics: extractOllamaMetrics
27210
+ })
27211
+ );
27212
+ }
27213
+ onDisable() {
27214
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
27215
+ }
27216
+ };
27217
+ function isNonNegativeNumber(value) {
27218
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
27219
+ }
27220
+ function normalizeFinishReason(response, hasToolCalls = false) {
27221
+ if (hasToolCalls) {
27222
+ return "tool_calls";
27223
+ }
27224
+ return response?.done_reason || "stop";
27225
+ }
27226
+ function stringifyArguments(value) {
27227
+ if (typeof value === "string") {
27228
+ return value;
27229
+ }
27230
+ try {
27231
+ return JSON.stringify(value ?? {});
27232
+ } catch {
27233
+ return String(value);
27234
+ }
27235
+ }
27236
+ function syntheticToolCallId(name, index) {
27237
+ const normalizedName = name.replace(/[^a-zA-Z0-9_-]/g, "_") || "tool";
27238
+ return `ollama_call_${normalizedName}_${index}`;
27239
+ }
27240
+ function normalizeToolCall(toolCall, index) {
27241
+ const name = toolCall.function?.name;
27242
+ if (typeof name !== "string" || name.length === 0) {
27243
+ return void 0;
27244
+ }
27245
+ return {
27246
+ id: typeof toolCall.id === "string" && toolCall.id.length > 0 ? toolCall.id : syntheticToolCallId(name, index),
27247
+ type: "function",
27248
+ function: {
27249
+ name,
27250
+ arguments: stringifyArguments(toolCall.function?.arguments)
27251
+ }
27252
+ };
27253
+ }
27254
+ function normalizeToolCalls(toolCalls, syntheticIdOffset = 0) {
27255
+ if (!Array.isArray(toolCalls)) {
27256
+ return [];
27257
+ }
27258
+ return toolCalls.flatMap((toolCall, index) => {
27259
+ const normalized = normalizeToolCall(toolCall, syntheticIdOffset + index);
27260
+ return normalized ? [normalized] : [];
27261
+ });
27262
+ }
27263
+ function countOllamaToolCalls(messages) {
27264
+ if (!Array.isArray(messages)) {
27265
+ return 0;
27266
+ }
27267
+ return messages.reduce(
27268
+ (count, message) => count + (isObject(message) && Array.isArray(message.tool_calls) ? message.tool_calls.length : 0),
27269
+ 0
27270
+ );
27271
+ }
27272
+ function imageBytes(value) {
27273
+ if (value instanceof Uint8Array) {
27274
+ return value;
27275
+ }
27276
+ if (value instanceof ArrayBuffer) {
27277
+ return new Uint8Array(value);
27278
+ }
27279
+ if (typeof value !== "string" || value.startsWith("data:")) {
27280
+ return void 0;
27281
+ }
27282
+ try {
27283
+ const decoded = atob(value.slice(0, 24));
27284
+ return Uint8Array.from(decoded, (character) => character.charCodeAt(0));
27285
+ } catch {
27286
+ return void 0;
27287
+ }
27288
+ }
27289
+ function inferImageMediaType(value) {
27290
+ if (typeof value === "string") {
27291
+ const dataUrlType = value.match(/^data:(image\/[^;]+);base64,/i)?.[1];
27292
+ if (dataUrlType) {
27293
+ return dataUrlType;
27294
+ }
27295
+ }
27296
+ const bytes = imageBytes(value);
27297
+ if (!bytes) {
27298
+ return void 0;
27299
+ }
27300
+ if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
27301
+ return "image/png";
27302
+ }
27303
+ if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
27304
+ return "image/jpeg";
27305
+ }
27306
+ const signature = String.fromCharCode(...bytes.slice(0, 12));
27307
+ if (signature.startsWith("GIF87a") || signature.startsWith("GIF89a")) {
27308
+ return "image/gif";
27309
+ }
27310
+ if (signature.startsWith("RIFF") && signature.slice(8, 12) === "WEBP") {
27311
+ return "image/webp";
27312
+ }
27313
+ return void 0;
27314
+ }
27315
+ function normalizeTextAndImages(content, images) {
27316
+ if (!images || images.length === 0) {
27317
+ return { content };
27318
+ }
27319
+ const imageParts = [];
27320
+ const unrecognizedImages = [];
27321
+ for (const image of images) {
27322
+ let localImagePath;
27323
+ let localPathMediaType;
27324
+ if (typeof image === "string" && !/^data:/i.test(image) && !/^https?:\/\//i.test(image)) {
27325
+ const extension = image.match(/\.([a-z0-9]+)$/i)?.[1]?.toLowerCase();
27326
+ const extensionMediaType = {
27327
+ png: "image/png",
27328
+ jpg: "image/jpeg",
27329
+ jpeg: "image/jpeg",
27330
+ gif: "image/gif",
27331
+ webp: "image/webp"
27332
+ }[extension ?? ""];
27333
+ if (extensionMediaType && isomorph_default.statSync) {
27334
+ try {
27335
+ if (isomorph_default.statSync(image).isFile()) {
27336
+ localImagePath = image;
27337
+ localPathMediaType = extensionMediaType;
27338
+ }
27339
+ } catch {
27340
+ }
27341
+ }
27342
+ }
27343
+ const mediaType = localPathMediaType ?? inferImageMediaType(image);
27344
+ if (!mediaType) {
27345
+ unrecognizedImages.push(image);
27346
+ continue;
27347
+ }
27348
+ const processedImage = localImagePath ? new Attachment({
27349
+ data: localImagePath,
27350
+ filename: localImagePath.split(/[\\/]/).at(-1) ?? "image",
27351
+ contentType: mediaType
27352
+ }) : processInputAttachments({
27353
+ type: "image",
27354
+ image,
27355
+ mediaType
27356
+ }).image;
27357
+ imageParts.push({
27358
+ type: "image_url",
27359
+ image_url: { url: processedImage }
27360
+ });
27361
+ }
27362
+ return {
27363
+ content: imageParts.length > 0 ? [...content ? [{ type: "text", text: content }] : [], ...imageParts] : content,
27364
+ ...unrecognizedImages.length > 0 ? { unrecognizedImages } : {}
27365
+ };
27366
+ }
27367
+ function normalizeMessage(message, toolCallId, syntheticToolCallIdOffset = 0) {
27368
+ if (typeof message.role !== "string") {
27369
+ return void 0;
27370
+ }
27371
+ const toolCalls = normalizeToolCalls(
27372
+ message.tool_calls,
27373
+ syntheticToolCallIdOffset
27374
+ );
27375
+ if (message.role === "tool") {
27376
+ const toolName = typeof message.tool_name === "string" && message.tool_name.length > 0 ? message.tool_name : "tool";
27377
+ return {
27378
+ role: "tool",
27379
+ tool_call_id: toolCallId ?? syntheticToolCallId(toolName, 0),
27380
+ content: typeof message.content === "string" ? message.content : ""
27381
+ };
27382
+ }
27383
+ const normalizedContent = normalizeTextAndImages(
27384
+ typeof message.content === "string" ? message.content || (toolCalls.length > 0 ? null : "") : toolCalls.length > 0 ? null : "",
27385
+ message.images
27386
+ );
27387
+ return {
27388
+ role: message.role,
27389
+ content: normalizedContent.content,
27390
+ ...typeof message.thinking === "string" && message.thinking.length > 0 ? { reasoning: message.thinking } : {},
27391
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
27392
+ ...normalizedContent.unrecognizedImages ? { images: normalizedContent.unrecognizedImages } : {}
27393
+ };
27394
+ }
27395
+ function normalizeMessages(messages) {
27396
+ if (!Array.isArray(messages)) {
27397
+ return [];
27398
+ }
27399
+ const pendingToolCallIds = /* @__PURE__ */ new Map();
27400
+ let syntheticToolCallIdOffset = 0;
27401
+ return messages.flatMap((message) => {
27402
+ if (!isObject(message)) {
27403
+ return [];
27404
+ }
27405
+ const ollamaMessage = message;
27406
+ let toolCallId;
27407
+ if (ollamaMessage.role === "tool") {
27408
+ const toolName = ollamaMessage.tool_name;
27409
+ if (typeof toolName === "string") {
27410
+ toolCallId = pendingToolCallIds.get(toolName)?.shift();
27411
+ }
27412
+ }
27413
+ const normalized = normalizeMessage(
27414
+ ollamaMessage,
27415
+ toolCallId,
27416
+ syntheticToolCallIdOffset
27417
+ );
27418
+ if (Array.isArray(ollamaMessage.tool_calls)) {
27419
+ syntheticToolCallIdOffset += ollamaMessage.tool_calls.length;
27420
+ }
27421
+ if (ollamaMessage.role === "assistant" && normalized) {
27422
+ const toolCalls = Array.isArray(normalized.tool_calls) ? normalized.tool_calls : [];
27423
+ for (const toolCall of toolCalls) {
27424
+ if (!isObject(toolCall) || !isObject(toolCall.function)) {
27425
+ continue;
27426
+ }
27427
+ const name = toolCall.function.name;
27428
+ const id = toolCall.id;
27429
+ if (typeof name === "string" && typeof id === "string") {
27430
+ const ids = pendingToolCallIds.get(name) ?? [];
27431
+ ids.push(id);
27432
+ pendingToolCallIds.set(name, ids);
27433
+ }
27434
+ }
27435
+ }
27436
+ return normalized ? [normalized] : [];
27437
+ });
27438
+ }
27439
+ function normalizeToolDefinition(tool) {
27440
+ const fn = tool.function;
27441
+ if (!fn || typeof fn.name !== "string" || fn.name.length === 0) {
27442
+ return void 0;
27443
+ }
27444
+ return {
27445
+ type: "function",
27446
+ function: {
27447
+ name: fn.name,
27448
+ ...typeof fn.description === "string" ? { description: fn.description } : {},
27449
+ ...isObject(fn.parameters) ? { parameters: fn.parameters } : {}
27450
+ }
27451
+ };
27452
+ }
27453
+ function extractToolsMetadata(tools) {
27454
+ if (!Array.isArray(tools)) {
27455
+ return {};
27456
+ }
27457
+ const normalized = tools.flatMap((tool) => {
27458
+ if (!isObject(tool)) {
27459
+ return [];
27460
+ }
27461
+ const definition = normalizeToolDefinition(tool);
27462
+ return definition ? [definition] : [];
27463
+ });
27464
+ return normalized.length > 0 ? { tools: normalized } : {};
27465
+ }
27466
+ function extractOptionsMetadata(options) {
27467
+ if (!isObject(options)) {
27468
+ return {};
27469
+ }
27470
+ const metadata = {};
27471
+ const mappings = [
27472
+ ["temperature", "temperature"],
27473
+ ["top_p", "top_p"],
27474
+ ["num_predict", "max_tokens"],
27475
+ ["frequency_penalty", "frequency_penalty"],
27476
+ ["presence_penalty", "presence_penalty"],
27477
+ ["stop", "stop"]
27478
+ ];
27479
+ for (const [source, target] of mappings) {
27480
+ if (options[source] !== void 0) {
27481
+ metadata[target] = options[source];
27482
+ }
27483
+ }
27484
+ return metadata;
27485
+ }
27486
+ function extractRequestMetadata(request) {
27487
+ return {
27488
+ provider: "ollama",
27489
+ ...typeof request?.model === "string" ? { model: request.model } : {},
27490
+ ...extractOptionsMetadata(request?.options),
27491
+ ...request?.format !== void 0 ? { response_format: request.format } : {}
27492
+ };
27493
+ }
27494
+ function extractOllamaChatInput([request]) {
27495
+ return {
27496
+ input: normalizeMessages(request.messages),
27497
+ metadata: {
27498
+ ...extractRequestMetadata(request),
27499
+ ...extractToolsMetadata(request.tools)
27500
+ }
27501
+ };
27502
+ }
27503
+ function extractOllamaGenerateInput([request]) {
27504
+ const normalizedPrompt = normalizeTextAndImages(
27505
+ typeof request.prompt === "string" ? request.prompt : "",
27506
+ Array.isArray(request.images) ? request.images : void 0
27507
+ );
27508
+ const input = [
27509
+ ...typeof request.system === "string" ? [{ role: "system", content: request.system }] : [],
27510
+ {
27511
+ role: "user",
27512
+ content: normalizedPrompt.content,
27513
+ ...typeof request.suffix === "string" ? { suffix: request.suffix } : {},
27514
+ ...normalizedPrompt.unrecognizedImages ? { images: normalizedPrompt.unrecognizedImages } : {}
27515
+ }
27516
+ ];
27517
+ return {
27518
+ input,
27519
+ metadata: extractRequestMetadata(request)
27520
+ };
27521
+ }
27522
+ function extractOllamaEmbedInput([request]) {
27523
+ return {
27524
+ input: request.input,
27525
+ metadata: extractRequestMetadata(request)
27526
+ };
27527
+ }
27528
+ function extractOllamaChatOutput(result, syntheticToolCallIdOffset = 0) {
27529
+ if (!isObject(result) || !isObject(result.message)) {
27530
+ return void 0;
27531
+ }
27532
+ const message = normalizeMessage(
27533
+ result.message,
27534
+ void 0,
27535
+ syntheticToolCallIdOffset
27536
+ );
27537
+ if (!message) {
27538
+ return void 0;
27539
+ }
27540
+ const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
27541
+ return [
27542
+ {
27543
+ index: 0,
27544
+ finish_reason: normalizeFinishReason(result, toolCalls.length > 0),
27545
+ message
27546
+ }
27547
+ ];
27548
+ }
27549
+ function extractOllamaGenerateOutput(result) {
27550
+ if (!isObject(result) || typeof result.response !== "string") {
27551
+ return void 0;
27552
+ }
27553
+ return [
27554
+ {
27555
+ index: 0,
27556
+ finish_reason: normalizeFinishReason(result),
27557
+ message: {
27558
+ role: "assistant",
27559
+ content: result.response,
27560
+ ...typeof result.thinking === "string" && result.thinking.length > 0 ? { reasoning: result.thinking } : {}
27561
+ }
27562
+ }
27563
+ ];
27564
+ }
27565
+ function extractOllamaEmbedOutput(result) {
27566
+ const embedding = Array.isArray(result?.embeddings) ? result.embeddings[0] : void 0;
27567
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
27568
+ }
27569
+ function extractOllamaResponseMetadata(result) {
27570
+ return typeof result?.model === "string" ? { model: result.model } : void 0;
27571
+ }
27572
+ function extractOllamaMetrics(result) {
27573
+ const metrics = {};
27574
+ const promptTokens = result?.prompt_eval_count;
27575
+ const completionTokens = result?.eval_count;
27576
+ if (isNonNegativeNumber(promptTokens)) {
27577
+ metrics.prompt_tokens = promptTokens;
27578
+ }
27579
+ if (isNonNegativeNumber(completionTokens)) {
27580
+ metrics.completion_tokens = completionTokens;
27581
+ }
27582
+ if (isNonNegativeNumber(promptTokens) || isNonNegativeNumber(completionTokens)) {
27583
+ metrics.tokens = (isNonNegativeNumber(promptTokens) ? promptTokens : 0) + (isNonNegativeNumber(completionTokens) ? completionTokens : 0);
27584
+ }
27585
+ return metrics;
27586
+ }
27587
+ function aggregateOllamaChatChunks(chunks, _result, event, _startTime) {
27588
+ const last = chunks.at(-1);
27589
+ const message = {
27590
+ role: "assistant",
27591
+ content: chunks.map((chunk) => chunk.message?.content ?? "").join(""),
27592
+ thinking: chunks.map((chunk) => chunk.message?.thinking ?? "").join(""),
27593
+ tool_calls: chunks.flatMap((chunk) => chunk.message?.tool_calls ?? [])
27594
+ };
27595
+ const response = {
27596
+ ...last,
27597
+ message
27598
+ };
27599
+ return {
27600
+ output: extractOllamaChatOutput(
27601
+ response,
27602
+ countOllamaToolCalls(event?.arguments?.[0]?.messages)
27603
+ ),
27604
+ metrics: extractOllamaMetrics(last ?? {}),
27605
+ metadata: extractOllamaResponseMetadata(last ?? {})
27606
+ };
27607
+ }
27608
+ function aggregateOllamaGenerateChunks(chunks, _result, _event, _startTime) {
27609
+ const last = chunks.at(-1);
27610
+ const response = {
27611
+ ...last,
27612
+ response: chunks.map((chunk) => chunk.response ?? "").join(""),
27613
+ thinking: chunks.map((chunk) => chunk.thinking ?? "").join("")
27614
+ };
27615
+ return {
27616
+ output: extractOllamaGenerateOutput(response),
27617
+ metrics: extractOllamaMetrics(last ?? {}),
27618
+ metadata: extractOllamaResponseMetadata(last ?? {})
27619
+ };
27620
+ }
27621
+
25851
27622
  // src/instrumentation/plugins/google-adk-channels.ts
25852
27623
  var googleADKChannels = defineChannels(
25853
27624
  "@google/adk",
@@ -28632,7 +30403,7 @@ function getStringProperty2(obj, key) {
28632
30403
  return typeof value === "string" ? value : void 0;
28633
30404
  }
28634
30405
  function extractMetricsFromUsage(usage) {
28635
- const metrics = {
30406
+ const rawMetrics = {
28636
30407
  prompt_tokens: usage.inputTokens,
28637
30408
  completion_tokens: usage.outputTokens,
28638
30409
  ...extractAnthropicCacheTokens(
@@ -28641,10 +30412,10 @@ function extractMetricsFromUsage(usage) {
28641
30412
  )
28642
30413
  };
28643
30414
  if (usage.reasoningTokens !== void 0) {
28644
- metrics.completion_reasoning_tokens = usage.reasoningTokens;
28645
- metrics.reasoning_tokens = usage.reasoningTokens;
30415
+ rawMetrics.completion_reasoning_tokens = usage.reasoningTokens;
30416
+ rawMetrics.reasoning_tokens = usage.reasoningTokens;
28646
30417
  }
28647
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
30418
+ const metrics = finalizeAnthropicTokens(rawMetrics);
28648
30419
  const metadata = {
28649
30420
  model: usage.model
28650
30421
  };
@@ -29583,17 +31354,20 @@ var FlueObserveBridge = class {
29583
31354
  return;
29584
31355
  }
29585
31356
  const metadata = {
31357
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
29586
31358
  ...extractEventMetadata(event),
29587
31359
  "flue.operation": event.operationKind,
29588
31360
  provider: "flue"
29589
31361
  };
29590
31362
  const parent = this.parentSpanForEvent(event);
29591
- const span = startFlueSpan(parent, {
31363
+ const args = {
29592
31364
  name: `flue.${event.operationKind}`,
29593
31365
  spanAttributes: { type: "task" /* TASK */ },
29594
31366
  startTime: eventTime(event.timestamp),
29595
31367
  event: { metadata }
29596
- });
31368
+ };
31369
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
31370
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
29597
31371
  this.operationsById.set(event.operationId, { metadata, span });
29598
31372
  }
29599
31373
  handleOperation(event) {
@@ -29601,16 +31375,21 @@ var FlueObserveBridge = class {
29601
31375
  return;
29602
31376
  }
29603
31377
  const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
29604
- const output = operationOutput(event);
31378
+ const output = operationOutput(event) ?? outputFromAgentTurn(state.latestAgentOutput);
29605
31379
  const metadata = {
29606
31380
  ...state.metadata,
29607
31381
  ...extractEventMetadata(event),
29608
31382
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
29609
31383
  ...event.usage ? { "flue.usage": event.usage } : {}
29610
31384
  };
31385
+ const input = flueOperationInput(event);
31386
+ if (!state.loggedInput && input !== void 0) {
31387
+ safeLog3(state.span, { input });
31388
+ state.loggedInput = true;
31389
+ }
29611
31390
  this.finishPendingChildrenForOperation(event, output);
29612
31391
  safeLog3(state.span, {
29613
- ...event.isError ? { error: toLoggedError(event.error) } : {},
31392
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
29614
31393
  metadata,
29615
31394
  metrics: durationMetrics2(event.durationMs),
29616
31395
  output
@@ -29624,6 +31403,8 @@ var FlueObserveBridge = class {
29624
31403
  return;
29625
31404
  }
29626
31405
  const input = flueTurnRequestInput(event);
31406
+ const operation = event.operationId ? this.operationsById.get(event.operationId) : void 0;
31407
+ const turnInput = prepareFlueTurnInput(event, input, operation);
29627
31408
  const model = flueTurnRequestModel(event);
29628
31409
  const provider = flueTurnRequestProvider(event);
29629
31410
  const api = flueTurnRequestApi(event);
@@ -29636,20 +31417,22 @@ var FlueObserveBridge = class {
29636
31417
  ...provider ? { "flue.provider": provider } : {},
29637
31418
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
29638
31419
  ...reasoning ? { reasoning } : {},
29639
- ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
29640
- ...input?.tools ? { tools: input.tools } : {}
31420
+ ...turnInput.metadata
29641
31421
  };
29642
31422
  const parent = this.parentSpanForTurn(event);
29643
31423
  const span = startFlueSpan(parent, {
29644
- name: `llm:${model ?? event.purpose ?? "unknown"}`,
31424
+ name: "flue.turn",
29645
31425
  spanAttributes: { type: "llm" /* LLM */ },
29646
31426
  startTime: eventTime(event.timestamp),
29647
31427
  event: {
29648
- input: input?.messages,
31428
+ input: turnInput.messages,
29649
31429
  metadata
29650
31430
  }
29651
31431
  });
29652
- this.logOperationInput(event.operationId, input?.messages ?? input);
31432
+ this.logOperationInput(
31433
+ event.operationId,
31434
+ latestUserMessageInput(input?.messages)
31435
+ );
29653
31436
  this.turnsByKey.set(key, { metadata, span });
29654
31437
  }
29655
31438
  handleTurn(event) {
@@ -29685,6 +31468,12 @@ var FlueObserveBridge = class {
29685
31468
  },
29686
31469
  output
29687
31470
  });
31471
+ if (event.purpose === "agent" && event.operationId) {
31472
+ const operation = this.operationsById.get(event.operationId);
31473
+ if (operation) {
31474
+ operation.latestAgentOutput = output;
31475
+ }
31476
+ }
29688
31477
  safeEnd(state.span, eventTime(event.timestamp));
29689
31478
  this.turnsByKey.delete(key);
29690
31479
  }
@@ -29764,7 +31553,7 @@ var FlueObserveBridge = class {
29764
31553
  return;
29765
31554
  }
29766
31555
  safeLog3(state.span, {
29767
- ...event.isError ? { error: toLoggedError(event.result) } : {},
31556
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.result) } : {},
29768
31557
  metadata: {
29769
31558
  ...state.metadata,
29770
31559
  ...extractEventMetadata(event),
@@ -29810,6 +31599,7 @@ var FlueObserveBridge = class {
29810
31599
  ...event.usage ? { "flue.usage": event.usage } : {}
29811
31600
  };
29812
31601
  safeLog3(state.span, {
31602
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
29813
31603
  metadata,
29814
31604
  metrics: {
29815
31605
  ...durationMetrics2(event.durationMs),
@@ -29889,16 +31679,20 @@ var FlueObserveBridge = class {
29889
31679
  }
29890
31680
  startSyntheticOperation(event) {
29891
31681
  const metadata = {
31682
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
29892
31683
  ...extractEventMetadata(event),
29893
31684
  "flue.operation": event.operationKind,
29894
31685
  provider: "flue"
29895
31686
  };
29896
- const span = startFlueSpan(this.parentSpanForEvent(event), {
31687
+ const args = {
29897
31688
  name: `flue.${event.operationKind}`,
29898
31689
  spanAttributes: { type: "task" /* TASK */ },
29899
31690
  startTime: eventTime(event.timestamp),
29900
31691
  event: { metadata }
29901
- });
31692
+ };
31693
+ const parent = this.parentSpanForEvent(event);
31694
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
31695
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
29902
31696
  return { metadata, span };
29903
31697
  }
29904
31698
  startSyntheticTurn(event) {
@@ -29914,7 +31708,7 @@ var FlueObserveBridge = class {
29914
31708
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
29915
31709
  };
29916
31710
  const span = startFlueSpan(this.parentSpanForEvent(event), {
29917
- name: `llm:${model ?? event.purpose ?? "unknown"}`,
31711
+ name: "flue.turn",
29918
31712
  spanAttributes: { type: "llm" /* LLM */ },
29919
31713
  startTime: eventTime(event.timestamp),
29920
31714
  event: { metadata }
@@ -30046,7 +31840,10 @@ function extractEventMetadata(event, ctx) {
30046
31840
  return {
30047
31841
  ...event.runId ? { "flue.run_id": event.runId } : {},
30048
31842
  ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
31843
+ ...event.submissionId ? { "flue.submission_id": event.submissionId } : {},
30049
31844
  ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
31845
+ ...event.agentName ? { "flue.agent_name": event.agentName } : {},
31846
+ ...event.conversationId ? { "flue.conversation_id": event.conversationId } : {},
30050
31847
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
30051
31848
  ...event.session ? { "flue.session": event.session } : {},
30052
31849
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
@@ -30074,8 +31871,73 @@ function flueRunInput(event) {
30074
31871
  function flueTurnRequestInput(event) {
30075
31872
  return event.request?.input ?? event.input;
30076
31873
  }
31874
+ function prepareFlueTurnInput(event, input, operation) {
31875
+ const messages = input?.messages;
31876
+ const tracksUserTurn = event.purpose === "agent" && operation?.metadata["flue.operation"] === "prompt" && Array.isArray(messages);
31877
+ if (!tracksUserTurn) {
31878
+ return {
31879
+ messages,
31880
+ metadata: {
31881
+ ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
31882
+ ...input?.tools ? { tools: input.tools } : {}
31883
+ }
31884
+ };
31885
+ }
31886
+ const previous = operation.turnInputState;
31887
+ const previousMessageCount = previous?.messageCount ?? 0;
31888
+ const boundaryFingerprint = messages.length > 0 ? fingerprintJsonValue(messages[messages.length - 1]) : void 0;
31889
+ const continuesPreviousInput = previous !== void 0 && messages.length >= previousMessageCount && (previousMessageCount === 0 || previous.boundaryFingerprint !== void 0 && previous.boundaryFingerprint === fingerprintJsonValue(messages[previousMessageCount - 1]));
31890
+ const inputMode = previous === void 0 ? "full" : continuesPreviousInput ? "delta" : "reset";
31891
+ const systemPromptFingerprint = fingerprintJsonValue(input?.systemPrompt);
31892
+ const toolsFingerprint = fingerprintJsonValue(input?.tools);
31893
+ operation.turnInputState = {
31894
+ ...boundaryFingerprint !== void 0 ? { boundaryFingerprint } : {},
31895
+ messageCount: messages.length,
31896
+ ...systemPromptFingerprint !== void 0 ? { systemPromptFingerprint } : {},
31897
+ ...toolsFingerprint !== void 0 ? { toolsFingerprint } : {}
31898
+ };
31899
+ return {
31900
+ messages: continuesPreviousInput ? messages.slice(previousMessageCount) : messages,
31901
+ metadata: {
31902
+ "flue.input_mode": inputMode,
31903
+ ...continuesPreviousInput ? { "flue.input_message_offset": previousMessageCount } : {},
31904
+ ...input?.systemPrompt && (!continuesPreviousInput || systemPromptFingerprint !== previous?.systemPromptFingerprint) ? { "flue.system_prompt": input.systemPrompt } : {},
31905
+ ...input?.tools && (!continuesPreviousInput || toolsFingerprint !== previous?.toolsFingerprint) ? { tools: input.tools } : {}
31906
+ }
31907
+ };
31908
+ }
31909
+ function fingerprintJsonValue(value) {
31910
+ try {
31911
+ const serialized = JSON.stringify(value);
31912
+ if (serialized === void 0) {
31913
+ return void 0;
31914
+ }
31915
+ let hash = 2166136261;
31916
+ for (let i = 0; i < serialized.length; i++) {
31917
+ hash = Math.imul(hash ^ serialized.charCodeAt(i), 16777619);
31918
+ }
31919
+ return `${serialized.length}:${hash >>> 0}`;
31920
+ } catch {
31921
+ return void 0;
31922
+ }
31923
+ }
31924
+ function latestUserMessageInput(messages) {
31925
+ if (!messages) {
31926
+ return void 0;
31927
+ }
31928
+ for (let i = messages.length - 1; i >= 0; i--) {
31929
+ const message = messages[i];
31930
+ if (isObjectLike(message) && Reflect.get(message, "role") === "user") {
31931
+ return [message];
31932
+ }
31933
+ }
31934
+ return void 0;
31935
+ }
31936
+ function flueOperationInput(event) {
31937
+ return typeof event.agentInput?.text === "string" ? [{ content: event.agentInput.text, role: "user" }] : void 0;
31938
+ }
30077
31939
  function flueTurnRequestModel(event) {
30078
- return event.request?.model ?? event.model;
31940
+ return event.request?.requestedModel ?? event.request?.model ?? event.model;
30079
31941
  }
30080
31942
  function flueTurnRequestProvider(event) {
30081
31943
  return event.request?.providerName ?? event.provider ?? event.request?.providerId;
@@ -30084,10 +31946,10 @@ function flueTurnRequestApi(event) {
30084
31946
  return event.request?.api ?? event.api;
30085
31947
  }
30086
31948
  function flueTurnRequestReasoning(event) {
30087
- return event.request?.reasoning ?? event.reasoning;
31949
+ return event.request?.reasoningLevel ?? event.request?.reasoning ?? event.reasoning;
30088
31950
  }
30089
31951
  function flueTurnModel(event) {
30090
- return event.request?.model ?? event.model;
31952
+ return event.response?.responseModel ?? event.request?.requestedModel ?? event.request?.model ?? event.model;
30091
31953
  }
30092
31954
  function flueTurnProvider(event) {
30093
31955
  return event.request?.providerName ?? event.provider ?? event.request?.providerId;
@@ -30102,7 +31964,7 @@ function flueTurnOutput(event) {
30102
31964
  return event.response?.output ?? event.output;
30103
31965
  }
30104
31966
  function flueTurnStopReason(event) {
30105
- return event.response?.stopReason ?? event.stopReason;
31967
+ return event.response?.finishReason ?? event.response?.stopReason ?? event.stopReason;
30106
31968
  }
30107
31969
  function flueTurnError(event) {
30108
31970
  return event.response?.error ?? event.response?.errorInfo?.message ?? event.error;
@@ -30117,6 +31979,9 @@ function flueToolInput(event) {
30117
31979
  return event.input;
30118
31980
  }
30119
31981
  function flueToolOutput(event) {
31982
+ if (Object.hasOwn(event, "effectiveResult")) {
31983
+ return event.effectiveResult;
31984
+ }
30120
31985
  return event.output !== void 0 ? event.output : event.result;
30121
31986
  }
30122
31987
  function flueToolError(event) {
@@ -30124,10 +31989,36 @@ function flueToolError(event) {
30124
31989
  }
30125
31990
  function operationOutput(event) {
30126
31991
  if (event.operationKind === "prompt" || event.operationKind === "skill") {
30127
- return llmResultFromOperationResult(event.result);
31992
+ return outputFromAgentInvocation(event.agentOutput) ?? llmResultFromOperationResult(event.result);
30128
31993
  }
30129
31994
  return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
30130
31995
  }
31996
+ function outputFromAgentInvocation(output) {
31997
+ if (output?.type === "text") {
31998
+ return output.text;
31999
+ }
32000
+ if (output?.type === "data") {
32001
+ return output.data;
32002
+ }
32003
+ return void 0;
32004
+ }
32005
+ function outputFromAgentTurn(output) {
32006
+ if (!isObjectLike(output)) {
32007
+ return output;
32008
+ }
32009
+ const content = Reflect.get(output, "content");
32010
+ if (!Array.isArray(content)) {
32011
+ return output;
32012
+ }
32013
+ const text = content.flatMap((part) => {
32014
+ if (!isObjectLike(part) || Reflect.get(part, "type") !== "text") {
32015
+ return [];
32016
+ }
32017
+ const value = Reflect.get(part, "text");
32018
+ return typeof value === "string" ? [value] : [];
32019
+ });
32020
+ return text.length > 0 ? text.join("") : output;
32021
+ }
30131
32022
  function llmResultFromOperationResult(result) {
30132
32023
  if (!isObjectLike(result)) {
30133
32024
  return result;
@@ -30202,6 +32093,21 @@ function startFlueSpan(parent, args) {
30202
32093
  withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE)
30203
32094
  );
30204
32095
  }
32096
+ function startFlueRootSpan(args) {
32097
+ const state = _internalGetGlobalState();
32098
+ const spanId = state.idGenerator.getSpanId();
32099
+ const rootSpanId = state.idGenerator.shareRootSpanId() ? spanId : state.idGenerator.getTraceId();
32100
+ return withCurrent(
32101
+ NOOP_SPAN,
32102
+ () => startSpan({
32103
+ ...withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE),
32104
+ parentSpanIds: { parentSpanIds: [], rootSpanId },
32105
+ spanId,
32106
+ state
32107
+ }),
32108
+ state
32109
+ );
32110
+ }
30205
32111
  function runWithCurrentSpanStore(span, next) {
30206
32112
  const state = _internalGetGlobalState();
30207
32113
  const contextManager = state?.contextManager;
@@ -30226,7 +32132,7 @@ function safeEnd(span, endTime) {
30226
32132
  }
30227
32133
  }
30228
32134
  function logInstrumentationError3(label, error) {
30229
- console.error(`Error in ${label} instrumentation:`, error);
32135
+ debugLogger.debug(`Error in ${label} instrumentation:`, error);
30230
32136
  }
30231
32137
 
30232
32138
  // src/wrappers/langchain/callback-handler.ts
@@ -31155,12 +33061,13 @@ var piCodingAgentChannels = defineChannels(
31155
33061
  );
31156
33062
 
31157
33063
  // src/instrumentation/plugins/pi-coding-agent-plugin.ts
31158
- var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
33064
+ var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
33065
+ var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
31159
33066
  var piPromptContextStore;
31160
33067
  var PiCodingAgentPlugin = class extends BasePlugin {
31161
33068
  activePromptStates = /* @__PURE__ */ new Set();
31162
33069
  onEnable() {
31163
- this.subscribeToPrompt();
33070
+ this.interceptPrompt();
31164
33071
  }
31165
33072
  onDisable() {
31166
33073
  for (const unsubscribe of this.unsubscribers) {
@@ -31168,65 +33075,74 @@ var PiCodingAgentPlugin = class extends BasePlugin {
31168
33075
  }
31169
33076
  this.unsubscribers = [];
31170
33077
  for (const state of [...this.activePromptStates]) {
31171
- void finalizePiPromptRun(state).catch((error) => {
31172
- logInstrumentationError4("Pi Coding Agent disable cleanup", error);
31173
- });
33078
+ finishPiPromptRun(state);
31174
33079
  }
31175
33080
  }
31176
- subscribeToPrompt() {
31177
- const channel2 = piCodingAgentChannels.prompt.tracingChannel();
31178
- const states = /* @__PURE__ */ new WeakMap();
31179
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
31180
- const handlers = {
31181
- start: (event) => {
31182
- const state = startPiPromptRun(event, (state2) => {
31183
- this.activePromptStates.delete(state2);
31184
- });
31185
- if (state) {
31186
- this.activePromptStates.add(state);
31187
- states.set(event, state);
31188
- }
31189
- },
31190
- asyncEnd: async (event) => {
31191
- const state = states.get(event);
31192
- if (!state) {
31193
- return;
31194
- }
31195
- states.delete(event);
31196
- state.promptCallEnded = true;
31197
- if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
31198
- if (!state.sawStreamFn) {
31199
- state.queued = true;
31200
- if (!state.streamPatchState.queuedPromptStates.includes(state)) {
31201
- state.streamPatchState.queuedPromptStates.push(state);
31202
- }
33081
+ interceptPrompt() {
33082
+ this.unsubscribers.push(
33083
+ piCodingAgentChannels.prompt.intercept(
33084
+ (target, thisArg, args, additional) => {
33085
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
33086
+ let state;
33087
+ try {
33088
+ state = startPiPromptRun(
33089
+ {
33090
+ ...additional,
33091
+ arguments: args,
33092
+ self: thisArg
33093
+ },
33094
+ (finalizedState) => {
33095
+ this.activePromptStates.delete(finalizedState);
33096
+ }
33097
+ );
33098
+ } catch (error) {
33099
+ logInstrumentationError4("Pi Coding Agent prompt start", error);
31203
33100
  }
31204
- return;
31205
- }
31206
- await finalizePiPromptRun(state);
31207
- },
31208
- error: async (event) => {
31209
- const state = states.get(event);
31210
- if (!state) {
31211
- return;
33101
+ if (!state) {
33102
+ return runWithAutoInstrumentationSuppressed(invokeTarget);
33103
+ }
33104
+ this.activePromptStates.add(state);
33105
+ return promptContextStore().run(
33106
+ state,
33107
+ () => runWithAutoInstrumentationSuppressed(() => {
33108
+ let result;
33109
+ try {
33110
+ result = invokeTarget();
33111
+ } catch (error) {
33112
+ finishPiPromptRun(state, error);
33113
+ throw error;
33114
+ }
33115
+ return Promise.resolve(result).then(
33116
+ (value) => {
33117
+ finishPiPromptCall(state);
33118
+ return value;
33119
+ },
33120
+ (error) => {
33121
+ finishPiPromptRun(state, error);
33122
+ throw error;
33123
+ }
33124
+ );
33125
+ })
33126
+ );
31212
33127
  }
31213
- states.delete(event);
31214
- await finalizePiPromptRun(state, event.error);
31215
- }
31216
- };
31217
- channel2.subscribe(handlers);
31218
- this.unsubscribers.push(() => {
31219
- unbindAutoInstrumentationSuppression?.();
31220
- channel2.unsubscribe(handlers);
31221
- });
33128
+ )
33129
+ );
31222
33130
  }
31223
33131
  };
33132
+ function finishPiPromptCall(state) {
33133
+ state.promptCallEnded = true;
33134
+ if (state.deferCompletionUntilTurnEnd && !state.turnEnded) {
33135
+ return;
33136
+ }
33137
+ finishPiPromptRun(state);
33138
+ }
31224
33139
  function startPiPromptRun(event, onFinalize) {
31225
33140
  const session = extractSession(event);
31226
33141
  const agent = session?.agent;
31227
33142
  if (!session || !isPiAgent(agent)) {
31228
33143
  return void 0;
31229
33144
  }
33145
+ installPiAgentInstrumentation(agent);
31230
33146
  const metadata = {
31231
33147
  ...extractSessionMetadata(session),
31232
33148
  ...extractPromptOptionsMetadata(event.arguments[1]),
@@ -31248,9 +33164,7 @@ function startPiPromptRun(event, onFinalize) {
31248
33164
  INSTRUMENTATION_NAMES.PI_CODING_AGENT
31249
33165
  )
31250
33166
  );
31251
- const streamPatchState = installPiStreamPatch(agent);
31252
33167
  const options = event.arguments[1];
31253
- const promptText = event.arguments[0];
31254
33168
  const state = {
31255
33169
  activeLlmSpans: /* @__PURE__ */ new Set(),
31256
33170
  activeToolSpans: /* @__PURE__ */ new Map(),
@@ -31262,29 +33176,10 @@ function startPiPromptRun(event, onFinalize) {
31262
33176
  metrics: {},
31263
33177
  onFinalize,
31264
33178
  promptCallEnded: false,
31265
- ...typeof promptText === "string" ? { promptText } : {},
31266
- queued: false,
31267
33179
  span,
31268
- sawStreamFn: false,
31269
33180
  startTime: getCurrentUnixTimestamp(),
31270
- streamPatchState,
31271
33181
  turnEnded: false
31272
33182
  };
31273
- state.restorePromptContext = enterPiPromptContext(state);
31274
- streamPatchState.activePromptStates.add(state);
31275
- try {
31276
- state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
31277
- try {
31278
- await runWithAutoInstrumentationSuppressed(
31279
- () => handlePiAgentEvent(state, agentEvent)
31280
- );
31281
- } catch (error) {
31282
- logInstrumentationError4("Pi Coding Agent event", error);
31283
- }
31284
- });
31285
- } catch (error) {
31286
- logInstrumentationError4("Pi Coding Agent event subscription", error);
31287
- }
31288
33183
  return state;
31289
33184
  }
31290
33185
  function extractSession(event) {
@@ -31298,111 +33193,55 @@ function promptContextStore() {
31298
33193
  piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
31299
33194
  return piPromptContextStore;
31300
33195
  }
31301
- function currentPromptContextFrames() {
31302
- return promptContextStore().getStore()?.frames ?? [];
31303
- }
31304
33196
  function currentPiPromptState() {
31305
- const frames = currentPromptContextFrames();
31306
- return frames[frames.length - 1]?.state;
31307
- }
31308
- function enterPiPromptContext(state) {
31309
- const frame = {
31310
- id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
31311
- state
31312
- };
31313
- promptContextStore().enterWith({
31314
- frames: [...currentPromptContextFrames(), frame]
31315
- });
31316
- return () => {
31317
- const frames = currentPromptContextFrames().filter(
31318
- (candidate) => candidate.id !== frame.id
31319
- );
31320
- promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
31321
- };
31322
- }
31323
- function installPiStreamPatch(agent) {
31324
- const existing = piStreamPatchStates.get(agent);
31325
- if (existing) {
31326
- if (agent.streamFn !== existing.wrappedStreamFn) {
31327
- debugLogger.debug(
31328
- "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
31329
- );
31330
- }
31331
- return existing;
31332
- }
31333
- const patchState = {
31334
- activePromptStates: /* @__PURE__ */ new Set(),
31335
- agent,
31336
- originalStreamFn: agent.streamFn,
31337
- queuedPromptStates: [],
31338
- wrappedStreamFn: agent.streamFn
31339
- };
31340
- patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
31341
- agent.streamFn = patchState.wrappedStreamFn;
31342
- piStreamPatchStates.set(agent, patchState);
31343
- return patchState;
31344
- }
31345
- function resolveStreamPromptState(patchState, context) {
31346
- let lastUserText;
31347
- if (Array.isArray(context.messages)) {
31348
- for (let i = context.messages.length - 1; i >= 0; i--) {
31349
- const message = context.messages[i];
31350
- if (isPiUserMessage(message)) {
31351
- if (typeof message.content === "string") {
31352
- lastUserText = message.content;
31353
- } else {
31354
- lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
31355
- }
31356
- break;
31357
- }
31358
- }
31359
- }
31360
- if (lastUserText !== void 0) {
31361
- const queuedMatch = patchState.queuedPromptStates.find(
31362
- (state) => state.promptText === lastUserText
31363
- );
31364
- if (queuedMatch) {
31365
- return queuedMatch;
31366
- }
31367
- const matches = [...patchState.activePromptStates].filter(
31368
- (state) => state.promptText === lastUserText
33197
+ return promptContextStore().getStore();
33198
+ }
33199
+ function installPiAgentInstrumentation(agent) {
33200
+ const existing = piAgentPatchStates.get(agent);
33201
+ if (!existing || agent.streamFn !== existing.wrappedStreamFn) {
33202
+ const patchState = {
33203
+ originalStreamFn: agent.streamFn,
33204
+ wrappedStreamFn: agent.streamFn
33205
+ };
33206
+ patchState.wrappedStreamFn = makeInstrumentedStreamFn(
33207
+ agent,
33208
+ patchState.originalStreamFn
31369
33209
  );
31370
- if (matches.length === 1) {
31371
- return matches[0];
31372
- }
33210
+ agent.streamFn = patchState.wrappedStreamFn;
33211
+ piAgentPatchStates.set(agent, patchState);
31373
33212
  }
31374
- const contextState = currentPiPromptState();
31375
- if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
31376
- return contextState;
33213
+ if (piAgentEventSubscriptions.has(agent)) {
33214
+ return;
31377
33215
  }
31378
- if (patchState.activePromptStates.size === 1) {
31379
- return [...patchState.activePromptStates][0];
33216
+ try {
33217
+ agent.subscribe(async (event) => {
33218
+ const state = currentPiPromptState();
33219
+ if (!state || state.agent !== agent || state.finalized) {
33220
+ return;
33221
+ }
33222
+ try {
33223
+ await runWithAutoInstrumentationSuppressed(
33224
+ () => handlePiAgentEvent(state, event)
33225
+ );
33226
+ } catch (error) {
33227
+ logInstrumentationError4("Pi Coding Agent event", error);
33228
+ }
33229
+ });
33230
+ piAgentEventSubscriptions.add(agent);
33231
+ } catch (error) {
33232
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
31380
33233
  }
31381
- return void 0;
31382
33234
  }
31383
- function makeSharedInstrumentedStreamFn(patchState) {
33235
+ function makeInstrumentedStreamFn(agent, originalStreamFn) {
31384
33236
  return async function instrumentedPiStreamFn(model, context, options) {
31385
- const state = resolveStreamPromptState(patchState, context);
31386
- if (!state) {
31387
- const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
31388
- model,
31389
- context,
31390
- options
31391
- ]);
31392
- return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
33237
+ const invokeOriginal = () => Reflect.apply(originalStreamFn, this, [model, context, options]);
33238
+ const state = currentPiPromptState();
33239
+ if (!state || state.agent !== agent || state.finalized) {
33240
+ return invokeOriginal();
31393
33241
  }
31394
- state.sawStreamFn = true;
31395
- removeQueuedPromptState(state);
31396
- state.streamPatchState.eventPromptState = state;
31397
33242
  const llmState = await startPiLlmSpan(state, model, context, options);
31398
33243
  try {
31399
- const stream = await runWithAutoInstrumentationSuppressed(
31400
- () => Reflect.apply(patchState.originalStreamFn, this, [
31401
- model,
31402
- context,
31403
- options
31404
- ])
31405
- );
33244
+ const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
31406
33245
  return patchAssistantMessageStream(stream, state, llmState);
31407
33246
  } catch (error) {
31408
33247
  finishPiLlmSpan(state, llmState, void 0, error);
@@ -31549,13 +33388,6 @@ async function handlePiAgentEvent(state, event) {
31549
33388
  if (state.finalized) {
31550
33389
  return;
31551
33390
  }
31552
- const eventPromptState = state.streamPatchState.eventPromptState;
31553
- if (eventPromptState && eventPromptState !== state) {
31554
- return;
31555
- }
31556
- if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
31557
- return;
31558
- }
31559
33391
  switch (event.type) {
31560
33392
  case "message_end":
31561
33393
  if (isPiAssistantMessage(event.message)) {
@@ -31570,11 +33402,8 @@ async function handlePiAgentEvent(state, event) {
31570
33402
  addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
31571
33403
  }
31572
33404
  }
31573
- if (state.streamPatchState.eventPromptState === state) {
31574
- state.streamPatchState.eventPromptState = void 0;
31575
- }
31576
33405
  if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
31577
- await finalizePiPromptRun(state);
33406
+ finishPiPromptRun(state);
31578
33407
  }
31579
33408
  return;
31580
33409
  case "tool_execution_start":
@@ -31647,19 +33476,13 @@ function finishPiToolSpan(state, event) {
31647
33476
  }
31648
33477
  }
31649
33478
  }
31650
- async function finalizePiPromptRun(state, error) {
33479
+ function finishPiPromptRun(state, error) {
31651
33480
  if (state.finalized) {
31652
33481
  return;
31653
33482
  }
31654
33483
  state.finalized = true;
31655
33484
  state.onFinalize?.(state);
31656
- restorePiStreamFn(state);
31657
- try {
31658
- state.unsubscribeAgent?.();
31659
- } catch (unsubscribeError) {
31660
- logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
31661
- }
31662
- await finishOpenLlmSpans(state, error);
33485
+ finishOpenLlmSpans(state, error);
31663
33486
  finishOpenToolSpans(state, error);
31664
33487
  const metadata = {
31665
33488
  ...state.metadata,
@@ -31676,34 +33499,14 @@ async function finalizePiPromptRun(state, error) {
31676
33499
  output: state.output
31677
33500
  });
31678
33501
  } finally {
31679
- state.span.end();
31680
- }
31681
- }
31682
- function restorePiStreamFn(state) {
31683
- const patchState = state.streamPatchState;
31684
- patchState.activePromptStates.delete(state);
31685
- removeQueuedPromptState(state);
31686
- if (patchState.eventPromptState === state) {
31687
- patchState.eventPromptState = void 0;
31688
- }
31689
- state.restorePromptContext?.();
31690
- if (patchState.activePromptStates.size > 0) {
31691
- return;
31692
- }
31693
- if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
31694
- patchState.agent.streamFn = patchState.originalStreamFn;
31695
- }
31696
- piStreamPatchStates.delete(patchState.agent);
31697
- }
31698
- function removeQueuedPromptState(state) {
31699
- state.queued = false;
31700
- const queuedPromptStates = state.streamPatchState.queuedPromptStates;
31701
- const index = queuedPromptStates.indexOf(state);
31702
- if (index >= 0) {
31703
- queuedPromptStates.splice(index, 1);
33502
+ try {
33503
+ state.span.end();
33504
+ } catch (endError) {
33505
+ logInstrumentationError4("Pi Coding Agent prompt end", endError);
33506
+ }
31704
33507
  }
31705
33508
  }
31706
- async function finishOpenLlmSpans(state, error) {
33509
+ function finishOpenLlmSpans(state, error) {
31707
33510
  for (const llmState of [...state.activeLlmSpans]) {
31708
33511
  finishPiLlmSpan(state, llmState, void 0, error);
31709
33512
  }
@@ -31784,7 +33587,7 @@ function normalizeAssistantMessage(message) {
31784
33587
  (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
31785
33588
  ).join("");
31786
33589
  const toolCalls = message.content.flatMap(
31787
- (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
33590
+ (part) => part.type === "toolCall" ? [normalizeToolCall2(part)] : []
31788
33591
  );
31789
33592
  return {
31790
33593
  role: "assistant",
@@ -31819,13 +33622,13 @@ function normalizeUserContent(content) {
31819
33622
  return part;
31820
33623
  });
31821
33624
  }
31822
- function normalizeToolCall(toolCall) {
33625
+ function normalizeToolCall2(toolCall) {
31823
33626
  return {
31824
33627
  id: toolCall.id,
31825
33628
  type: "function",
31826
33629
  function: {
31827
33630
  name: toolCall.name,
31828
- arguments: stringifyArguments(toolCall.arguments)
33631
+ arguments: stringifyArguments2(toolCall.arguments)
31829
33632
  }
31830
33633
  };
31831
33634
  }
@@ -32008,7 +33811,7 @@ function cleanMetrics5(metrics) {
32008
33811
  }
32009
33812
  return cleaned;
32010
33813
  }
32011
- function stringifyArguments(value) {
33814
+ function stringifyArguments2(value) {
32012
33815
  if (typeof value === "string") {
32013
33816
  return value;
32014
33817
  }
@@ -32204,8 +34007,7 @@ function startAgentStream(event, activeChildParents) {
32204
34007
  ...extractAgentMetadata2(agent),
32205
34008
  ...extractModelMetadata3(model),
32206
34009
  "strands.operation": "Agent.stream",
32207
- provider: extractProvider(model),
32208
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34010
+ provider: extractProvider(model)
32209
34011
  };
32210
34012
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
32211
34013
  const attachmentCache = createStrandsAttachmentCache();
@@ -32255,8 +34057,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
32255
34057
  const metadata = {
32256
34058
  "strands.operation": operation,
32257
34059
  provider: "strands",
32258
- ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {},
32259
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34060
+ ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
32260
34061
  };
32261
34062
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
32262
34063
  const input = processStrandsInputAttachments(event.arguments[0]);
@@ -33042,6 +34843,320 @@ function logInstrumentationError5(context, error) {
33042
34843
  debugLogger.debug(`${context}:`, error);
33043
34844
  }
33044
34845
 
34846
+ // src/instrumentation/plugins/voyageai-channels.ts
34847
+ var voyageAIChannels = defineChannels(
34848
+ "voyageai",
34849
+ {
34850
+ embed: channel({
34851
+ channelName: "embed",
34852
+ kind: "async"
34853
+ }),
34854
+ multimodalEmbed: channel({
34855
+ channelName: "multimodalEmbed",
34856
+ kind: "async"
34857
+ }),
34858
+ rerank: channel({
34859
+ channelName: "rerank",
34860
+ kind: "async"
34861
+ }),
34862
+ contextualizedEmbed: channel({
34863
+ channelName: "contextualizedEmbed",
34864
+ kind: "async"
34865
+ })
34866
+ },
34867
+ { instrumentationName: INSTRUMENTATION_NAMES.VOYAGEAI }
34868
+ );
34869
+
34870
+ // src/instrumentation/plugins/voyageai-plugin.ts
34871
+ var RERANK_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
34872
+ "model",
34873
+ "returnDocuments",
34874
+ "topK",
34875
+ "truncation"
34876
+ ]);
34877
+ var VoyageAIPlugin = class extends BasePlugin {
34878
+ onEnable() {
34879
+ this.unsubscribers.push(
34880
+ interceptVoyageAICall(
34881
+ voyageAIChannels.embed,
34882
+ "voyageai.embed",
34883
+ extractTextEmbeddingInput,
34884
+ summarizeEmbeddingOutput,
34885
+ extractEmbeddingUsageMetrics
34886
+ ),
34887
+ interceptVoyageAICall(
34888
+ voyageAIChannels.multimodalEmbed,
34889
+ "voyageai.multimodalEmbed",
34890
+ extractMultimodalEmbeddingInput,
34891
+ summarizeEmbeddingOutput,
34892
+ extractEmbeddingUsageMetrics
34893
+ ),
34894
+ interceptVoyageAICall(
34895
+ voyageAIChannels.rerank,
34896
+ "voyageai.rerank",
34897
+ extractRerankInput,
34898
+ summarizeRerankOutput
34899
+ ),
34900
+ interceptVoyageAICall(
34901
+ voyageAIChannels.contextualizedEmbed,
34902
+ "voyageai.contextualizedEmbed",
34903
+ extractContextualizedEmbeddingInput,
34904
+ summarizeContextualizedEmbeddingOutput,
34905
+ extractEmbeddingUsageMetrics
34906
+ )
34907
+ );
34908
+ }
34909
+ onDisable() {
34910
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
34911
+ }
34912
+ };
34913
+ function interceptVoyageAICall(channel2, name, extractInput2, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
34914
+ return channel2.intercept((target, thisArg, args) => {
34915
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
34916
+ if (isAutoInstrumentationSuppressed()) {
34917
+ return invokeTarget();
34918
+ }
34919
+ let span;
34920
+ try {
34921
+ const { input, metadata } = extractInput2(args);
34922
+ span = startSpan(
34923
+ withSpanInstrumentationName(
34924
+ {
34925
+ event: { input, metadata },
34926
+ name,
34927
+ spanAttributes: { type: "llm" /* LLM */ }
34928
+ },
34929
+ INSTRUMENTATION_NAMES.VOYAGEAI
34930
+ )
34931
+ );
34932
+ } catch (error) {
34933
+ debugLogger.error(`Error starting span for ${name}:`, error);
34934
+ return invokeTarget();
34935
+ }
34936
+ let result;
34937
+ try {
34938
+ result = withCurrent(
34939
+ span,
34940
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
34941
+ );
34942
+ } catch (error) {
34943
+ finishVoyageAISpan(span, name, () => span.log({ error }));
34944
+ throw error;
34945
+ }
34946
+ void Promise.resolve(result).then(
34947
+ (value) => finishVoyageAISpan(span, name, () => {
34948
+ const metadata = extractResponseMetadata3(value);
34949
+ span.log({
34950
+ output: extractOutput2(value),
34951
+ ...metadata ? { metadata } : {},
34952
+ metrics: extractMetrics2(value)
34953
+ });
34954
+ }),
34955
+ (error) => finishVoyageAISpan(span, name, () => span.log({ error }))
34956
+ );
34957
+ return result;
34958
+ });
34959
+ }
34960
+ function finishVoyageAISpan(span, name, log2) {
34961
+ try {
34962
+ log2();
34963
+ } catch (error) {
34964
+ debugLogger.error(`Error logging span for ${name}:`, error);
34965
+ }
34966
+ try {
34967
+ span.end();
34968
+ } catch (error) {
34969
+ debugLogger.error(`Error ending span for ${name}:`, error);
34970
+ }
34971
+ }
34972
+ function getRequestArg2(args) {
34973
+ if (Array.isArray(args)) {
34974
+ return isObject(args[0]) ? args[0] : void 0;
34975
+ }
34976
+ if (!isObject(args)) {
34977
+ return void 0;
34978
+ }
34979
+ const firstArg = Reflect.get(args, "0");
34980
+ return isObject(firstArg) ? firstArg : void 0;
34981
+ }
34982
+ function pickMetadata(request, allowlist) {
34983
+ const metadata = {};
34984
+ if (request) {
34985
+ for (const key of allowlist) {
34986
+ if (!Object.hasOwn(request, key)) {
34987
+ continue;
34988
+ }
34989
+ const value = request[key];
34990
+ if (value !== void 0) {
34991
+ metadata[key] = value;
34992
+ }
34993
+ }
34994
+ }
34995
+ return {
34996
+ ...metadata,
34997
+ provider: "voyage"
34998
+ };
34999
+ }
35000
+ function buildEmbeddingInput(inputs, request) {
35001
+ const outputDimensions = request?.outputDimension;
35002
+ return {
35003
+ inputs,
35004
+ ...typeof outputDimensions === "number" && Number.isFinite(outputDimensions) ? { output_dimensions: outputDimensions } : {}
35005
+ };
35006
+ }
35007
+ function embeddingMetadata(request) {
35008
+ return {
35009
+ ...typeof request?.model === "string" ? { model: request.model } : {},
35010
+ provider: "voyage"
35011
+ };
35012
+ }
35013
+ function extractTextEmbeddingInput(args) {
35014
+ const request = getRequestArg2(args);
35015
+ const rawInput = request?.input;
35016
+ const values = Array.isArray(rawInput) ? rawInput : [rawInput];
35017
+ return {
35018
+ input: buildEmbeddingInput(
35019
+ values.flatMap(
35020
+ (value) => typeof value === "string" ? [{ content: value }] : []
35021
+ ),
35022
+ request
35023
+ ),
35024
+ metadata: embeddingMetadata(request)
35025
+ };
35026
+ }
35027
+ function extractContextualizedEmbeddingInput(args) {
35028
+ const request = getRequestArg2(args);
35029
+ const rawInputs = request?.inputs;
35030
+ const values = Array.isArray(rawInputs) ? rawInputs.flatMap((value) => Array.isArray(value) ? value : [value]) : [];
35031
+ return {
35032
+ input: buildEmbeddingInput(
35033
+ values.flatMap(
35034
+ (value) => typeof value === "string" ? [{ content: value }] : []
35035
+ ),
35036
+ request
35037
+ ),
35038
+ metadata: embeddingMetadata(request)
35039
+ };
35040
+ }
35041
+ function extractMultimodalEmbeddingInput(args) {
35042
+ const request = getRequestArg2(args);
35043
+ const rawInputs = request?.inputs;
35044
+ const inputs = Array.isArray(rawInputs) ? rawInputs.map((rawInput) => {
35045
+ const rawContent = isObject(rawInput) ? rawInput.content : void 0;
35046
+ return {
35047
+ content: Array.isArray(rawContent) ? rawContent.flatMap(normalizeMultimodalContentPart) : []
35048
+ };
35049
+ }) : [];
35050
+ const input = buildEmbeddingInput(inputs, request);
35051
+ const processedInput = processInputAttachments(input);
35052
+ return {
35053
+ input: hasInlineEmbeddingMedia(processedInput) ? input : processedInput,
35054
+ metadata: embeddingMetadata(request)
35055
+ };
35056
+ }
35057
+ function normalizeMultimodalContentPart(part) {
35058
+ if (!isObject(part) || typeof part.type !== "string") {
35059
+ return [];
35060
+ }
35061
+ if (part.type === "text") {
35062
+ return typeof part.text === "string" ? [{ type: "text", text: part.text }] : [];
35063
+ }
35064
+ const camelCaseField = {
35065
+ image_base64: "imageBase64",
35066
+ image_url: "imageUrl",
35067
+ video_base64: "videoBase64",
35068
+ video_url: "videoUrl"
35069
+ };
35070
+ const field = camelCaseField[part.type];
35071
+ if (!field) {
35072
+ return [];
35073
+ }
35074
+ const data = typeof part[field] === "string" ? part[field] : part[part.type];
35075
+ if (typeof data !== "string") {
35076
+ return [];
35077
+ }
35078
+ return part.type.startsWith("image_") ? [{ type: "image_url", image_url: { url: data } }] : [{ type: "file", file: { file_data: data } }];
35079
+ }
35080
+ function hasInlineEmbeddingMedia(input) {
35081
+ return input.inputs.some(
35082
+ ({ content }) => Array.isArray(content) ? content.some((part) => {
35083
+ const value = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
35084
+ return typeof value === "string" && value.startsWith("data:");
35085
+ }) : false
35086
+ );
35087
+ }
35088
+ function extractRerankInput(args) {
35089
+ const request = getRequestArg2(args);
35090
+ const documents = request?.documents;
35091
+ return {
35092
+ input: {
35093
+ documents,
35094
+ query: request?.query
35095
+ },
35096
+ metadata: {
35097
+ ...pickMetadata(request, RERANK_METADATA_ALLOWLIST),
35098
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
35099
+ }
35100
+ };
35101
+ }
35102
+ function extractResponseMetadata3(result) {
35103
+ if (!isObject(result)) {
35104
+ return void 0;
35105
+ }
35106
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35107
+ const model = typeof result.model === "string" ? result.model : typeof rawResponse?.model === "string" ? rawResponse.model : void 0;
35108
+ return model ? { model } : void 0;
35109
+ }
35110
+ function summarizeEmbeddingOutput(result) {
35111
+ return {
35112
+ count: isObject(result) && Array.isArray(result.data) ? result.data.length : 0
35113
+ };
35114
+ }
35115
+ function summarizeRerankOutput(result) {
35116
+ if (!isObject(result) || !Array.isArray(result.data)) {
35117
+ return void 0;
35118
+ }
35119
+ return result.data.slice(0, 100).map((item) => ({
35120
+ index: isObject(item) ? item.index : void 0,
35121
+ relevance_score: isObject(item) ? (typeof item.relevanceScore === "number" ? item.relevanceScore : item.relevance_score) ?? null : null
35122
+ }));
35123
+ }
35124
+ function summarizeContextualizedEmbeddingOutput(result) {
35125
+ if (!isObject(result)) {
35126
+ return { count: 0 };
35127
+ }
35128
+ if (Array.isArray(result.results)) {
35129
+ return {
35130
+ count: result.results.reduce(
35131
+ (count, item) => count + (isObject(item) && Array.isArray(item.embeddings) ? item.embeddings.length : 0),
35132
+ 0
35133
+ )
35134
+ };
35135
+ }
35136
+ if (!Array.isArray(result.data)) {
35137
+ return { count: 0 };
35138
+ }
35139
+ return {
35140
+ count: result.data.reduce(
35141
+ (count, item) => count + (isObject(item) && Array.isArray(item.data) ? item.data.length : 0),
35142
+ 0
35143
+ )
35144
+ };
35145
+ }
35146
+ function extractEmbeddingUsageMetrics(result) {
35147
+ const metrics = extractUsageMetrics3(result);
35148
+ return typeof metrics.tokens === "number" ? { prompt_tokens: metrics.tokens, tokens: metrics.tokens } : {};
35149
+ }
35150
+ function extractUsageMetrics3(result) {
35151
+ if (!isObject(result)) {
35152
+ return {};
35153
+ }
35154
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35155
+ const usage = isObject(result.usage) ? result.usage : isObject(rawResponse?.usage) ? rawResponse.usage : void 0;
35156
+ const tokens = typeof result.totalTokens === "number" ? result.totalTokens : usage?.totalTokens ?? usage?.total_tokens;
35157
+ return typeof tokens === "number" && Number.isFinite(tokens) && tokens >= 0 ? { tokens } : {};
35158
+ }
35159
+
33045
35160
  // src/instrumentation/plugins/cloudflare-ai-chat-channels.ts
33046
35161
  var cloudflareAIChatChannels = defineChannels(
33047
35162
  "@cloudflare/ai-chat",
@@ -33576,6 +35691,7 @@ var BraintrustPlugin = class extends BasePlugin {
33576
35691
  anthropicPlugin = null;
33577
35692
  aiSDKPlugin = null;
33578
35693
  claudeAgentSDKPlugin = null;
35694
+ cloudflareThinkPlugin = null;
33579
35695
  cursorSDKPlugin = null;
33580
35696
  openAIAgentsPlugin = null;
33581
35697
  googleGenAIPlugin = null;
@@ -33584,6 +35700,7 @@ var BraintrustPlugin = class extends BasePlugin {
33584
35700
  openRouterPlugin = null;
33585
35701
  openRouterAgentPlugin = null;
33586
35702
  mistralPlugin = null;
35703
+ ollamaPlugin = null;
33587
35704
  googleADKPlugin = null;
33588
35705
  coherePlugin = null;
33589
35706
  groqPlugin = null;
@@ -33595,6 +35712,7 @@ var BraintrustPlugin = class extends BasePlugin {
33595
35712
  langSmithPlugin = null;
33596
35713
  piCodingAgentPlugin = null;
33597
35714
  strandsAgentSDKPlugin = null;
35715
+ voyageAIPlugin = null;
33598
35716
  cloudflareAIChatPlugin = null;
33599
35717
  cloudflareAgentsPlugin = null;
33600
35718
  constructor(config = {}) {
@@ -33623,6 +35741,10 @@ var BraintrustPlugin = class extends BasePlugin {
33623
35741
  this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
33624
35742
  this.claudeAgentSDKPlugin.enable();
33625
35743
  }
35744
+ if (integrations.cloudflareThink !== false) {
35745
+ this.cloudflareThinkPlugin = new CloudflareThinkPlugin();
35746
+ this.cloudflareThinkPlugin.enable();
35747
+ }
33626
35748
  if (integrations.cursorSDK !== false && integrations.cursor !== false) {
33627
35749
  this.cursorSDKPlugin = new CursorSDKPlugin();
33628
35750
  this.cursorSDKPlugin.enable();
@@ -33653,6 +35775,10 @@ var BraintrustPlugin = class extends BasePlugin {
33653
35775
  this.mistralPlugin = new MistralPlugin();
33654
35776
  this.mistralPlugin.enable();
33655
35777
  }
35778
+ if (integrations.ollama !== false) {
35779
+ this.ollamaPlugin = new OllamaPlugin();
35780
+ this.ollamaPlugin.enable();
35781
+ }
33656
35782
  if (integrations.googleADK !== false) {
33657
35783
  this.googleADKPlugin = new GoogleADKPlugin();
33658
35784
  this.googleADKPlugin.enable();
@@ -33661,6 +35787,10 @@ var BraintrustPlugin = class extends BasePlugin {
33661
35787
  this.coherePlugin = new CoherePlugin();
33662
35788
  this.coherePlugin.enable();
33663
35789
  }
35790
+ if (integrations.voyageai !== false) {
35791
+ this.voyageAIPlugin = new VoyageAIPlugin();
35792
+ this.voyageAIPlugin.enable();
35793
+ }
33664
35794
  if (integrations.groq !== false) {
33665
35795
  this.groqPlugin = new GroqPlugin();
33666
35796
  this.groqPlugin.enable();
@@ -33729,6 +35859,10 @@ var BraintrustPlugin = class extends BasePlugin {
33729
35859
  this.claudeAgentSDKPlugin.disable();
33730
35860
  this.claudeAgentSDKPlugin = null;
33731
35861
  }
35862
+ if (this.cloudflareThinkPlugin) {
35863
+ this.cloudflareThinkPlugin.disable();
35864
+ this.cloudflareThinkPlugin = null;
35865
+ }
33732
35866
  if (this.cursorSDKPlugin) {
33733
35867
  this.cursorSDKPlugin.disable();
33734
35868
  this.cursorSDKPlugin = null;
@@ -33761,6 +35895,10 @@ var BraintrustPlugin = class extends BasePlugin {
33761
35895
  this.mistralPlugin.disable();
33762
35896
  this.mistralPlugin = null;
33763
35897
  }
35898
+ if (this.ollamaPlugin) {
35899
+ this.ollamaPlugin.disable();
35900
+ this.ollamaPlugin = null;
35901
+ }
33764
35902
  if (this.googleADKPlugin) {
33765
35903
  this.googleADKPlugin.disable();
33766
35904
  this.googleADKPlugin = null;
@@ -33769,6 +35907,10 @@ var BraintrustPlugin = class extends BasePlugin {
33769
35907
  this.coherePlugin.disable();
33770
35908
  this.coherePlugin = null;
33771
35909
  }
35910
+ if (this.voyageAIPlugin) {
35911
+ this.voyageAIPlugin.disable();
35912
+ this.voyageAIPlugin = null;
35913
+ }
33772
35914
  if (this.groqPlugin) {
33773
35915
  this.groqPlugin.disable();
33774
35916
  this.groqPlugin = null;
@@ -33846,6 +35988,7 @@ var envIntegrationAliases = {
33846
35988
  cloudflareaichat: "cloudflareAIChat",
33847
35989
  "cloudflare-ai-chat": "cloudflareAIChat",
33848
35990
  "@cloudflare/ai-chat": "cloudflareAIChat",
35991
+ cloudflarethink: "cloudflareThink",
33849
35992
  cursor: "cursor",
33850
35993
  "cursor-sdk": "cursorSDK",
33851
35994
  cursorsdk: "cursorSDK",
@@ -33866,6 +36009,7 @@ var envIntegrationAliases = {
33866
36009
  openrouteragent: "openrouterAgent",
33867
36010
  "openrouter-agent": "openrouterAgent",
33868
36011
  mistral: "mistral",
36012
+ ollama: "ollama",
33869
36013
  googleadk: "googleADK",
33870
36014
  "google-adk": "googleADK",
33871
36015
  cohere: "cohere",
@@ -33886,7 +36030,10 @@ var envIntegrationAliases = {
33886
36030
  "langchain-js": "langchain",
33887
36031
  "@langchain": "langchain",
33888
36032
  langgraph: "langgraph",
33889
- langsmith: "langsmith"
36033
+ langsmith: "langsmith",
36034
+ voyage: "voyageai",
36035
+ "voyage-ai": "voyageai",
36036
+ voyageai: "voyageai"
33890
36037
  };
33891
36038
  function getDefaultInstrumentationIntegrations() {
33892
36039
  return {
@@ -33901,6 +36048,7 @@ function getDefaultInstrumentationIntegrations() {
33901
36048
  huggingface: true,
33902
36049
  claudeAgentSDK: true,
33903
36050
  cloudflareAIChat: true,
36051
+ cloudflareThink: true,
33904
36052
  cursor: true,
33905
36053
  cursorSDK: true,
33906
36054
  flue: true,
@@ -33909,6 +36057,7 @@ function getDefaultInstrumentationIntegrations() {
33909
36057
  openrouter: true,
33910
36058
  openrouterAgent: true,
33911
36059
  mistral: true,
36060
+ ollama: true,
33912
36061
  cohere: true,
33913
36062
  groq: true,
33914
36063
  bedrock: true,
@@ -33919,6 +36068,7 @@ function getDefaultInstrumentationIntegrations() {
33919
36068
  langchain: true,
33920
36069
  langgraph: true,
33921
36070
  langsmith: true,
36071
+ voyageai: true,
33922
36072
  piCodingAgent: true,
33923
36073
  strandsAgentSDK: true,
33924
36074
  cloudflareAgents: true
@@ -34339,9 +36489,9 @@ function configureNode() {
34339
36489
  return value;
34340
36490
  }
34341
36491
  const envPaths = [];
34342
- for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
34343
- envPaths.push(path.join(dir2, ".env.braintrust"));
34344
- if (path.dirname(dir2) === dir2) {
36492
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path2.dirname(dir2), depth++) {
36493
+ envPaths.push(path2.join(dir2, ".env.braintrust"));
36494
+ if (path2.dirname(dir2) === dir2) {
34345
36495
  break;
34346
36496
  }
34347
36497
  }
@@ -34383,10 +36533,10 @@ function configureNode() {
34383
36533
  isomorph_default.processOn = (event, handler) => {
34384
36534
  process.on(event, handler);
34385
36535
  };
34386
- isomorph_default.basename = path.basename;
36536
+ isomorph_default.basename = path2.basename;
34387
36537
  isomorph_default.writeln = (text) => process.stdout.write(text + "\n");
34388
- isomorph_default.pathJoin = path.join;
34389
- isomorph_default.pathDirname = path.dirname;
36538
+ isomorph_default.pathJoin = path2.join;
36539
+ isomorph_default.pathDirname = path2.dirname;
34390
36540
  isomorph_default.mkdir = fs.mkdir;
34391
36541
  isomorph_default.writeFile = fs.writeFile;
34392
36542
  isomorph_default.readFile = fs.readFile;
@@ -34421,8 +36571,8 @@ function configureNode() {
34421
36571
  registry.enable();
34422
36572
  }
34423
36573
  function getNearestBraintrustEnvValue(name) {
34424
- for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
34425
- const envPath = path.join(dir2, ".env.braintrust");
36574
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path2.dirname(dir2), depth++) {
36575
+ const envPath = path2.join(dir2, ".env.braintrust");
34426
36576
  try {
34427
36577
  const parsed = dotenv.parse(fsSync.readFileSync(envPath, "utf8"));
34428
36578
  const value = parsed[name];
@@ -34432,7 +36582,7 @@ function getNearestBraintrustEnvValue(name) {
34432
36582
  return void 0;
34433
36583
  }
34434
36584
  }
34435
- if (path.dirname(dir2) === dir2) {
36585
+ if (path2.dirname(dir2) === dir2) {
34436
36586
  break;
34437
36587
  }
34438
36588
  }
@@ -35998,8 +38148,8 @@ function validateParametersWithJsonSchema(parameters, schema) {
35998
38148
  const validate = ajv.compile(schema);
35999
38149
  if (!validate(parameters)) {
36000
38150
  const errorMessages = validate.errors?.map((err) => {
36001
- const path2 = err.instancePath || "root";
36002
- return `${path2}: ${err.message}`;
38151
+ const path3 = err.instancePath || "root";
38152
+ return `${path3}: ${err.message}`;
36003
38153
  }).join(", ");
36004
38154
  throw Error(`Invalid parameters: ${errorMessages}`);
36005
38155
  }
@@ -36028,6 +38178,9 @@ function rehydrateRemoteParameters(parameters, schema) {
36028
38178
  }
36029
38179
 
36030
38180
  // src/framework.ts
38181
+ function BaseExperiment(options = {}) {
38182
+ return { _type: "BaseExperiment", ...options };
38183
+ }
36031
38184
  var EvalResultWithSummary = class {
36032
38185
  constructor(summary, results) {
36033
38186
  this.summary = summary;
@@ -36088,6 +38241,26 @@ async function getExperimentParametersRef(parameters) {
36088
38241
  version: resolvedParameters.version
36089
38242
  };
36090
38243
  }
38244
+ async function _internalInitEvaluatorExperiment(projectName, evaluator, data, options = {}) {
38245
+ if (options.disabled) return null;
38246
+ const { baseExperiment } = callEvaluatorData(data);
38247
+ const parameters = await getExperimentParametersRef(evaluator.parameters);
38248
+ return initExperiment(evaluator.state, {
38249
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: projectName },
38250
+ experiment: options.experimentName ?? evaluator.experimentName,
38251
+ description: evaluator.description,
38252
+ metadata: evaluator.metadata,
38253
+ tags: evaluator.tags,
38254
+ isPublic: evaluator.isPublic,
38255
+ update: options.update ?? evaluator.update,
38256
+ baseExperiment: evaluator.baseExperimentName ?? baseExperiment,
38257
+ baseExperimentId: evaluator.baseExperimentId,
38258
+ gitMetadataSettings: evaluator.gitMetadataSettings,
38259
+ repoInfo: evaluator.repoInfo,
38260
+ dataset: Dataset2.isDataset(data) ? data : void 0,
38261
+ parameters
38262
+ });
38263
+ }
36091
38264
  function callEvaluatorData(data) {
36092
38265
  const dataResult = typeof data === "function" ? data() : data;
36093
38266
  let baseExperiment = void 0;
@@ -36105,6 +38278,48 @@ function isAsyncIterable7(value) {
36105
38278
  function isIterable(value) {
36106
38279
  return typeof value === "object" && value !== null && Symbol.iterator in value && typeof value[Symbol.iterator] === "function";
36107
38280
  }
38281
+ async function _internalResolveEvaluatorData(evaluator, experiment) {
38282
+ if (typeof evaluator.data === "string") {
38283
+ throw new Error("Unimplemented: string data paths");
38284
+ }
38285
+ let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
38286
+ if ("_type" in dataResult) {
38287
+ if (dataResult._type !== "BaseExperiment") {
38288
+ throw new Error("Invalid _type");
38289
+ }
38290
+ if (!experiment) {
38291
+ throw new Error(
38292
+ "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
38293
+ );
38294
+ }
38295
+ let name = dataResult.name;
38296
+ if (isEmpty2(name)) {
38297
+ const baseExperiment = await experiment.fetchBaseExperiment();
38298
+ if (!baseExperiment) {
38299
+ throw new Error("BaseExperiment() failed to fetch base experiment");
38300
+ }
38301
+ name = baseExperiment.name;
38302
+ }
38303
+ dataResult = initExperiment(evaluator.state, {
38304
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
38305
+ experiment: name,
38306
+ open: true
38307
+ }).asDataset();
38308
+ }
38309
+ const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
38310
+ if (isAsyncIterable7(resolvedDataResult)) {
38311
+ return resolvedDataResult;
38312
+ }
38313
+ if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
38314
+ const iterable = resolvedDataResult;
38315
+ return (async function* () {
38316
+ for (const datum of iterable) yield datum;
38317
+ })();
38318
+ }
38319
+ throw new Error(
38320
+ "Evaluator data must be an array, iterable, or async iterable"
38321
+ );
38322
+ }
36108
38323
  globalThis._evals = {
36109
38324
  functions: [],
36110
38325
  prompts: [],
@@ -36151,25 +38366,13 @@ async function Eval(name, evaluator, reporterOrOpts) {
36151
38366
  }
36152
38367
  const resolvedReporter = options.reporter || defaultReporter;
36153
38368
  try {
36154
- const { data, baseExperiment: defaultBaseExperiment } = callEvaluatorData(
36155
- evaluator.data
38369
+ const { data } = callEvaluatorData(evaluator.data);
38370
+ const experiment = await _internalInitEvaluatorExperiment(
38371
+ name,
38372
+ evaluator,
38373
+ data,
38374
+ { disabled: Boolean(options.parent || options.noSendLogs) }
36156
38375
  );
36157
- const parameters = await getExperimentParametersRef(evaluator.parameters);
36158
- const experiment = options.parent || options.noSendLogs ? null : initExperiment(evaluator.state, {
36159
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: name },
36160
- experiment: evaluator.experimentName,
36161
- description: evaluator.description,
36162
- metadata: evaluator.metadata,
36163
- tags: evaluator.tags,
36164
- isPublic: evaluator.isPublic,
36165
- update: evaluator.update,
36166
- baseExperiment: evaluator.baseExperimentName ?? defaultBaseExperiment,
36167
- baseExperimentId: evaluator.baseExperimentId,
36168
- gitMetadataSettings: evaluator.gitMetadataSettings,
36169
- repoInfo: evaluator.repoInfo,
36170
- dataset: Dataset2.isDataset(data) ? data : void 0,
36171
- parameters
36172
- });
36173
38376
  if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
36174
38377
  await experiment._waitForId();
36175
38378
  }
@@ -36238,8 +38441,8 @@ function serializeJSONWithPlainString(v) {
36238
38441
  }
36239
38442
  }
36240
38443
  function evaluateFilter(object, filter2) {
36241
- const { path: path2, pattern } = filter2;
36242
- const key = path2.reduce(
38444
+ const { path: path3, pattern } = filter2;
38445
+ const key = path3.reduce(
36243
38446
  (acc, p) => typeof acc === "object" && acc !== null ? (
36244
38447
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
36245
38448
  acc[p]
@@ -36257,19 +38460,74 @@ function scorerName(scorer, scorer_idx) {
36257
38460
  function classifierName(classifier, classifier_idx) {
36258
38461
  return classifier.name || `classifier_${classifier_idx}`;
36259
38462
  }
38463
+ async function _internalRunEvaluatorTask(task, datum, trialIndex, parameters, span, reportProgress = () => void 0) {
38464
+ const metadata = {
38465
+ ..."metadata" in datum ? datum.metadata : {}
38466
+ };
38467
+ const hooks = {
38468
+ meta(value) {
38469
+ Object.assign(metadata, value);
38470
+ },
38471
+ metadata,
38472
+ expected: "expected" in datum ? datum.expected : void 0,
38473
+ span,
38474
+ parameters,
38475
+ reportProgress,
38476
+ trialIndex,
38477
+ tags: [...datum.tags ?? []]
38478
+ };
38479
+ const output = await task(datum.input, hooks);
38480
+ span.log({ output });
38481
+ return {
38482
+ output,
38483
+ metadata: hooks.metadata,
38484
+ tags: hooks.tags ?? []
38485
+ };
38486
+ }
36260
38487
  function buildSpanMetadata(results) {
36261
- return results.length === 1 ? results[0].metadata : results.reduce(
36262
- (prev, s) => mergeDicts(prev, { [s.name]: s.metadata }),
36263
- {}
38488
+ return results.length === 1 ? results[0].metadata : Object.fromEntries(
38489
+ results.map((result) => [result.name, result.metadata])
36264
38490
  );
36265
38491
  }
36266
38492
  function buildSpanScores(results) {
36267
- const scoresRecord = results.reduce(
36268
- (prev, s) => mergeDicts(prev, { [s.name]: s.score }),
36269
- {}
38493
+ const scoresRecord = Object.fromEntries(
38494
+ results.map((result) => [result.name, result.score])
36270
38495
  );
36271
38496
  return { resultMetadata: buildSpanMetadata(results), scoresRecord };
36272
38497
  }
38498
+ function _internalPrepareEvaluatorScore(scoreValue, name) {
38499
+ if (scoreValue === null) return { results: null };
38500
+ if (Array.isArray(scoreValue)) {
38501
+ for (const score of scoreValue) {
38502
+ if (!(typeof score === "object" && !isEmpty2(score))) {
38503
+ throw new Error(
38504
+ `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
38505
+ );
38506
+ }
38507
+ }
38508
+ }
38509
+ let results;
38510
+ if (Array.isArray(scoreValue)) {
38511
+ results = scoreValue;
38512
+ } else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
38513
+ results = [scoreValue];
38514
+ } else {
38515
+ results = [{ name, score: scoreValue }];
38516
+ }
38517
+ const { resultMetadata, scoresRecord } = buildSpanScores(results);
38518
+ const fields = (score) => {
38519
+ const { metadata: _metadata, name: _name, ...rest } = score;
38520
+ return rest;
38521
+ };
38522
+ return {
38523
+ results,
38524
+ output: results.length === 1 ? fields(results[0]) : Object.fromEntries(
38525
+ results.map((score) => [score.name ?? name, fields(score)])
38526
+ ),
38527
+ metadata: resultMetadata,
38528
+ scores: scoresRecord
38529
+ };
38530
+ }
36273
38531
  async function runInScorerSpan(rootSpan, spanName, spanType, propagatedEvent, eventInput, fn) {
36274
38532
  try {
36275
38533
  const value = await rootSpan.traced(fn, {
@@ -36314,6 +38572,27 @@ function toClassificationItem(c) {
36314
38572
  ...c.metadata !== void 0 ? { metadata: c.metadata } : {}
36315
38573
  };
36316
38574
  }
38575
+ function _internalPrepareEvaluatorClassification(value, name) {
38576
+ if (value === null) return { results: null };
38577
+ const results = (Array.isArray(value) ? value : [value]).map(
38578
+ (result) => validateClassificationResult(result, name)
38579
+ );
38580
+ const classifications = /* @__PURE__ */ Object.create(null);
38581
+ for (const result of results) {
38582
+ (classifications[result.name] ??= []).push(toClassificationItem(result));
38583
+ }
38584
+ return {
38585
+ results,
38586
+ output: results.length === 1 ? toClassificationItem(results[0]) : Object.fromEntries(
38587
+ results.map((result) => [
38588
+ result.name,
38589
+ toClassificationItem(result)
38590
+ ])
38591
+ ),
38592
+ metadata: buildSpanMetadata(results),
38593
+ classifications
38594
+ };
38595
+ }
36317
38596
  function logScoringFailures(kind, failures, metadata, rootSpan, state) {
36318
38597
  if (!failures.length) return [];
36319
38598
  const errorMap = Object.fromEntries(
@@ -36352,54 +38631,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
36352
38631
  (evaluator.state ?? _internalGetGlobalState())?.spanCache?.start();
36353
38632
  }
36354
38633
  try {
36355
- if (typeof evaluator.data === "string") {
36356
- throw new Error("Unimplemented: string data paths");
36357
- }
36358
- let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
36359
38634
  parameters = await validateParameters(
36360
38635
  parameters ?? {},
36361
38636
  evaluator.parameters
36362
38637
  );
36363
- if ("_type" in dataResult) {
36364
- if (dataResult._type !== "BaseExperiment") {
36365
- throw new Error("Invalid _type");
36366
- }
36367
- if (!experiment) {
36368
- throw new Error(
36369
- "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
36370
- );
36371
- }
36372
- let name = dataResult.name;
36373
- if (isEmpty2(name)) {
36374
- const baseExperiment = await experiment.fetchBaseExperiment();
36375
- if (!baseExperiment) {
36376
- throw new Error("BaseExperiment() failed to fetch base experiment");
36377
- }
36378
- name = baseExperiment.name;
36379
- }
36380
- dataResult = initExperiment(evaluator.state, {
36381
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
36382
- experiment: name,
36383
- open: true
36384
- }).asDataset();
36385
- }
36386
- const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
36387
- const dataIterable = (() => {
36388
- if (isAsyncIterable7(resolvedDataResult)) {
36389
- return resolvedDataResult;
36390
- }
36391
- if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
36392
- const iterable = resolvedDataResult;
36393
- return (async function* () {
36394
- for (const datum of iterable) {
36395
- yield datum;
36396
- }
36397
- })();
36398
- }
36399
- throw new Error(
36400
- "Evaluator data must be an array, iterable, or async iterable"
36401
- );
36402
- })();
38638
+ const dataIterable = await _internalResolveEvaluatorData(
38639
+ evaluator,
38640
+ experiment
38641
+ );
36403
38642
  progressReporter.start(evaluator.evalName, 0);
36404
38643
  const experimentIdPromise = experiment ? (async () => {
36405
38644
  try {
@@ -36468,57 +38707,45 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
36468
38707
  ensureSpansFlushed,
36469
38708
  state
36470
38709
  }) : void 0;
36471
- let metadata = {
36472
- ..."metadata" in datum ? datum.metadata : {}
36473
- };
38710
+ let metadata = {};
36474
38711
  const expected = "expected" in datum ? datum.expected : void 0;
36475
38712
  let output = void 0;
36476
38713
  let error = void 0;
36477
- let tags = [...datum.tags ?? []];
36478
- const scores = {};
36479
- const classifications = {};
38714
+ let tags = [];
38715
+ const scores = /* @__PURE__ */ Object.create(null);
38716
+ const classifications = /* @__PURE__ */ Object.create(null);
36480
38717
  const scorerNames = (evaluator.scores ?? []).map(scorerName);
36481
38718
  const classifierNames = (evaluator.classifiers ?? []).map(
36482
38719
  classifierName
36483
38720
  );
36484
38721
  let unhandledScores = scorerNames;
36485
38722
  try {
36486
- const meta = (o) => metadata = { ...metadata, ...o };
36487
- await rootSpan.traced(
36488
- async (span) => {
36489
- const hooksForTask = {
36490
- meta,
36491
- metadata,
36492
- expected,
36493
- span,
36494
- parameters: parameters ?? {},
36495
- reportProgress: (event) => {
36496
- stream?.({
36497
- ...event,
36498
- id: rootSpan.id,
36499
- origin: baseEvent.event?.origin,
36500
- name: evaluator.evalName,
36501
- object_type: "task"
36502
- });
36503
- },
36504
- trialIndex,
36505
- tags
36506
- };
36507
- const outputResult = evaluator.task(datum.input, hooksForTask);
36508
- if (outputResult instanceof Promise) {
36509
- output = await outputResult;
36510
- } else {
36511
- output = outputResult;
38723
+ const taskResult = await rootSpan.traced(
38724
+ (span) => _internalRunEvaluatorTask(
38725
+ evaluator.task,
38726
+ datum,
38727
+ trialIndex,
38728
+ parameters ?? {},
38729
+ span,
38730
+ (event) => {
38731
+ stream?.({
38732
+ ...event,
38733
+ id: rootSpan.id,
38734
+ origin: baseEvent.event?.origin,
38735
+ name: evaluator.evalName,
38736
+ object_type: "task"
38737
+ });
36512
38738
  }
36513
- tags = hooksForTask.tags ?? [];
36514
- span.log({ output });
36515
- },
38739
+ ),
36516
38740
  {
36517
38741
  name: "task",
36518
38742
  spanAttributes: { type: "task" /* TASK */ },
36519
38743
  event: { input: datum.input }
36520
38744
  }
36521
38745
  );
38746
+ output = taskResult.output;
38747
+ metadata = taskResult.metadata;
38748
+ tags = taskResult.tags;
36522
38749
  if (tags.length) {
36523
38750
  rootSpan.log({ output, metadata, expected, tags });
36524
38751
  } else {
@@ -36528,20 +38755,18 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
36528
38755
  await rootSpan.flush();
36529
38756
  }
36530
38757
  const scoringArgs = {
38758
+ id: datum.id,
36531
38759
  input: datum.input,
36532
38760
  expected: "expected" in datum ? datum.expected : void 0,
36533
38761
  metadata,
36534
38762
  output,
38763
+ tags,
36535
38764
  trace
36536
38765
  };
36537
38766
  const { trace: _trace, ...scoringArgsForLogging } = scoringArgs;
36538
38767
  const propagatedEvent = makeScorerPropagatedEvent(
36539
38768
  await rootSpan.export()
36540
38769
  );
36541
- const getOtherFields = (s) => {
36542
- const { metadata: _metadata, name: _name, ...rest } = s;
36543
- return rest;
36544
- };
36545
38770
  const [scoreResults, classificationResults] = await Promise.all([
36546
38771
  Promise.all(
36547
38772
  (evaluator.scores ?? []).map(
@@ -36555,35 +38780,17 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
36555
38780
  const scoreValue = await Promise.resolve(
36556
38781
  score(scoringArgs)
36557
38782
  );
36558
- if (scoreValue === null) return null;
36559
- if (Array.isArray(scoreValue)) {
36560
- for (const s of scoreValue) {
36561
- if (!(typeof s === "object" && !isEmpty2(s))) {
36562
- throw new Error(
36563
- `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(s)}`
36564
- );
36565
- }
36566
- }
36567
- }
36568
- const results = Array.isArray(scoreValue) ? scoreValue : typeof scoreValue === "object" && !isEmpty2(scoreValue) ? [scoreValue] : [
36569
- {
36570
- name: scorerNames[score_idx],
36571
- score: scoreValue
36572
- }
36573
- ];
36574
- const { resultMetadata, scoresRecord } = buildSpanScores(results);
36575
- const resultOutput = results.length === 1 ? getOtherFields(results[0]) : results.reduce(
36576
- (prev, s) => mergeDicts(prev, {
36577
- [s.name]: getOtherFields(s)
36578
- }),
36579
- {}
38783
+ const prepared = _internalPrepareEvaluatorScore(
38784
+ scoreValue,
38785
+ scorerNames[score_idx]
36580
38786
  );
38787
+ if (prepared.results === null) return null;
36581
38788
  span.log({
36582
- output: resultOutput,
36583
- metadata: resultMetadata,
36584
- scores: scoresRecord
38789
+ output: prepared.output,
38790
+ metadata: prepared.metadata,
38791
+ scores: prepared.scores
36585
38792
  });
36586
- return results;
38793
+ return prepared.results;
36587
38794
  }
36588
38795
  )
36589
38796
  )
@@ -36600,24 +38807,16 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
36600
38807
  const classifierValue = await Promise.resolve(
36601
38808
  classifier(scoringArgs)
36602
38809
  );
36603
- if (classifierValue === null) return null;
36604
- const rawResults = (Array.isArray(classifierValue) ? classifierValue : [classifierValue]).map(
36605
- (result) => validateClassificationResult(
36606
- result,
36607
- classifierNames[idx]
36608
- )
36609
- );
36610
- const resultOutput = rawResults.length === 1 ? toClassificationItem(rawResults[0]) : rawResults.reduce(
36611
- (prev, r) => mergeDicts(prev, {
36612
- [r.name]: toClassificationItem(r)
36613
- }),
36614
- {}
38810
+ const prepared = _internalPrepareEvaluatorClassification(
38811
+ classifierValue,
38812
+ classifierNames[idx]
36615
38813
  );
38814
+ if (prepared.results === null) return null;
36616
38815
  span.log({
36617
- output: resultOutput,
36618
- metadata: buildSpanMetadata(rawResults)
38816
+ output: prepared.output,
38817
+ metadata: prepared.metadata
36619
38818
  });
36620
- return rawResults;
38819
+ return prepared.results;
36621
38820
  }
36622
38821
  )
36623
38822
  )
@@ -36846,7 +39045,7 @@ function accumulateScores(accumulator, scores) {
36846
39045
  }
36847
39046
  }
36848
39047
  function ensureScoreAccumulator(results) {
36849
- const accumulator = {};
39048
+ const accumulator = /* @__PURE__ */ Object.create(null);
36850
39049
  for (const result of results) {
36851
39050
  accumulateScores(accumulator, result.scores);
36852
39051
  }
@@ -38020,6 +40219,8 @@ async function getDataset(state, data) {
38020
40219
  environment: data.dataset_environment ?? void 0,
38021
40220
  _internal_btql: data._internal_btql ?? void 0
38022
40221
  });
40222
+ } else if ("experiment_name" in data) {
40223
+ return BaseExperiment({ name: data.experiment_name });
38023
40224
  } else {
38024
40225
  return data.data;
38025
40226
  }