braintrust 3.27.0 → 3.29.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 (54) hide show
  1. package/README.md +1 -1
  2. package/dev/dist/index.d.mts +879 -197
  3. package/dev/dist/index.d.ts +879 -197
  4. package/dev/dist/index.js +2960 -1865
  5. package/dev/dist/index.mjs +2217 -1122
  6. package/dist/apply-auto-instrumentation.js +345 -260
  7. package/dist/apply-auto-instrumentation.mjs +137 -52
  8. package/dist/auto-instrumentations/bundler/esbuild.cjs +124 -7
  9. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/next.cjs +124 -7
  11. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  12. package/dist/auto-instrumentations/bundler/rollup.cjs +124 -7
  13. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.cjs +124 -7
  15. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  16. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +124 -7
  17. package/dist/auto-instrumentations/bundler/webpack.cjs +124 -7
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  19. package/dist/auto-instrumentations/{chunk-ZNHTSSGI.mjs → chunk-AOIYCVEL.mjs} +34 -3
  20. package/dist/auto-instrumentations/{chunk-XEYKUBLY.mjs → chunk-DKTGDNA7.mjs} +91 -5
  21. package/dist/auto-instrumentations/{chunk-BW33ULMW.mjs → chunk-OMCZ3MV2.mjs} +1 -1
  22. package/dist/auto-instrumentations/hook.mjs +1186 -161
  23. package/dist/auto-instrumentations/index.cjs +34 -3
  24. package/dist/auto-instrumentations/index.mjs +1 -1
  25. package/dist/browser.d.mts +1388 -75
  26. package/dist/browser.d.ts +1388 -75
  27. package/dist/browser.js +3954 -1124
  28. package/dist/browser.mjs +3954 -1124
  29. package/dist/{chunk-MF7NU6BT.js → chunk-6Z5S7VOU.js} +175 -25
  30. package/dist/{chunk-CZM5JIQL.mjs → chunk-7FA6VP2S.mjs} +172 -22
  31. package/dist/{chunk-YKD22IMR.mjs → chunk-M6XPNJC4.mjs} +2102 -1113
  32. package/dist/{chunk-QRHGVBKU.js → chunk-XLLGRXGR.js} +3273 -2284
  33. package/dist/cli.js +6353 -1483
  34. package/dist/edge-light.d.mts +1 -1
  35. package/dist/edge-light.d.ts +1 -1
  36. package/dist/edge-light.js +3954 -1124
  37. package/dist/edge-light.mjs +3954 -1124
  38. package/dist/index.d.mts +1972 -659
  39. package/dist/index.d.ts +1972 -659
  40. package/dist/index.js +2453 -676
  41. package/dist/index.mjs +1973 -196
  42. package/dist/instrumentation/index.d.mts +738 -15
  43. package/dist/instrumentation/index.d.ts +738 -15
  44. package/dist/instrumentation/index.js +2791 -874
  45. package/dist/instrumentation/index.mjs +2791 -874
  46. package/dist/vitest-evals-reporter.js +16 -16
  47. package/dist/vitest-evals-reporter.mjs +2 -2
  48. package/dist/workerd.d.mts +1 -1
  49. package/dist/workerd.d.ts +1 -1
  50. package/dist/workerd.js +3954 -1124
  51. package/dist/workerd.mjs +3954 -1124
  52. package/package.json +2 -3
  53. package/util/dist/index.d.mts +1596 -109
  54. package/util/dist/index.d.ts +1596 -109
@@ -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";
@@ -664,8 +664,6 @@ function newGlobalTracingChannel(nameOrChannels) {
664
664
  var DefaultAsyncLocalStorage = class {
665
665
  constructor() {
666
666
  }
667
- enterWith(_) {
668
- }
669
667
  run(_, callback) {
670
668
  return callback();
671
669
  }
@@ -800,34 +798,93 @@ setGlobalHookErrorReporter((error) => {
800
798
  debugLogger.error("Global instrumentation hook error:", error);
801
799
  });
802
800
 
803
- // src/gitutil.ts
804
- import { simpleGit } from "simple-git";
805
- var COMMON_BASE_BRANCHES = ["main", "master", "develop"];
806
- async function currentRepo() {
807
- try {
808
- const git = simpleGit();
809
- if (await git.checkIsRepo()) {
810
- return git;
811
- } else {
812
- return null;
801
+ // src/git-command.ts
802
+ import { execFile } from "node:child_process";
803
+ import { constants } from "node:fs";
804
+ import { access } from "node:fs/promises";
805
+ import * as path from "node:path";
806
+ var GIT_EXECUTABLE_NAMES = process.platform === "win32" ? ["git.exe", "git"] : ["git"];
807
+ var GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
808
+ var gitExecutablePromise;
809
+ function executableSearchPath() {
810
+ return Object.entries(process.env).find(
811
+ ([name]) => name.toUpperCase() === "PATH"
812
+ )?.[1];
813
+ }
814
+ async function findGitExecutable(searchPath = executableSearchPath()) {
815
+ if (!searchPath) {
816
+ return void 0;
817
+ }
818
+ for (const rawSearchDir of searchPath.split(path.delimiter)) {
819
+ const searchDir = rawSearchDir.trim().replace(/^"(.*)"$/, "$1");
820
+ if (!path.isAbsolute(searchDir)) {
821
+ continue;
813
822
  }
814
- } catch {
815
- return null;
823
+ for (const executableName of GIT_EXECUTABLE_NAMES) {
824
+ const candidate = path.join(searchDir, executableName);
825
+ try {
826
+ await access(
827
+ candidate,
828
+ process.platform === "win32" ? constants.F_OK : constants.X_OK
829
+ );
830
+ return candidate;
831
+ } catch {
832
+ }
833
+ }
834
+ }
835
+ return void 0;
836
+ }
837
+ async function resolveGitExecutable() {
838
+ gitExecutablePromise ??= findGitExecutable();
839
+ return await gitExecutablePromise;
840
+ }
841
+ async function runGitCommand(args, options = {}) {
842
+ const executable = await resolveGitExecutable();
843
+ if (!executable) {
844
+ throw new Error("Could not find a git executable on PATH");
816
845
  }
846
+ return await new Promise((resolve, reject2) => {
847
+ execFile(
848
+ executable,
849
+ args,
850
+ {
851
+ cwd: options.cwd,
852
+ encoding: "utf8",
853
+ maxBuffer: GIT_MAX_BUFFER_BYTES
854
+ },
855
+ (error, stdout) => {
856
+ if (error) {
857
+ reject2(error);
858
+ } else {
859
+ resolve(stdout);
860
+ }
861
+ }
862
+ );
863
+ });
817
864
  }
865
+
866
+ // src/gitutil.ts
867
+ var COMMON_BASE_BRANCHES = ["main", "master", "develop"];
818
868
  var _baseBranch = null;
819
869
  async function getBaseBranch(remote = void 0) {
820
870
  if (_baseBranch === null) {
821
- const git = await currentRepo();
822
- if (git === null) {
871
+ const repoPath = await currentRepoPath();
872
+ if (!repoPath) {
823
873
  throw new Error("Not in a git repo");
824
874
  }
825
- const remoteName = remote ?? (await git.getRemotes())[0]?.name;
875
+ const runGit = async (args) => await runGitCommand(args, { cwd: repoPath });
876
+ const remoteName = remote ?? (await runGit(["remote"])).trim().split(/\r?\n/)[0];
826
877
  if (!remoteName) {
827
878
  throw new Error("No remote found");
828
879
  }
829
880
  let branch = null;
830
- const repoBranches = new Set((await git.branchLocal()).all);
881
+ const repoBranches = new Set(
882
+ (await runGit([
883
+ "for-each-ref",
884
+ "--format=%(refname:short)",
885
+ "refs/heads/"
886
+ ])).trim().split(/\r?\n/)
887
+ );
831
888
  const matchingBaseBranches = COMMON_BASE_BRANCHES.filter(
832
889
  (b) => repoBranches.has(b)
833
890
  );
@@ -835,7 +892,7 @@ async function getBaseBranch(remote = void 0) {
835
892
  branch = matchingBaseBranches[0];
836
893
  } else {
837
894
  try {
838
- const remoteInfo = await git.remote(["show", remoteName]);
895
+ const remoteInfo = await runGit(["remote", "show", remoteName]);
839
896
  if (!remoteInfo) {
840
897
  throw new Error(`Could not find remote ${remoteName}`);
841
898
  }
@@ -853,27 +910,28 @@ async function getBaseBranch(remote = void 0) {
853
910
  return _baseBranch;
854
911
  }
855
912
  async function getBaseBranchAncestor(remote = void 0) {
856
- const git = await currentRepo();
857
- if (git === null) {
913
+ const repoPath = await currentRepoPath();
914
+ if (!repoPath) {
858
915
  throw new Error("Not in a git repo");
859
916
  }
860
917
  const { remote: remoteName, branch: baseBranch } = await getBaseBranch(remote);
861
- const isDirty = (await git.diffSummary()).files.length > 0;
918
+ const isDirty = (await runGitCommand(["diff", "--name-only"], {
919
+ cwd: repoPath
920
+ })).trim().length > 0;
862
921
  const head = isDirty ? "HEAD" : "HEAD^";
863
922
  try {
864
- const ancestor = await git.raw([
865
- "merge-base",
866
- head,
867
- `${remoteName}/${baseBranch}`
868
- ]);
923
+ const ancestor = await runGitCommand(
924
+ ["merge-base", head, `${remoteName}/${baseBranch}`],
925
+ { cwd: repoPath }
926
+ );
869
927
  return ancestor.trim();
870
928
  } catch {
871
929
  return void 0;
872
930
  }
873
931
  }
874
932
  async function getPastNAncestors(n = 1e3, remote = void 0) {
875
- const git = await currentRepo();
876
- if (git === null) {
933
+ const repoPath = await currentRepoPath();
934
+ if (!repoPath) {
877
935
  return [];
878
936
  }
879
937
  let ancestor = void 0;
@@ -888,8 +946,10 @@ async function getPastNAncestors(n = 1e3, remote = void 0) {
888
946
  if (!ancestor) {
889
947
  return [];
890
948
  }
891
- const commits = await git.log({ from: ancestor, to: "HEAD", maxCount: n });
892
- return commits.all.slice(0, n).map((c) => c.hash);
949
+ const commits = (await runGitCommand(["rev-list", `--max-count=${n}`, `${ancestor}..HEAD`], {
950
+ cwd: repoPath
951
+ })).trim();
952
+ return commits ? commits.split(/\r?\n/).slice(0, n) : [];
893
953
  }
894
954
  async function attempt(fn) {
895
955
  try {
@@ -920,9 +980,14 @@ async function getRepoInfo(settings) {
920
980
  });
921
981
  return sanitized;
922
982
  }
983
+ async function currentRepoPath() {
984
+ return await attempt(
985
+ async () => (await runGitCommand(["rev-parse", "--show-toplevel"])).trim()
986
+ );
987
+ }
923
988
  async function repoInfo() {
924
- const git = await currentRepo();
925
- if (git === null) {
989
+ const repoPath = await currentRepoPath();
990
+ if (!repoPath) {
926
991
  return void 0;
927
992
  }
928
993
  let commit = void 0;
@@ -933,29 +998,32 @@ async function repoInfo() {
933
998
  let tag = void 0;
934
999
  let branch = void 0;
935
1000
  let git_diff = void 0;
936
- const dirty = (await git.diffSummary()).files.length > 0;
937
- commit = await attempt(async () => await git.revparse(["HEAD"]));
1001
+ const runGit = async (args) => await runGitCommand(args, { cwd: repoPath });
1002
+ const dirty = (await runGit(["diff", "--name-only"])).trim().length > 0;
1003
+ commit = await attempt(
1004
+ async () => (await runGit(["rev-parse", "HEAD"])).trim()
1005
+ );
938
1006
  commit_message = await attempt(
939
- async () => (await git.raw(["log", "-1", "--pretty=%B"])).trim()
1007
+ async () => (await runGit(["log", "-1", "--pretty=%B"])).trim()
940
1008
  );
941
1009
  commit_time = await attempt(
942
- async () => (await git.raw(["log", "-1", "--pretty=%cI"])).trim()
1010
+ async () => (await runGit(["log", "-1", "--pretty=%cI"])).trim()
943
1011
  );
944
1012
  author_name = await attempt(
945
- async () => (await git.raw(["log", "-1", "--pretty=%aN"])).trim()
1013
+ async () => (await runGit(["log", "-1", "--pretty=%aN"])).trim()
946
1014
  );
947
1015
  author_email = await attempt(
948
- async () => (await git.raw(["log", "-1", "--pretty=%aE"])).trim()
1016
+ async () => (await runGit(["log", "-1", "--pretty=%aE"])).trim()
949
1017
  );
950
1018
  tag = await attempt(
951
- async () => (await git.raw(["describe", "--tags", "--exact-match", "--always"])).trim()
1019
+ async () => (await runGit(["describe", "--tags", "--exact-match", "--always"])).trim()
952
1020
  );
953
1021
  branch = await attempt(
954
- async () => (await git.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim()
1022
+ async () => (await runGit(["rev-parse", "--abbrev-ref", "HEAD"])).trim()
955
1023
  );
956
1024
  if (dirty) {
957
1025
  git_diff = await attempt(
958
- async () => truncateToByteLimit(await git.raw(["--no-ext-diff", "diff", "HEAD"]))
1026
+ async () => truncateToByteLimit(await runGit(["diff", "--no-ext-diff", "HEAD"]))
959
1027
  );
960
1028
  }
961
1029
  return {
@@ -2036,15 +2104,15 @@ function mergeDictsWithPaths({
2036
2104
  function mergeDictsWithPathsHelper({
2037
2105
  mergeInto,
2038
2106
  mergeFrom,
2039
- path: path2,
2107
+ path: path3,
2040
2108
  mergePaths
2041
2109
  }) {
2042
2110
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
2043
2111
  if (FORBIDDEN_MERGE_KEYS.has(k)) return;
2044
- const fullPath = path2.concat([k]);
2112
+ const fullPath = path3.concat([k]);
2045
2113
  const fullPathSerialized = JSON.stringify(fullPath);
2046
2114
  const mergeIntoV = recordFind(mergeInto, k);
2047
- const isSetUnionField = path2.length === 0 && SET_UNION_FIELDS.has(k) && !mergePaths.has(fullPathSerialized);
2115
+ const isSetUnionField = path3.length === 0 && SET_UNION_FIELDS.has(k) && !mergePaths.has(fullPathSerialized);
2048
2116
  if (isSetUnionField && isArray(mergeIntoV) && isArray(mergeFromV)) {
2049
2117
  const seen = /* @__PURE__ */ new Set();
2050
2118
  const combined = [];
@@ -2077,9 +2145,9 @@ function mergeDicts(mergeInto, mergeFrom) {
2077
2145
  function recordFind(m, k) {
2078
2146
  return m[k];
2079
2147
  }
2080
- function getObjValueByPath(row, path2) {
2148
+ function getObjValueByPath(row, path3) {
2081
2149
  let curr = row;
2082
- for (const p of path2) {
2150
+ for (const p of path3) {
2083
2151
  if (!isObjectOrArray(curr)) {
2084
2152
  return null;
2085
2153
  }
@@ -2706,7 +2774,10 @@ var AclObjectType = z6.union([
2706
2774
  "org_member",
2707
2775
  "project_log",
2708
2776
  "org_project",
2709
- "org_audit_logs"
2777
+ "org_audit_logs",
2778
+ "project_group",
2779
+ "ai_secret",
2780
+ "org_ai_secret"
2710
2781
  ]),
2711
2782
  z6.null()
2712
2783
  ]);
@@ -2835,7 +2906,8 @@ var AsyncScoringState = z6.union([
2835
2906
  token: z6.string(),
2836
2907
  function_ids: z6.array(z6.unknown()),
2837
2908
  skip_logging: z6.union([z6.boolean(), z6.null()]).optional(),
2838
- 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()
2839
2911
  }),
2840
2912
  z6.object({ status: z6.literal("disabled") }),
2841
2913
  z6.null(),
@@ -2904,7 +2976,7 @@ var FunctionTypeEnum = z6.enum([
2904
2976
  "parameters",
2905
2977
  "sandbox"
2906
2978
  ]);
2907
- var NullableSavedFunctionId = z6.union([
2979
+ var FacetPreprocessorId = z6.union([
2908
2980
  z6.object({
2909
2981
  type: z6.literal("function"),
2910
2982
  id: z6.string(),
@@ -2915,10 +2987,23 @@ var NullableSavedFunctionId = z6.union([
2915
2987
  name: z6.string(),
2916
2988
  function_type: FunctionTypeEnum.optional().default("scorer")
2917
2989
  }),
2990
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
2918
2991
  z6.null()
2919
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
+ ]);
2920
3005
  var TopicMapGenerationSettings = z6.object({
2921
- algorithm: z6.enum(["hdbscan", "kmeans"]),
3006
+ algorithm: z6.enum(["hdbscan", "kmeans", "community"]),
2922
3007
  dimension_reduction: z6.enum(["umap", "pca", "none"]),
2923
3008
  sample_size: z6.number().int().gt(0).optional(),
2924
3009
  n_clusters: z6.number().int().gt(0).optional(),
@@ -2930,6 +3015,7 @@ var TopicMapGenerationSettings = z6.object({
2930
3015
  var TopicMapData = z6.object({
2931
3016
  type: z6.literal("topic_map"),
2932
3017
  source_facet: z6.string(),
3018
+ source_facet_function: SavedFunctionId.and(z6.unknown()).optional(),
2933
3019
  embedding_model: z6.string(),
2934
3020
  bundle_key: z6.string().optional(),
2935
3021
  report_key: z6.string().optional(),
@@ -2943,7 +3029,7 @@ var TopicMapData = z6.object({
2943
3029
  });
2944
3030
  var BatchedFacetData = z6.object({
2945
3031
  type: z6.literal("batched_facet"),
2946
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
3032
+ preprocessor: FacetPreprocessorId.optional(),
2947
3033
  facets: z6.array(
2948
3034
  z6.object({
2949
3035
  name: z6.string(),
@@ -3204,18 +3290,6 @@ var ObjectReferenceNullish = z6.union([
3204
3290
  }),
3205
3291
  z6.null()
3206
3292
  ]);
3207
- var SavedFunctionId = z6.union([
3208
- z6.object({
3209
- type: z6.literal("function"),
3210
- id: z6.string(),
3211
- version: z6.string().optional()
3212
- }),
3213
- z6.object({
3214
- type: z6.literal("global"),
3215
- name: z6.string(),
3216
- function_type: FunctionTypeEnum.optional().default("scorer")
3217
- })
3218
- ]);
3219
3293
  var DatasetEvent = z6.object({
3220
3294
  id: z6.string(),
3221
3295
  _xact_id: z6.string(),
@@ -3437,7 +3511,7 @@ var ExtendedSavedFunctionId = z6.union([
3437
3511
  ]);
3438
3512
  var FacetData = z6.object({
3439
3513
  type: z6.literal("facet"),
3440
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
3514
+ preprocessor: FacetPreprocessorId.optional(),
3441
3515
  prompt: z6.string(),
3442
3516
  model: z6.string().optional(),
3443
3517
  embedding_model: z6.string().optional(),
@@ -3536,7 +3610,7 @@ var PromptParserNullish = z6.union([
3536
3610
  }),
3537
3611
  z6.null()
3538
3612
  ]);
3539
- var PreprocessorSavedFunctionId = z6.union([
3613
+ var PreprocessorId = z6.union([
3540
3614
  z6.object({
3541
3615
  type: z6.literal("function"),
3542
3616
  id: z6.string(),
@@ -3547,6 +3621,7 @@ var PreprocessorSavedFunctionId = z6.union([
3547
3621
  name: z6.string(),
3548
3622
  function_type: z6.literal("preprocessor").optional().default("preprocessor")
3549
3623
  }),
3624
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
3550
3625
  z6.null()
3551
3626
  ]);
3552
3627
  var PromptDataNullish = z6.union([
@@ -3554,7 +3629,7 @@ var PromptDataNullish = z6.union([
3554
3629
  prompt: PromptBlockDataNullish,
3555
3630
  options: PromptOptionsNullish,
3556
3631
  parser: PromptParserNullish,
3557
- preprocessor: PreprocessorSavedFunctionId,
3632
+ preprocessor: PreprocessorId,
3558
3633
  tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
3559
3634
  template_format: z6.union([
3560
3635
  z6.enum(["mustache", "nunjucks", "none"]),
@@ -3756,7 +3831,7 @@ var PromptData = z6.object({
3756
3831
  prompt: PromptBlockDataNullish,
3757
3832
  options: PromptOptionsNullish,
3758
3833
  parser: PromptParserNullish,
3759
- preprocessor: PreprocessorSavedFunctionId,
3834
+ preprocessor: PreprocessorId,
3760
3835
  tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
3761
3836
  template_format: z6.union([
3762
3837
  z6.enum(["mustache", "nunjucks", "none"]),
@@ -3942,6 +4017,19 @@ var MessageRole = z6.enum([
3942
4017
  "model",
3943
4018
  "developer"
3944
4019
  ]);
4020
+ var NullableSavedFunctionId = z6.union([
4021
+ z6.object({
4022
+ type: z6.literal("function"),
4023
+ id: z6.string(),
4024
+ version: z6.string().optional()
4025
+ }),
4026
+ z6.object({
4027
+ type: z6.literal("global"),
4028
+ name: z6.string(),
4029
+ function_type: FunctionTypeEnum.optional().default("scorer")
4030
+ }),
4031
+ z6.null()
4032
+ ]);
3945
4033
  var ObjectReference = z6.object({
3946
4034
  object_type: z6.enum([
3947
4035
  "project_logs",
@@ -3963,6 +4051,7 @@ var TraceScope = z6.object({
3963
4051
  });
3964
4052
  var OnlineScoreConfig = z6.union([
3965
4053
  z6.object({
4054
+ status: AutomationStatus.optional(),
3966
4055
  sampling_rate: z6.number().gte(0).lte(1),
3967
4056
  scorers: z6.array(SavedFunctionId),
3968
4057
  btql_filter: z6.union([z6.string(), z6.null()]).optional(),
@@ -4043,6 +4132,72 @@ var Project = z6.object({
4043
4132
  user_id: z6.union([z6.string(), z6.null()]).optional(),
4044
4133
  settings: ProjectSettings.optional()
4045
4134
  });
4135
+ var WindowedAutomationConfig = z6.object({
4136
+ event_type: z6.literal("windowed"),
4137
+ product_origin: z6.union([z6.literal("patterns"), z6.null()]).optional(),
4138
+ status: AutomationStatus.optional(),
4139
+ threshold: z6.object({
4140
+ calculation: z6.object({
4141
+ type: z6.literal("btql"),
4142
+ btql_query: z6.string().min(1),
4143
+ output: z6.object({
4144
+ type: z6.literal("scalar"),
4145
+ value_column: z6.string().min(1)
4146
+ })
4147
+ }),
4148
+ policy: z6.object({
4149
+ condition: z6.object({
4150
+ type: z6.literal("threshold"),
4151
+ operator: z6.enum(["lt", "lte", "gt", "gte", "eq", "neq"]),
4152
+ threshold: z6.number()
4153
+ }),
4154
+ pending_seconds: z6.number().int().gte(0).lte(2592e3),
4155
+ no_data_behavior: z6.enum(["keep_last", "resolve", "alert"]),
4156
+ renotify_interval_seconds: z6.union([z6.number(), z6.null()]).optional(),
4157
+ notify_on_recovery: z6.boolean().optional().default(true)
4158
+ })
4159
+ }).optional(),
4160
+ window: z6.object({
4161
+ window_seconds: z6.number().int().gte(1).lte(2592e3),
4162
+ schedule: z6.union([
4163
+ z6.object({
4164
+ type: z6.literal("interval"),
4165
+ evaluation_interval_seconds: z6.number().int().gte(1).lte(2592e3)
4166
+ }),
4167
+ z6.object({
4168
+ type: z6.literal("cron"),
4169
+ cron_expression: z6.string().min(1),
4170
+ timezone: z6.union([z6.string(), z6.null()]).optional()
4171
+ })
4172
+ ]),
4173
+ evaluation_delay_seconds: z6.number().int().gte(0).lte(2592e3)
4174
+ }),
4175
+ loop: z6.object({
4176
+ prompt: z6.string().min(1).max(1e4),
4177
+ include_trigger_input: z6.boolean().optional().default(false),
4178
+ agent_slug: z6.string().min(1),
4179
+ auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
4180
+ harness: z6.enum(["native", "codex", "claude-code"]).optional(),
4181
+ model: z6.string().min(1).optional(),
4182
+ reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
4183
+ }).optional(),
4184
+ actions: z6.array(
4185
+ z6.union([
4186
+ z6.object({
4187
+ type: z6.literal("webhook"),
4188
+ url: z6.string(),
4189
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4190
+ }),
4191
+ z6.object({
4192
+ type: z6.literal("slack"),
4193
+ workspace_id: z6.string(),
4194
+ channel: z6.string(),
4195
+ message_template: z6.string().optional(),
4196
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4197
+ })
4198
+ ])
4199
+ ).max(20).optional().default([])
4200
+ });
4046
4201
  var TopicAutomationFacetModel = z6.union([
4047
4202
  z6.enum(["brain-facet-latest", "brain-facet-1", "brain-facet-2"]),
4048
4203
  z6.null()
@@ -4084,7 +4239,8 @@ var TopicDigestAutomationConfig = z6.object({
4084
4239
  type: z6.literal("slack"),
4085
4240
  workspace_id: z6.string(),
4086
4241
  channel: z6.string(),
4087
- message_template: z6.string().optional()
4242
+ message_template: z6.string().optional(),
4243
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4088
4244
  }),
4089
4245
  topic_map_function_ids: z6.array(z6.string()).max(10).optional()
4090
4246
  });
@@ -4098,15 +4254,21 @@ var ProjectAutomation = z6.object({
4098
4254
  config: z6.union([
4099
4255
  z6.object({
4100
4256
  event_type: z6.literal("logs"),
4257
+ status: AutomationStatus.optional(),
4101
4258
  btql_filter: z6.string(),
4102
4259
  interval_seconds: z6.number().gte(1).lte(2592e3),
4103
4260
  action: z6.union([
4104
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
4261
+ z6.object({
4262
+ type: z6.literal("webhook"),
4263
+ url: z6.string(),
4264
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4265
+ }),
4105
4266
  z6.object({
4106
4267
  type: z6.literal("slack"),
4107
4268
  workspace_id: z6.string(),
4108
4269
  channel: z6.string(),
4109
- message_template: z6.string().optional()
4270
+ message_template: z6.string().optional(),
4271
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4110
4272
  })
4111
4273
  ])
4112
4274
  }),
@@ -4157,21 +4319,38 @@ var ProjectAutomation = z6.object({
4157
4319
  }),
4158
4320
  z6.object({
4159
4321
  event_type: z6.literal("environment_update"),
4322
+ status: AutomationStatus.optional(),
4160
4323
  environment_filter: z6.array(z6.string()).optional(),
4161
4324
  action: z6.union([
4162
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
4325
+ z6.object({
4326
+ type: z6.literal("webhook"),
4327
+ url: z6.string(),
4328
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4329
+ }),
4163
4330
  z6.object({
4164
4331
  type: z6.literal("slack"),
4165
4332
  workspace_id: z6.string(),
4166
4333
  channel: z6.string(),
4167
- message_template: z6.string().optional()
4334
+ message_template: z6.string().optional(),
4335
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4168
4336
  })
4169
4337
  ])
4170
4338
  }),
4339
+ WindowedAutomationConfig,
4171
4340
  TopicAutomationConfig,
4172
4341
  TopicDigestAutomationConfig
4173
4342
  ])
4174
4343
  });
4344
+ var ProjectGroup = z6.object({
4345
+ id: z6.string().uuid(),
4346
+ org_id: z6.string().uuid(),
4347
+ user_id: z6.union([z6.string(), z6.null()]).optional(),
4348
+ created: z6.union([z6.string(), z6.null()]).optional(),
4349
+ name: z6.string(),
4350
+ description: z6.union([z6.string(), z6.null()]).optional(),
4351
+ deleted_at: z6.union([z6.string(), z6.null()]).optional(),
4352
+ member_projects: z6.array(z6.string().uuid()).max(1e4)
4353
+ });
4175
4354
  var ProjectLogsEvent = z6.object({
4176
4355
  id: z6.string(),
4177
4356
  _xact_id: z6.string(),
@@ -4389,7 +4568,8 @@ var RunEval = z6.object({
4389
4568
  dataset_environment: z6.union([z6.string(), z6.null()]).optional(),
4390
4569
  _internal_btql: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional()
4391
4570
  }),
4392
- z6.object({ data: z6.array(z6.unknown()) })
4571
+ z6.object({ data: z6.array(z6.unknown()) }),
4572
+ z6.object({ experiment_name: z6.string() })
4393
4573
  ]),
4394
4574
  name: z6.string().optional(),
4395
4575
  parameters: z6.object({}).partial().passthrough().optional(),
@@ -4594,7 +4774,10 @@ var View = z6.object({
4594
4774
  "for_review_datasets"
4595
4775
  ]),
4596
4776
  name: z6.string(),
4777
+ description: z6.union([z6.string(), z6.null()]).optional(),
4778
+ starred: z6.boolean().optional(),
4597
4779
  created: z6.union([z6.string(), z6.null()]).optional(),
4780
+ updated_at: z6.union([z6.string(), z6.null()]).optional(),
4598
4781
  view_data: ViewData.optional(),
4599
4782
  options: ViewOptions.optional(),
4600
4783
  user_id: z6.union([z6.string(), z6.null()]).optional(),
@@ -5121,10 +5304,10 @@ var DiskCache = class {
5121
5304
  return;
5122
5305
  }
5123
5306
  const stats = await Promise.all(
5124
- paths.map(async (path2) => {
5125
- const stat2 = await isomorph_default.stat(path2);
5307
+ paths.map(async (path3) => {
5308
+ const stat2 = await isomorph_default.stat(path3);
5126
5309
  return {
5127
- path: path2,
5310
+ path: path3,
5128
5311
  mtime: stat2.mtime.getTime()
5129
5312
  };
5130
5313
  })
@@ -5296,44 +5479,72 @@ function createCacheLayers({
5296
5479
  }
5297
5480
 
5298
5481
  // src/prompt-cache/prompt-cache.ts
5299
- function createCacheKey(key) {
5482
+ function createCacheKey(key, namespace) {
5483
+ let cacheKey;
5300
5484
  if (key.id) {
5301
- return `id:${key.id}`;
5302
- }
5303
- const prefix = key.projectId ?? key.projectName;
5304
- if (!prefix) {
5305
- throw new Error("Either projectId or projectName must be provided");
5306
- }
5307
- if (!key.slug) {
5308
- throw new Error("Slug must be provided when not using ID");
5485
+ cacheKey = `id:${key.id}`;
5486
+ } else {
5487
+ const prefix = key.projectId ?? key.projectName;
5488
+ if (!prefix) {
5489
+ throw new Error("Either projectId or projectName must be provided");
5490
+ }
5491
+ if (!key.slug) {
5492
+ throw new Error("Slug must be provided when not using ID");
5493
+ }
5494
+ cacheKey = `${prefix}:${key.slug}:${key.version ?? "latest"}`;
5309
5495
  }
5310
- return `${prefix}:${key.slug}:${key.version ?? "latest"}`;
5496
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
5311
5497
  }
5312
- var PromptCache = class {
5498
+ var PromptCache = class _PromptCache {
5313
5499
  memoryCache;
5314
5500
  diskCache;
5501
+ namespace;
5502
+ expectedResolvedOrgIdentity;
5315
5503
  constructor(options) {
5316
5504
  this.memoryCache = options.memoryCache;
5317
5505
  this.diskCache = options.diskCache;
5506
+ this.namespace = options.namespace;
5507
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
5508
+ }
5509
+ /**
5510
+ * Returns a cache view that shares the same storage layers but isolates all
5511
+ * entries under the provided namespace.
5512
+ */
5513
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
5514
+ return new _PromptCache({
5515
+ memoryCache: this.memoryCache,
5516
+ diskCache: this.diskCache,
5517
+ namespace,
5518
+ expectedResolvedOrgIdentity
5519
+ });
5318
5520
  }
5319
5521
  /**
5320
5522
  * Retrieves a prompt from the cache.
5321
5523
  * First checks the in-memory LRU cache, then falls back to checking the disk cache if available.
5322
5524
  */
5323
5525
  async get(key) {
5324
- const cacheKey = createCacheKey(key);
5526
+ const cacheKey = createCacheKey(key, this.namespace);
5325
5527
  if (this.memoryCache) {
5326
- const memoryPrompt = this.memoryCache.get(cacheKey);
5327
- if (memoryPrompt !== void 0) {
5328
- return memoryPrompt;
5528
+ const memoryEntry = this.memoryCache.get(cacheKey);
5529
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
5530
+ return memoryEntry.value;
5329
5531
  }
5330
5532
  }
5331
5533
  if (this.diskCache) {
5332
- const diskPrompt = await this.diskCache.get(cacheKey);
5333
- if (!diskPrompt) {
5534
+ const diskEntry = await this.diskCache.get(cacheKey);
5535
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
5334
5536
  return void 0;
5335
5537
  }
5336
- this.memoryCache?.set(cacheKey, diskPrompt);
5538
+ const serializedPrompt = diskEntry.value;
5539
+ const diskPrompt = new Prompt2(
5540
+ serializedPrompt.metadata,
5541
+ serializedPrompt.defaults,
5542
+ serializedPrompt.noTrace
5543
+ );
5544
+ this.memoryCache?.set(cacheKey, {
5545
+ value: diskPrompt,
5546
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
5547
+ });
5337
5548
  return diskPrompt;
5338
5549
  }
5339
5550
  return void 0;
@@ -5347,58 +5558,91 @@ var PromptCache = class {
5347
5558
  * @throws If there is an error writing to the disk cache.
5348
5559
  */
5349
5560
  async set(key, value) {
5350
- const cacheKey = createCacheKey(key);
5351
- this.memoryCache?.set(cacheKey, value);
5561
+ const cacheKey = createCacheKey(key, this.namespace);
5562
+ const memoryEntry = {
5563
+ value,
5564
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5565
+ };
5566
+ this.memoryCache?.set(cacheKey, memoryEntry);
5352
5567
  if (this.diskCache) {
5353
- await this.diskCache.set(cacheKey, value);
5568
+ await this.diskCache.set(cacheKey, {
5569
+ value: value._internalSerializeForCache(),
5570
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5571
+ });
5354
5572
  }
5355
5573
  }
5356
5574
  };
5357
5575
 
5358
5576
  // src/prompt-cache/parameters-cache.ts
5359
- function createCacheKey2(key) {
5577
+ function createCacheKey2(key, namespace) {
5578
+ let cacheKey;
5360
5579
  if (key.id) {
5361
- return `parameters:id:${key.id}`;
5362
- }
5363
- const prefix = key.projectId ?? key.projectName;
5364
- if (!prefix) {
5365
- throw new Error("Either projectId or projectName must be provided");
5366
- }
5367
- if (!key.slug) {
5368
- throw new Error("Slug must be provided when not using ID");
5580
+ cacheKey = `parameters:id:${key.id}`;
5581
+ } else {
5582
+ const prefix = key.projectId ?? key.projectName;
5583
+ if (!prefix) {
5584
+ throw new Error("Either projectId or projectName must be provided");
5585
+ }
5586
+ if (!key.slug) {
5587
+ throw new Error("Slug must be provided when not using ID");
5588
+ }
5589
+ cacheKey = `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
5369
5590
  }
5370
- return `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
5591
+ return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
5371
5592
  }
5372
- var ParametersCache = class {
5593
+ var ParametersCache = class _ParametersCache {
5373
5594
  memoryCache;
5374
5595
  diskCache;
5596
+ namespace;
5597
+ expectedResolvedOrgIdentity;
5375
5598
  constructor(options) {
5376
5599
  this.memoryCache = options.memoryCache;
5377
5600
  this.diskCache = options.diskCache;
5601
+ this.namespace = options.namespace;
5602
+ this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
5603
+ }
5604
+ withNamespace(namespace, expectedResolvedOrgIdentity) {
5605
+ return new _ParametersCache({
5606
+ memoryCache: this.memoryCache,
5607
+ diskCache: this.diskCache,
5608
+ namespace,
5609
+ expectedResolvedOrgIdentity
5610
+ });
5378
5611
  }
5379
5612
  async get(key) {
5380
- const cacheKey = createCacheKey2(key);
5613
+ const cacheKey = createCacheKey2(key, this.namespace);
5381
5614
  if (this.memoryCache) {
5382
- const memoryParams = this.memoryCache.get(cacheKey);
5383
- if (memoryParams !== void 0) {
5384
- return memoryParams;
5615
+ const memoryEntry = this.memoryCache.get(cacheKey);
5616
+ if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
5617
+ return memoryEntry.value;
5385
5618
  }
5386
5619
  }
5387
5620
  if (this.diskCache) {
5388
- const diskParams = await this.diskCache.get(cacheKey);
5389
- if (!diskParams) {
5621
+ const diskEntry = await this.diskCache.get(cacheKey);
5622
+ if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
5390
5623
  return void 0;
5391
5624
  }
5392
- this.memoryCache?.set(cacheKey, diskParams);
5393
- return diskParams;
5625
+ const diskParameters = new RemoteEvalParameters(diskEntry.value.metadata);
5626
+ this.memoryCache?.set(cacheKey, {
5627
+ value: diskParameters,
5628
+ resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
5629
+ });
5630
+ return diskParameters;
5394
5631
  }
5395
5632
  return void 0;
5396
5633
  }
5397
5634
  async set(key, value) {
5398
- const cacheKey = createCacheKey2(key);
5399
- this.memoryCache?.set(cacheKey, value);
5635
+ const cacheKey = createCacheKey2(key, this.namespace);
5636
+ const memoryEntry = {
5637
+ value,
5638
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5639
+ };
5640
+ this.memoryCache?.set(cacheKey, memoryEntry);
5400
5641
  if (this.diskCache) {
5401
- await this.diskCache.set(cacheKey, value);
5642
+ await this.diskCache.set(cacheKey, {
5643
+ value: value._internalSerializeForCache(),
5644
+ resolvedOrgIdentity: this.expectedResolvedOrgIdentity
5645
+ });
5402
5646
  }
5403
5647
  }
5404
5648
  };
@@ -5702,6 +5946,7 @@ var INSTRUMENTATION_NAMES = {
5702
5946
  CLOUDFLARE_THINK: "cloudflare-think",
5703
5947
  COHERE: "cohere",
5704
5948
  CURSOR_SDK: "cursor-sdk",
5949
+ DEEPSEEK_HARNESS: "deepseek-harness",
5705
5950
  EVE: "eve",
5706
5951
  FLUE: "flue",
5707
5952
  GENKIT: "genkit",
@@ -5721,12 +5966,13 @@ var INSTRUMENTATION_NAMES = {
5721
5966
  OPENROUTER: "openrouter",
5722
5967
  OPENROUTER_AGENT: "openrouter-agent",
5723
5968
  PI_CODING_AGENT: "pi-coding-agent",
5724
- STRANDS_AGENT_SDK: "strands-agent-sdk"
5969
+ STRANDS_AGENT_SDK: "strands-agent-sdk",
5970
+ VOYAGEAI: "voyageai"
5725
5971
  };
5726
5972
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5727
5973
  "braintrust.spanInstrumentationName"
5728
5974
  );
5729
- var SDK_VERSION = true ? "3.27.0" : "0.0.0";
5975
+ var SDK_VERSION = true ? "3.29.0" : "0.0.0";
5730
5976
  function withSpanInstrumentationName(args, instrumentationName) {
5731
5977
  return {
5732
5978
  ...args,
@@ -5845,6 +6091,16 @@ var datasetSnapshotRegisterResponseSchema = z8.object({
5845
6091
  dataset_snapshot: DatasetSnapshot,
5846
6092
  found_existing: z8.boolean().optional()
5847
6093
  });
6094
+ var datasetObjectInfoSchema = z8.object({
6095
+ object_id: z8.string(),
6096
+ object_name: z8.string(),
6097
+ parent_cols: z8.object({
6098
+ project: z8.object({
6099
+ id: z8.string(),
6100
+ name: z8.string()
6101
+ })
6102
+ })
6103
+ });
5848
6104
  var datasetRestorePreviewResultSchema = z8.object({
5849
6105
  rows_to_restore: z8.number(),
5850
6106
  rows_to_delete: z8.number()
@@ -5921,6 +6177,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
5921
6177
  var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
5922
6178
  "braintrust.initial-span-write-as-merge"
5923
6179
  );
6180
+ var RESUME_SPAN_WITHOUT_INITIAL_WRITE = /* @__PURE__ */ Symbol(
6181
+ "braintrust.resume-span-without-initial-write"
6182
+ );
5924
6183
  var INTERNAL_SPAN_CONTEXT = /* @__PURE__ */ Symbol("braintrust.internal-span-context");
5925
6184
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
5926
6185
  "braintrust.currentSpanStore"
@@ -6055,12 +6314,53 @@ var loginSchema = z8.strictObject({
6055
6314
  });
6056
6315
  var stateNonce = 0;
6057
6316
  var V1_PROXY_SUFFIX = "/v1/proxy";
6317
+ var LOADER_LOGIN_CACHE_MAX = 16;
6058
6318
  function normalizeProxyConnUrl(proxyUrl) {
6059
6319
  return proxyUrl.endsWith(V1_PROXY_SUFFIX) ? proxyUrl.slice(0, proxyUrl.length - V1_PROXY_SUFFIX.length) : proxyUrl;
6060
6320
  }
6061
6321
  var BraintrustState = class _BraintrustState {
6322
+ id;
6323
+ currentExperiment;
6324
+ // Note: the value of IsAsyncFlush doesn't really matter here, since we
6325
+ // (safely) dynamically cast it whenever retrieving the logger.
6326
+ currentLogger;
6327
+ currentParent;
6328
+ currentSpan;
6329
+ // Any time we re-log in, we directly update the apiConn inside the logger.
6330
+ // This is preferable to replacing the whole logger, which would create the
6331
+ // possibility of multiple loggers floating around, which may not log in a
6332
+ // deterministic order.
6333
+ _bgLogger;
6334
+ _overrideBgLogger = null;
6335
+ appUrl = null;
6336
+ appPublicUrl = null;
6337
+ loginToken = null;
6338
+ orgId = null;
6339
+ orgName = null;
6340
+ apiUrl = null;
6341
+ proxyUrl = null;
6342
+ loggedIn = false;
6343
+ gitMetadataSettings;
6344
+ debugLogLevel;
6345
+ debugLogLevelConfigured = false;
6346
+ fetch = globalThis.fetch;
6347
+ _appConn = null;
6348
+ _apiConn = null;
6349
+ _proxyConn = null;
6350
+ promptCache;
6351
+ parametersCache;
6352
+ spanCache;
6353
+ _idGenerator = null;
6354
+ _contextManager = null;
6355
+ _otelFlushCallback = null;
6356
+ spanOriginEnvironment;
6357
+ traceContextSigningSecret;
6358
+ loaderLoginCache = /* @__PURE__ */ new WeakMap();
6359
+ loginParams;
6360
+ activeLoginOrgNameSelector;
6062
6361
  constructor(loginParams) {
6063
- this.loginParams = loginParams;
6362
+ this.loginParams = { ...loginParams };
6363
+ this.activeLoginOrgNameSelector = loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
6064
6364
  this.id = `${(/* @__PURE__ */ new Date()).toLocaleString()}-${stateNonce++}`;
6065
6365
  this.currentExperiment = void 0;
6066
6366
  this.currentLogger = void 0;
@@ -6097,12 +6397,14 @@ var BraintrustState = class _BraintrustState {
6097
6397
  const {
6098
6398
  memoryCache: parametersMemoryCache,
6099
6399
  diskCache: parametersDiskCache
6100
- } = createCacheLayers({
6101
- memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
6102
- diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
6103
- diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
6104
- getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
6105
- });
6400
+ } = createCacheLayers(
6401
+ {
6402
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
6403
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
6404
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
6405
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
6406
+ }
6407
+ );
6106
6408
  this.parametersCache = new ParametersCache({
6107
6409
  memoryCache: parametersMemoryCache,
6108
6410
  diskCache: parametersDiskCache
@@ -6111,43 +6413,6 @@ var BraintrustState = class _BraintrustState {
6111
6413
  this.spanOriginEnvironment = detectSpanOriginEnvironment();
6112
6414
  this._internalSetTraceContextSigningSecret(loginParams.apiKey);
6113
6415
  }
6114
- loginParams;
6115
- id;
6116
- currentExperiment;
6117
- // Note: the value of IsAsyncFlush doesn't really matter here, since we
6118
- // (safely) dynamically cast it whenever retrieving the logger.
6119
- currentLogger;
6120
- currentParent;
6121
- currentSpan;
6122
- // Any time we re-log in, we directly update the apiConn inside the logger.
6123
- // This is preferable to replacing the whole logger, which would create the
6124
- // possibility of multiple loggers floating around, which may not log in a
6125
- // deterministic order.
6126
- _bgLogger;
6127
- _overrideBgLogger = null;
6128
- appUrl = null;
6129
- appPublicUrl = null;
6130
- loginToken = null;
6131
- orgId = null;
6132
- orgName = null;
6133
- apiUrl = null;
6134
- proxyUrl = null;
6135
- loggedIn = false;
6136
- gitMetadataSettings;
6137
- debugLogLevel;
6138
- debugLogLevelConfigured = false;
6139
- fetch = globalThis.fetch;
6140
- _appConn = null;
6141
- _apiConn = null;
6142
- _proxyConn = null;
6143
- promptCache;
6144
- parametersCache;
6145
- spanCache;
6146
- _idGenerator = null;
6147
- _contextManager = null;
6148
- _otelFlushCallback = null;
6149
- spanOriginEnvironment;
6150
- traceContextSigningSecret;
6151
6416
  /** @internal */
6152
6417
  _internalSetTraceContextSigningSecret(secret) {
6153
6418
  const normalizedSecret = secret?.trim();
@@ -6172,6 +6437,101 @@ var BraintrustState = class _BraintrustState {
6172
6437
  this._appConn = null;
6173
6438
  this._apiConn = null;
6174
6439
  this._proxyConn = null;
6440
+ this.loaderLoginCache = /* @__PURE__ */ new WeakMap();
6441
+ }
6442
+ /** @internal */
6443
+ async _internalResolveLoaderLoginOptions({
6444
+ apiKey,
6445
+ appUrl,
6446
+ orgName,
6447
+ fetch: fetch2,
6448
+ forceLogin
6449
+ }) {
6450
+ const resolvedAppUrl = appUrl ?? (this.loggedIn ? this.appUrl ?? void 0 : void 0) ?? this.loginParams.appUrl ?? isomorph_default.getEnv("BRAINTRUST_APP_URL") ?? "https://www.braintrust.dev";
6451
+ const resolvedApiKey = apiKey ?? (this.loggedIn ? this.loginToken ?? void 0 : void 0) ?? this.loginParams.apiKey ?? await isomorph_default.getBraintrustApiKey();
6452
+ if (!resolvedApiKey) {
6453
+ throw new Error(
6454
+ "Please specify an api key (e.g. by setting BRAINTRUST_API_KEY)."
6455
+ );
6456
+ }
6457
+ const normalizedApiKey = HTTPConnection.sanitize_token(resolvedApiKey);
6458
+ const usesActiveCredential = this.loggedIn && normalizedApiKey === this.loginToken;
6459
+ const requestedOrgName = orgName ?? (usesActiveCredential ? this.activeLoginOrgNameSelector : void 0) ?? this.loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
6460
+ const resolvedOrgName = orgName ?? (usesActiveCredential ? this.orgName ?? void 0 : void 0) ?? requestedOrgName;
6461
+ const resolvedFetch = fetch2 ?? (this.loggedIn ? this.fetch : void 0) ?? this.loginParams.fetch ?? globalThis.fetch;
6462
+ const credentialCacheNamespace = JSON.stringify([
6463
+ "loader-credential",
6464
+ resolvedAppUrl,
6465
+ requestedOrgName,
6466
+ normalizedApiKey
6467
+ ]);
6468
+ return {
6469
+ apiKey: normalizedApiKey,
6470
+ appUrl: resolvedAppUrl,
6471
+ orgName: resolvedOrgName,
6472
+ fetch: resolvedFetch,
6473
+ forceLogin,
6474
+ credentialCacheNamespace,
6475
+ existingState: !forceLogin && usesActiveCredential && resolvedAppUrl === this.appUrl && resolvedOrgName === this.orgName && resolvedFetch === this.fetch ? this : void 0
6476
+ };
6477
+ }
6478
+ /** @internal */
6479
+ _internalGetLoaderCacheViews(loginOptions, requestState) {
6480
+ const expectedResolvedOrgIdentity = requestState?.orgId && requestState.appUrl ? JSON.stringify([
6481
+ "loader-org",
6482
+ requestState.appUrl,
6483
+ requestState.orgId
6484
+ ]) : void 0;
6485
+ return {
6486
+ promptCache: this.promptCache.withNamespace(
6487
+ loginOptions.credentialCacheNamespace,
6488
+ expectedResolvedOrgIdentity
6489
+ ),
6490
+ parametersCache: this.parametersCache.withNamespace(
6491
+ loginOptions.credentialCacheNamespace,
6492
+ expectedResolvedOrgIdentity
6493
+ )
6494
+ };
6495
+ }
6496
+ /** @internal */
6497
+ async _internalGetLoaderState({
6498
+ apiKey,
6499
+ appUrl,
6500
+ orgName,
6501
+ fetch: fetch2,
6502
+ forceLogin,
6503
+ existingState
6504
+ }) {
6505
+ if (existingState) {
6506
+ return existingState;
6507
+ }
6508
+ let cache = this.loaderLoginCache.get(fetch2);
6509
+ if (!cache) {
6510
+ cache = new LRUCache({ max: LOADER_LOGIN_CACHE_MAX });
6511
+ this.loaderLoginCache.set(fetch2, cache);
6512
+ }
6513
+ const cacheKey = JSON.stringify([appUrl, orgName, apiKey]);
6514
+ if (!forceLogin) {
6515
+ const cachedState = cache.get(cacheKey);
6516
+ if (cachedState) {
6517
+ return cachedState;
6518
+ }
6519
+ }
6520
+ const statePromise = loginToLoaderRequestState({
6521
+ orgName,
6522
+ apiKey,
6523
+ appUrl,
6524
+ fetch: fetch2
6525
+ });
6526
+ cache.set(cacheKey, statePromise);
6527
+ try {
6528
+ return await statePromise;
6529
+ } catch (error) {
6530
+ if (cache.get(cacheKey) === statePromise) {
6531
+ cache.delete(cacheKey);
6532
+ }
6533
+ throw error;
6534
+ }
6175
6535
  }
6176
6536
  resetIdGenState() {
6177
6537
  this._idGenerator = null;
@@ -6220,6 +6580,8 @@ var BraintrustState = class _BraintrustState {
6220
6580
  this.debugLogLevel = other.debugLogLevel;
6221
6581
  this.debugLogLevelConfigured = other.debugLogLevelConfigured;
6222
6582
  this.traceContextSigningSecret = other.traceContextSigningSecret;
6583
+ this.fetch = other.fetch;
6584
+ this.activeLoginOrgNameSelector = other.activeLoginOrgNameSelector;
6223
6585
  setGlobalDebugLogLevel(
6224
6586
  this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
6225
6587
  );
@@ -6427,36 +6789,76 @@ var FailedHTTPResponse = class extends Error {
6427
6789
  status;
6428
6790
  text;
6429
6791
  data;
6430
- constructor(status, text, data) {
6792
+ cause;
6793
+ constructor(status, text, data, cause) {
6431
6794
  super(`${status}: ${text} (${data})`);
6432
6795
  this.status = status;
6433
6796
  this.text = text;
6434
6797
  this.data = data;
6798
+ this.cause = cause;
6435
6799
  }
6436
6800
  };
6801
+ var HTTPTransportError = class extends Error {
6802
+ cause;
6803
+ constructor(cause) {
6804
+ super(cause instanceof Error ? cause.message : String(cause));
6805
+ this.name = "HTTPTransportError";
6806
+ this.cause = cause;
6807
+ }
6808
+ };
6809
+ var httpTransportErrorCauses = /* @__PURE__ */ new WeakSet();
6810
+ function recordHTTPTransportError(error) {
6811
+ if (typeof error === "object" && error !== null || typeof error === "function") {
6812
+ httpTransportErrorCauses.add(error);
6813
+ }
6814
+ }
6815
+ function rethrowHTTPTransportError(error, classifyTransportErrors) {
6816
+ if (classifyTransportErrors) {
6817
+ throw new HTTPTransportError(error);
6818
+ }
6819
+ recordHTTPTransportError(error);
6820
+ throw error;
6821
+ }
6822
+ async function readJSONResponse(response, classifyTransportErrors = false) {
6823
+ let data;
6824
+ try {
6825
+ data = await response.text();
6826
+ } catch (error) {
6827
+ rethrowHTTPTransportError(error, classifyTransportErrors);
6828
+ }
6829
+ return JSON.parse(data);
6830
+ }
6437
6831
  async function checkResponse(resp) {
6438
6832
  if (resp.ok) {
6439
6833
  return resp;
6440
- } else {
6834
+ }
6835
+ let data;
6836
+ try {
6837
+ data = await resp.text();
6838
+ } catch (error) {
6441
6839
  throw new FailedHTTPResponse(
6442
6840
  resp.status,
6443
6841
  resp.statusText,
6444
- await resp.text()
6842
+ "Unable to read response body",
6843
+ error
6445
6844
  );
6446
6845
  }
6846
+ throw new FailedHTTPResponse(resp.status, resp.statusText, data);
6447
6847
  }
6448
6848
  var HTTPConnection = class _HTTPConnection {
6449
- base_url;
6450
- token;
6451
- headers;
6452
- fetch;
6453
- constructor(base_url, fetch2) {
6849
+ constructor(base_url, fetch2, classifyTransportErrors = false) {
6850
+ this.classifyTransportErrors = classifyTransportErrors;
6454
6851
  this.base_url = base_url;
6455
6852
  this.token = null;
6456
6853
  this.headers = {};
6457
6854
  this._reset();
6458
6855
  this.fetch = fetch2;
6459
6856
  }
6857
+ classifyTransportErrors;
6858
+ base_url;
6859
+ token;
6860
+ headers;
6861
+ fetch;
6460
6862
  setFetch(fetch2) {
6461
6863
  this.fetch = fetch2;
6462
6864
  }
@@ -6486,9 +6888,9 @@ var HTTPConnection = class _HTTPConnection {
6486
6888
  this.headers["Authorization"] = `Bearer ${this.token}`;
6487
6889
  }
6488
6890
  }
6489
- async get(path2, params = void 0, config) {
6891
+ async get(path3, params = void 0, config) {
6490
6892
  const { headers, ...rest } = config || {};
6491
- const url = new URL(_urljoin(this.base_url, path2));
6893
+ const url = new URL(_urljoin(this.base_url, path3));
6492
6894
  url.search = new URLSearchParams(
6493
6895
  params ? Object.entries(params).filter(([_, v]) => v !== void 0).flatMap(
6494
6896
  ([k, v]) => v !== void 0 ? typeof v === "string" ? [[k, v]] : v.map((x) => [k, x]) : []
@@ -6496,9 +6898,9 @@ var HTTPConnection = class _HTTPConnection {
6496
6898
  ).toString();
6497
6899
  const this_fetch = this.fetch;
6498
6900
  const this_headers = this.headers;
6499
- return await checkResponse(
6500
- // Using toString() here makes it work with isomorphic fetch
6501
- await this_fetch(url.toString(), {
6901
+ let response;
6902
+ try {
6903
+ response = await this_fetch(url.toString(), {
6502
6904
  headers: {
6503
6905
  Accept: "application/json",
6504
6906
  ...this_headers,
@@ -6506,10 +6908,16 @@ var HTTPConnection = class _HTTPConnection {
6506
6908
  },
6507
6909
  keepalive: true,
6508
6910
  ...rest
6509
- })
6510
- );
6911
+ });
6912
+ } catch (error) {
6913
+ if (config?.signal?.aborted) {
6914
+ throw getAbortReason(config.signal);
6915
+ }
6916
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
6917
+ }
6918
+ return await checkResponse(response);
6511
6919
  }
6512
- async post(path2, params, config, retries = 0) {
6920
+ async post(path3, params, config, retries = 0) {
6513
6921
  const { headers, ...rest } = config || {};
6514
6922
  const this_fetch = this.fetch;
6515
6923
  const this_base_url = this.base_url;
@@ -6517,8 +6925,9 @@ var HTTPConnection = class _HTTPConnection {
6517
6925
  const tries = retries + 1;
6518
6926
  for (let i = 0; i < tries; i++) {
6519
6927
  try {
6520
- return await checkResponse(
6521
- await this_fetch(_urljoin(this_base_url, path2), {
6928
+ let response;
6929
+ try {
6930
+ response = await this_fetch(_urljoin(this_base_url, path3), {
6522
6931
  method: "POST",
6523
6932
  headers: {
6524
6933
  Accept: "application/json",
@@ -6529,8 +6938,14 @@ var HTTPConnection = class _HTTPConnection {
6529
6938
  body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
6530
6939
  keepalive: true,
6531
6940
  ...rest
6532
- })
6533
- );
6941
+ });
6942
+ } catch (error) {
6943
+ if (config?.signal?.aborted) {
6944
+ throw getAbortReason(config.signal);
6945
+ }
6946
+ rethrowHTTPTransportError(error, this.classifyTransportErrors);
6947
+ }
6948
+ return await checkResponse(response);
6534
6949
  } catch (error) {
6535
6950
  if (config?.signal?.aborted) {
6536
6951
  throw getAbortReason(config.signal);
@@ -6539,7 +6954,7 @@ var HTTPConnection = class _HTTPConnection {
6539
6954
  throw error;
6540
6955
  }
6541
6956
  debugLogger.debug(
6542
- `Retrying API request ${path2} after ${formatHTTPError(error)}`
6957
+ `Retrying API request ${path3} after ${formatHTTPError(error)}`
6543
6958
  );
6544
6959
  const sleepTimeMs = HTTP_RETRY_BASE_SLEEP_TIME_S * 1e3 * 2 ** i + Math.random() * HTTP_RETRY_JITTER_MS;
6545
6960
  debugLogger.info(
@@ -6555,7 +6970,7 @@ var HTTPConnection = class _HTTPConnection {
6555
6970
  for (let i = 0; i < tries; i++) {
6556
6971
  try {
6557
6972
  const resp = await this.get(`${object_type}`, args);
6558
- return await resp.json();
6973
+ return await readJSONResponse(resp, this.classifyTransportErrors);
6559
6974
  } catch (e) {
6560
6975
  if (i < tries - 1) {
6561
6976
  debugLogger.debug(
@@ -6578,7 +6993,7 @@ var HTTPConnection = class _HTTPConnection {
6578
6993
  const resp = await this.post(`${object_type}`, args, {
6579
6994
  headers: { "Content-Type": "application/json" }
6580
6995
  });
6581
- return await resp.json();
6996
+ return await readJSONResponse(resp, this.classifyTransportErrors);
6582
6997
  }
6583
6998
  // Custom inspect for Node.js console.log
6584
6999
  [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
@@ -8398,6 +8813,7 @@ function initDataset(projectOrOptions, optionalOptions) {
8398
8813
  const {
8399
8814
  project,
8400
8815
  dataset,
8816
+ datasetId,
8401
8817
  description,
8402
8818
  version,
8403
8819
  snapshotName,
@@ -8413,6 +8829,11 @@ function initDataset(projectOrOptions, optionalOptions) {
8413
8829
  state: stateArg,
8414
8830
  _internal_btql
8415
8831
  } = options;
8832
+ if (datasetId !== void 0 && (description !== void 0 || metadata !== void 0)) {
8833
+ throw new Error(
8834
+ "Cannot specify description or metadata when datasetId is provided"
8835
+ );
8836
+ }
8416
8837
  const selection = normalizeDatasetSelection({
8417
8838
  version,
8418
8839
  environment,
@@ -8433,6 +8854,35 @@ function initDataset(projectOrOptions, optionalOptions) {
8433
8854
  fetch: fetch2,
8434
8855
  forceLogin
8435
8856
  });
8857
+ if (datasetId !== void 0) {
8858
+ const objectInfo = datasetObjectInfoSchema.array().parse(
8859
+ await state.appConn().post_json("api/self/get_object_info", {
8860
+ object_type: "dataset",
8861
+ object_ids: [datasetId]
8862
+ })
8863
+ );
8864
+ if (objectInfo.length === 0) {
8865
+ throw new Error(`Dataset with ID ${datasetId} not found`);
8866
+ }
8867
+ if (objectInfo.length !== 1) {
8868
+ throw new Error(
8869
+ `Expected exactly one dataset with ID ${datasetId}, but found ${objectInfo.length}`
8870
+ );
8871
+ }
8872
+ const datasetInfo = objectInfo[0];
8873
+ return {
8874
+ project: {
8875
+ id: datasetInfo.parent_cols.project.id,
8876
+ name: datasetInfo.parent_cols.project.name,
8877
+ fullInfo: datasetInfo.parent_cols.project
8878
+ },
8879
+ dataset: {
8880
+ id: datasetInfo.object_id,
8881
+ name: datasetInfo.object_name,
8882
+ fullInfo: datasetInfo
8883
+ }
8884
+ };
8885
+ }
8436
8886
  const args = {
8437
8887
  org_id: state.orgId,
8438
8888
  project_name: project,
@@ -8607,6 +9057,52 @@ async function login(options = {}) {
8607
9057
  await state.login(options);
8608
9058
  return state;
8609
9059
  }
9060
+ async function loginToLoaderRequestState({
9061
+ appUrl,
9062
+ apiKey,
9063
+ orgName,
9064
+ fetch: fetch2
9065
+ }) {
9066
+ let orgId;
9067
+ let apiUrl;
9068
+ if (apiKey === TEST_API_KEY) {
9069
+ orgId = "test-org-id";
9070
+ apiUrl = "https://braintrust.dev/fake-api-url";
9071
+ } else {
9072
+ let loginResponse;
9073
+ try {
9074
+ loginResponse = await fetch2(_urljoin(appUrl, `/api/apikey/login`), {
9075
+ method: "POST",
9076
+ headers: {
9077
+ "Content-Type": "application/json",
9078
+ Authorization: `Bearer ${apiKey}`
9079
+ }
9080
+ });
9081
+ } catch (error) {
9082
+ throw new HTTPTransportError(error);
9083
+ }
9084
+ const info = await readJSONResponse(
9085
+ await checkResponse(loginResponse),
9086
+ true
9087
+ );
9088
+ const org = selectLoginOrg(info.org_info, orgName);
9089
+ orgId = org.id;
9090
+ apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
9091
+ if (!apiUrl) {
9092
+ throw new Error(
9093
+ orgName ? `Unable to log into organization '${orgName}'. Are you sure this credential is scoped to the organization?` : "Unable to log into any organization with the provided credential."
9094
+ );
9095
+ }
9096
+ }
9097
+ const apiConnection = new HTTPConnection(apiUrl, fetch2, true);
9098
+ apiConnection.set_token(apiKey);
9099
+ apiConnection.make_long_lived();
9100
+ return {
9101
+ appUrl,
9102
+ orgId,
9103
+ apiConn: () => apiConnection
9104
+ };
9105
+ }
8610
9106
  async function loginToState(options = {}) {
8611
9107
  const {
8612
9108
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
@@ -8638,16 +9134,18 @@ async function loginToState(options = {}) {
8638
9134
  _saveOrgInfo(state, testOrgInfo, testOrgInfo[0].name);
8639
9135
  return state;
8640
9136
  } else {
8641
- const resp = await checkResponse(
8642
- await fetch2(_urljoin(state.appUrl, `/api/apikey/login`), {
9137
+ const loginResponse = await fetch2(
9138
+ _urljoin(state.appUrl, `/api/apikey/login`),
9139
+ {
8643
9140
  method: "POST",
8644
9141
  headers: {
8645
9142
  "Content-Type": "application/json",
8646
9143
  Authorization: `Bearer ${apiKey}`
8647
9144
  }
8648
- })
9145
+ }
8649
9146
  );
8650
- const info = await resp.json();
9147
+ const resp = await checkResponse(loginResponse);
9148
+ const info = await readJSONResponse(resp);
8651
9149
  _saveOrgInfo(state, info.org_info, orgName);
8652
9150
  if (!state.apiUrl) {
8653
9151
  if (orgName) {
@@ -9049,27 +9547,28 @@ function withCurrent(span, callback, state = void 0) {
9049
9547
  function withParent(parent, callback, state = void 0) {
9050
9548
  return (state ?? _globalState).currentParent.run(parent, () => callback());
9051
9549
  }
9052
- function _saveOrgInfo(state, org_info, org_name) {
9053
- if (org_info.length === 0) {
9550
+ function _saveOrgInfo(state, orgInfo, orgName) {
9551
+ const org = selectLoginOrg(orgInfo, orgName);
9552
+ state.orgId = org.id;
9553
+ state.orgName = org.name;
9554
+ state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
9555
+ state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
9556
+ state.gitMetadataSettings = org.git_metadata || void 0;
9557
+ }
9558
+ function selectLoginOrg(orgInfo, orgName) {
9559
+ if (orgInfo.length === 0) {
9054
9560
  throw new LoginInvalidOrgError(
9055
9561
  "This user is not part of any organizations."
9056
9562
  );
9057
9563
  }
9058
- for (const org of org_info) {
9059
- if (org_name === void 0 || org.name === org_name) {
9060
- state.orgId = org.id;
9061
- state.orgName = org.name;
9062
- state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
9063
- state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
9064
- state.gitMetadataSettings = org.git_metadata || void 0;
9065
- break;
9564
+ for (const org of orgInfo) {
9565
+ if (orgName === void 0 || org.name === orgName) {
9566
+ return org;
9066
9567
  }
9067
9568
  }
9068
- if (state.orgId === void 0) {
9069
- throw new LoginInvalidOrgError(
9070
- `Organization ${org_name} not found. Must be one of ${org_info.map((x) => x.name).join(", ")}`
9071
- );
9072
- }
9569
+ throw new LoginInvalidOrgError(
9570
+ `Organization ${orgName} not found. Must be one of ${orgInfo.map((org) => org.name).join(", ")}`
9571
+ );
9073
9572
  }
9074
9573
  function validateTags(tags) {
9075
9574
  const seen = /* @__PURE__ */ new Set();
@@ -9304,7 +9803,7 @@ var ObjectFetcher = class {
9304
9803
  const objectId = await this.id;
9305
9804
  const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
9306
9805
  const internalLimit = getInternalBtqlLimit(this._internal_btql);
9307
- const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
9806
+ let remainingLimit = internalLimit;
9308
9807
  const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
9309
9808
  Object.entries(this._internal_btql ?? {}).filter(
9310
9809
  ([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
@@ -9313,6 +9812,10 @@ var ObjectFetcher = class {
9313
9812
  let cursor = void 0;
9314
9813
  let iterations = 0;
9315
9814
  while (true) {
9815
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9816
+ return;
9817
+ }
9818
+ const limit = remainingLimit === void 0 ? batchLimit : Math.min(batchLimit, remainingLimit);
9316
9819
  const resp = await state.apiConn().post(
9317
9820
  `btql`,
9318
9821
  {
@@ -9352,7 +9855,14 @@ var ObjectFetcher = class {
9352
9855
  const respJson = await resp.json();
9353
9856
  const mutate = this.mutateRecord;
9354
9857
  for (const record of respJson.data ?? []) {
9355
- yield mutate ? mutate(record) : record;
9858
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9859
+ return;
9860
+ }
9861
+ const mutatedRecord = mutate ? mutate(record) : record;
9862
+ if (remainingLimit !== void 0) {
9863
+ remainingLimit--;
9864
+ }
9865
+ yield mutatedRecord;
9356
9866
  }
9357
9867
  if (!respJson.cursor) {
9358
9868
  break;
@@ -9872,7 +10382,9 @@ var SpanImpl = class _SpanImpl {
9872
10382
  this._rootSpanId = resolvedIds.rootSpanId;
9873
10383
  this._spanParents = resolvedIds.spanParents;
9874
10384
  this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
9875
- this.logInternal({ event, internalData });
10385
+ if (!args[RESUME_SPAN_WITHOUT_INITIAL_WRITE]) {
10386
+ this.logInternal({ event, internalData });
10387
+ }
9876
10388
  this.isMerge = true;
9877
10389
  }
9878
10390
  getParentInfo() {
@@ -10959,6 +11471,14 @@ var Prompt2 = class _Prompt {
10959
11471
  static isPrompt(data) {
10960
11472
  return typeof data === "object" && data !== null && "__braintrust_prompt_marker" in data;
10961
11473
  }
11474
+ /** @internal */
11475
+ _internalSerializeForCache() {
11476
+ return {
11477
+ metadata: this.metadata,
11478
+ defaults: this.defaults,
11479
+ noTrace: this.noTrace
11480
+ };
11481
+ }
10962
11482
  static fromPromptData(name, promptData) {
10963
11483
  return new _Prompt(
10964
11484
  {
@@ -10999,6 +11519,10 @@ var RemoteEvalParameters = class {
10999
11519
  get data() {
11000
11520
  return this.metadata.function_data.data ?? {};
11001
11521
  }
11522
+ /** @internal */
11523
+ _internalSerializeForCache() {
11524
+ return { metadata: this.metadata };
11525
+ }
11002
11526
  validate(data) {
11003
11527
  if (typeof data !== "object" || data === null) {
11004
11528
  return false;
@@ -11690,56 +12214,14 @@ function suppressionStore() {
11690
12214
  autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
11691
12215
  return autoInstrumentationSuppressionStore;
11692
12216
  }
11693
- function currentFrames() {
11694
- return suppressionStore().getStore()?.frames ?? [];
11695
- }
11696
12217
  function isAutoInstrumentationSuppressed() {
11697
- const frames = currentFrames();
11698
- return frames[frames.length - 1]?.mode === "suppress";
12218
+ return suppressionStore().getStore() === true;
11699
12219
  }
11700
12220
  function runWithAutoInstrumentationSuppressed(callback) {
11701
- const frame = {
11702
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
11703
- mode: "suppress"
11704
- };
11705
- return suppressionStore().run(
11706
- { frames: [...currentFrames(), frame] },
11707
- callback
11708
- );
11709
- }
11710
- function bindAutoInstrumentationSuppressionToStart(tracingChannel) {
11711
- const startChannel = tracingChannel.start;
11712
- if (!startChannel) {
11713
- return void 0;
11714
- }
11715
- const store = suppressionStore();
11716
- startChannel.bindStore(store, () => ({
11717
- frames: [
11718
- ...currentFrames(),
11719
- {
11720
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
11721
- mode: "suppress"
11722
- }
11723
- ]
11724
- }));
11725
- return () => {
11726
- startChannel.unbindStore(store);
11727
- };
12221
+ return suppressionStore().run(true, callback);
11728
12222
  }
11729
- function enterAutoInstrumentationAllowed() {
11730
- const frame = {
11731
- id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
11732
- mode: "allow"
11733
- };
11734
- suppressionStore().enterWith({
11735
- frames: [...currentFrames(), frame]
11736
- });
11737
- return () => {
11738
- const frames = currentFrames().filter(
11739
- (candidate) => candidate.id !== frame.id
11740
- );
11741
- suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
11742
- };
12223
+ function runWithAutoInstrumentationAllowed(callback) {
12224
+ return suppressionStore().run(void 0, callback);
11743
12225
  }
11744
12226
 
11745
12227
  // src/instrumentation/core/channel-tracing.ts
@@ -12430,6 +12912,22 @@ function processInputAttachments(input) {
12430
12912
  };
12431
12913
  }
12432
12914
  }
12915
+ 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;
12916
+ const voyageBase64Value = voyageBase64Key ? node[voyageBase64Key] : void 0;
12917
+ if (voyageBase64Key && typeof voyageBase64Value === "string" && voyageBase64Value.startsWith("data:")) {
12918
+ const mediaType = inferMediaTypeFromDataUrl(
12919
+ voyageBase64Value,
12920
+ node.type === "video_base64" ? "video/mp4" : "image/png"
12921
+ );
12922
+ const filename = `${node.type === "video_base64" ? "video" : "image"}.${getExtensionFromMediaType(mediaType)}`;
12923
+ const attachment = toAttachment(voyageBase64Value, mediaType, filename);
12924
+ if (attachment) {
12925
+ return {
12926
+ ...node,
12927
+ [voyageBase64Key]: attachment
12928
+ };
12929
+ }
12930
+ }
12433
12931
  if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
12434
12932
  const mediaType = inferMediaTypeFromDataUrl(
12435
12933
  node.file.file_data,
@@ -13012,13 +13510,33 @@ function aggregateChatLogprobs(existing, incoming) {
13012
13510
  }
13013
13511
  return aggregated;
13014
13512
  }
13513
+ function createAggregatedChatChoice(index) {
13514
+ return {
13515
+ index,
13516
+ role: void 0,
13517
+ content: void 0,
13518
+ refusal: void 0,
13519
+ toolCallsByIndex: /* @__PURE__ */ new Map(),
13520
+ logprobs: void 0,
13521
+ finish_reason: void 0
13522
+ };
13523
+ }
13524
+ function toChatChoice(choice) {
13525
+ const toolCalls = Array.from(choice.toolCallsByIndex.entries()).sort(([left], [right]) => left - right).map(([, toolCall]) => toolCall);
13526
+ return {
13527
+ index: choice.index,
13528
+ message: {
13529
+ role: choice.role,
13530
+ content: choice.content,
13531
+ ...choice.refusal !== void 0 ? { refusal: choice.refusal } : {},
13532
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
13533
+ },
13534
+ logprobs: choice.logprobs ?? null,
13535
+ finish_reason: choice.finish_reason
13536
+ };
13537
+ }
13015
13538
  function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
13016
- let role = void 0;
13017
- let content = void 0;
13018
- let refusal = void 0;
13019
- let tool_calls = void 0;
13020
- let logprobs = void 0;
13021
- let finish_reason = void 0;
13539
+ const choicesByIndex = /* @__PURE__ */ new Map();
13022
13540
  let metrics = {};
13023
13541
  for (const chunk of chunks) {
13024
13542
  if (chunk.usage) {
@@ -13027,62 +13545,75 @@ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
13027
13545
  ...parseMetricsFromUsage(chunk.usage)
13028
13546
  };
13029
13547
  }
13030
- const choice = chunk.choices?.[0];
13031
- if (!choice) {
13032
- continue;
13033
- }
13034
- if (choice.finish_reason) {
13035
- finish_reason = choice.finish_reason;
13036
- }
13037
- logprobs = aggregateChatLogprobs(logprobs, choice.logprobs);
13038
- const delta = choice.delta;
13039
- if (!delta) {
13548
+ const choices = chunk.choices;
13549
+ if (!choices?.length) {
13040
13550
  continue;
13041
13551
  }
13042
- if (delta.finish_reason) {
13043
- finish_reason = delta.finish_reason;
13044
- }
13045
- if (!role && delta.role) {
13046
- role = delta.role;
13047
- }
13048
- if (delta.content) {
13049
- content = (content || "") + delta.content;
13050
- }
13051
- if (delta.refusal) {
13052
- refusal = (refusal || "") + delta.refusal;
13053
- }
13054
- if (delta.tool_calls) {
13055
- const toolDelta = delta.tool_calls[0];
13056
- if (!tool_calls || toolDelta.id && tool_calls[tool_calls.length - 1].id !== toolDelta.id) {
13057
- tool_calls = [
13058
- ...tool_calls || [],
13059
- {
13060
- id: toolDelta.id,
13061
- type: toolDelta.type,
13062
- function: toolDelta.function
13552
+ for (const choice of choices) {
13553
+ const choiceIndex = choice.index;
13554
+ let aggregatedChoice = choicesByIndex.get(choiceIndex);
13555
+ if (!aggregatedChoice) {
13556
+ aggregatedChoice = createAggregatedChatChoice(choiceIndex);
13557
+ choicesByIndex.set(choiceIndex, aggregatedChoice);
13558
+ }
13559
+ if (choice.finish_reason) {
13560
+ aggregatedChoice.finish_reason = choice.finish_reason;
13561
+ }
13562
+ aggregatedChoice.logprobs = aggregateChatLogprobs(
13563
+ aggregatedChoice.logprobs,
13564
+ choice.logprobs
13565
+ );
13566
+ const delta = choice.delta;
13567
+ if (!delta) {
13568
+ continue;
13569
+ }
13570
+ if (delta.finish_reason) {
13571
+ aggregatedChoice.finish_reason = delta.finish_reason;
13572
+ }
13573
+ if (!aggregatedChoice.role && delta.role) {
13574
+ aggregatedChoice.role = delta.role;
13575
+ }
13576
+ if (delta.content) {
13577
+ aggregatedChoice.content = (aggregatedChoice.content || "") + delta.content;
13578
+ }
13579
+ if (delta.refusal) {
13580
+ aggregatedChoice.refusal = (aggregatedChoice.refusal || "") + delta.refusal;
13581
+ }
13582
+ if (delta.tool_calls) {
13583
+ for (const toolDelta of delta.tool_calls) {
13584
+ let aggregatedToolCall = aggregatedChoice.toolCallsByIndex.get(
13585
+ toolDelta.index
13586
+ );
13587
+ if (!aggregatedToolCall) {
13588
+ aggregatedToolCall = {
13589
+ function: { arguments: "" }
13590
+ };
13591
+ aggregatedChoice.toolCallsByIndex.set(
13592
+ toolDelta.index,
13593
+ aggregatedToolCall
13594
+ );
13063
13595
  }
13064
- ];
13065
- } else {
13066
- tool_calls[tool_calls.length - 1].function.arguments += toolDelta.function.arguments;
13596
+ if (toolDelta.id !== void 0) {
13597
+ aggregatedToolCall.id = toolDelta.id;
13598
+ }
13599
+ if (toolDelta.type !== void 0) {
13600
+ aggregatedToolCall.type = toolDelta.type;
13601
+ }
13602
+ if (toolDelta.function?.name !== void 0) {
13603
+ aggregatedToolCall.function.name = toolDelta.function.name;
13604
+ }
13605
+ if (toolDelta.function?.arguments !== void 0) {
13606
+ aggregatedToolCall.function.arguments += toolDelta.function.arguments;
13607
+ }
13608
+ }
13067
13609
  }
13068
13610
  }
13069
13611
  }
13070
13612
  metrics = withCachedMetric(metrics, streamResult, endEvent);
13613
+ const output = Array.from(choicesByIndex.values()).sort((left, right) => left.index - right.index).map(toChatChoice);
13071
13614
  return {
13072
13615
  metrics,
13073
- output: [
13074
- {
13075
- index: 0,
13076
- message: {
13077
- role,
13078
- content,
13079
- ...refusal !== void 0 ? { refusal } : {},
13080
- tool_calls
13081
- },
13082
- logprobs: logprobs ?? null,
13083
- finish_reason
13084
- }
13085
- ]
13616
+ output: output.length > 0 ? output : [toChatChoice(createAggregatedChatChoice(0))]
13086
13617
  };
13087
13618
  }
13088
13619
  function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
@@ -13777,12 +14308,30 @@ function logInstrumentationError(context, error) {
13777
14308
 
13778
14309
  // src/wrappers/anthropic-tokens-util.ts
13779
14310
  function finalizeAnthropicTokens(metrics) {
13780
- const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + (metrics.prompt_cache_creation_tokens || 0);
13781
- return {
14311
+ const hasSplitCacheCreationTokens = metrics.prompt_cache_creation_5m_tokens !== void 0 || metrics.prompt_cache_creation_1h_tokens !== void 0;
14312
+ const splitCacheCreationTokens = (metrics.prompt_cache_creation_5m_tokens || 0) + (metrics.prompt_cache_creation_1h_tokens || 0);
14313
+ const aggregateCacheCreationTokens = metrics.prompt_cache_creation_tokens || 0;
14314
+ const effectiveCacheCreationTokens = Math.max(
14315
+ aggregateCacheCreationTokens,
14316
+ splitCacheCreationTokens
14317
+ );
14318
+ const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + effectiveCacheCreationTokens;
14319
+ const finalized = {
13782
14320
  ...metrics,
13783
14321
  prompt_tokens,
13784
14322
  tokens: prompt_tokens + (metrics.completion_tokens || 0)
13785
14323
  };
14324
+ if (hasSplitCacheCreationTokens && splitCacheCreationTokens >= aggregateCacheCreationTokens) {
14325
+ delete finalized.prompt_cache_creation_tokens;
14326
+ }
14327
+ return finalized;
14328
+ }
14329
+ function toNumericMetrics(metrics) {
14330
+ return Object.fromEntries(
14331
+ Object.entries(metrics).filter(
14332
+ (entry) => entry[1] !== void 0
14333
+ )
14334
+ );
13786
14335
  }
13787
14336
  function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens = 0) {
13788
14337
  const cacheTokens = {};
@@ -14375,6 +14924,24 @@ function parseMetricsFromUsage2(usage) {
14375
14924
  saveIfExistsTo("output_tokens", "completion_tokens");
14376
14925
  saveIfExistsTo("cache_read_input_tokens", "prompt_cached_tokens");
14377
14926
  saveIfExistsTo("cache_creation_input_tokens", "prompt_cache_creation_tokens");
14927
+ if (isObject(usage.cache_creation)) {
14928
+ const cacheCreation = usage.cache_creation;
14929
+ for (const [source, target] of [
14930
+ ["ephemeral_5m_input_tokens", "prompt_cache_creation_5m_tokens"],
14931
+ ["ephemeral_1h_input_tokens", "prompt_cache_creation_1h_tokens"]
14932
+ ]) {
14933
+ const value = cacheCreation[source];
14934
+ if (typeof value === "number") {
14935
+ metrics[target] = value;
14936
+ }
14937
+ }
14938
+ }
14939
+ if (isObject(usage.output_tokens_details)) {
14940
+ const thinkingTokens = usage.output_tokens_details.thinking_tokens;
14941
+ if (typeof thinkingTokens === "number") {
14942
+ metrics.completion_reasoning_tokens = thinkingTokens;
14943
+ }
14944
+ }
14378
14945
  if (isObject(usage.server_tool_use)) {
14379
14946
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
14380
14947
  if (typeof value === "number") {
@@ -15331,7 +15898,6 @@ function endHarnessTurn(parent) {
15331
15898
  function braintrustAISDKTelemetry() {
15332
15899
  const operations = /* @__PURE__ */ new Map();
15333
15900
  const operationKeysByCallId = /* @__PURE__ */ new Map();
15334
- const workflowOperationKeyStore = isomorph_default.newAsyncLocalStorage();
15335
15901
  const modelSpans = /* @__PURE__ */ new Map();
15336
15902
  const objectSpans = /* @__PURE__ */ new Map();
15337
15903
  const embedSpans = /* @__PURE__ */ new Map();
@@ -15374,9 +15940,6 @@ function braintrustAISDKTelemetry() {
15374
15940
  return;
15375
15941
  }
15376
15942
  operations.delete(operationKey);
15377
- if (workflowOperationKeyStore.getStore() === operationKey) {
15378
- workflowOperationKeyStore.enterWith(void 0);
15379
- }
15380
15943
  const keys = operationKeysByCallId.get(state.callId);
15381
15944
  if (!keys) {
15382
15945
  return;
@@ -15424,14 +15987,7 @@ function braintrustAISDKTelemetry() {
15424
15987
  return key;
15425
15988
  }
15426
15989
  }
15427
- const workflowOperationKey = workflowOperationKeyStore.getStore();
15428
- if (workflowOperationKey && keys.includes(workflowOperationKey)) {
15429
- return workflowOperationKey;
15430
- }
15431
- if (callId === "workflow-agent") {
15432
- return void 0;
15433
- }
15434
- return mode === "finish" ? keys[0] : keys[keys.length - 1];
15990
+ return callId === "workflow-agent" || mode === "active" ? keys[keys.length - 1] : keys[0];
15435
15991
  };
15436
15992
  const operationKeyFromEvent = (event, mode = "active") => {
15437
15993
  const explicit = explicitOperationKey(event);
@@ -15445,17 +16001,13 @@ function braintrustAISDKTelemetry() {
15445
16001
  if (operationKey) {
15446
16002
  return operationKey;
15447
16003
  }
15448
- const workflowOperationKey2 = workflowOperationKeyStore.getStore();
15449
- if (workflowOperationKey2 && operations.has(workflowOperationKey2)) {
15450
- return workflowOperationKey2;
16004
+ const workflowAgentKeys2 = operationKeysByCallId.get("workflow-agent");
16005
+ if (workflowAgentKeys2?.length) {
16006
+ return workflowAgentKeys2[workflowAgentKeys2.length - 1];
15451
16007
  }
15452
16008
  return callId === "workflow-agent" ? void 0 : callId;
15453
16009
  }
15454
16010
  }
15455
- const workflowOperationKey = workflowOperationKeyStore.getStore();
15456
- if (workflowOperationKey && operations.has(workflowOperationKey)) {
15457
- return workflowOperationKey;
15458
- }
15459
16011
  const wrapperSpan = currentWorkflowAgentWrapperSpan();
15460
16012
  if (wrapperSpan?.spanId) {
15461
16013
  for (const [operationKey, state] of operations) {
@@ -15465,8 +16017,8 @@ function braintrustAISDKTelemetry() {
15465
16017
  }
15466
16018
  }
15467
16019
  const workflowAgentKeys = operationKeysByCallId.get("workflow-agent");
15468
- if (workflowAgentKeys?.length === 1) {
15469
- return workflowAgentKeys[0];
16020
+ if (workflowAgentKeys?.length) {
16021
+ return workflowAgentKeys[workflowAgentKeys.length - 1];
15470
16022
  }
15471
16023
  if (operations.size === 1) {
15472
16024
  return operations.keys().next().value;
@@ -15669,9 +16221,6 @@ function braintrustAISDKTelemetry() {
15669
16221
  if (!ownsSpan) {
15670
16222
  return;
15671
16223
  }
15672
- if (workflowAgent) {
15673
- workflowOperationKeyStore.enterWith(operationKey);
15674
- }
15675
16224
  let metadata = metadataFromEvent(event);
15676
16225
  const logPayload = { metadata };
15677
16226
  const workflowAgentCallInput = workflowAgent ? operationInput(event, operationName) : void 0;
@@ -16143,6 +16692,10 @@ var aiSDKChannels = defineChannels(
16143
16692
  channelName: "generateText",
16144
16693
  kind: "async"
16145
16694
  }),
16695
+ generateImage: channel({
16696
+ channelName: "generateImage",
16697
+ kind: "async"
16698
+ }),
16146
16699
  streamText: channel({
16147
16700
  channelName: "streamText",
16148
16701
  kind: "async"
@@ -16330,7 +16883,7 @@ var AISDKPlugin = class extends BasePlugin {
16330
16883
  }
16331
16884
  subscribeToAISDK() {
16332
16885
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
16333
- this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
16886
+ this.unsubscribers.push(interceptAISDKV7TelemetryDispatcher());
16334
16887
  this.unsubscribers.push(subscribeToHarnessAgentCreateSession());
16335
16888
  this.unsubscribers.push(
16336
16889
  subscribeToHarnessContinuation(
@@ -16358,6 +16911,18 @@ var AISDKPlugin = class extends BasePlugin {
16358
16911
  aggregateChunks: aggregateAISDKChunks
16359
16912
  })
16360
16913
  );
16914
+ this.unsubscribers.push(
16915
+ traceAsyncChannel(aiSDKChannels.generateImage, {
16916
+ name: "generateImage",
16917
+ type: "llm" /* LLM */,
16918
+ extractInput: ([params], event) => prepareAISDKGenerateImageInput(params, event.self),
16919
+ extractOutput: (result, endEvent) => processAISDKGenerateImageOutput(
16920
+ result,
16921
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
16922
+ ),
16923
+ extractMetrics: (result) => extractTokenMetrics(result)
16924
+ })
16925
+ );
16361
16926
  this.unsubscribers.push(
16362
16927
  traceStreamingChannel(aiSDKChannels.streamText, {
16363
16928
  name: "streamText",
@@ -16847,26 +17412,29 @@ function subscribeToHarnessContinuation(continuationChannel, defaultDenyOutputPa
16847
17412
  channel2.unsubscribe(handlers);
16848
17413
  };
16849
17414
  }
16850
- function subscribeToAISDKV7TelemetryDispatcher() {
16851
- const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
17415
+ function interceptAISDKV7TelemetryDispatcher() {
16852
17416
  const telemetry = braintrustAISDKTelemetry();
16853
- const handlers = {
16854
- end: (event) => {
16855
- const telemetryOptions = event.arguments?.[0]?.telemetry;
16856
- if (telemetryOptions?.isEnabled === false) {
16857
- return;
17417
+ return aiSDKChannels.v7CreateTelemetryDispatcher.intercept(
17418
+ (target, thisArg, args) => {
17419
+ const dispatcher = Reflect.apply(target, thisArg, args);
17420
+ const telemetryOptions = args[0]?.telemetry;
17421
+ if (telemetryOptions?.isEnabled !== false) {
17422
+ try {
17423
+ patchAISDKV7TelemetryDispatcher(
17424
+ dispatcher,
17425
+ telemetry,
17426
+ telemetryOptions
17427
+ );
17428
+ } catch (error) {
17429
+ debugLogger.error(
17430
+ "Error instrumenting AI SDK v7 telemetry dispatcher:",
17431
+ error
17432
+ );
17433
+ }
16858
17434
  }
16859
- patchAISDKV7TelemetryDispatcher(
16860
- event.result,
16861
- telemetry,
16862
- telemetryOptions
16863
- );
17435
+ return dispatcher;
16864
17436
  }
16865
- };
16866
- channel2.subscribe(handlers);
16867
- return () => {
16868
- channel2.unsubscribe(handlers);
16869
- };
17437
+ );
16870
17438
  }
16871
17439
  function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry, telemetryOptions) {
16872
17440
  if (!isObject(dispatcher)) {
@@ -16966,7 +17534,7 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
16966
17534
  return defaultDenyOutputPaths;
16967
17535
  }
16968
17536
  const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
16969
- if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path2) => typeof path2 === "string")) {
17537
+ if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path3) => typeof path3 === "string")) {
16970
17538
  return runtimeDenyOutputPaths;
16971
17539
  }
16972
17540
  return defaultDenyOutputPaths;
@@ -17191,16 +17759,10 @@ var convertImageToAttachment = (image, explicitMimeType) => {
17191
17759
  }
17192
17760
  }
17193
17761
  if (explicitMimeType) {
17194
- if (image instanceof Uint8Array) {
17195
- return new Attachment({
17196
- data: new Blob([image], { type: explicitMimeType }),
17197
- filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
17198
- contentType: explicitMimeType
17199
- });
17200
- }
17201
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
17762
+ const blob = convertDataToBlob(image, explicitMimeType);
17763
+ if (blob) {
17202
17764
  return new Attachment({
17203
- data: new Blob([image], { type: explicitMimeType }),
17765
+ data: blob,
17204
17766
  filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
17205
17767
  contentType: explicitMimeType
17206
17768
  });
@@ -17254,6 +17816,25 @@ var convertDataToAttachment = (data, mimeType, filename) => {
17254
17816
  function processAISDKCallInput(params) {
17255
17817
  return processInputAttachmentsSync(params);
17256
17818
  }
17819
+ function processAISDKGenerateImageInput(params) {
17820
+ const prompt = params.prompt;
17821
+ if (!isObject(prompt) || Array.isArray(prompt)) {
17822
+ return processAISDKCallInput(params);
17823
+ }
17824
+ const processedPrompt = { ...prompt };
17825
+ if (Array.isArray(prompt.images)) {
17826
+ processedPrompt.images = prompt.images.map(
17827
+ (image) => convertImageToAttachment(image, "image/png") ?? image
17828
+ );
17829
+ }
17830
+ if (prompt.mask !== void 0) {
17831
+ processedPrompt.mask = convertImageToAttachment(prompt.mask, "image/png") ?? prompt.mask;
17832
+ }
17833
+ return processAISDKCallInput({
17834
+ ...params,
17835
+ prompt: processedPrompt
17836
+ });
17837
+ }
17257
17838
  function processAISDKWorkflowAgentCallInput(params) {
17258
17839
  const processed = processAISDKCallInput(params);
17259
17840
  return {
@@ -17392,6 +17973,12 @@ function prepareAISDKEmbedInput(params, self) {
17392
17973
  metadata: extractMetadataFromEmbedParams(params, self)
17393
17974
  };
17394
17975
  }
17976
+ function prepareAISDKGenerateImageInput(params, self) {
17977
+ return {
17978
+ input: processAISDKGenerateImageInput(params).input,
17979
+ metadata: extractMetadataFromCallParams(params, self)
17980
+ };
17981
+ }
17395
17982
  function prepareAISDKRerankInput(params, self) {
17396
17983
  const { documents, query } = params;
17397
17984
  return {
@@ -18728,11 +19315,11 @@ function processAISDKOutput(output, denyOutputPaths) {
18728
19315
  if (!output) return output;
18729
19316
  const merged = extractSerializableOutputFields(output);
18730
19317
  const deleteOutputPaths = denyOutputPaths.filter(
18731
- (path2) => path2.toLowerCase().endsWith("headers")
19318
+ (path3) => path3.toLowerCase().endsWith("headers")
18732
19319
  );
18733
19320
  const sanitized = omit(merged, denyOutputPaths, deleteOutputPaths);
18734
- for (const path2 of TRANSPORT_PAYLOAD_ROOT_PATHS) {
18735
- const stack = [{ obj: sanitized, keys: parsePath(path2) }];
19321
+ for (const path3 of TRANSPORT_PAYLOAD_ROOT_PATHS) {
19322
+ const stack = [{ obj: sanitized, keys: parsePath(path3) }];
18736
19323
  while (stack.length > 0) {
18737
19324
  const entry = stack.pop();
18738
19325
  if (!entry || entry.keys.length === 0) {
@@ -18767,6 +19354,57 @@ function processAISDKOutput(output, denyOutputPaths) {
18767
19354
  }
18768
19355
  return normalizeAISDKLoggedOutput(sanitized);
18769
19356
  }
19357
+ function processAISDKGenerateImageOutput(output, denyOutputPaths) {
19358
+ if (!output || typeof output !== "object") {
19359
+ return output;
19360
+ }
19361
+ const summarized = {};
19362
+ for (const field of [
19363
+ "usage",
19364
+ "warnings",
19365
+ "providerMetadata",
19366
+ "experimental_providerMetadata",
19367
+ "responses"
19368
+ ]) {
19369
+ const value = safeSerializableFieldRead(output, field);
19370
+ if (value !== void 0 && isSerializableOutputValue(value)) {
19371
+ summarized[field] = value;
19372
+ }
19373
+ }
19374
+ const images = safeSerializableFieldRead(output, "images");
19375
+ const image = safeSerializableFieldRead(output, "image");
19376
+ const generatedFiles = Array.isArray(images) && images.length > 0 ? images : image !== void 0 ? [image] : [];
19377
+ const loggedOutput = normalizeAISDKLoggedOutput(
19378
+ omit(summarized, denyOutputPaths)
19379
+ );
19380
+ if (generatedFiles.length > 0) {
19381
+ loggedOutput.images = generatedFiles.map(
19382
+ (file, index) => convertAISDKGeneratedFileToAttachment(file, index)
19383
+ );
19384
+ }
19385
+ return loggedOutput;
19386
+ }
19387
+ function convertAISDKGeneratedFileToAttachment(file, index) {
19388
+ if (!file || typeof file !== "object") {
19389
+ return file;
19390
+ }
19391
+ const generatedFile = file;
19392
+ const generatedMediaType = safeSerializableFieldRead(
19393
+ generatedFile,
19394
+ "mediaType"
19395
+ );
19396
+ const mediaType = typeof generatedMediaType === "string" ? generatedMediaType : "application/octet-stream";
19397
+ const data = safeSerializableFieldRead(generatedFile, "base64") ?? safeSerializableFieldRead(generatedFile, "uint8Array");
19398
+ const blob = convertDataToBlob(data, mediaType);
19399
+ if (blob) {
19400
+ return new Attachment({
19401
+ data: blob,
19402
+ filename: `generated_image_${index}.${getExtensionFromMediaType(mediaType)}`,
19403
+ contentType: mediaType
19404
+ });
19405
+ }
19406
+ return file;
19407
+ }
18770
19408
  function processAISDKEmbeddingOutput(output, denyOutputPaths) {
18771
19409
  if (!output || typeof output !== "object") {
18772
19410
  return output;
@@ -19171,11 +19809,11 @@ function firstNumber2(...values) {
19171
19809
  function deepCopy(obj) {
19172
19810
  return JSON.parse(JSON.stringify(obj));
19173
19811
  }
19174
- function parsePath(path2) {
19812
+ function parsePath(path3) {
19175
19813
  const keys = [];
19176
19814
  let current = "";
19177
- for (let i = 0; i < path2.length; i++) {
19178
- const char = path2[i];
19815
+ for (let i = 0; i < path3.length; i++) {
19816
+ const char = path3[i];
19179
19817
  if (char === ".") {
19180
19818
  if (current) {
19181
19819
  keys.push(current);
@@ -19188,8 +19826,8 @@ function parsePath(path2) {
19188
19826
  }
19189
19827
  let bracketContent = "";
19190
19828
  i++;
19191
- while (i < path2.length && path2[i] !== "]") {
19192
- bracketContent += path2[i];
19829
+ while (i < path3.length && path3[i] !== "]") {
19830
+ bracketContent += path3[i];
19193
19831
  i++;
19194
19832
  }
19195
19833
  if (bracketContent === "") {
@@ -19244,9 +19882,9 @@ function omitAtPath(obj, keys, deleteLeaf = false) {
19244
19882
  function omit(obj, paths, deletePaths = []) {
19245
19883
  const result = deepCopy(obj);
19246
19884
  const deletePathSet = new Set(deletePaths);
19247
- for (const path2 of paths) {
19248
- const keys = parsePath(path2);
19249
- omitAtPath(result, keys, deletePathSet.has(path2));
19885
+ for (const path3 of paths) {
19886
+ const keys = parsePath(path3);
19887
+ omitAtPath(result, keys, deletePathSet.has(path3));
19250
19888
  }
19251
19889
  return result;
19252
19890
  }
@@ -19267,118 +19905,22 @@ var claudeAgentSDKChannels = defineChannels(
19267
19905
  var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
19268
19906
 
19269
19907
  // src/instrumentation/plugins/claude-agent-sdk-local-tool-context.ts
19270
- var LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED = /* @__PURE__ */ Symbol.for(
19271
- "braintrust.claude_agent_sdk.local_tool_context_async_iterator_patched"
19272
- );
19273
- function createLocalToolContextStore() {
19274
- const maybeIsoWithAsyncLocalStorage = isomorph_default;
19275
- if (typeof maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage === "function") {
19276
- return maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage();
19277
- }
19278
- let currentStore;
19279
- return {
19280
- enterWith(store) {
19281
- currentStore = store;
19282
- },
19283
- getStore() {
19284
- return currentStore;
19285
- },
19286
- run(store, callback) {
19287
- const previousStore = currentStore;
19288
- currentStore = store;
19289
- try {
19290
- return callback();
19291
- } finally {
19292
- currentStore = previousStore;
19293
- }
19294
- }
19295
- };
19296
- }
19297
- var localToolContextStore = createLocalToolContextStore();
19298
- var fallbackLocalToolParentResolver;
19299
- function createClaudeLocalToolContext() {
19300
- return {};
19301
- }
19302
- function runWithClaudeLocalToolContext(callback, context) {
19303
- return localToolContextStore.run(
19304
- context ?? createClaudeLocalToolContext(),
19305
- callback
19306
- );
19908
+ var localToolContextStore = isomorph_default.newAsyncLocalStorage();
19909
+ var localToolParentResolversByToolUseId = /* @__PURE__ */ new Map();
19910
+ function runWithClaudeLocalToolContext(callback, resolver) {
19911
+ return localToolContextStore.run(resolver, callback);
19307
19912
  }
19308
- function ensureClaudeLocalToolContext() {
19309
- const existing = localToolContextStore.getStore();
19310
- if (existing) {
19311
- return existing;
19312
- }
19313
- const created = {};
19314
- localToolContextStore.enterWith(created);
19315
- return created;
19913
+ function registerClaudeLocalToolParentResolver(toolUseId, resolver) {
19914
+ localToolParentResolversByToolUseId.set(toolUseId, resolver);
19316
19915
  }
19317
- function setClaudeLocalToolParentResolver(resolver) {
19318
- fallbackLocalToolParentResolver = resolver;
19319
- const context = ensureClaudeLocalToolContext();
19320
- if (!context) {
19321
- return;
19916
+ function getClaudeLocalToolParentResolver(toolUseId) {
19917
+ const currentResolver = localToolContextStore.getStore();
19918
+ if (!toolUseId) {
19919
+ return currentResolver;
19322
19920
  }
19323
- context.resolveLocalToolParent = resolver;
19324
- }
19325
- function getClaudeLocalToolParentResolver() {
19326
- return localToolContextStore.getStore()?.resolveLocalToolParent ?? fallbackLocalToolParentResolver;
19327
- }
19328
- function isAsyncIterable3(value) {
19329
- return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
19330
- }
19331
- function bindClaudeLocalToolContextToAsyncIterable(result, localToolContext) {
19332
- if (!isAsyncIterable3(result) || Object.isFrozen(result) || Object.isSealed(result)) {
19333
- return result;
19334
- }
19335
- const stream = result;
19336
- const originalAsyncIterator = stream[Symbol.asyncIterator];
19337
- if (originalAsyncIterator[LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED]) {
19338
- return result;
19339
- }
19340
- const patchedAsyncIterator = function() {
19341
- return runWithClaudeLocalToolContext(() => {
19342
- const iterator = Reflect.apply(originalAsyncIterator, this, []);
19343
- if (!iterator || typeof iterator !== "object") {
19344
- return iterator;
19345
- }
19346
- const patchMethod = (methodName) => {
19347
- const originalMethod = Reflect.get(iterator, methodName);
19348
- if (typeof originalMethod !== "function") {
19349
- return;
19350
- }
19351
- Reflect.set(
19352
- iterator,
19353
- methodName,
19354
- (...args) => runWithClaudeLocalToolContext(
19355
- () => Reflect.apply(
19356
- originalMethod,
19357
- iterator,
19358
- args
19359
- ),
19360
- localToolContext
19361
- )
19362
- );
19363
- };
19364
- patchMethod("next");
19365
- patchMethod("return");
19366
- patchMethod("throw");
19367
- return iterator;
19368
- }, localToolContext);
19369
- };
19370
- Object.defineProperty(
19371
- patchedAsyncIterator,
19372
- LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED,
19373
- {
19374
- configurable: false,
19375
- enumerable: false,
19376
- value: true,
19377
- writable: false
19378
- }
19379
- );
19380
- Reflect.set(stream, Symbol.asyncIterator, patchedAsyncIterator);
19381
- return result;
19921
+ const registeredResolver = localToolParentResolversByToolUseId.get(toolUseId);
19922
+ localToolParentResolversByToolUseId.delete(toolUseId);
19923
+ return currentResolver ?? registeredResolver;
19382
19924
  }
19383
19925
 
19384
19926
  // src/instrumentation/plugins/claude-agent-sdk-local-tool-spans.ts
@@ -19404,7 +19946,7 @@ function wrapLocalClaudeToolHandler(handler, getMetadata) {
19404
19946
  const metadata = getMetadata();
19405
19947
  const rawToolName = metadata.serverName ? `mcp__${metadata.serverName}__${metadata.toolName}` : metadata.toolName;
19406
19948
  const toolUseId = getToolUseIdFromExtra(handlerArgs[1]);
19407
- const localToolParentResolver = getClaudeLocalToolParentResolver();
19949
+ const localToolParentResolver = getClaudeLocalToolParentResolver(toolUseId);
19408
19950
  const spanName = metadata.serverName ? `tool: ${metadata.serverName}/${metadata.toolName}` : `tool: ${metadata.toolName}`;
19409
19951
  const runWithResolvedParent = async () => {
19410
19952
  const parent = toolUseId && localToolParentResolver ? await localToolParentResolver(toolUseId).catch(() => void 0) : void 0;
@@ -19673,37 +20215,97 @@ function seedTaskToolUseIdMapping(taskIdToToolUseId, message) {
19673
20215
  taskIdToToolUseId.set(message.task_id, message.tool_use_id);
19674
20216
  }
19675
20217
  }
19676
- function extractUsageFromMessage(message) {
19677
- const metrics = {};
19678
- let usage;
19679
- if (message.type === "assistant") {
19680
- usage = message.message?.usage;
19681
- } else if (message.type === "result") {
19682
- usage = message.usage;
19683
- }
20218
+ function tokenCount(value) {
20219
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : void 0;
20220
+ }
20221
+ function copyUsage(usage) {
19684
20222
  if (!usage || typeof usage !== "object") {
19685
- return metrics;
20223
+ return void 0;
20224
+ }
20225
+ const copy = {};
20226
+ for (const key of [
20227
+ "input_tokens",
20228
+ "output_tokens",
20229
+ "cache_read_input_tokens",
20230
+ "cache_creation_input_tokens"
20231
+ ]) {
20232
+ const value = tokenCount(Reflect.get(usage, key));
20233
+ if (value !== void 0) {
20234
+ copy[key] = value;
20235
+ }
20236
+ }
20237
+ const cacheCreation = Reflect.get(usage, "cache_creation");
20238
+ if (cacheCreation && typeof cacheCreation === "object") {
20239
+ const cacheCreationCopy = {};
20240
+ for (const key of [
20241
+ "ephemeral_5m_input_tokens",
20242
+ "ephemeral_1h_input_tokens"
20243
+ ]) {
20244
+ const value = tokenCount(Reflect.get(cacheCreation, key));
20245
+ if (value !== void 0) {
20246
+ cacheCreationCopy[key] = value;
20247
+ }
20248
+ }
20249
+ if (Object.keys(cacheCreationCopy).length > 0) {
20250
+ copy.cache_creation = cacheCreationCopy;
20251
+ }
20252
+ }
20253
+ return Object.keys(copy).length > 0 ? copy : void 0;
20254
+ }
20255
+ function mergeUsage(base, override) {
20256
+ if (!base || !override) {
20257
+ return override ?? base;
20258
+ }
20259
+ const cacheCreation = base.cache_creation || override.cache_creation ? { ...base.cache_creation, ...override.cache_creation } : void 0;
20260
+ return {
20261
+ ...base,
20262
+ ...override,
20263
+ ...cacheCreation && { cache_creation: cacheCreation }
20264
+ };
20265
+ }
20266
+ function extractUsage(usage, includeOutput) {
20267
+ const metrics = {};
20268
+ if (!usage) {
20269
+ return {};
19686
20270
  }
19687
20271
  const inputTokens = getNumberProperty(usage, "input_tokens");
19688
20272
  if (inputTokens !== void 0) {
19689
20273
  metrics.prompt_tokens = inputTokens;
19690
20274
  }
19691
- const outputTokens = getNumberProperty(usage, "output_tokens");
19692
- if (outputTokens !== void 0) {
19693
- metrics.completion_tokens = outputTokens;
20275
+ if (includeOutput) {
20276
+ const outputTokens = getNumberProperty(usage, "output_tokens");
20277
+ if (outputTokens !== void 0) {
20278
+ metrics.completion_tokens = outputTokens;
20279
+ }
19694
20280
  }
19695
20281
  const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
19696
20282
  const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
19697
- if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
19698
- Object.assign(
19699
- metrics,
19700
- extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
19701
- );
20283
+ Object.assign(
20284
+ metrics,
20285
+ extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
20286
+ );
20287
+ const cacheCreation5mTokens = getNumberProperty(
20288
+ usage.cache_creation,
20289
+ "ephemeral_5m_input_tokens"
20290
+ );
20291
+ const cacheCreation1hTokens = getNumberProperty(
20292
+ usage.cache_creation,
20293
+ "ephemeral_1h_input_tokens"
20294
+ );
20295
+ if (cacheCreation5mTokens !== void 0) {
20296
+ metrics.prompt_cache_creation_5m_tokens = cacheCreation5mTokens;
19702
20297
  }
19703
- if (Object.keys(metrics).length > 0) {
19704
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
20298
+ if (cacheCreation1hTokens !== void 0) {
20299
+ metrics.prompt_cache_creation_1h_tokens = cacheCreation1hTokens;
19705
20300
  }
19706
- return metrics;
20301
+ if (Object.keys(metrics).length === 0) {
20302
+ return {};
20303
+ }
20304
+ const finalized = finalizeAnthropicTokens(metrics);
20305
+ if (metrics.completion_tokens === void 0) {
20306
+ delete finalized.tokens;
20307
+ }
20308
+ return toNumericMetrics(finalized);
19707
20309
  }
19708
20310
  function buildLLMInput(promptMessages, conversationHistory) {
19709
20311
  const inputParts = [...promptMessages, ...conversationHistory];
@@ -19737,16 +20339,16 @@ function buildRootPromptMessages(prompt, capturedPromptMessages) {
19737
20339
  function formatCapturedMessages(messages) {
19738
20340
  return messages.length > 0 ? messages : [];
19739
20341
  }
19740
- async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
20342
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, usage, hasFinalOutputUsage, existingSpan) {
19741
20343
  if (messages.length === 0) {
19742
20344
  return void 0;
19743
20345
  }
19744
20346
  const lastMessage = messages[messages.length - 1];
19745
- if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
20347
+ if (lastMessage.type !== "assistant") {
19746
20348
  return void 0;
19747
20349
  }
19748
- const model = lastMessage.message.model || options.model;
19749
- const usage = extractUsageFromMessage(lastMessage);
20350
+ const model = lastMessage.message?.model || options.model;
20351
+ const metrics = options.includePartialMessages ? extractUsage(usage, hasFinalOutputUsage) : {};
19750
20352
  const input = buildLLMInput(promptMessages, conversationHistory);
19751
20353
  const outputs = messages.map(
19752
20354
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
@@ -19768,8 +20370,8 @@ async function createLLMSpanForMessages(messages, promptMessages, conversationHi
19768
20370
  );
19769
20371
  span.log({
19770
20372
  input,
19771
- metadata: model ? { model } : void 0,
19772
- metrics: usage,
20373
+ metadata: { ...model && { model }, provider: "anthropic" },
20374
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
19773
20375
  output: outputs
19774
20376
  });
19775
20377
  const spanExport = await span.export();
@@ -19859,12 +20461,19 @@ function prepareLocalToolHandlersInMcpServers(mcpServers) {
19859
20461
  }
19860
20462
  return { hasLocalToolHandlers, localToolHookNames };
19861
20463
  }
19862
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20464
+ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
19863
20465
  const preToolUse = async (input, toolUseID) => {
19864
20466
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
19865
20467
  return {};
19866
20468
  }
20469
+ if (!toolUseToParent.has(toolUseID) && input.agent_id) {
20470
+ const parentToolUseId = taskIdToToolUseId.get(input.agent_id);
20471
+ if (parentToolUseId) {
20472
+ toolUseToParent.set(toolUseID, parentToolUseId);
20473
+ }
20474
+ }
19867
20475
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
20476
+ registerClaudeLocalToolParentResolver(toolUseID, resolveParentSpan);
19868
20477
  return {};
19869
20478
  }
19870
20479
  const parsed = parseToolName(input.tool_name);
@@ -20059,9 +20668,6 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20059
20668
  }
20060
20669
  const metadata = {
20061
20670
  ...subAgentDetailsToMetadata(details),
20062
- ...input.agent_transcript_path && {
20063
- "claude_agent_sdk.agent_transcript_path": input.agent_transcript_path
20064
- },
20065
20671
  "claude_agent_sdk.stop_hook_active": input.stop_hook_active
20066
20672
  };
20067
20673
  try {
@@ -20083,7 +20689,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20083
20689
  subagentStop
20084
20690
  };
20085
20691
  }
20086
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20692
+ function injectTracingHooks(options, resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20087
20693
  const {
20088
20694
  preToolUse,
20089
20695
  postToolUse,
@@ -20092,6 +20698,8 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
20092
20698
  subagentStop
20093
20699
  } = createToolTracingHooks(
20094
20700
  resolveParentSpan,
20701
+ taskIdToToolUseId,
20702
+ toolUseToParent,
20095
20703
  activeToolSpans,
20096
20704
  options.mcpServers,
20097
20705
  localToolHookNames,
@@ -20173,6 +20781,13 @@ async function finalizeCurrentMessageGroup(state) {
20173
20781
  }
20174
20782
  }
20175
20783
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
20784
+ const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20785
+ const messageId = lastMessage?.message?.id;
20786
+ const usage = state.options.includePartialMessages ? mergeUsage(
20787
+ copyUsage(lastMessage?.message?.usage),
20788
+ messageId ? state.usageByMessageId.get(messageId) : void 0
20789
+ ) : void 0;
20790
+ const hasFinalOutputUsage = messageId !== void 0 && state.finalOutputUsageMessageIds.has(messageId);
20176
20791
  const llmSpanResult = await createLLMSpanForMessages(
20177
20792
  state.currentMessages,
20178
20793
  promptMessages,
@@ -20180,6 +20795,8 @@ async function finalizeCurrentMessageGroup(state) {
20180
20795
  state.options,
20181
20796
  state.currentMessageStartTime,
20182
20797
  parentSpan,
20798
+ usage,
20799
+ hasFinalOutputUsage,
20183
20800
  existingLlmSpan
20184
20801
  );
20185
20802
  if (llmSpanResult) {
@@ -20197,9 +20814,17 @@ async function finalizeCurrentMessageGroup(state) {
20197
20814
  }
20198
20815
  }
20199
20816
  state.activeLlmSpansByParentToolUse.delete(parentKey);
20200
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20201
- if (lastMessage?.message?.usage) {
20202
- state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
20817
+ if (messageId) {
20818
+ state.usageByMessageId.delete(messageId);
20819
+ state.finalOutputUsageMessageIds.delete(messageId);
20820
+ for (const [
20821
+ parent,
20822
+ activeMessageId
20823
+ ] of state.activePartialMessageIdByParentKey) {
20824
+ if (activeMessageId === messageId) {
20825
+ state.activePartialMessageIdByParentKey.delete(parent);
20826
+ }
20827
+ }
20203
20828
  }
20204
20829
  state.currentMessages.length = 0;
20205
20830
  }
@@ -20290,6 +20915,10 @@ async function ensureActiveLlmSpanForParentToolUse(rootSpan, activeLlmSpansByPar
20290
20915
  );
20291
20916
  llmParentSpan = await subAgentSpan.export();
20292
20917
  }
20918
+ const racedLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
20919
+ if (racedLlmSpan) {
20920
+ return racedLlmSpan;
20921
+ }
20293
20922
  const llmSpan = startSpan(
20294
20923
  withSpanInstrumentationName(
20295
20924
  {
@@ -20409,7 +21038,49 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
20409
21038
  }
20410
21039
  return true;
20411
21040
  }
21041
+ function handlePartialUsageMessage(state, message) {
21042
+ if (message.type !== "stream_event") {
21043
+ return false;
21044
+ }
21045
+ const event = message.event;
21046
+ if (!event || typeof event !== "object") {
21047
+ return true;
21048
+ }
21049
+ const parentKey = llmParentKey(message.parent_tool_use_id ?? null);
21050
+ if (event.type === "message_start") {
21051
+ const messageId2 = event.message?.id;
21052
+ const usage = copyUsage(event.message?.usage);
21053
+ if (messageId2) {
21054
+ state.activePartialMessageIdByParentKey.set(parentKey, messageId2);
21055
+ if (usage) {
21056
+ state.usageByMessageId.set(messageId2, usage);
21057
+ }
21058
+ }
21059
+ return true;
21060
+ }
21061
+ const messageId = state.activePartialMessageIdByParentKey.get(parentKey);
21062
+ if (!messageId) {
21063
+ return true;
21064
+ }
21065
+ if (event.type === "message_delta") {
21066
+ const update = copyUsage(event.usage);
21067
+ if (update) {
21068
+ const usage = state.usageByMessageId.get(messageId) ?? {};
21069
+ Object.assign(usage, update);
21070
+ state.usageByMessageId.set(messageId, usage);
21071
+ if (update.output_tokens !== void 0) {
21072
+ state.finalOutputUsageMessageIds.add(messageId);
21073
+ }
21074
+ }
21075
+ } else if (event.type === "message_stop") {
21076
+ state.activePartialMessageIdByParentKey.delete(parentKey);
21077
+ }
21078
+ return true;
21079
+ }
20412
21080
  async function handleStreamMessage(state, message) {
21081
+ if (handlePartialUsageMessage(state, message)) {
21082
+ return;
21083
+ }
20413
21084
  maybeTrackToolUseContext(state, message);
20414
21085
  if (await maybeHandleTaskLifecycleMessage(state, message)) {
20415
21086
  return;
@@ -20456,36 +21127,9 @@ async function handleStreamMessage(state, message) {
20456
21127
  );
20457
21128
  state.currentMessages.push(message);
20458
21129
  }
20459
- if (message.type !== "result" || !message.usage) {
21130
+ if (message.type !== "result") {
20460
21131
  return;
20461
21132
  }
20462
- const finalUsageMetrics = extractUsageFromMessage(message);
20463
- if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
20464
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20465
- if (lastMessage?.message?.usage) {
20466
- const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
20467
- if (adjustedTokens >= 0) {
20468
- lastMessage.message.usage.output_tokens = adjustedTokens;
20469
- }
20470
- const resultUsage = message.usage;
20471
- if (resultUsage && typeof resultUsage === "object") {
20472
- const cacheReadTokens = getNumberProperty(
20473
- resultUsage,
20474
- "cache_read_input_tokens"
20475
- );
20476
- if (cacheReadTokens !== void 0) {
20477
- lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
20478
- }
20479
- const cacheCreationTokens = getNumberProperty(
20480
- resultUsage,
20481
- "cache_creation_input_tokens"
20482
- );
20483
- if (cacheCreationTokens !== void 0) {
20484
- lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
20485
- }
20486
- }
20487
- }
20488
- }
20489
21133
  const metadata = {};
20490
21134
  if (message.num_turns !== void 0) {
20491
21135
  metadata.num_turns = message.num_turns;
@@ -20493,8 +21137,12 @@ async function handleStreamMessage(state, message) {
20493
21137
  if (message.session_id !== void 0) {
20494
21138
  metadata.session_id = message.session_id;
20495
21139
  }
20496
- if (Object.keys(metadata).length > 0) {
20497
- state.span.log({ metadata });
21140
+ const metrics = state.options.includePartialMessages ? {} : extractUsage(copyUsage(message.usage), true);
21141
+ if (Object.keys(metadata).length > 0 || Object.keys(metrics).length > 0) {
21142
+ state.span.log({
21143
+ ...Object.keys(metadata).length > 0 ? { metadata } : {},
21144
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
21145
+ });
20498
21146
  }
20499
21147
  }
20500
21148
  async function finalizeQuerySpan(state) {
@@ -20518,6 +21166,9 @@ async function finalizeQuerySpan(state) {
20518
21166
  llmSpan.end();
20519
21167
  }
20520
21168
  state.activeLlmSpansByParentToolUse.clear();
21169
+ state.activePartialMessageIdByParentKey.clear();
21170
+ state.finalOutputUsageMessageIds.clear();
21171
+ state.usageByMessageId.clear();
20521
21172
  for (const toolSpan of state.activeToolSpans.values()) {
20522
21173
  toolSpan.end();
20523
21174
  }
@@ -20533,7 +21184,7 @@ async function finalizeQuerySpan(state) {
20533
21184
  }
20534
21185
  var ClaudeAgentSDKPlugin = class extends BasePlugin {
20535
21186
  onEnable() {
20536
- this.subscribeToQuery();
21187
+ this.interceptQuery();
20537
21188
  }
20538
21189
  onDisable() {
20539
21190
  for (const unsubscribe of this.unsubscribers) {
@@ -20541,207 +21192,218 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
20541
21192
  }
20542
21193
  this.unsubscribers = [];
20543
21194
  }
20544
- subscribeToQuery() {
20545
- const channel2 = claudeAgentSDKChannels.query.tracingChannel();
20546
- const spans = /* @__PURE__ */ new WeakMap();
20547
- const handlers = {
20548
- start: (event) => {
20549
- const params = event.arguments[0] ?? {};
20550
- const originalPrompt = params.prompt;
20551
- const options = params.options ?? {};
20552
- const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
20553
- let promptStarted = false;
20554
- let capturedPromptMessages;
20555
- let resolvePromptDone;
20556
- const promptDone = new Promise((resolve) => {
20557
- resolvePromptDone = resolve;
20558
- });
20559
- if (promptIsAsyncIterable) {
20560
- capturedPromptMessages = [];
20561
- const promptStream = originalPrompt;
20562
- params.prompt = (async function* () {
20563
- promptStarted = true;
20564
- try {
20565
- for await (const message of promptStream) {
20566
- capturedPromptMessages.push(message);
20567
- yield message;
20568
- }
20569
- } finally {
20570
- resolvePromptDone?.();
21195
+ interceptQuery() {
21196
+ const startQuery = (params) => {
21197
+ const originalPrompt = params.prompt;
21198
+ const options = params.options ?? {};
21199
+ const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
21200
+ let promptStarted = false;
21201
+ let capturedPromptMessages;
21202
+ let resolvePromptDone;
21203
+ const promptDone = new Promise((resolve) => {
21204
+ resolvePromptDone = resolve;
21205
+ });
21206
+ if (promptIsAsyncIterable) {
21207
+ capturedPromptMessages = [];
21208
+ const promptStream = originalPrompt;
21209
+ params.prompt = (async function* () {
21210
+ promptStarted = true;
21211
+ try {
21212
+ for await (const message of promptStream) {
21213
+ capturedPromptMessages.push(message);
21214
+ yield message;
20571
21215
  }
20572
- })();
20573
- }
20574
- const span = startSpan(
20575
- withSpanInstrumentationName(
20576
- {
20577
- name: "Claude Agent",
20578
- spanAttributes: {
20579
- type: "task" /* TASK */
20580
- }
20581
- },
20582
- INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
20583
- )
20584
- );
20585
- const startTime = getCurrentUnixTimestamp();
20586
- try {
20587
- span.log({
20588
- input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
20589
- metadata: filterSerializableOptions(options)
20590
- });
20591
- } catch (error) {
20592
- console.error("Error extracting input for Claude Agent SDK:", error);
20593
- }
20594
- const activeToolSpans = /* @__PURE__ */ new Map();
20595
- const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
20596
- const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
20597
- const subAgentSpans = /* @__PURE__ */ new Map();
20598
- const endedSubAgentSpans = /* @__PURE__ */ new Set();
20599
- const toolUseToParent = /* @__PURE__ */ new Map();
20600
- const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
20601
- const latestRootLlmParentRef = {
20602
- value: void 0
20603
- };
20604
- const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
20605
- const taskIdToToolUseId = /* @__PURE__ */ new Map();
20606
- const promptMessagesByParentKey = /* @__PURE__ */ new Map();
20607
- const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
20608
- const localToolContext = createClaudeLocalToolContext();
20609
- const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
20610
- const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
20611
- const resolveToolUseParentSpan = async (toolUseID, context) => {
20612
- const trackedParentToolUseId = toolUseToParent.get(toolUseID);
20613
- const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
20614
- const parentKey = llmParentKey(parentToolUseId);
20615
- const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
20616
- const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
20617
- if (!activeLlmSpan && !latestLlmParent) {
20618
- await ensureActiveLlmSpanForParentToolUse(
20619
- span,
20620
- activeLlmSpansByParentToolUse,
20621
- subAgentDetailsByToolUseId,
20622
- activeToolSpans,
20623
- subAgentSpans,
20624
- parentToolUseId,
20625
- getCurrentUnixTimestamp()
20626
- );
20627
- }
20628
- if (parentToolUseId) {
20629
- const subAgentSpan = await ensureSubAgentSpan(
20630
- subAgentDetailsByToolUseId,
20631
- span,
20632
- activeToolSpans,
20633
- subAgentSpans,
20634
- parentToolUseId
20635
- );
20636
- return subAgentSpan.export();
21216
+ } finally {
21217
+ resolvePromptDone?.();
20637
21218
  }
20638
- return span.export();
20639
- };
20640
- localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
20641
- setClaudeLocalToolParentResolver(resolveToolUseParentSpan);
20642
- const optionsWithHooks = injectTracingHooks(
20643
- options,
20644
- resolveToolUseParentSpan,
20645
- activeToolSpans,
20646
- localToolHookNames,
20647
- skipLocalToolHooks,
20648
- subAgentDetailsByToolUseId,
20649
- subAgentSpans,
20650
- endedSubAgentSpans
20651
- );
20652
- params.options = optionsWithHooks;
20653
- event.arguments[0] = params;
20654
- spans.set(event, {
20655
- accumulatedOutputTokens: 0,
20656
- activeLlmSpansByParentToolUse,
20657
- activeToolSpans,
20658
- conversationHistoryByParentKey,
20659
- capturedPromptMessages,
20660
- currentMessageId: void 0,
20661
- currentMessageStartTime: startTime,
20662
- currentMessages: [],
20663
- endedSubAgentSpans,
20664
- finalResults: [],
20665
- options: optionsWithHooks,
20666
- originalPrompt,
20667
- processing: Promise.resolve(),
20668
- promptDone,
20669
- promptMessagesByParentKey,
20670
- promptStarted: () => promptStarted,
20671
- promptSourcePriorityByParentKey,
20672
- span,
20673
- subAgentDetailsByToolUseId,
20674
- subAgentSpans,
20675
- taskIdToToolUseId,
20676
- latestLlmParentBySubAgentToolUse,
20677
- latestRootLlmParentRef,
20678
- toolUseToParent,
20679
- localToolContext
21219
+ })();
21220
+ }
21221
+ const span = startSpan(
21222
+ withSpanInstrumentationName(
21223
+ {
21224
+ name: "Claude Agent",
21225
+ spanAttributes: {
21226
+ type: "task" /* TASK */
21227
+ }
21228
+ },
21229
+ INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
21230
+ )
21231
+ );
21232
+ const startTime = getCurrentUnixTimestamp();
21233
+ try {
21234
+ span.log({
21235
+ input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
21236
+ metadata: filterSerializableOptions(options)
20680
21237
  });
20681
- },
20682
- end: (event) => {
20683
- const state = spans.get(event);
20684
- if (!state) {
20685
- return;
20686
- }
20687
- const eventResult = bindClaudeLocalToolContextToAsyncIterable(
20688
- event.result,
20689
- state.localToolContext
20690
- );
20691
- if (eventResult === void 0) {
20692
- state.span.end();
20693
- spans.delete(event);
20694
- return;
20695
- }
20696
- if (isAsyncIterable(eventResult)) {
20697
- patchStreamIfNeeded(eventResult, {
20698
- onChunk: (message) => {
20699
- maybeTrackToolUseContext(state, message);
20700
- state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
20701
- console.error(
20702
- "Error processing Claude Agent SDK stream chunk:",
20703
- error
20704
- );
20705
- });
20706
- },
20707
- onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
20708
- spans.delete(event);
20709
- }),
20710
- onError: (error) => state.processing.then(() => {
20711
- state.span.log({
20712
- error: error.message
20713
- });
20714
- }).then(() => finalizeQuerySpan(state)).finally(() => {
20715
- spans.delete(event);
20716
- })
20717
- });
20718
- return;
20719
- }
20720
- try {
20721
- state.span.log({ output: eventResult });
20722
- } catch (error) {
20723
- console.error("Error extracting output for Claude Agent SDK:", error);
20724
- } finally {
20725
- state.span.end();
20726
- spans.delete(event);
21238
+ } catch (error) {
21239
+ console.error("Error extracting input for Claude Agent SDK:", error);
21240
+ }
21241
+ const activeToolSpans = /* @__PURE__ */ new Map();
21242
+ const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
21243
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
21244
+ const subAgentSpans = /* @__PURE__ */ new Map();
21245
+ const endedSubAgentSpans = /* @__PURE__ */ new Set();
21246
+ const toolUseToParent = /* @__PURE__ */ new Map();
21247
+ const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
21248
+ const latestRootLlmParentRef = {
21249
+ value: void 0
21250
+ };
21251
+ const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
21252
+ const taskIdToToolUseId = /* @__PURE__ */ new Map();
21253
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
21254
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
21255
+ const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
21256
+ const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
21257
+ const resolveToolUseParentSpan = async (toolUseID, context) => {
21258
+ const trackedParentToolUseId = toolUseToParent.get(toolUseID);
21259
+ const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
21260
+ const parentKey = llmParentKey(parentToolUseId);
21261
+ const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
21262
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
21263
+ if (!activeLlmSpan && !latestLlmParent) {
21264
+ await ensureActiveLlmSpanForParentToolUse(
21265
+ span,
21266
+ activeLlmSpansByParentToolUse,
21267
+ subAgentDetailsByToolUseId,
21268
+ activeToolSpans,
21269
+ subAgentSpans,
21270
+ parentToolUseId,
21271
+ getCurrentUnixTimestamp()
21272
+ );
20727
21273
  }
20728
- },
20729
- error: (event) => {
20730
- const state = spans.get(event);
20731
- if (!state || !event.error) {
20732
- return;
21274
+ if (parentToolUseId) {
21275
+ const subAgentSpan = await ensureSubAgentSpan(
21276
+ subAgentDetailsByToolUseId,
21277
+ span,
21278
+ activeToolSpans,
21279
+ subAgentSpans,
21280
+ parentToolUseId
21281
+ );
21282
+ return subAgentSpan.export();
20733
21283
  }
20734
- state.span.log({
20735
- error: event.error.message
21284
+ return span.export();
21285
+ };
21286
+ const optionsWithHooks = injectTracingHooks(
21287
+ options,
21288
+ resolveToolUseParentSpan,
21289
+ taskIdToToolUseId,
21290
+ toolUseToParent,
21291
+ activeToolSpans,
21292
+ localToolHookNames,
21293
+ skipLocalToolHooks,
21294
+ subAgentDetailsByToolUseId,
21295
+ subAgentSpans,
21296
+ endedSubAgentSpans
21297
+ );
21298
+ params.options = optionsWithHooks;
21299
+ return {
21300
+ activeLlmSpansByParentToolUse,
21301
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
21302
+ activeToolSpans,
21303
+ conversationHistoryByParentKey,
21304
+ capturedPromptMessages,
21305
+ currentMessageId: void 0,
21306
+ currentMessageStartTime: startTime,
21307
+ currentMessages: [],
21308
+ endedSubAgentSpans,
21309
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
21310
+ finalResults: [],
21311
+ options: optionsWithHooks,
21312
+ originalPrompt,
21313
+ processing: Promise.resolve(),
21314
+ promptDone,
21315
+ promptMessagesByParentKey,
21316
+ promptStarted: () => promptStarted,
21317
+ promptSourcePriorityByParentKey,
21318
+ span,
21319
+ subAgentDetailsByToolUseId,
21320
+ subAgentSpans,
21321
+ taskIdToToolUseId,
21322
+ latestLlmParentBySubAgentToolUse,
21323
+ latestRootLlmParentRef,
21324
+ toolUseToParent,
21325
+ usageByMessageId: /* @__PURE__ */ new Map(),
21326
+ localToolParentResolver: resolveToolUseParentSpan
21327
+ };
21328
+ };
21329
+ const finishQuery = (state, result) => {
21330
+ if (isAsyncIterable(result)) {
21331
+ patchStreamIfNeeded(result, {
21332
+ aroundNext: (callback) => runWithClaudeLocalToolContext(
21333
+ callback,
21334
+ state.localToolParentResolver
21335
+ ),
21336
+ onChunk: (message) => {
21337
+ maybeTrackToolUseContext(state, message);
21338
+ state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
21339
+ console.error(
21340
+ "Error processing Claude Agent SDK stream chunk:",
21341
+ error
21342
+ );
21343
+ });
21344
+ },
21345
+ onComplete: () => state.processing.then(() => finalizeQuerySpan(state)),
21346
+ onError: (error) => state.processing.then(() => {
21347
+ state.span.log({ error: error.message });
21348
+ }).then(() => finalizeQuerySpan(state))
20736
21349
  });
21350
+ return;
21351
+ }
21352
+ try {
21353
+ state.span.log({ output: result });
21354
+ } catch (error) {
21355
+ console.error("Error extracting output for Claude Agent SDK:", error);
21356
+ } finally {
20737
21357
  state.span.end();
20738
- spans.delete(event);
20739
21358
  }
20740
21359
  };
20741
- channel2.subscribe(handlers);
20742
- this.unsubscribers.push(() => {
20743
- channel2.unsubscribe(handlers);
20744
- });
21360
+ this.unsubscribers.push(
21361
+ claudeAgentSDKChannels.query.intercept((target, thisArg, args) => {
21362
+ let state;
21363
+ try {
21364
+ args[0] ??= {};
21365
+ state = startQuery(args[0]);
21366
+ } catch (error) {
21367
+ debugLogger.error(
21368
+ "Error starting Claude Agent SDK instrumentation:",
21369
+ error
21370
+ );
21371
+ }
21372
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
21373
+ try {
21374
+ const result = state ? runWithClaudeLocalToolContext(
21375
+ invokeTarget,
21376
+ state.localToolParentResolver
21377
+ ) : invokeTarget();
21378
+ if (state) {
21379
+ try {
21380
+ finishQuery(state, result);
21381
+ } catch (error) {
21382
+ debugLogger.error(
21383
+ "Error finalizing Claude Agent SDK instrumentation:",
21384
+ error
21385
+ );
21386
+ }
21387
+ }
21388
+ return result;
21389
+ } catch (error) {
21390
+ if (state) {
21391
+ try {
21392
+ state.span.log({
21393
+ error: error instanceof Error ? error.message : String(error)
21394
+ });
21395
+ state.span.end();
21396
+ } catch (instrumentationError) {
21397
+ debugLogger.error(
21398
+ "Error handling Claude Agent SDK instrumentation failure:",
21399
+ instrumentationError
21400
+ );
21401
+ }
21402
+ }
21403
+ throw error;
21404
+ }
21405
+ })
21406
+ );
20745
21407
  }
20746
21408
  };
20747
21409
 
@@ -23150,9 +23812,9 @@ function extractEmbedPromptTokenCount(response) {
23150
23812
  let sawAny = false;
23151
23813
  for (const embedding of embeddings) {
23152
23814
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
23153
- const tokenCount = embeddingStats?.tokenCount;
23154
- if (typeof tokenCount === "number" && Number.isFinite(tokenCount)) {
23155
- total += tokenCount;
23815
+ const tokenCount2 = embeddingStats?.tokenCount;
23816
+ if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
23817
+ total += tokenCount2;
23156
23818
  sawAny = true;
23157
23819
  }
23158
23820
  }
@@ -24855,7 +25517,7 @@ function patchOpenRouterCallModelResult(args) {
24855
25517
  span,
24856
25518
  () => originalMethod.apply(resultLike, args2)
24857
25519
  );
24858
- if (!isAsyncIterable4(stream)) {
25520
+ if (!isAsyncIterable3(stream)) {
24859
25521
  return stream;
24860
25522
  }
24861
25523
  return wrapAsyncIterableWithSpan({
@@ -25050,7 +25712,7 @@ function wrapAsyncIterableWithSpan(args) {
25050
25712
  }
25051
25713
  };
25052
25714
  }
25053
- function isAsyncIterable4(value) {
25715
+ function isAsyncIterable3(value) {
25054
25716
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
25055
25717
  }
25056
25718
  function normalizeError(error) {
@@ -25928,7 +26590,7 @@ function patchOpenRouterCallModelResult2(args) {
25928
26590
  span,
25929
26591
  () => originalMethod.apply(resultLike, args2)
25930
26592
  );
25931
- if (!isAsyncIterable5(stream)) {
26593
+ if (!isAsyncIterable4(stream)) {
25932
26594
  return stream;
25933
26595
  }
25934
26596
  return wrapAsyncIterableWithSpan2({
@@ -26123,7 +26785,7 @@ function wrapAsyncIterableWithSpan2(args) {
26123
26785
  }
26124
26786
  };
26125
26787
  }
26126
- function isAsyncIterable5(value) {
26788
+ function isAsyncIterable4(value) {
26127
26789
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
26128
26790
  }
26129
26791
  function normalizeError2(error) {
@@ -30047,7 +30709,7 @@ function getStringProperty2(obj, key) {
30047
30709
  return typeof value === "string" ? value : void 0;
30048
30710
  }
30049
30711
  function extractMetricsFromUsage(usage) {
30050
- const metrics = {
30712
+ const rawMetrics = {
30051
30713
  prompt_tokens: usage.inputTokens,
30052
30714
  completion_tokens: usage.outputTokens,
30053
30715
  ...extractAnthropicCacheTokens(
@@ -30056,10 +30718,10 @@ function extractMetricsFromUsage(usage) {
30056
30718
  )
30057
30719
  };
30058
30720
  if (usage.reasoningTokens !== void 0) {
30059
- metrics.completion_reasoning_tokens = usage.reasoningTokens;
30060
- metrics.reasoning_tokens = usage.reasoningTokens;
30721
+ rawMetrics.completion_reasoning_tokens = usage.reasoningTokens;
30722
+ rawMetrics.reasoning_tokens = usage.reasoningTokens;
30061
30723
  }
30062
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
30724
+ const metrics = finalizeAnthropicTokens(rawMetrics);
30063
30725
  const metadata = {
30064
30726
  model: usage.model
30065
30727
  };
@@ -30998,17 +31660,20 @@ var FlueObserveBridge = class {
30998
31660
  return;
30999
31661
  }
31000
31662
  const metadata = {
31663
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
31001
31664
  ...extractEventMetadata(event),
31002
31665
  "flue.operation": event.operationKind,
31003
31666
  provider: "flue"
31004
31667
  };
31005
31668
  const parent = this.parentSpanForEvent(event);
31006
- const span = startFlueSpan(parent, {
31669
+ const args = {
31007
31670
  name: `flue.${event.operationKind}`,
31008
31671
  spanAttributes: { type: "task" /* TASK */ },
31009
31672
  startTime: eventTime(event.timestamp),
31010
31673
  event: { metadata }
31011
- });
31674
+ };
31675
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
31676
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
31012
31677
  this.operationsById.set(event.operationId, { metadata, span });
31013
31678
  }
31014
31679
  handleOperation(event) {
@@ -31023,6 +31688,11 @@ var FlueObserveBridge = class {
31023
31688
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
31024
31689
  ...event.usage ? { "flue.usage": event.usage } : {}
31025
31690
  };
31691
+ const input = flueOperationInput(event);
31692
+ if (!state.loggedInput && input !== void 0) {
31693
+ safeLog3(state.span, { input });
31694
+ state.loggedInput = true;
31695
+ }
31026
31696
  this.finishPendingChildrenForOperation(event, output);
31027
31697
  safeLog3(state.span, {
31028
31698
  ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
@@ -31039,6 +31709,8 @@ var FlueObserveBridge = class {
31039
31709
  return;
31040
31710
  }
31041
31711
  const input = flueTurnRequestInput(event);
31712
+ const operation = event.operationId ? this.operationsById.get(event.operationId) : void 0;
31713
+ const turnInput = prepareFlueTurnInput(event, input, operation);
31042
31714
  const model = flueTurnRequestModel(event);
31043
31715
  const provider = flueTurnRequestProvider(event);
31044
31716
  const api = flueTurnRequestApi(event);
@@ -31051,8 +31723,7 @@ var FlueObserveBridge = class {
31051
31723
  ...provider ? { "flue.provider": provider } : {},
31052
31724
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
31053
31725
  ...reasoning ? { reasoning } : {},
31054
- ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
31055
- ...input?.tools ? { tools: input.tools } : {}
31726
+ ...turnInput.metadata
31056
31727
  };
31057
31728
  const parent = this.parentSpanForTurn(event);
31058
31729
  const span = startFlueSpan(parent, {
@@ -31060,11 +31731,14 @@ var FlueObserveBridge = class {
31060
31731
  spanAttributes: { type: "llm" /* LLM */ },
31061
31732
  startTime: eventTime(event.timestamp),
31062
31733
  event: {
31063
- input: input?.messages,
31734
+ input: turnInput.messages,
31064
31735
  metadata
31065
31736
  }
31066
31737
  });
31067
- this.logOperationInput(event.operationId, input?.messages ?? input);
31738
+ this.logOperationInput(
31739
+ event.operationId,
31740
+ latestUserMessageInput(input?.messages)
31741
+ );
31068
31742
  this.turnsByKey.set(key, { metadata, span });
31069
31743
  }
31070
31744
  handleTurn(event) {
@@ -31311,16 +31985,20 @@ var FlueObserveBridge = class {
31311
31985
  }
31312
31986
  startSyntheticOperation(event) {
31313
31987
  const metadata = {
31988
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
31314
31989
  ...extractEventMetadata(event),
31315
31990
  "flue.operation": event.operationKind,
31316
31991
  provider: "flue"
31317
31992
  };
31318
- const span = startFlueSpan(this.parentSpanForEvent(event), {
31993
+ const args = {
31319
31994
  name: `flue.${event.operationKind}`,
31320
31995
  spanAttributes: { type: "task" /* TASK */ },
31321
31996
  startTime: eventTime(event.timestamp),
31322
31997
  event: { metadata }
31323
- });
31998
+ };
31999
+ const parent = this.parentSpanForEvent(event);
32000
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
32001
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
31324
32002
  return { metadata, span };
31325
32003
  }
31326
32004
  startSyntheticTurn(event) {
@@ -31499,6 +32177,71 @@ function flueRunInput(event) {
31499
32177
  function flueTurnRequestInput(event) {
31500
32178
  return event.request?.input ?? event.input;
31501
32179
  }
32180
+ function prepareFlueTurnInput(event, input, operation) {
32181
+ const messages = input?.messages;
32182
+ const tracksUserTurn = event.purpose === "agent" && operation?.metadata["flue.operation"] === "prompt" && Array.isArray(messages);
32183
+ if (!tracksUserTurn) {
32184
+ return {
32185
+ messages,
32186
+ metadata: {
32187
+ ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
32188
+ ...input?.tools ? { tools: input.tools } : {}
32189
+ }
32190
+ };
32191
+ }
32192
+ const previous = operation.turnInputState;
32193
+ const previousMessageCount = previous?.messageCount ?? 0;
32194
+ const boundaryFingerprint = messages.length > 0 ? fingerprintJsonValue(messages[messages.length - 1]) : void 0;
32195
+ const continuesPreviousInput = previous !== void 0 && messages.length >= previousMessageCount && (previousMessageCount === 0 || previous.boundaryFingerprint !== void 0 && previous.boundaryFingerprint === fingerprintJsonValue(messages[previousMessageCount - 1]));
32196
+ const inputMode = previous === void 0 ? "full" : continuesPreviousInput ? "delta" : "reset";
32197
+ const systemPromptFingerprint = fingerprintJsonValue(input?.systemPrompt);
32198
+ const toolsFingerprint = fingerprintJsonValue(input?.tools);
32199
+ operation.turnInputState = {
32200
+ ...boundaryFingerprint !== void 0 ? { boundaryFingerprint } : {},
32201
+ messageCount: messages.length,
32202
+ ...systemPromptFingerprint !== void 0 ? { systemPromptFingerprint } : {},
32203
+ ...toolsFingerprint !== void 0 ? { toolsFingerprint } : {}
32204
+ };
32205
+ return {
32206
+ messages: continuesPreviousInput ? messages.slice(previousMessageCount) : messages,
32207
+ metadata: {
32208
+ "flue.input_mode": inputMode,
32209
+ ...continuesPreviousInput ? { "flue.input_message_offset": previousMessageCount } : {},
32210
+ ...input?.systemPrompt && (!continuesPreviousInput || systemPromptFingerprint !== previous?.systemPromptFingerprint) ? { "flue.system_prompt": input.systemPrompt } : {},
32211
+ ...input?.tools && (!continuesPreviousInput || toolsFingerprint !== previous?.toolsFingerprint) ? { tools: input.tools } : {}
32212
+ }
32213
+ };
32214
+ }
32215
+ function fingerprintJsonValue(value) {
32216
+ try {
32217
+ const serialized = JSON.stringify(value);
32218
+ if (serialized === void 0) {
32219
+ return void 0;
32220
+ }
32221
+ let hash = 2166136261;
32222
+ for (let i = 0; i < serialized.length; i++) {
32223
+ hash = Math.imul(hash ^ serialized.charCodeAt(i), 16777619);
32224
+ }
32225
+ return `${serialized.length}:${hash >>> 0}`;
32226
+ } catch {
32227
+ return void 0;
32228
+ }
32229
+ }
32230
+ function latestUserMessageInput(messages) {
32231
+ if (!messages) {
32232
+ return void 0;
32233
+ }
32234
+ for (let i = messages.length - 1; i >= 0; i--) {
32235
+ const message = messages[i];
32236
+ if (isObjectLike(message) && Reflect.get(message, "role") === "user") {
32237
+ return [message];
32238
+ }
32239
+ }
32240
+ return void 0;
32241
+ }
32242
+ function flueOperationInput(event) {
32243
+ return typeof event.agentInput?.text === "string" ? [{ content: event.agentInput.text, role: "user" }] : void 0;
32244
+ }
31502
32245
  function flueTurnRequestModel(event) {
31503
32246
  return event.request?.requestedModel ?? event.request?.model ?? event.model;
31504
32247
  }
@@ -31656,6 +32399,21 @@ function startFlueSpan(parent, args) {
31656
32399
  withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE)
31657
32400
  );
31658
32401
  }
32402
+ function startFlueRootSpan(args) {
32403
+ const state = _internalGetGlobalState();
32404
+ const spanId = state.idGenerator.getSpanId();
32405
+ const rootSpanId = state.idGenerator.shareRootSpanId() ? spanId : state.idGenerator.getTraceId();
32406
+ return withCurrent(
32407
+ NOOP_SPAN,
32408
+ () => startSpan({
32409
+ ...withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE),
32410
+ parentSpanIds: { parentSpanIds: [], rootSpanId },
32411
+ spanId,
32412
+ state
32413
+ }),
32414
+ state
32415
+ );
32416
+ }
31659
32417
  function runWithCurrentSpanStore(span, next) {
31660
32418
  const state = _internalGetGlobalState();
31661
32419
  const contextManager = state?.contextManager;
@@ -32019,12 +32777,14 @@ function getMetricsFromResponse(response) {
32019
32777
  continue;
32020
32778
  }
32021
32779
  const inputTokenDetails = usageMetadata.input_token_details;
32780
+ const outputTokenDetails = usageMetadata.output_token_details;
32022
32781
  return normalizeTokenMetrics({
32023
32782
  total_tokens: usageMetadata.total_tokens,
32024
32783
  prompt_tokens: usageMetadata.input_tokens,
32025
32784
  completion_tokens: usageMetadata.output_tokens,
32026
32785
  prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
32027
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
32786
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
32787
+ completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
32028
32788
  });
32029
32789
  }
32030
32790
  const llmOutput = response.llmOutput || {};
@@ -32611,6 +33371,9 @@ var piCodingAgentChannels = defineChannels(
32611
33371
  // src/instrumentation/plugins/pi-coding-agent-plugin.ts
32612
33372
  var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
32613
33373
  var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
33374
+ var PI_TOOL_EXECUTE_WRAPPED = /* @__PURE__ */ Symbol.for(
33375
+ "braintrust.pi_coding_agent.tool_execute_wrapped"
33376
+ );
32614
33377
  var piPromptContextStore;
32615
33378
  var PiCodingAgentPlugin = class extends BasePlugin {
32616
33379
  activePromptStates = /* @__PURE__ */ new Set();
@@ -32691,6 +33454,7 @@ function startPiPromptRun(event, onFinalize) {
32691
33454
  return void 0;
32692
33455
  }
32693
33456
  installPiAgentInstrumentation(agent);
33457
+ wrapPiToolExecutors(agent.state?.tools);
32694
33458
  const metadata = {
32695
33459
  ...extractSessionMetadata(session),
32696
33460
  ...extractPromptOptionsMetadata(event.arguments[1]),
@@ -32787,6 +33551,7 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
32787
33551
  if (!state || state.agent !== agent || state.finalized) {
32788
33552
  return invokeOriginal();
32789
33553
  }
33554
+ wrapPiToolExecutors(context.tools);
32790
33555
  const llmState = await startPiLlmSpan(state, model, context, options);
32791
33556
  try {
32792
33557
  const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
@@ -32797,6 +33562,33 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
32797
33562
  }
32798
33563
  };
32799
33564
  }
33565
+ function wrapPiToolExecutors(tools) {
33566
+ if (!tools) {
33567
+ return;
33568
+ }
33569
+ for (const tool of tools) {
33570
+ try {
33571
+ const execute = tool.execute;
33572
+ if (typeof execute !== "function" || execute[PI_TOOL_EXECUTE_WRAPPED]) {
33573
+ continue;
33574
+ }
33575
+ const wrappedExecute = function(...args) {
33576
+ return runWithAutoInstrumentationAllowed(
33577
+ () => Reflect.apply(execute, this, args)
33578
+ );
33579
+ };
33580
+ Object.defineProperty(wrappedExecute, PI_TOOL_EXECUTE_WRAPPED, {
33581
+ configurable: false,
33582
+ enumerable: false,
33583
+ value: true,
33584
+ writable: false
33585
+ });
33586
+ tool.execute = wrappedExecute;
33587
+ } catch (error) {
33588
+ logInstrumentationError4("Pi Coding Agent tool wrapping", error);
33589
+ }
33590
+ }
33591
+ }
32800
33592
  async function startPiLlmSpan(state, model, context, options) {
32801
33593
  const metadata = {
32802
33594
  ...extractModelMetadata2(model),
@@ -32968,35 +33760,26 @@ async function startPiToolSpan(state, event) {
32968
33760
  if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
32969
33761
  return;
32970
33762
  }
32971
- const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
32972
33763
  const metadata = {
32973
33764
  "gen_ai.tool.call.id": event.toolCallId,
32974
33765
  "gen_ai.tool.name": event.toolName,
32975
33766
  "pi_coding_agent.tool.name": event.toolName
32976
33767
  };
32977
- try {
32978
- const span = startSpan(
32979
- withSpanInstrumentationName(
32980
- {
32981
- event: {
32982
- input: event.args,
32983
- metadata
32984
- },
32985
- name: event.toolName || "tool",
32986
- parent: await state.span.export(),
32987
- spanAttributes: { type: "tool" /* TOOL */ }
33768
+ const span = startSpan(
33769
+ withSpanInstrumentationName(
33770
+ {
33771
+ event: {
33772
+ input: event.args,
33773
+ metadata
32988
33774
  },
32989
- INSTRUMENTATION_NAMES.PI_CODING_AGENT
32990
- )
32991
- );
32992
- state.activeToolSpans.set(event.toolCallId, {
32993
- restoreAutoInstrumentation,
32994
- span
32995
- });
32996
- } catch (error) {
32997
- restoreAutoInstrumentation();
32998
- throw error;
32999
- }
33775
+ name: event.toolName || "tool",
33776
+ parent: await state.span.export(),
33777
+ spanAttributes: { type: "tool" /* TOOL */ }
33778
+ },
33779
+ INSTRUMENTATION_NAMES.PI_CODING_AGENT
33780
+ )
33781
+ );
33782
+ state.activeToolSpans.set(event.toolCallId, { span });
33000
33783
  }
33001
33784
  function finishPiToolSpan(state, event) {
33002
33785
  const toolState = state.activeToolSpans.get(event.toolCallId);
@@ -33017,11 +33800,7 @@ function finishPiToolSpan(state, event) {
33017
33800
  output: event.result
33018
33801
  });
33019
33802
  } finally {
33020
- try {
33021
- toolState.span.end();
33022
- } finally {
33023
- toolState.restoreAutoInstrumentation?.();
33024
- }
33803
+ toolState.span.end();
33025
33804
  }
33026
33805
  }
33027
33806
  function finishPiPromptRun(state, error) {
@@ -33092,14 +33871,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
33092
33871
  }
33093
33872
  function finishOpenToolSpans(state, error) {
33094
33873
  for (const [, toolState] of state.activeToolSpans) {
33095
- try {
33096
- safeLog4(toolState.span, {
33097
- error: error ? toLoggedError(error) : "Pi tool did not complete"
33098
- });
33099
- toolState.span.end();
33100
- } finally {
33101
- toolState.restoreAutoInstrumentation?.();
33102
- }
33874
+ safeLog4(toolState.span, {
33875
+ error: error ? toLoggedError(error) : "Pi tool did not complete"
33876
+ });
33877
+ toolState.span.end();
33103
33878
  }
33104
33879
  state.activeToolSpans.clear();
33105
33880
  }
@@ -33418,12 +34193,12 @@ var MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES = 32;
33418
34193
  var StrandsAgentSDKPlugin = class extends BasePlugin {
33419
34194
  activeChildParents = /* @__PURE__ */ new WeakMap();
33420
34195
  onEnable() {
33421
- this.subscribeToAgentStream();
33422
- this.subscribeToMultiAgentStream(
34196
+ this.interceptAgentStream();
34197
+ this.interceptMultiAgentStream(
33423
34198
  strandsAgentSDKChannels.graphStream,
33424
34199
  "Graph.stream"
33425
34200
  );
33426
- this.subscribeToMultiAgentStream(
34201
+ this.interceptMultiAgentStream(
33427
34202
  strandsAgentSDKChannels.swarmStream,
33428
34203
  "Swarm.stream"
33429
34204
  );
@@ -33434,143 +34209,109 @@ var StrandsAgentSDKPlugin = class extends BasePlugin {
33434
34209
  }
33435
34210
  this.unsubscribers = [];
33436
34211
  }
33437
- subscribeToAgentStream() {
33438
- const channel2 = strandsAgentSDKChannels.agentStream.tracingChannel();
33439
- const states = /* @__PURE__ */ new WeakMap();
33440
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
33441
- const handlers = {
33442
- start: (event) => {
33443
- const state = startAgentStream(event, this.activeChildParents);
33444
- if (state) {
33445
- states.set(event, state);
33446
- }
33447
- },
33448
- end: (event) => {
33449
- const state = states.get(event);
33450
- if (!state) {
33451
- return;
33452
- }
33453
- const result = event.result;
33454
- if (isAsyncIterable(result)) {
33455
- patchStreamIfNeeded(result, {
33456
- aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
33457
- onChunk: (chunk) => handleAgentStreamEvent(state, chunk),
33458
- onComplete: () => {
33459
- finalizeAgentStream(state);
33460
- states.delete(event);
33461
- },
33462
- onError: (error) => {
33463
- finalizeAgentStream(state, error);
33464
- states.delete(event);
33465
- }
33466
- });
33467
- return;
33468
- }
33469
- finalizeAgentStream(state, void 0, result);
33470
- states.delete(event);
33471
- },
33472
- error: (event) => {
33473
- const state = states.get(event);
33474
- if (!state || !event.error) {
33475
- return;
33476
- }
33477
- finalizeAgentStream(state, event.error);
33478
- states.delete(event);
33479
- }
33480
- };
33481
- channel2.subscribe(handlers);
33482
- this.unsubscribers.push(() => {
33483
- unbindAutoInstrumentationSuppression?.();
33484
- channel2.unsubscribe(handlers);
33485
- });
34212
+ interceptAgentStream() {
34213
+ this.unsubscribers.push(
34214
+ strandsAgentSDKChannels.agentStream.intercept(
34215
+ (target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
34216
+ finalize: finalizeAgentStream,
34217
+ handleChunk: handleAgentStreamEvent,
34218
+ invoke: () => Reflect.apply(target, thisArg, args),
34219
+ name: "Strands Agent SDK",
34220
+ start: () => startAgentStream(
34221
+ args[0],
34222
+ extractAgent(additional.agent, thisArg),
34223
+ this.activeChildParents
34224
+ )
34225
+ })
34226
+ )
34227
+ );
33486
34228
  }
33487
- subscribeToMultiAgentStream(channel2, operation) {
33488
- const tracingChannel = channel2.tracingChannel();
33489
- const states = /* @__PURE__ */ new WeakMap();
33490
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(tracingChannel);
33491
- const handlers = {
33492
- start: (event) => {
33493
- const state = startMultiAgentStream(
33494
- event,
33495
- operation,
33496
- this.activeChildParents
33497
- );
33498
- if (state) {
33499
- states.set(event, state);
33500
- }
33501
- },
33502
- end: (event) => {
33503
- const state = states.get(event);
33504
- if (!state) {
33505
- return;
33506
- }
33507
- const result = event.result;
33508
- if (isAsyncIterable(result)) {
33509
- patchStreamIfNeeded(result, {
33510
- aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
33511
- onChunk: (chunk) => handleMultiAgentStreamEvent(
33512
- state,
33513
- chunk,
33514
- this.activeChildParents
33515
- ),
33516
- onComplete: () => {
33517
- finalizeMultiAgentStream(state, this.activeChildParents);
33518
- states.delete(event);
33519
- },
33520
- onError: (error) => {
33521
- finalizeMultiAgentStream(state, this.activeChildParents, error);
33522
- states.delete(event);
33523
- }
33524
- });
33525
- return;
33526
- }
33527
- finalizeMultiAgentStream(
33528
- state,
33529
- this.activeChildParents,
33530
- void 0,
33531
- result
34229
+ interceptMultiAgentStream(channel2, operation) {
34230
+ this.unsubscribers.push(
34231
+ channel2.intercept(
34232
+ (target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
34233
+ finalize: (state, error, output) => finalizeMultiAgentStream(
34234
+ state,
34235
+ this.activeChildParents,
34236
+ error,
34237
+ output
34238
+ ),
34239
+ handleChunk: (state, chunk) => handleMultiAgentStreamEvent(state, chunk, this.activeChildParents),
34240
+ invoke: () => Reflect.apply(target, thisArg, args),
34241
+ name: "Strands multi-agent",
34242
+ start: () => startMultiAgentStream(
34243
+ args[0],
34244
+ extractOrchestrator(additional.orchestrator, thisArg),
34245
+ operation,
34246
+ this.activeChildParents
34247
+ )
34248
+ })
34249
+ )
34250
+ );
34251
+ }
34252
+ };
34253
+ function instrumentStrandsStreamInvocation(options) {
34254
+ let state;
34255
+ try {
34256
+ state = options.start();
34257
+ } catch (error) {
34258
+ debugLogger.error(`Error starting ${options.name} instrumentation:`, error);
34259
+ }
34260
+ let result;
34261
+ try {
34262
+ result = runWithAutoInstrumentationSuppressed(options.invoke);
34263
+ } catch (error) {
34264
+ if (state) {
34265
+ try {
34266
+ options.finalize(state, error);
34267
+ } catch (instrumentationError) {
34268
+ debugLogger.error(
34269
+ `Error handling ${options.name} instrumentation failure:`,
34270
+ instrumentationError
33532
34271
  );
33533
- states.delete(event);
33534
- },
33535
- error: (event) => {
33536
- const state = states.get(event);
33537
- if (!state || !event.error) {
33538
- return;
33539
- }
33540
- finalizeMultiAgentStream(state, this.activeChildParents, event.error);
33541
- states.delete(event);
33542
34272
  }
33543
- };
33544
- tracingChannel.subscribe(handlers);
33545
- this.unsubscribers.push(() => {
33546
- unbindAutoInstrumentationSuppression?.();
33547
- tracingChannel.unsubscribe(handlers);
33548
- });
34273
+ }
34274
+ throw error;
33549
34275
  }
33550
- };
33551
- function startAgentStream(event, activeChildParents) {
33552
- const agent = extractAgent(event);
34276
+ if (state) {
34277
+ try {
34278
+ if (isAsyncIterable(result)) {
34279
+ patchStreamIfNeeded(result, {
34280
+ aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
34281
+ onChunk: (chunk) => options.handleChunk(state, chunk),
34282
+ onComplete: () => options.finalize(state),
34283
+ onError: (error) => options.finalize(state, error)
34284
+ });
34285
+ } else {
34286
+ options.finalize(state, void 0, result);
34287
+ }
34288
+ } catch (error) {
34289
+ debugLogger.error(
34290
+ `Error finalizing ${options.name} instrumentation:`,
34291
+ error
34292
+ );
34293
+ }
34294
+ }
34295
+ return result;
34296
+ }
34297
+ function startAgentStream(input, agent, activeChildParents) {
33553
34298
  const model = agent?.model;
33554
34299
  const metadata = {
33555
34300
  ...extractAgentMetadata2(agent),
33556
34301
  ...extractModelMetadata3(model),
33557
34302
  "strands.operation": "Agent.stream",
33558
- provider: extractProvider(model),
33559
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34303
+ provider: extractProvider(model)
33560
34304
  };
33561
34305
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
33562
34306
  const attachmentCache = createStrandsAttachmentCache();
33563
- const input = processStrandsInputAttachments(
33564
- event.arguments[0],
33565
- attachmentCache
33566
- );
34307
+ const processedInput = processStrandsInputAttachments(input, attachmentCache);
33567
34308
  const span = parentSpan ? withCurrent(
33568
34309
  parentSpan,
33569
34310
  () => startSpan(
33570
34311
  withSpanInstrumentationName(
33571
34312
  {
33572
34313
  event: {
33573
- input,
34314
+ input: processedInput,
33574
34315
  metadata
33575
34316
  },
33576
34317
  name: formatAgentSpanName(agent),
@@ -33583,7 +34324,7 @@ function startAgentStream(event, activeChildParents) {
33583
34324
  withSpanInstrumentationName(
33584
34325
  {
33585
34326
  event: {
33586
- input,
34327
+ input: processedInput,
33587
34328
  metadata
33588
34329
  },
33589
34330
  name: formatAgentSpanName(agent),
@@ -33601,23 +34342,21 @@ function startAgentStream(event, activeChildParents) {
33601
34342
  startTime: getCurrentUnixTimestamp()
33602
34343
  };
33603
34344
  }
33604
- function startMultiAgentStream(event, operation, activeChildParents) {
33605
- const orchestrator = extractOrchestrator(event);
34345
+ function startMultiAgentStream(input, orchestrator, operation, activeChildParents) {
33606
34346
  const metadata = {
33607
34347
  "strands.operation": operation,
33608
34348
  provider: "strands",
33609
- ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {},
33610
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34349
+ ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
33611
34350
  };
33612
34351
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
33613
- const input = processStrandsInputAttachments(event.arguments[0]);
34352
+ const processedInput = processStrandsInputAttachments(input);
33614
34353
  const span = parentSpan ? withCurrent(
33615
34354
  parentSpan,
33616
34355
  () => startSpan(
33617
34356
  withSpanInstrumentationName(
33618
34357
  {
33619
34358
  event: {
33620
- input,
34359
+ input: processedInput,
33621
34360
  metadata
33622
34361
  },
33623
34362
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -33630,7 +34369,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
33630
34369
  withSpanInstrumentationName(
33631
34370
  {
33632
34371
  event: {
33633
- input,
34372
+ input: processedInput,
33634
34373
  metadata
33635
34374
  },
33636
34375
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -34001,12 +34740,12 @@ function finalizeMultiAgentStream(state, activeChildParents, error, output) {
34001
34740
  });
34002
34741
  state.span.end();
34003
34742
  }
34004
- function extractAgent(event) {
34005
- const candidate = event.agent ?? event.self;
34743
+ function extractAgent(agent, self) {
34744
+ const candidate = agent ?? self;
34006
34745
  return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
34007
34746
  }
34008
- function extractOrchestrator(event) {
34009
- const candidate = event.orchestrator ?? event.self;
34747
+ function extractOrchestrator(orchestrator, self) {
34748
+ const candidate = orchestrator ?? self;
34010
34749
  return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
34011
34750
  }
34012
34751
  function extractAgentMetadata2(agent) {
@@ -34393,6 +35132,320 @@ function logInstrumentationError5(context, error) {
34393
35132
  debugLogger.debug(`${context}:`, error);
34394
35133
  }
34395
35134
 
35135
+ // src/instrumentation/plugins/voyageai-channels.ts
35136
+ var voyageAIChannels = defineChannels(
35137
+ "voyageai",
35138
+ {
35139
+ embed: channel({
35140
+ channelName: "embed",
35141
+ kind: "async"
35142
+ }),
35143
+ multimodalEmbed: channel({
35144
+ channelName: "multimodalEmbed",
35145
+ kind: "async"
35146
+ }),
35147
+ rerank: channel({
35148
+ channelName: "rerank",
35149
+ kind: "async"
35150
+ }),
35151
+ contextualizedEmbed: channel({
35152
+ channelName: "contextualizedEmbed",
35153
+ kind: "async"
35154
+ })
35155
+ },
35156
+ { instrumentationName: INSTRUMENTATION_NAMES.VOYAGEAI }
35157
+ );
35158
+
35159
+ // src/instrumentation/plugins/voyageai-plugin.ts
35160
+ var RERANK_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
35161
+ "model",
35162
+ "returnDocuments",
35163
+ "topK",
35164
+ "truncation"
35165
+ ]);
35166
+ var VoyageAIPlugin = class extends BasePlugin {
35167
+ onEnable() {
35168
+ this.unsubscribers.push(
35169
+ interceptVoyageAICall(
35170
+ voyageAIChannels.embed,
35171
+ "voyageai.embed",
35172
+ extractTextEmbeddingInput,
35173
+ summarizeEmbeddingOutput,
35174
+ extractEmbeddingUsageMetrics
35175
+ ),
35176
+ interceptVoyageAICall(
35177
+ voyageAIChannels.multimodalEmbed,
35178
+ "voyageai.multimodalEmbed",
35179
+ extractMultimodalEmbeddingInput,
35180
+ summarizeEmbeddingOutput,
35181
+ extractEmbeddingUsageMetrics
35182
+ ),
35183
+ interceptVoyageAICall(
35184
+ voyageAIChannels.rerank,
35185
+ "voyageai.rerank",
35186
+ extractRerankInput,
35187
+ summarizeRerankOutput
35188
+ ),
35189
+ interceptVoyageAICall(
35190
+ voyageAIChannels.contextualizedEmbed,
35191
+ "voyageai.contextualizedEmbed",
35192
+ extractContextualizedEmbeddingInput,
35193
+ summarizeContextualizedEmbeddingOutput,
35194
+ extractEmbeddingUsageMetrics
35195
+ )
35196
+ );
35197
+ }
35198
+ onDisable() {
35199
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
35200
+ }
35201
+ };
35202
+ function interceptVoyageAICall(channel2, name, extractInput2, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
35203
+ return channel2.intercept((target, thisArg, args) => {
35204
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
35205
+ if (isAutoInstrumentationSuppressed()) {
35206
+ return invokeTarget();
35207
+ }
35208
+ let span;
35209
+ try {
35210
+ const { input, metadata } = extractInput2(args);
35211
+ span = startSpan(
35212
+ withSpanInstrumentationName(
35213
+ {
35214
+ event: { input, metadata },
35215
+ name,
35216
+ spanAttributes: { type: "llm" /* LLM */ }
35217
+ },
35218
+ INSTRUMENTATION_NAMES.VOYAGEAI
35219
+ )
35220
+ );
35221
+ } catch (error) {
35222
+ debugLogger.error(`Error starting span for ${name}:`, error);
35223
+ return invokeTarget();
35224
+ }
35225
+ let result;
35226
+ try {
35227
+ result = withCurrent(
35228
+ span,
35229
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
35230
+ );
35231
+ } catch (error) {
35232
+ finishVoyageAISpan(span, name, () => span.log({ error }));
35233
+ throw error;
35234
+ }
35235
+ void Promise.resolve(result).then(
35236
+ (value) => finishVoyageAISpan(span, name, () => {
35237
+ const metadata = extractResponseMetadata3(value);
35238
+ span.log({
35239
+ output: extractOutput2(value),
35240
+ ...metadata ? { metadata } : {},
35241
+ metrics: extractMetrics2(value)
35242
+ });
35243
+ }),
35244
+ (error) => finishVoyageAISpan(span, name, () => span.log({ error }))
35245
+ );
35246
+ return result;
35247
+ });
35248
+ }
35249
+ function finishVoyageAISpan(span, name, log2) {
35250
+ try {
35251
+ log2();
35252
+ } catch (error) {
35253
+ debugLogger.error(`Error logging span for ${name}:`, error);
35254
+ }
35255
+ try {
35256
+ span.end();
35257
+ } catch (error) {
35258
+ debugLogger.error(`Error ending span for ${name}:`, error);
35259
+ }
35260
+ }
35261
+ function getRequestArg2(args) {
35262
+ if (Array.isArray(args)) {
35263
+ return isObject(args[0]) ? args[0] : void 0;
35264
+ }
35265
+ if (!isObject(args)) {
35266
+ return void 0;
35267
+ }
35268
+ const firstArg = Reflect.get(args, "0");
35269
+ return isObject(firstArg) ? firstArg : void 0;
35270
+ }
35271
+ function pickMetadata(request, allowlist) {
35272
+ const metadata = {};
35273
+ if (request) {
35274
+ for (const key of allowlist) {
35275
+ if (!Object.hasOwn(request, key)) {
35276
+ continue;
35277
+ }
35278
+ const value = request[key];
35279
+ if (value !== void 0) {
35280
+ metadata[key] = value;
35281
+ }
35282
+ }
35283
+ }
35284
+ return {
35285
+ ...metadata,
35286
+ provider: "voyage"
35287
+ };
35288
+ }
35289
+ function buildEmbeddingInput(inputs, request) {
35290
+ const outputDimensions = request?.outputDimension;
35291
+ return {
35292
+ inputs,
35293
+ ...typeof outputDimensions === "number" && Number.isFinite(outputDimensions) ? { output_dimensions: outputDimensions } : {}
35294
+ };
35295
+ }
35296
+ function embeddingMetadata(request) {
35297
+ return {
35298
+ ...typeof request?.model === "string" ? { model: request.model } : {},
35299
+ provider: "voyage"
35300
+ };
35301
+ }
35302
+ function extractTextEmbeddingInput(args) {
35303
+ const request = getRequestArg2(args);
35304
+ const rawInput = request?.input;
35305
+ const values = Array.isArray(rawInput) ? rawInput : [rawInput];
35306
+ return {
35307
+ input: buildEmbeddingInput(
35308
+ values.flatMap(
35309
+ (value) => typeof value === "string" ? [{ content: value }] : []
35310
+ ),
35311
+ request
35312
+ ),
35313
+ metadata: embeddingMetadata(request)
35314
+ };
35315
+ }
35316
+ function extractContextualizedEmbeddingInput(args) {
35317
+ const request = getRequestArg2(args);
35318
+ const rawInputs = request?.inputs;
35319
+ const values = Array.isArray(rawInputs) ? rawInputs.flatMap((value) => Array.isArray(value) ? value : [value]) : [];
35320
+ return {
35321
+ input: buildEmbeddingInput(
35322
+ values.flatMap(
35323
+ (value) => typeof value === "string" ? [{ content: value }] : []
35324
+ ),
35325
+ request
35326
+ ),
35327
+ metadata: embeddingMetadata(request)
35328
+ };
35329
+ }
35330
+ function extractMultimodalEmbeddingInput(args) {
35331
+ const request = getRequestArg2(args);
35332
+ const rawInputs = request?.inputs;
35333
+ const inputs = Array.isArray(rawInputs) ? rawInputs.map((rawInput) => {
35334
+ const rawContent = isObject(rawInput) ? rawInput.content : void 0;
35335
+ return {
35336
+ content: Array.isArray(rawContent) ? rawContent.flatMap(normalizeMultimodalContentPart) : []
35337
+ };
35338
+ }) : [];
35339
+ const input = buildEmbeddingInput(inputs, request);
35340
+ const processedInput = processInputAttachments(input);
35341
+ return {
35342
+ input: hasInlineEmbeddingMedia(processedInput) ? input : processedInput,
35343
+ metadata: embeddingMetadata(request)
35344
+ };
35345
+ }
35346
+ function normalizeMultimodalContentPart(part) {
35347
+ if (!isObject(part) || typeof part.type !== "string") {
35348
+ return [];
35349
+ }
35350
+ if (part.type === "text") {
35351
+ return typeof part.text === "string" ? [{ type: "text", text: part.text }] : [];
35352
+ }
35353
+ const camelCaseField = {
35354
+ image_base64: "imageBase64",
35355
+ image_url: "imageUrl",
35356
+ video_base64: "videoBase64",
35357
+ video_url: "videoUrl"
35358
+ };
35359
+ const field = camelCaseField[part.type];
35360
+ if (!field) {
35361
+ return [];
35362
+ }
35363
+ const data = typeof part[field] === "string" ? part[field] : part[part.type];
35364
+ if (typeof data !== "string") {
35365
+ return [];
35366
+ }
35367
+ return part.type.startsWith("image_") ? [{ type: "image_url", image_url: { url: data } }] : [{ type: "file", file: { file_data: data } }];
35368
+ }
35369
+ function hasInlineEmbeddingMedia(input) {
35370
+ return input.inputs.some(
35371
+ ({ content }) => Array.isArray(content) ? content.some((part) => {
35372
+ const value = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
35373
+ return typeof value === "string" && value.startsWith("data:");
35374
+ }) : false
35375
+ );
35376
+ }
35377
+ function extractRerankInput(args) {
35378
+ const request = getRequestArg2(args);
35379
+ const documents = request?.documents;
35380
+ return {
35381
+ input: {
35382
+ documents,
35383
+ query: request?.query
35384
+ },
35385
+ metadata: {
35386
+ ...pickMetadata(request, RERANK_METADATA_ALLOWLIST),
35387
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
35388
+ }
35389
+ };
35390
+ }
35391
+ function extractResponseMetadata3(result) {
35392
+ if (!isObject(result)) {
35393
+ return void 0;
35394
+ }
35395
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35396
+ const model = typeof result.model === "string" ? result.model : typeof rawResponse?.model === "string" ? rawResponse.model : void 0;
35397
+ return model ? { model } : void 0;
35398
+ }
35399
+ function summarizeEmbeddingOutput(result) {
35400
+ return {
35401
+ count: isObject(result) && Array.isArray(result.data) ? result.data.length : 0
35402
+ };
35403
+ }
35404
+ function summarizeRerankOutput(result) {
35405
+ if (!isObject(result) || !Array.isArray(result.data)) {
35406
+ return void 0;
35407
+ }
35408
+ return result.data.slice(0, 100).map((item) => ({
35409
+ index: isObject(item) ? item.index : void 0,
35410
+ relevance_score: isObject(item) ? (typeof item.relevanceScore === "number" ? item.relevanceScore : item.relevance_score) ?? null : null
35411
+ }));
35412
+ }
35413
+ function summarizeContextualizedEmbeddingOutput(result) {
35414
+ if (!isObject(result)) {
35415
+ return { count: 0 };
35416
+ }
35417
+ if (Array.isArray(result.results)) {
35418
+ return {
35419
+ count: result.results.reduce(
35420
+ (count, item) => count + (isObject(item) && Array.isArray(item.embeddings) ? item.embeddings.length : 0),
35421
+ 0
35422
+ )
35423
+ };
35424
+ }
35425
+ if (!Array.isArray(result.data)) {
35426
+ return { count: 0 };
35427
+ }
35428
+ return {
35429
+ count: result.data.reduce(
35430
+ (count, item) => count + (isObject(item) && Array.isArray(item.data) ? item.data.length : 0),
35431
+ 0
35432
+ )
35433
+ };
35434
+ }
35435
+ function extractEmbeddingUsageMetrics(result) {
35436
+ const metrics = extractUsageMetrics3(result);
35437
+ return typeof metrics.tokens === "number" ? { prompt_tokens: metrics.tokens, tokens: metrics.tokens } : {};
35438
+ }
35439
+ function extractUsageMetrics3(result) {
35440
+ if (!isObject(result)) {
35441
+ return {};
35442
+ }
35443
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35444
+ const usage = isObject(result.usage) ? result.usage : isObject(rawResponse?.usage) ? rawResponse.usage : void 0;
35445
+ const tokens = typeof result.totalTokens === "number" ? result.totalTokens : usage?.totalTokens ?? usage?.total_tokens;
35446
+ return typeof tokens === "number" && Number.isFinite(tokens) && tokens >= 0 ? { tokens } : {};
35447
+ }
35448
+
34396
35449
  // src/instrumentation/plugins/cloudflare-ai-chat-channels.ts
34397
35450
  var cloudflareAIChatChannels = defineChannels(
34398
35451
  "@cloudflare/ai-chat",
@@ -34948,6 +36001,7 @@ var BraintrustPlugin = class extends BasePlugin {
34948
36001
  langSmithPlugin = null;
34949
36002
  piCodingAgentPlugin = null;
34950
36003
  strandsAgentSDKPlugin = null;
36004
+ voyageAIPlugin = null;
34951
36005
  cloudflareAIChatPlugin = null;
34952
36006
  cloudflareAgentsPlugin = null;
34953
36007
  constructor(config = {}) {
@@ -35022,6 +36076,10 @@ var BraintrustPlugin = class extends BasePlugin {
35022
36076
  this.coherePlugin = new CoherePlugin();
35023
36077
  this.coherePlugin.enable();
35024
36078
  }
36079
+ if (integrations.voyageai !== false) {
36080
+ this.voyageAIPlugin = new VoyageAIPlugin();
36081
+ this.voyageAIPlugin.enable();
36082
+ }
35025
36083
  if (integrations.groq !== false) {
35026
36084
  this.groqPlugin = new GroqPlugin();
35027
36085
  this.groqPlugin.enable();
@@ -35138,6 +36196,10 @@ var BraintrustPlugin = class extends BasePlugin {
35138
36196
  this.coherePlugin.disable();
35139
36197
  this.coherePlugin = null;
35140
36198
  }
36199
+ if (this.voyageAIPlugin) {
36200
+ this.voyageAIPlugin.disable();
36201
+ this.voyageAIPlugin = null;
36202
+ }
35141
36203
  if (this.groqPlugin) {
35142
36204
  this.groqPlugin.disable();
35143
36205
  this.groqPlugin = null;
@@ -35257,7 +36319,10 @@ var envIntegrationAliases = {
35257
36319
  "langchain-js": "langchain",
35258
36320
  "@langchain": "langchain",
35259
36321
  langgraph: "langgraph",
35260
- langsmith: "langsmith"
36322
+ langsmith: "langsmith",
36323
+ voyage: "voyageai",
36324
+ "voyage-ai": "voyageai",
36325
+ voyageai: "voyageai"
35261
36326
  };
35262
36327
  function getDefaultInstrumentationIntegrations() {
35263
36328
  return {
@@ -35292,6 +36357,7 @@ function getDefaultInstrumentationIntegrations() {
35292
36357
  langchain: true,
35293
36358
  langgraph: true,
35294
36359
  langsmith: true,
36360
+ voyageai: true,
35295
36361
  piCodingAgent: true,
35296
36362
  strandsAgentSDK: true,
35297
36363
  cloudflareAgents: true
@@ -35712,9 +36778,9 @@ function configureNode() {
35712
36778
  return value;
35713
36779
  }
35714
36780
  const envPaths = [];
35715
- for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
35716
- envPaths.push(path.join(dir2, ".env.braintrust"));
35717
- if (path.dirname(dir2) === dir2) {
36781
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path2.dirname(dir2), depth++) {
36782
+ envPaths.push(path2.join(dir2, ".env.braintrust"));
36783
+ if (path2.dirname(dir2) === dir2) {
35718
36784
  break;
35719
36785
  }
35720
36786
  }
@@ -35756,10 +36822,10 @@ function configureNode() {
35756
36822
  isomorph_default.processOn = (event, handler) => {
35757
36823
  process.on(event, handler);
35758
36824
  };
35759
- isomorph_default.basename = path.basename;
36825
+ isomorph_default.basename = path2.basename;
35760
36826
  isomorph_default.writeln = (text) => process.stdout.write(text + "\n");
35761
- isomorph_default.pathJoin = path.join;
35762
- isomorph_default.pathDirname = path.dirname;
36827
+ isomorph_default.pathJoin = path2.join;
36828
+ isomorph_default.pathDirname = path2.dirname;
35763
36829
  isomorph_default.mkdir = fs.mkdir;
35764
36830
  isomorph_default.writeFile = fs.writeFile;
35765
36831
  isomorph_default.readFile = fs.readFile;
@@ -35794,8 +36860,8 @@ function configureNode() {
35794
36860
  registry.enable();
35795
36861
  }
35796
36862
  function getNearestBraintrustEnvValue(name) {
35797
- for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
35798
- const envPath = path.join(dir2, ".env.braintrust");
36863
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path2.dirname(dir2), depth++) {
36864
+ const envPath = path2.join(dir2, ".env.braintrust");
35799
36865
  try {
35800
36866
  const parsed = dotenv.parse(fsSync.readFileSync(envPath, "utf8"));
35801
36867
  const value = parsed[name];
@@ -35805,7 +36871,7 @@ function getNearestBraintrustEnvValue(name) {
35805
36871
  return void 0;
35806
36872
  }
35807
36873
  }
35808
- if (path.dirname(dir2) === dir2) {
36874
+ if (path2.dirname(dir2) === dir2) {
35809
36875
  break;
35810
36876
  }
35811
36877
  }
@@ -35887,7 +36953,7 @@ function isAsync(fn) {
35887
36953
  function isAsyncGenerator2(fn) {
35888
36954
  return fn[Symbol.toStringTag] === "AsyncGenerator";
35889
36955
  }
35890
- function isAsyncIterable6(obj) {
36956
+ function isAsyncIterable5(obj) {
35891
36957
  return typeof obj[Symbol.asyncIterator] === "function";
35892
36958
  }
35893
36959
  function wrapAsync(asyncFn) {
@@ -36059,7 +37125,7 @@ var eachOfLimit$2 = (limit) => {
36059
37125
  if (isAsyncGenerator2(obj)) {
36060
37126
  return asyncEachOfLimit(obj, limit, iteratee, callback);
36061
37127
  }
36062
- if (isAsyncIterable6(obj)) {
37128
+ if (isAsyncIterable5(obj)) {
36063
37129
  return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback);
36064
37130
  }
36065
37131
  var nextElem = createIterator(obj);
@@ -37371,8 +38437,8 @@ function validateParametersWithJsonSchema(parameters, schema) {
37371
38437
  const validate = ajv.compile(schema);
37372
38438
  if (!validate(parameters)) {
37373
38439
  const errorMessages = validate.errors?.map((err) => {
37374
- const path2 = err.instancePath || "root";
37375
- return `${path2}: ${err.message}`;
38440
+ const path3 = err.instancePath || "root";
38441
+ return `${path3}: ${err.message}`;
37376
38442
  }).join(", ");
37377
38443
  throw Error(`Invalid parameters: ${errorMessages}`);
37378
38444
  }
@@ -37401,6 +38467,9 @@ function rehydrateRemoteParameters(parameters, schema) {
37401
38467
  }
37402
38468
 
37403
38469
  // src/framework.ts
38470
+ function BaseExperiment(options = {}) {
38471
+ return { _type: "BaseExperiment", ...options };
38472
+ }
37404
38473
  var EvalResultWithSummary = class {
37405
38474
  constructor(summary, results) {
37406
38475
  this.summary = summary;
@@ -37461,6 +38530,26 @@ async function getExperimentParametersRef(parameters) {
37461
38530
  version: resolvedParameters.version
37462
38531
  };
37463
38532
  }
38533
+ async function _internalInitEvaluatorExperiment(projectName, evaluator, data, options = {}) {
38534
+ if (options.disabled) return null;
38535
+ const { baseExperiment } = callEvaluatorData(data);
38536
+ const parameters = await getExperimentParametersRef(evaluator.parameters);
38537
+ return initExperiment(evaluator.state, {
38538
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: projectName },
38539
+ experiment: options.experimentName ?? evaluator.experimentName,
38540
+ description: evaluator.description,
38541
+ metadata: evaluator.metadata,
38542
+ tags: evaluator.tags,
38543
+ isPublic: evaluator.isPublic,
38544
+ update: options.update ?? evaluator.update,
38545
+ baseExperiment: evaluator.baseExperimentName ?? baseExperiment,
38546
+ baseExperimentId: evaluator.baseExperimentId,
38547
+ gitMetadataSettings: evaluator.gitMetadataSettings,
38548
+ repoInfo: evaluator.repoInfo,
38549
+ dataset: Dataset2.isDataset(data) ? data : void 0,
38550
+ parameters
38551
+ });
38552
+ }
37464
38553
  function callEvaluatorData(data) {
37465
38554
  const dataResult = typeof data === "function" ? data() : data;
37466
38555
  let baseExperiment = void 0;
@@ -37472,12 +38561,54 @@ function callEvaluatorData(data) {
37472
38561
  baseExperiment
37473
38562
  };
37474
38563
  }
37475
- function isAsyncIterable7(value) {
38564
+ function isAsyncIterable6(value) {
37476
38565
  return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
37477
38566
  }
37478
38567
  function isIterable(value) {
37479
38568
  return typeof value === "object" && value !== null && Symbol.iterator in value && typeof value[Symbol.iterator] === "function";
37480
38569
  }
38570
+ async function _internalResolveEvaluatorData(evaluator, experiment) {
38571
+ if (typeof evaluator.data === "string") {
38572
+ throw new Error("Unimplemented: string data paths");
38573
+ }
38574
+ let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
38575
+ if ("_type" in dataResult) {
38576
+ if (dataResult._type !== "BaseExperiment") {
38577
+ throw new Error("Invalid _type");
38578
+ }
38579
+ if (!experiment) {
38580
+ throw new Error(
38581
+ "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
38582
+ );
38583
+ }
38584
+ let name = dataResult.name;
38585
+ if (isEmpty2(name)) {
38586
+ const baseExperiment = await experiment.fetchBaseExperiment();
38587
+ if (!baseExperiment) {
38588
+ throw new Error("BaseExperiment() failed to fetch base experiment");
38589
+ }
38590
+ name = baseExperiment.name;
38591
+ }
38592
+ dataResult = initExperiment(evaluator.state, {
38593
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
38594
+ experiment: name,
38595
+ open: true
38596
+ }).asDataset();
38597
+ }
38598
+ const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
38599
+ if (isAsyncIterable6(resolvedDataResult)) {
38600
+ return resolvedDataResult;
38601
+ }
38602
+ if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
38603
+ const iterable = resolvedDataResult;
38604
+ return (async function* () {
38605
+ for (const datum of iterable) yield datum;
38606
+ })();
38607
+ }
38608
+ throw new Error(
38609
+ "Evaluator data must be an array, iterable, or async iterable"
38610
+ );
38611
+ }
37481
38612
  globalThis._evals = {
37482
38613
  functions: [],
37483
38614
  prompts: [],
@@ -37524,25 +38655,13 @@ async function Eval(name, evaluator, reporterOrOpts) {
37524
38655
  }
37525
38656
  const resolvedReporter = options.reporter || defaultReporter;
37526
38657
  try {
37527
- const { data, baseExperiment: defaultBaseExperiment } = callEvaluatorData(
37528
- evaluator.data
38658
+ const { data } = callEvaluatorData(evaluator.data);
38659
+ const experiment = await _internalInitEvaluatorExperiment(
38660
+ name,
38661
+ evaluator,
38662
+ data,
38663
+ { disabled: Boolean(options.parent || options.noSendLogs) }
37529
38664
  );
37530
- const parameters = await getExperimentParametersRef(evaluator.parameters);
37531
- const experiment = options.parent || options.noSendLogs ? null : initExperiment(evaluator.state, {
37532
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: name },
37533
- experiment: evaluator.experimentName,
37534
- description: evaluator.description,
37535
- metadata: evaluator.metadata,
37536
- tags: evaluator.tags,
37537
- isPublic: evaluator.isPublic,
37538
- update: evaluator.update,
37539
- baseExperiment: evaluator.baseExperimentName ?? defaultBaseExperiment,
37540
- baseExperimentId: evaluator.baseExperimentId,
37541
- gitMetadataSettings: evaluator.gitMetadataSettings,
37542
- repoInfo: evaluator.repoInfo,
37543
- dataset: Dataset2.isDataset(data) ? data : void 0,
37544
- parameters
37545
- });
37546
38665
  if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
37547
38666
  await experiment._waitForId();
37548
38667
  }
@@ -37611,8 +38730,8 @@ function serializeJSONWithPlainString(v) {
37611
38730
  }
37612
38731
  }
37613
38732
  function evaluateFilter(object, filter2) {
37614
- const { path: path2, pattern } = filter2;
37615
- const key = path2.reduce(
38733
+ const { path: path3, pattern } = filter2;
38734
+ const key = path3.reduce(
37616
38735
  (acc, p) => typeof acc === "object" && acc !== null ? (
37617
38736
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37618
38737
  acc[p]
@@ -37630,19 +38749,74 @@ function scorerName(scorer, scorer_idx) {
37630
38749
  function classifierName(classifier, classifier_idx) {
37631
38750
  return classifier.name || `classifier_${classifier_idx}`;
37632
38751
  }
38752
+ async function _internalRunEvaluatorTask(task, datum, trialIndex, parameters, span, reportProgress = () => void 0) {
38753
+ const metadata = {
38754
+ ..."metadata" in datum ? datum.metadata : {}
38755
+ };
38756
+ const hooks = {
38757
+ meta(value) {
38758
+ Object.assign(metadata, value);
38759
+ },
38760
+ metadata,
38761
+ expected: "expected" in datum ? datum.expected : void 0,
38762
+ span,
38763
+ parameters,
38764
+ reportProgress,
38765
+ trialIndex,
38766
+ tags: [...datum.tags ?? []]
38767
+ };
38768
+ const output = await task(datum.input, hooks);
38769
+ span.log({ output });
38770
+ return {
38771
+ output,
38772
+ metadata: hooks.metadata,
38773
+ tags: hooks.tags ?? []
38774
+ };
38775
+ }
37633
38776
  function buildSpanMetadata(results) {
37634
- return results.length === 1 ? results[0].metadata : results.reduce(
37635
- (prev, s) => mergeDicts(prev, { [s.name]: s.metadata }),
37636
- {}
38777
+ return results.length === 1 ? results[0].metadata : Object.fromEntries(
38778
+ results.map((result) => [result.name, result.metadata])
37637
38779
  );
37638
38780
  }
37639
38781
  function buildSpanScores(results) {
37640
- const scoresRecord = results.reduce(
37641
- (prev, s) => mergeDicts(prev, { [s.name]: s.score }),
37642
- {}
38782
+ const scoresRecord = Object.fromEntries(
38783
+ results.map((result) => [result.name, result.score])
37643
38784
  );
37644
38785
  return { resultMetadata: buildSpanMetadata(results), scoresRecord };
37645
38786
  }
38787
+ function _internalPrepareEvaluatorScore(scoreValue, name) {
38788
+ if (scoreValue === null) return { results: null };
38789
+ if (Array.isArray(scoreValue)) {
38790
+ for (const score of scoreValue) {
38791
+ if (!(typeof score === "object" && !isEmpty2(score))) {
38792
+ throw new Error(
38793
+ `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
38794
+ );
38795
+ }
38796
+ }
38797
+ }
38798
+ let results;
38799
+ if (Array.isArray(scoreValue)) {
38800
+ results = scoreValue;
38801
+ } else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
38802
+ results = [scoreValue];
38803
+ } else {
38804
+ results = [{ name, score: scoreValue }];
38805
+ }
38806
+ const { resultMetadata, scoresRecord } = buildSpanScores(results);
38807
+ const fields = (score) => {
38808
+ const { metadata: _metadata, name: _name, ...rest } = score;
38809
+ return rest;
38810
+ };
38811
+ return {
38812
+ results,
38813
+ output: results.length === 1 ? fields(results[0]) : Object.fromEntries(
38814
+ results.map((score) => [score.name ?? name, fields(score)])
38815
+ ),
38816
+ metadata: resultMetadata,
38817
+ scores: scoresRecord
38818
+ };
38819
+ }
37646
38820
  async function runInScorerSpan(rootSpan, spanName, spanType, propagatedEvent, eventInput, fn) {
37647
38821
  try {
37648
38822
  const value = await rootSpan.traced(fn, {
@@ -37687,6 +38861,27 @@ function toClassificationItem(c) {
37687
38861
  ...c.metadata !== void 0 ? { metadata: c.metadata } : {}
37688
38862
  };
37689
38863
  }
38864
+ function _internalPrepareEvaluatorClassification(value, name) {
38865
+ if (value === null) return { results: null };
38866
+ const results = (Array.isArray(value) ? value : [value]).map(
38867
+ (result) => validateClassificationResult(result, name)
38868
+ );
38869
+ const classifications = /* @__PURE__ */ Object.create(null);
38870
+ for (const result of results) {
38871
+ (classifications[result.name] ??= []).push(toClassificationItem(result));
38872
+ }
38873
+ return {
38874
+ results,
38875
+ output: results.length === 1 ? toClassificationItem(results[0]) : Object.fromEntries(
38876
+ results.map((result) => [
38877
+ result.name,
38878
+ toClassificationItem(result)
38879
+ ])
38880
+ ),
38881
+ metadata: buildSpanMetadata(results),
38882
+ classifications
38883
+ };
38884
+ }
37690
38885
  function logScoringFailures(kind, failures, metadata, rootSpan, state) {
37691
38886
  if (!failures.length) return [];
37692
38887
  const errorMap = Object.fromEntries(
@@ -37725,54 +38920,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
37725
38920
  (evaluator.state ?? _internalGetGlobalState())?.spanCache?.start();
37726
38921
  }
37727
38922
  try {
37728
- if (typeof evaluator.data === "string") {
37729
- throw new Error("Unimplemented: string data paths");
37730
- }
37731
- let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
37732
38923
  parameters = await validateParameters(
37733
38924
  parameters ?? {},
37734
38925
  evaluator.parameters
37735
38926
  );
37736
- if ("_type" in dataResult) {
37737
- if (dataResult._type !== "BaseExperiment") {
37738
- throw new Error("Invalid _type");
37739
- }
37740
- if (!experiment) {
37741
- throw new Error(
37742
- "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
37743
- );
37744
- }
37745
- let name = dataResult.name;
37746
- if (isEmpty2(name)) {
37747
- const baseExperiment = await experiment.fetchBaseExperiment();
37748
- if (!baseExperiment) {
37749
- throw new Error("BaseExperiment() failed to fetch base experiment");
37750
- }
37751
- name = baseExperiment.name;
37752
- }
37753
- dataResult = initExperiment(evaluator.state, {
37754
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
37755
- experiment: name,
37756
- open: true
37757
- }).asDataset();
37758
- }
37759
- const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
37760
- const dataIterable = (() => {
37761
- if (isAsyncIterable7(resolvedDataResult)) {
37762
- return resolvedDataResult;
37763
- }
37764
- if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
37765
- const iterable = resolvedDataResult;
37766
- return (async function* () {
37767
- for (const datum of iterable) {
37768
- yield datum;
37769
- }
37770
- })();
37771
- }
37772
- throw new Error(
37773
- "Evaluator data must be an array, iterable, or async iterable"
37774
- );
37775
- })();
38927
+ const dataIterable = await _internalResolveEvaluatorData(
38928
+ evaluator,
38929
+ experiment
38930
+ );
37776
38931
  progressReporter.start(evaluator.evalName, 0);
37777
38932
  const experimentIdPromise = experiment ? (async () => {
37778
38933
  try {
@@ -37841,57 +38996,45 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
37841
38996
  ensureSpansFlushed,
37842
38997
  state
37843
38998
  }) : void 0;
37844
- let metadata = {
37845
- ..."metadata" in datum ? datum.metadata : {}
37846
- };
38999
+ let metadata = {};
37847
39000
  const expected = "expected" in datum ? datum.expected : void 0;
37848
39001
  let output = void 0;
37849
39002
  let error = void 0;
37850
- let tags = [...datum.tags ?? []];
37851
- const scores = {};
37852
- const classifications = {};
39003
+ let tags = [];
39004
+ const scores = /* @__PURE__ */ Object.create(null);
39005
+ const classifications = /* @__PURE__ */ Object.create(null);
37853
39006
  const scorerNames = (evaluator.scores ?? []).map(scorerName);
37854
39007
  const classifierNames = (evaluator.classifiers ?? []).map(
37855
39008
  classifierName
37856
39009
  );
37857
39010
  let unhandledScores = scorerNames;
37858
39011
  try {
37859
- const meta = (o) => metadata = { ...metadata, ...o };
37860
- await rootSpan.traced(
37861
- async (span) => {
37862
- const hooksForTask = {
37863
- meta,
37864
- metadata,
37865
- expected,
37866
- span,
37867
- parameters: parameters ?? {},
37868
- reportProgress: (event) => {
37869
- stream?.({
37870
- ...event,
37871
- id: rootSpan.id,
37872
- origin: baseEvent.event?.origin,
37873
- name: evaluator.evalName,
37874
- object_type: "task"
37875
- });
37876
- },
37877
- trialIndex,
37878
- tags
37879
- };
37880
- const outputResult = evaluator.task(datum.input, hooksForTask);
37881
- if (outputResult instanceof Promise) {
37882
- output = await outputResult;
37883
- } else {
37884
- output = outputResult;
39012
+ const taskResult = await rootSpan.traced(
39013
+ (span) => _internalRunEvaluatorTask(
39014
+ evaluator.task,
39015
+ datum,
39016
+ trialIndex,
39017
+ parameters ?? {},
39018
+ span,
39019
+ (event) => {
39020
+ stream?.({
39021
+ ...event,
39022
+ id: rootSpan.id,
39023
+ origin: baseEvent.event?.origin,
39024
+ name: evaluator.evalName,
39025
+ object_type: "task"
39026
+ });
37885
39027
  }
37886
- tags = hooksForTask.tags ?? [];
37887
- span.log({ output });
37888
- },
39028
+ ),
37889
39029
  {
37890
39030
  name: "task",
37891
39031
  spanAttributes: { type: "task" /* TASK */ },
37892
39032
  event: { input: datum.input }
37893
39033
  }
37894
39034
  );
39035
+ output = taskResult.output;
39036
+ metadata = taskResult.metadata;
39037
+ tags = taskResult.tags;
37895
39038
  if (tags.length) {
37896
39039
  rootSpan.log({ output, metadata, expected, tags });
37897
39040
  } else {
@@ -37901,20 +39044,18 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
37901
39044
  await rootSpan.flush();
37902
39045
  }
37903
39046
  const scoringArgs = {
39047
+ id: datum.id,
37904
39048
  input: datum.input,
37905
39049
  expected: "expected" in datum ? datum.expected : void 0,
37906
39050
  metadata,
37907
39051
  output,
39052
+ tags,
37908
39053
  trace
37909
39054
  };
37910
39055
  const { trace: _trace, ...scoringArgsForLogging } = scoringArgs;
37911
39056
  const propagatedEvent = makeScorerPropagatedEvent(
37912
39057
  await rootSpan.export()
37913
39058
  );
37914
- const getOtherFields = (s) => {
37915
- const { metadata: _metadata, name: _name, ...rest } = s;
37916
- return rest;
37917
- };
37918
39059
  const [scoreResults, classificationResults] = await Promise.all([
37919
39060
  Promise.all(
37920
39061
  (evaluator.scores ?? []).map(
@@ -37928,35 +39069,17 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
37928
39069
  const scoreValue = await Promise.resolve(
37929
39070
  score(scoringArgs)
37930
39071
  );
37931
- if (scoreValue === null) return null;
37932
- if (Array.isArray(scoreValue)) {
37933
- for (const s of scoreValue) {
37934
- if (!(typeof s === "object" && !isEmpty2(s))) {
37935
- throw new Error(
37936
- `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(s)}`
37937
- );
37938
- }
37939
- }
37940
- }
37941
- const results = Array.isArray(scoreValue) ? scoreValue : typeof scoreValue === "object" && !isEmpty2(scoreValue) ? [scoreValue] : [
37942
- {
37943
- name: scorerNames[score_idx],
37944
- score: scoreValue
37945
- }
37946
- ];
37947
- const { resultMetadata, scoresRecord } = buildSpanScores(results);
37948
- const resultOutput = results.length === 1 ? getOtherFields(results[0]) : results.reduce(
37949
- (prev, s) => mergeDicts(prev, {
37950
- [s.name]: getOtherFields(s)
37951
- }),
37952
- {}
39072
+ const prepared = _internalPrepareEvaluatorScore(
39073
+ scoreValue,
39074
+ scorerNames[score_idx]
37953
39075
  );
39076
+ if (prepared.results === null) return null;
37954
39077
  span.log({
37955
- output: resultOutput,
37956
- metadata: resultMetadata,
37957
- scores: scoresRecord
39078
+ output: prepared.output,
39079
+ metadata: prepared.metadata,
39080
+ scores: prepared.scores
37958
39081
  });
37959
- return results;
39082
+ return prepared.results;
37960
39083
  }
37961
39084
  )
37962
39085
  )
@@ -37973,24 +39096,16 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
37973
39096
  const classifierValue = await Promise.resolve(
37974
39097
  classifier(scoringArgs)
37975
39098
  );
37976
- if (classifierValue === null) return null;
37977
- const rawResults = (Array.isArray(classifierValue) ? classifierValue : [classifierValue]).map(
37978
- (result) => validateClassificationResult(
37979
- result,
37980
- classifierNames[idx]
37981
- )
37982
- );
37983
- const resultOutput = rawResults.length === 1 ? toClassificationItem(rawResults[0]) : rawResults.reduce(
37984
- (prev, r) => mergeDicts(prev, {
37985
- [r.name]: toClassificationItem(r)
37986
- }),
37987
- {}
39099
+ const prepared = _internalPrepareEvaluatorClassification(
39100
+ classifierValue,
39101
+ classifierNames[idx]
37988
39102
  );
39103
+ if (prepared.results === null) return null;
37989
39104
  span.log({
37990
- output: resultOutput,
37991
- metadata: buildSpanMetadata(rawResults)
39105
+ output: prepared.output,
39106
+ metadata: prepared.metadata
37992
39107
  });
37993
- return rawResults;
39108
+ return prepared.results;
37994
39109
  }
37995
39110
  )
37996
39111
  )
@@ -38219,7 +39334,7 @@ function accumulateScores(accumulator, scores) {
38219
39334
  }
38220
39335
  }
38221
39336
  function ensureScoreAccumulator(results) {
38222
- const accumulator = {};
39337
+ const accumulator = /* @__PURE__ */ Object.create(null);
38223
39338
  for (const result of results) {
38224
39339
  accumulateScores(accumulator, result.scores);
38225
39340
  }
@@ -39381,39 +40496,19 @@ async function getDataset(state, data) {
39381
40496
  _internal_btql: data._internal_btql ?? void 0
39382
40497
  });
39383
40498
  } else if ("dataset_id" in data) {
39384
- const datasetInfo = await getDatasetById({
39385
- state,
39386
- datasetId: data.dataset_id
39387
- });
39388
40499
  return initDataset({
39389
40500
  state,
39390
- projectId: datasetInfo.projectId,
39391
- dataset: datasetInfo.dataset,
40501
+ datasetId: data.dataset_id,
39392
40502
  version: data.dataset_version ?? void 0,
39393
40503
  environment: data.dataset_environment ?? void 0,
39394
40504
  _internal_btql: data._internal_btql ?? void 0
39395
40505
  });
40506
+ } else if ("experiment_name" in data) {
40507
+ return BaseExperiment({ name: data.experiment_name });
39396
40508
  } else {
39397
40509
  return data.data;
39398
40510
  }
39399
40511
  }
39400
- var datasetFetchSchema = z14.object({
39401
- project_id: z14.string(),
39402
- name: z14.string()
39403
- });
39404
- async function getDatasetById({
39405
- state,
39406
- datasetId
39407
- }) {
39408
- const dataset = await state.appConn().post_json("api/dataset/get", {
39409
- id: datasetId
39410
- });
39411
- const parsed = z14.array(datasetFetchSchema).parse(dataset);
39412
- if (parsed.length === 0) {
39413
- throw new Error(`Dataset '${datasetId}' not found`);
39414
- }
39415
- return { projectId: parsed[0].project_id, dataset: parsed[0].name };
39416
- }
39417
40512
  function makeScorer(state, name, score, projectId) {
39418
40513
  const ret = async (input) => {
39419
40514
  const request = {