braintrust 3.27.0 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dev/dist/index.d.mts +519 -186
  2. package/dev/dist/index.d.ts +519 -186
  3. package/dev/dist/index.js +1837 -1009
  4. package/dev/dist/index.mjs +1172 -344
  5. package/dist/apply-auto-instrumentation.js +262 -210
  6. package/dist/apply-auto-instrumentation.mjs +54 -2
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +81 -2
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +81 -2
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +81 -2
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +81 -2
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +81 -2
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +81 -2
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  18. package/dist/auto-instrumentations/{chunk-XEYKUBLY.mjs → chunk-26PKVUKB.mjs} +80 -2
  19. package/dist/auto-instrumentations/{chunk-BW33ULMW.mjs → chunk-HD35AM3M.mjs} +1 -1
  20. package/dist/auto-instrumentations/{chunk-ZNHTSSGI.mjs → chunk-NP7V4XB2.mjs} +2 -1
  21. package/dist/auto-instrumentations/hook.mjs +236 -30
  22. package/dist/auto-instrumentations/index.cjs +2 -1
  23. package/dist/auto-instrumentations/index.mjs +1 -1
  24. package/dist/browser.d.mts +628 -53
  25. package/dist/browser.d.ts +628 -53
  26. package/dist/browser.js +2301 -284
  27. package/dist/browser.mjs +2301 -284
  28. package/dist/{chunk-MF7NU6BT.js → chunk-BBE7SNRV.js} +34 -4
  29. package/dist/{chunk-QRHGVBKU.js → chunk-OBBWQW6K.js} +1799 -1023
  30. package/dist/{chunk-YKD22IMR.mjs → chunk-UPFNQCGB.mjs} +966 -190
  31. package/dist/{chunk-CZM5JIQL.mjs → chunk-ZHUHZWFY.mjs} +33 -3
  32. package/dist/cli.js +1224 -398
  33. package/dist/edge-light.d.mts +1 -1
  34. package/dist/edge-light.d.ts +1 -1
  35. package/dist/edge-light.js +2301 -284
  36. package/dist/edge-light.mjs +2301 -284
  37. package/dist/index.d.mts +1212 -637
  38. package/dist/index.d.ts +1212 -637
  39. package/dist/index.js +1880 -590
  40. package/dist/index.mjs +1450 -160
  41. package/dist/instrumentation/index.d.mts +190 -6
  42. package/dist/instrumentation/index.d.ts +190 -6
  43. package/dist/instrumentation/index.js +823 -116
  44. package/dist/instrumentation/index.mjs +823 -116
  45. package/dist/vitest-evals-reporter.js +16 -16
  46. package/dist/vitest-evals-reporter.mjs +2 -2
  47. package/dist/workerd.d.mts +1 -1
  48. package/dist/workerd.d.ts +1 -1
  49. package/dist/workerd.js +2301 -284
  50. package/dist/workerd.mjs +2301 -284
  51. package/package.json +2 -3
  52. package/util/dist/index.d.mts +1545 -100
  53. package/util/dist/index.d.ts +1545 -100
package/dist/browser.mjs CHANGED
@@ -1567,12 +1567,12 @@ function base64ToUint8Array(base64) {
1567
1567
  return uint8Array;
1568
1568
  }
1569
1569
  function uint8ArrayToString(uint8Array) {
1570
- const decoder = new TextDecoder("utf-8");
1571
- return decoder.decode(uint8Array);
1570
+ const decoder2 = new TextDecoder("utf-8");
1571
+ return decoder2.decode(uint8Array);
1572
1572
  }
1573
1573
  function stringToUint8Array(str) {
1574
- const encoder = new TextEncoder();
1575
- return encoder.encode(str);
1574
+ const encoder2 = new TextEncoder();
1575
+ return encoder2.encode(str);
1576
1576
  }
1577
1577
 
1578
1578
  // util/span_identifier_v3.ts
@@ -2476,7 +2476,8 @@ var AclObjectType = z6.union([
2476
2476
  "org_member",
2477
2477
  "project_log",
2478
2478
  "org_project",
2479
- "org_audit_logs"
2479
+ "org_audit_logs",
2480
+ "project_group"
2480
2481
  ]),
2481
2482
  z6.null()
2482
2483
  ]);
@@ -2605,7 +2606,8 @@ var AsyncScoringState = z6.union([
2605
2606
  token: z6.string(),
2606
2607
  function_ids: z6.array(z6.unknown()),
2607
2608
  skip_logging: z6.union([z6.boolean(), z6.null()]).optional(),
2608
- triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional()
2609
+ triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional(),
2610
+ last_triggered_xact_id: z6.union([z6.string(), z6.number(), z6.null()]).optional()
2609
2611
  }),
2610
2612
  z6.object({ status: z6.literal("disabled") }),
2611
2613
  z6.null(),
@@ -2674,7 +2676,7 @@ var FunctionTypeEnum = z6.enum([
2674
2676
  "parameters",
2675
2677
  "sandbox"
2676
2678
  ]);
2677
- var NullableSavedFunctionId = z6.union([
2679
+ var FacetPreprocessorId = z6.union([
2678
2680
  z6.object({
2679
2681
  type: z6.literal("function"),
2680
2682
  id: z6.string(),
@@ -2685,10 +2687,23 @@ var NullableSavedFunctionId = z6.union([
2685
2687
  name: z6.string(),
2686
2688
  function_type: FunctionTypeEnum.optional().default("scorer")
2687
2689
  }),
2690
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
2688
2691
  z6.null()
2689
2692
  ]);
2693
+ var SavedFunctionId = z6.union([
2694
+ z6.object({
2695
+ type: z6.literal("function"),
2696
+ id: z6.string(),
2697
+ version: z6.string().optional()
2698
+ }),
2699
+ z6.object({
2700
+ type: z6.literal("global"),
2701
+ name: z6.string(),
2702
+ function_type: FunctionTypeEnum.optional().default("scorer")
2703
+ })
2704
+ ]);
2690
2705
  var TopicMapGenerationSettings = z6.object({
2691
- algorithm: z6.enum(["hdbscan", "kmeans"]),
2706
+ algorithm: z6.enum(["hdbscan", "kmeans", "community"]),
2692
2707
  dimension_reduction: z6.enum(["umap", "pca", "none"]),
2693
2708
  sample_size: z6.number().int().gt(0).optional(),
2694
2709
  n_clusters: z6.number().int().gt(0).optional(),
@@ -2700,6 +2715,7 @@ var TopicMapGenerationSettings = z6.object({
2700
2715
  var TopicMapData = z6.object({
2701
2716
  type: z6.literal("topic_map"),
2702
2717
  source_facet: z6.string(),
2718
+ source_facet_function: SavedFunctionId.and(z6.unknown()).optional(),
2703
2719
  embedding_model: z6.string(),
2704
2720
  bundle_key: z6.string().optional(),
2705
2721
  report_key: z6.string().optional(),
@@ -2713,7 +2729,7 @@ var TopicMapData = z6.object({
2713
2729
  });
2714
2730
  var BatchedFacetData = z6.object({
2715
2731
  type: z6.literal("batched_facet"),
2716
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
2732
+ preprocessor: FacetPreprocessorId.optional(),
2717
2733
  facets: z6.array(
2718
2734
  z6.object({
2719
2735
  name: z6.string(),
@@ -2974,18 +2990,6 @@ var ObjectReferenceNullish = z6.union([
2974
2990
  }),
2975
2991
  z6.null()
2976
2992
  ]);
2977
- var SavedFunctionId = z6.union([
2978
- z6.object({
2979
- type: z6.literal("function"),
2980
- id: z6.string(),
2981
- version: z6.string().optional()
2982
- }),
2983
- z6.object({
2984
- type: z6.literal("global"),
2985
- name: z6.string(),
2986
- function_type: FunctionTypeEnum.optional().default("scorer")
2987
- })
2988
- ]);
2989
2993
  var DatasetEvent = z6.object({
2990
2994
  id: z6.string(),
2991
2995
  _xact_id: z6.string(),
@@ -3207,7 +3211,7 @@ var ExtendedSavedFunctionId = z6.union([
3207
3211
  ]);
3208
3212
  var FacetData = z6.object({
3209
3213
  type: z6.literal("facet"),
3210
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
3214
+ preprocessor: FacetPreprocessorId.optional(),
3211
3215
  prompt: z6.string(),
3212
3216
  model: z6.string().optional(),
3213
3217
  embedding_model: z6.string().optional(),
@@ -3712,6 +3716,19 @@ var MessageRole = z6.enum([
3712
3716
  "model",
3713
3717
  "developer"
3714
3718
  ]);
3719
+ var NullableSavedFunctionId = z6.union([
3720
+ z6.object({
3721
+ type: z6.literal("function"),
3722
+ id: z6.string(),
3723
+ version: z6.string().optional()
3724
+ }),
3725
+ z6.object({
3726
+ type: z6.literal("global"),
3727
+ name: z6.string(),
3728
+ function_type: FunctionTypeEnum.optional().default("scorer")
3729
+ }),
3730
+ z6.null()
3731
+ ]);
3715
3732
  var ObjectReference = z6.object({
3716
3733
  object_type: z6.enum([
3717
3734
  "project_logs",
@@ -3733,6 +3750,7 @@ var TraceScope = z6.object({
3733
3750
  });
3734
3751
  var OnlineScoreConfig = z6.union([
3735
3752
  z6.object({
3753
+ status: AutomationStatus.optional(),
3736
3754
  sampling_rate: z6.number().gte(0).lte(1),
3737
3755
  scorers: z6.array(SavedFunctionId),
3738
3756
  btql_filter: z6.union([z6.string(), z6.null()]).optional(),
@@ -3813,6 +3831,72 @@ var Project = z6.object({
3813
3831
  user_id: z6.union([z6.string(), z6.null()]).optional(),
3814
3832
  settings: ProjectSettings.optional()
3815
3833
  });
3834
+ var WindowedAutomationConfig = z6.object({
3835
+ event_type: z6.literal("windowed"),
3836
+ product_origin: z6.union([z6.literal("patterns"), z6.null()]).optional(),
3837
+ status: AutomationStatus.optional(),
3838
+ threshold: z6.object({
3839
+ calculation: z6.object({
3840
+ type: z6.literal("btql"),
3841
+ btql_query: z6.string().min(1),
3842
+ output: z6.object({
3843
+ type: z6.literal("scalar"),
3844
+ value_column: z6.string().min(1)
3845
+ })
3846
+ }),
3847
+ policy: z6.object({
3848
+ condition: z6.object({
3849
+ type: z6.literal("threshold"),
3850
+ operator: z6.enum(["lt", "lte", "gt", "gte", "eq", "neq"]),
3851
+ threshold: z6.number()
3852
+ }),
3853
+ pending_seconds: z6.number().int().gte(0).lte(2592e3),
3854
+ no_data_behavior: z6.enum(["keep_last", "resolve", "alert"]),
3855
+ renotify_interval_seconds: z6.union([z6.number(), z6.null()]).optional(),
3856
+ notify_on_recovery: z6.boolean().optional().default(true)
3857
+ })
3858
+ }).optional(),
3859
+ window: z6.object({
3860
+ window_seconds: z6.number().int().gte(1).lte(2592e3),
3861
+ schedule: z6.union([
3862
+ z6.object({
3863
+ type: z6.literal("interval"),
3864
+ evaluation_interval_seconds: z6.number().int().gte(1).lte(2592e3)
3865
+ }),
3866
+ z6.object({
3867
+ type: z6.literal("cron"),
3868
+ cron_expression: z6.string().min(1),
3869
+ timezone: z6.union([z6.string(), z6.null()]).optional()
3870
+ })
3871
+ ]),
3872
+ evaluation_delay_seconds: z6.number().int().gte(0).lte(2592e3)
3873
+ }),
3874
+ loop: z6.object({
3875
+ prompt: z6.string().min(1).max(1e4),
3876
+ include_trigger_input: z6.boolean().optional().default(false),
3877
+ agent_slug: z6.string().min(1),
3878
+ auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
3879
+ harness: z6.enum(["native", "codex", "claude-code"]).optional(),
3880
+ model: z6.string().min(1).optional(),
3881
+ reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
3882
+ }).optional(),
3883
+ actions: z6.array(
3884
+ z6.union([
3885
+ z6.object({
3886
+ type: z6.literal("webhook"),
3887
+ url: z6.string(),
3888
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3889
+ }),
3890
+ z6.object({
3891
+ type: z6.literal("slack"),
3892
+ workspace_id: z6.string(),
3893
+ channel: z6.string(),
3894
+ message_template: z6.string().optional(),
3895
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3896
+ })
3897
+ ])
3898
+ ).max(20).optional().default([])
3899
+ });
3816
3900
  var TopicAutomationFacetModel = z6.union([
3817
3901
  z6.enum(["brain-facet-latest", "brain-facet-1", "brain-facet-2"]),
3818
3902
  z6.null()
@@ -3854,7 +3938,8 @@ var TopicDigestAutomationConfig = z6.object({
3854
3938
  type: z6.literal("slack"),
3855
3939
  workspace_id: z6.string(),
3856
3940
  channel: z6.string(),
3857
- message_template: z6.string().optional()
3941
+ message_template: z6.string().optional(),
3942
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3858
3943
  }),
3859
3944
  topic_map_function_ids: z6.array(z6.string()).max(10).optional()
3860
3945
  });
@@ -3868,15 +3953,21 @@ var ProjectAutomation = z6.object({
3868
3953
  config: z6.union([
3869
3954
  z6.object({
3870
3955
  event_type: z6.literal("logs"),
3956
+ status: AutomationStatus.optional(),
3871
3957
  btql_filter: z6.string(),
3872
3958
  interval_seconds: z6.number().gte(1).lte(2592e3),
3873
3959
  action: z6.union([
3874
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
3960
+ z6.object({
3961
+ type: z6.literal("webhook"),
3962
+ url: z6.string(),
3963
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3964
+ }),
3875
3965
  z6.object({
3876
3966
  type: z6.literal("slack"),
3877
3967
  workspace_id: z6.string(),
3878
3968
  channel: z6.string(),
3879
- message_template: z6.string().optional()
3969
+ message_template: z6.string().optional(),
3970
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3880
3971
  })
3881
3972
  ])
3882
3973
  }),
@@ -3927,21 +4018,38 @@ var ProjectAutomation = z6.object({
3927
4018
  }),
3928
4019
  z6.object({
3929
4020
  event_type: z6.literal("environment_update"),
4021
+ status: AutomationStatus.optional(),
3930
4022
  environment_filter: z6.array(z6.string()).optional(),
3931
4023
  action: z6.union([
3932
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
4024
+ z6.object({
4025
+ type: z6.literal("webhook"),
4026
+ url: z6.string(),
4027
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
4028
+ }),
3933
4029
  z6.object({
3934
4030
  type: z6.literal("slack"),
3935
4031
  workspace_id: z6.string(),
3936
4032
  channel: z6.string(),
3937
- message_template: z6.string().optional()
4033
+ message_template: z6.string().optional(),
4034
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3938
4035
  })
3939
4036
  ])
3940
4037
  }),
4038
+ WindowedAutomationConfig,
3941
4039
  TopicAutomationConfig,
3942
4040
  TopicDigestAutomationConfig
3943
4041
  ])
3944
4042
  });
4043
+ var ProjectGroup = z6.object({
4044
+ id: z6.string().uuid(),
4045
+ org_id: z6.string().uuid(),
4046
+ user_id: z6.union([z6.string(), z6.null()]).optional(),
4047
+ created: z6.union([z6.string(), z6.null()]).optional(),
4048
+ name: z6.string(),
4049
+ description: z6.union([z6.string(), z6.null()]).optional(),
4050
+ deleted_at: z6.union([z6.string(), z6.null()]).optional(),
4051
+ member_projects: z6.array(z6.string().uuid()).max(1e4)
4052
+ });
3945
4053
  var ProjectLogsEvent = z6.object({
3946
4054
  id: z6.string(),
3947
4055
  _xact_id: z6.string(),
@@ -4159,7 +4267,8 @@ var RunEval = z6.object({
4159
4267
  dataset_environment: z6.union([z6.string(), z6.null()]).optional(),
4160
4268
  _internal_btql: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional()
4161
4269
  }),
4162
- z6.object({ data: z6.array(z6.unknown()) })
4270
+ z6.object({ data: z6.array(z6.unknown()) }),
4271
+ z6.object({ experiment_name: z6.string() })
4163
4272
  ]),
4164
4273
  name: z6.string().optional(),
4165
4274
  parameters: z6.object({}).partial().passthrough().optional(),
@@ -4364,7 +4473,9 @@ var View = z6.object({
4364
4473
  "for_review_datasets"
4365
4474
  ]),
4366
4475
  name: z6.string(),
4476
+ description: z6.union([z6.string(), z6.null()]).optional(),
4367
4477
  created: z6.union([z6.string(), z6.null()]).optional(),
4478
+ updated_at: z6.union([z6.string(), z6.null()]).optional(),
4368
4479
  view_data: ViewData.optional(),
4369
4480
  options: ViewOptions.optional(),
4370
4481
  user_id: z6.union([z6.string(), z6.null()]).optional(),
@@ -4700,7 +4811,7 @@ var BraintrustStream = class _BraintrustStream {
4700
4811
  }
4701
4812
  };
4702
4813
  function btStreamParser() {
4703
- const decoder = new TextDecoder();
4814
+ const decoder2 = new TextDecoder();
4704
4815
  let parser;
4705
4816
  return new TransformStream({
4706
4817
  async start(controller) {
@@ -4717,7 +4828,7 @@ function btStreamParser() {
4717
4828
  },
4718
4829
  async transform(chunk, controller) {
4719
4830
  if (chunk instanceof Uint8Array) {
4720
- parser.feed(decoder.decode(chunk, { stream: true }));
4831
+ parser.feed(decoder2.decode(chunk, { stream: true }));
4721
4832
  } else if (typeof chunk === "string") {
4722
4833
  parser.feed(chunk);
4723
4834
  } else {
@@ -4725,7 +4836,7 @@ function btStreamParser() {
4725
4836
  }
4726
4837
  },
4727
4838
  async flush(controller) {
4728
- const tail = decoder.decode();
4839
+ const tail = decoder2.decode();
4729
4840
  if (tail) {
4730
4841
  parser.feed(tail);
4731
4842
  }
@@ -4734,7 +4845,7 @@ function btStreamParser() {
4734
4845
  });
4735
4846
  }
4736
4847
  function createFinalValuePassThroughStream(onFinal, onError) {
4737
- const decoder = new TextDecoder();
4848
+ const decoder2 = new TextDecoder();
4738
4849
  const textChunks = [];
4739
4850
  const jsonChunks = [];
4740
4851
  const reasoningChunks = [];
@@ -4747,10 +4858,10 @@ function createFinalValuePassThroughStream(onFinal, onError) {
4747
4858
  data: chunk
4748
4859
  });
4749
4860
  } else if (chunk instanceof Uint8Array) {
4750
- textChunks.push(decoder.decode(chunk));
4861
+ textChunks.push(decoder2.decode(chunk));
4751
4862
  controller.enqueue({
4752
4863
  type: "text_delta",
4753
- data: decoder.decode(chunk)
4864
+ data: decoder2.decode(chunk)
4754
4865
  });
4755
4866
  } else if (braintrustStreamChunkSchema.safeParse(chunk).success) {
4756
4867
  const chunkType = chunk.type;
@@ -5491,12 +5602,13 @@ var INSTRUMENTATION_NAMES = {
5491
5602
  OPENROUTER: "openrouter",
5492
5603
  OPENROUTER_AGENT: "openrouter-agent",
5493
5604
  PI_CODING_AGENT: "pi-coding-agent",
5494
- STRANDS_AGENT_SDK: "strands-agent-sdk"
5605
+ STRANDS_AGENT_SDK: "strands-agent-sdk",
5606
+ VOYAGEAI: "voyageai"
5495
5607
  };
5496
5608
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5497
5609
  "braintrust.spanInstrumentationName"
5498
5610
  );
5499
- var SDK_VERSION = true ? "3.27.0" : "0.0.0";
5611
+ var SDK_VERSION = true ? "3.28.0" : "0.0.0";
5500
5612
  function withSpanInstrumentationName(args, instrumentationName) {
5501
5613
  return {
5502
5614
  ...args,
@@ -5691,6 +5803,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
5691
5803
  var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
5692
5804
  "braintrust.initial-span-write-as-merge"
5693
5805
  );
5806
+ var RESUME_SPAN_WITHOUT_INITIAL_WRITE = /* @__PURE__ */ Symbol(
5807
+ "braintrust.resume-span-without-initial-write"
5808
+ );
5694
5809
  var INTERNAL_SPAN_CONTEXT = /* @__PURE__ */ Symbol("braintrust.internal-span-context");
5695
5810
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
5696
5811
  "braintrust.currentSpanStore"
@@ -6914,6 +7029,30 @@ function updateSpan({
6914
7029
  event
6915
7030
  });
6916
7031
  }
7032
+ function _internalResumeSpan({
7033
+ exported,
7034
+ state
7035
+ }) {
7036
+ const resolvedState = state ?? _globalState;
7037
+ const components = SpanComponentsV4.fromStr(exported);
7038
+ const { row_id, root_span_id, span_id } = components.data;
7039
+ if (!row_id || !root_span_id || !span_id) {
7040
+ throw new Error("Only exported root spans can be resumed");
7041
+ }
7042
+ return new SpanImpl({
7043
+ state: resolvedState,
7044
+ parentObjectType: components.data.object_type,
7045
+ parentObjectId: new LazyValue(
7046
+ spanComponentsToObjectIdLambda(resolvedState, components)
7047
+ ),
7048
+ parentComputeObjectMetadataArgs: void 0,
7049
+ parentSpanIds: { parentSpanIds: [], rootSpanId: root_span_id },
7050
+ spanId: span_id,
7051
+ event: { id: row_id },
7052
+ propagatedEvent: components.data.propagated_event ?? void 0,
7053
+ [RESUME_SPAN_WITHOUT_INITIAL_WRITE]: true
7054
+ });
7055
+ }
6917
7056
  function spanComponentsToObjectIdLambda(state, components) {
6918
7057
  if (components.data.object_id) {
6919
7058
  const ret = components.data.object_id;
@@ -9794,7 +9933,7 @@ var ObjectFetcher = class {
9794
9933
  const objectId = await this.id;
9795
9934
  const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
9796
9935
  const internalLimit = getInternalBtqlLimit(this._internal_btql);
9797
- const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
9936
+ let remainingLimit = internalLimit;
9798
9937
  const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
9799
9938
  Object.entries(this._internal_btql ?? {}).filter(
9800
9939
  ([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
@@ -9803,6 +9942,10 @@ var ObjectFetcher = class {
9803
9942
  let cursor = void 0;
9804
9943
  let iterations = 0;
9805
9944
  while (true) {
9945
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9946
+ return;
9947
+ }
9948
+ const limit = remainingLimit === void 0 ? batchLimit : Math.min(batchLimit, remainingLimit);
9806
9949
  const resp = await state.apiConn().post(
9807
9950
  `btql`,
9808
9951
  {
@@ -9842,7 +9985,14 @@ var ObjectFetcher = class {
9842
9985
  const respJson = await resp.json();
9843
9986
  const mutate = this.mutateRecord;
9844
9987
  for (const record of respJson.data ?? []) {
9845
- yield mutate ? mutate(record) : record;
9988
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9989
+ return;
9990
+ }
9991
+ const mutatedRecord = mutate ? mutate(record) : record;
9992
+ if (remainingLimit !== void 0) {
9993
+ remainingLimit--;
9994
+ }
9995
+ yield mutatedRecord;
9846
9996
  }
9847
9997
  if (!respJson.cursor) {
9848
9998
  break;
@@ -10362,7 +10512,9 @@ var SpanImpl = class _SpanImpl {
10362
10512
  this._rootSpanId = resolvedIds.rootSpanId;
10363
10513
  this._spanParents = resolvedIds.spanParents;
10364
10514
  this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
10365
- this.logInternal({ event, internalData });
10515
+ if (!args[RESUME_SPAN_WITHOUT_INITIAL_WRITE]) {
10516
+ this.logInternal({ event, internalData });
10517
+ }
10366
10518
  this.isMerge = true;
10367
10519
  }
10368
10520
  getParentInfo() {
@@ -13018,6 +13170,22 @@ function processInputAttachments(input) {
13018
13170
  };
13019
13171
  }
13020
13172
  }
13173
+ 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;
13174
+ const voyageBase64Value = voyageBase64Key ? node[voyageBase64Key] : void 0;
13175
+ if (voyageBase64Key && typeof voyageBase64Value === "string" && voyageBase64Value.startsWith("data:")) {
13176
+ const mediaType = inferMediaTypeFromDataUrl(
13177
+ voyageBase64Value,
13178
+ node.type === "video_base64" ? "video/mp4" : "image/png"
13179
+ );
13180
+ const filename = `${node.type === "video_base64" ? "video" : "image"}.${getExtensionFromMediaType(mediaType)}`;
13181
+ const attachment = toAttachment(voyageBase64Value, mediaType, filename);
13182
+ if (attachment) {
13183
+ return {
13184
+ ...node,
13185
+ [voyageBase64Key]: attachment
13186
+ };
13187
+ }
13188
+ }
13021
13189
  if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
13022
13190
  const mediaType = inferMediaTypeFromDataUrl(
13023
13191
  node.file.file_data,
@@ -14365,12 +14533,30 @@ function logInstrumentationError(context, error) {
14365
14533
 
14366
14534
  // src/wrappers/anthropic-tokens-util.ts
14367
14535
  function finalizeAnthropicTokens(metrics) {
14368
- const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + (metrics.prompt_cache_creation_tokens || 0);
14369
- return {
14536
+ const hasSplitCacheCreationTokens = metrics.prompt_cache_creation_5m_tokens !== void 0 || metrics.prompt_cache_creation_1h_tokens !== void 0;
14537
+ const splitCacheCreationTokens = (metrics.prompt_cache_creation_5m_tokens || 0) + (metrics.prompt_cache_creation_1h_tokens || 0);
14538
+ const aggregateCacheCreationTokens = metrics.prompt_cache_creation_tokens || 0;
14539
+ const effectiveCacheCreationTokens = Math.max(
14540
+ aggregateCacheCreationTokens,
14541
+ splitCacheCreationTokens
14542
+ );
14543
+ const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + effectiveCacheCreationTokens;
14544
+ const finalized = {
14370
14545
  ...metrics,
14371
14546
  prompt_tokens,
14372
14547
  tokens: prompt_tokens + (metrics.completion_tokens || 0)
14373
14548
  };
14549
+ if (hasSplitCacheCreationTokens && splitCacheCreationTokens >= aggregateCacheCreationTokens) {
14550
+ delete finalized.prompt_cache_creation_tokens;
14551
+ }
14552
+ return finalized;
14553
+ }
14554
+ function toNumericMetrics(metrics) {
14555
+ return Object.fromEntries(
14556
+ Object.entries(metrics).filter(
14557
+ (entry) => entry[1] !== void 0
14558
+ )
14559
+ );
14374
14560
  }
14375
14561
  function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens = 0) {
14376
14562
  const cacheTokens = {};
@@ -14976,6 +15162,18 @@ function parseMetricsFromUsage2(usage) {
14976
15162
  saveIfExistsTo("output_tokens", "completion_tokens");
14977
15163
  saveIfExistsTo("cache_read_input_tokens", "prompt_cached_tokens");
14978
15164
  saveIfExistsTo("cache_creation_input_tokens", "prompt_cache_creation_tokens");
15165
+ if (isObject(usage.cache_creation)) {
15166
+ const cacheCreation = usage.cache_creation;
15167
+ for (const [source, target] of [
15168
+ ["ephemeral_5m_input_tokens", "prompt_cache_creation_5m_tokens"],
15169
+ ["ephemeral_1h_input_tokens", "prompt_cache_creation_1h_tokens"]
15170
+ ]) {
15171
+ const value = cacheCreation[source];
15172
+ if (typeof value === "number") {
15173
+ metrics[target] = value;
15174
+ }
15175
+ }
15176
+ }
14979
15177
  if (isObject(usage.server_tool_use)) {
14980
15178
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
14981
15179
  if (typeof value === "number") {
@@ -20274,37 +20472,97 @@ function seedTaskToolUseIdMapping(taskIdToToolUseId, message) {
20274
20472
  taskIdToToolUseId.set(message.task_id, message.tool_use_id);
20275
20473
  }
20276
20474
  }
20277
- function extractUsageFromMessage(message) {
20278
- const metrics = {};
20279
- let usage;
20280
- if (message.type === "assistant") {
20281
- usage = message.message?.usage;
20282
- } else if (message.type === "result") {
20283
- usage = message.usage;
20284
- }
20475
+ function tokenCount(value) {
20476
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : void 0;
20477
+ }
20478
+ function copyUsage(usage) {
20285
20479
  if (!usage || typeof usage !== "object") {
20286
- return metrics;
20480
+ return void 0;
20481
+ }
20482
+ const copy = {};
20483
+ for (const key of [
20484
+ "input_tokens",
20485
+ "output_tokens",
20486
+ "cache_read_input_tokens",
20487
+ "cache_creation_input_tokens"
20488
+ ]) {
20489
+ const value = tokenCount(Reflect.get(usage, key));
20490
+ if (value !== void 0) {
20491
+ copy[key] = value;
20492
+ }
20493
+ }
20494
+ const cacheCreation = Reflect.get(usage, "cache_creation");
20495
+ if (cacheCreation && typeof cacheCreation === "object") {
20496
+ const cacheCreationCopy = {};
20497
+ for (const key of [
20498
+ "ephemeral_5m_input_tokens",
20499
+ "ephemeral_1h_input_tokens"
20500
+ ]) {
20501
+ const value = tokenCount(Reflect.get(cacheCreation, key));
20502
+ if (value !== void 0) {
20503
+ cacheCreationCopy[key] = value;
20504
+ }
20505
+ }
20506
+ if (Object.keys(cacheCreationCopy).length > 0) {
20507
+ copy.cache_creation = cacheCreationCopy;
20508
+ }
20509
+ }
20510
+ return Object.keys(copy).length > 0 ? copy : void 0;
20511
+ }
20512
+ function mergeUsage(base, override) {
20513
+ if (!base || !override) {
20514
+ return override ?? base;
20515
+ }
20516
+ const cacheCreation = base.cache_creation || override.cache_creation ? { ...base.cache_creation, ...override.cache_creation } : void 0;
20517
+ return {
20518
+ ...base,
20519
+ ...override,
20520
+ ...cacheCreation && { cache_creation: cacheCreation }
20521
+ };
20522
+ }
20523
+ function extractUsage(usage, includeOutput) {
20524
+ const metrics = {};
20525
+ if (!usage) {
20526
+ return {};
20287
20527
  }
20288
20528
  const inputTokens = getNumberProperty(usage, "input_tokens");
20289
20529
  if (inputTokens !== void 0) {
20290
20530
  metrics.prompt_tokens = inputTokens;
20291
20531
  }
20292
- const outputTokens = getNumberProperty(usage, "output_tokens");
20293
- if (outputTokens !== void 0) {
20294
- metrics.completion_tokens = outputTokens;
20532
+ if (includeOutput) {
20533
+ const outputTokens = getNumberProperty(usage, "output_tokens");
20534
+ if (outputTokens !== void 0) {
20535
+ metrics.completion_tokens = outputTokens;
20536
+ }
20295
20537
  }
20296
20538
  const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
20297
20539
  const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
20298
- if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
20299
- Object.assign(
20300
- metrics,
20301
- extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
20302
- );
20540
+ Object.assign(
20541
+ metrics,
20542
+ extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
20543
+ );
20544
+ const cacheCreation5mTokens = getNumberProperty(
20545
+ usage.cache_creation,
20546
+ "ephemeral_5m_input_tokens"
20547
+ );
20548
+ const cacheCreation1hTokens = getNumberProperty(
20549
+ usage.cache_creation,
20550
+ "ephemeral_1h_input_tokens"
20551
+ );
20552
+ if (cacheCreation5mTokens !== void 0) {
20553
+ metrics.prompt_cache_creation_5m_tokens = cacheCreation5mTokens;
20303
20554
  }
20304
- if (Object.keys(metrics).length > 0) {
20305
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
20555
+ if (cacheCreation1hTokens !== void 0) {
20556
+ metrics.prompt_cache_creation_1h_tokens = cacheCreation1hTokens;
20306
20557
  }
20307
- return metrics;
20558
+ if (Object.keys(metrics).length === 0) {
20559
+ return {};
20560
+ }
20561
+ const finalized = finalizeAnthropicTokens(metrics);
20562
+ if (metrics.completion_tokens === void 0) {
20563
+ delete finalized.tokens;
20564
+ }
20565
+ return toNumericMetrics(finalized);
20308
20566
  }
20309
20567
  function buildLLMInput(promptMessages, conversationHistory) {
20310
20568
  const inputParts = [...promptMessages, ...conversationHistory];
@@ -20338,16 +20596,16 @@ function buildRootPromptMessages(prompt, capturedPromptMessages) {
20338
20596
  function formatCapturedMessages(messages) {
20339
20597
  return messages.length > 0 ? messages : [];
20340
20598
  }
20341
- async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
20599
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, usage, hasFinalOutputUsage, existingSpan) {
20342
20600
  if (messages.length === 0) {
20343
20601
  return void 0;
20344
20602
  }
20345
20603
  const lastMessage = messages[messages.length - 1];
20346
- if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
20604
+ if (lastMessage.type !== "assistant") {
20347
20605
  return void 0;
20348
20606
  }
20349
- const model = lastMessage.message.model || options.model;
20350
- const usage = extractUsageFromMessage(lastMessage);
20607
+ const model = lastMessage.message?.model || options.model;
20608
+ const metrics = options.includePartialMessages ? extractUsage(usage, hasFinalOutputUsage) : {};
20351
20609
  const input = buildLLMInput(promptMessages, conversationHistory);
20352
20610
  const outputs = messages.map(
20353
20611
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
@@ -20369,8 +20627,8 @@ async function createLLMSpanForMessages(messages, promptMessages, conversationHi
20369
20627
  );
20370
20628
  span.log({
20371
20629
  input,
20372
- metadata: model ? { model } : void 0,
20373
- metrics: usage,
20630
+ metadata: { ...model && { model }, provider: "anthropic" },
20631
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
20374
20632
  output: outputs
20375
20633
  });
20376
20634
  const spanExport = await span.export();
@@ -20460,11 +20718,17 @@ function prepareLocalToolHandlersInMcpServers(mcpServers) {
20460
20718
  }
20461
20719
  return { hasLocalToolHandlers, localToolHookNames };
20462
20720
  }
20463
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20721
+ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20464
20722
  const preToolUse = async (input, toolUseID) => {
20465
20723
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
20466
20724
  return {};
20467
20725
  }
20726
+ if (!toolUseToParent.has(toolUseID) && input.agent_id) {
20727
+ const parentToolUseId = taskIdToToolUseId.get(input.agent_id);
20728
+ if (parentToolUseId) {
20729
+ toolUseToParent.set(toolUseID, parentToolUseId);
20730
+ }
20731
+ }
20468
20732
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
20469
20733
  return {};
20470
20734
  }
@@ -20660,9 +20924,6 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20660
20924
  }
20661
20925
  const metadata = {
20662
20926
  ...subAgentDetailsToMetadata(details),
20663
- ...input.agent_transcript_path && {
20664
- "claude_agent_sdk.agent_transcript_path": input.agent_transcript_path
20665
- },
20666
20927
  "claude_agent_sdk.stop_hook_active": input.stop_hook_active
20667
20928
  };
20668
20929
  try {
@@ -20684,7 +20945,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20684
20945
  subagentStop
20685
20946
  };
20686
20947
  }
20687
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20948
+ function injectTracingHooks(options, resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20688
20949
  const {
20689
20950
  preToolUse,
20690
20951
  postToolUse,
@@ -20693,6 +20954,8 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
20693
20954
  subagentStop
20694
20955
  } = createToolTracingHooks(
20695
20956
  resolveParentSpan,
20957
+ taskIdToToolUseId,
20958
+ toolUseToParent,
20696
20959
  activeToolSpans,
20697
20960
  options.mcpServers,
20698
20961
  localToolHookNames,
@@ -20774,6 +21037,13 @@ async function finalizeCurrentMessageGroup(state) {
20774
21037
  }
20775
21038
  }
20776
21039
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
21040
+ const lastMessage = state.currentMessages[state.currentMessages.length - 1];
21041
+ const messageId = lastMessage?.message?.id;
21042
+ const usage = state.options.includePartialMessages ? mergeUsage(
21043
+ copyUsage(lastMessage?.message?.usage),
21044
+ messageId ? state.usageByMessageId.get(messageId) : void 0
21045
+ ) : void 0;
21046
+ const hasFinalOutputUsage = messageId !== void 0 && state.finalOutputUsageMessageIds.has(messageId);
20777
21047
  const llmSpanResult = await createLLMSpanForMessages(
20778
21048
  state.currentMessages,
20779
21049
  promptMessages,
@@ -20781,6 +21051,8 @@ async function finalizeCurrentMessageGroup(state) {
20781
21051
  state.options,
20782
21052
  state.currentMessageStartTime,
20783
21053
  parentSpan,
21054
+ usage,
21055
+ hasFinalOutputUsage,
20784
21056
  existingLlmSpan
20785
21057
  );
20786
21058
  if (llmSpanResult) {
@@ -20798,9 +21070,17 @@ async function finalizeCurrentMessageGroup(state) {
20798
21070
  }
20799
21071
  }
20800
21072
  state.activeLlmSpansByParentToolUse.delete(parentKey);
20801
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20802
- if (lastMessage?.message?.usage) {
20803
- state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
21073
+ if (messageId) {
21074
+ state.usageByMessageId.delete(messageId);
21075
+ state.finalOutputUsageMessageIds.delete(messageId);
21076
+ for (const [
21077
+ parent,
21078
+ activeMessageId
21079
+ ] of state.activePartialMessageIdByParentKey) {
21080
+ if (activeMessageId === messageId) {
21081
+ state.activePartialMessageIdByParentKey.delete(parent);
21082
+ }
21083
+ }
20804
21084
  }
20805
21085
  state.currentMessages.length = 0;
20806
21086
  }
@@ -20891,6 +21171,10 @@ async function ensureActiveLlmSpanForParentToolUse(rootSpan, activeLlmSpansByPar
20891
21171
  );
20892
21172
  llmParentSpan = await subAgentSpan.export();
20893
21173
  }
21174
+ const racedLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
21175
+ if (racedLlmSpan) {
21176
+ return racedLlmSpan;
21177
+ }
20894
21178
  const llmSpan = startSpan(
20895
21179
  withSpanInstrumentationName(
20896
21180
  {
@@ -21010,7 +21294,49 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
21010
21294
  }
21011
21295
  return true;
21012
21296
  }
21297
+ function handlePartialUsageMessage(state, message) {
21298
+ if (message.type !== "stream_event") {
21299
+ return false;
21300
+ }
21301
+ const event = message.event;
21302
+ if (!event || typeof event !== "object") {
21303
+ return true;
21304
+ }
21305
+ const parentKey = llmParentKey(message.parent_tool_use_id ?? null);
21306
+ if (event.type === "message_start") {
21307
+ const messageId2 = event.message?.id;
21308
+ const usage = copyUsage(event.message?.usage);
21309
+ if (messageId2) {
21310
+ state.activePartialMessageIdByParentKey.set(parentKey, messageId2);
21311
+ if (usage) {
21312
+ state.usageByMessageId.set(messageId2, usage);
21313
+ }
21314
+ }
21315
+ return true;
21316
+ }
21317
+ const messageId = state.activePartialMessageIdByParentKey.get(parentKey);
21318
+ if (!messageId) {
21319
+ return true;
21320
+ }
21321
+ if (event.type === "message_delta") {
21322
+ const update = copyUsage(event.usage);
21323
+ if (update) {
21324
+ const usage = state.usageByMessageId.get(messageId) ?? {};
21325
+ Object.assign(usage, update);
21326
+ state.usageByMessageId.set(messageId, usage);
21327
+ if (update.output_tokens !== void 0) {
21328
+ state.finalOutputUsageMessageIds.add(messageId);
21329
+ }
21330
+ }
21331
+ } else if (event.type === "message_stop") {
21332
+ state.activePartialMessageIdByParentKey.delete(parentKey);
21333
+ }
21334
+ return true;
21335
+ }
21013
21336
  async function handleStreamMessage(state, message) {
21337
+ if (handlePartialUsageMessage(state, message)) {
21338
+ return;
21339
+ }
21014
21340
  maybeTrackToolUseContext(state, message);
21015
21341
  if (await maybeHandleTaskLifecycleMessage(state, message)) {
21016
21342
  return;
@@ -21057,36 +21383,9 @@ async function handleStreamMessage(state, message) {
21057
21383
  );
21058
21384
  state.currentMessages.push(message);
21059
21385
  }
21060
- if (message.type !== "result" || !message.usage) {
21386
+ if (message.type !== "result") {
21061
21387
  return;
21062
21388
  }
21063
- const finalUsageMetrics = extractUsageFromMessage(message);
21064
- if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
21065
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
21066
- if (lastMessage?.message?.usage) {
21067
- const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
21068
- if (adjustedTokens >= 0) {
21069
- lastMessage.message.usage.output_tokens = adjustedTokens;
21070
- }
21071
- const resultUsage = message.usage;
21072
- if (resultUsage && typeof resultUsage === "object") {
21073
- const cacheReadTokens = getNumberProperty(
21074
- resultUsage,
21075
- "cache_read_input_tokens"
21076
- );
21077
- if (cacheReadTokens !== void 0) {
21078
- lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
21079
- }
21080
- const cacheCreationTokens = getNumberProperty(
21081
- resultUsage,
21082
- "cache_creation_input_tokens"
21083
- );
21084
- if (cacheCreationTokens !== void 0) {
21085
- lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
21086
- }
21087
- }
21088
- }
21089
- }
21090
21389
  const metadata = {};
21091
21390
  if (message.num_turns !== void 0) {
21092
21391
  metadata.num_turns = message.num_turns;
@@ -21094,8 +21393,12 @@ async function handleStreamMessage(state, message) {
21094
21393
  if (message.session_id !== void 0) {
21095
21394
  metadata.session_id = message.session_id;
21096
21395
  }
21097
- if (Object.keys(metadata).length > 0) {
21098
- state.span.log({ metadata });
21396
+ const metrics = state.options.includePartialMessages ? {} : extractUsage(copyUsage(message.usage), true);
21397
+ if (Object.keys(metadata).length > 0 || Object.keys(metrics).length > 0) {
21398
+ state.span.log({
21399
+ ...Object.keys(metadata).length > 0 ? { metadata } : {},
21400
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
21401
+ });
21099
21402
  }
21100
21403
  }
21101
21404
  async function finalizeQuerySpan(state) {
@@ -21119,6 +21422,9 @@ async function finalizeQuerySpan(state) {
21119
21422
  llmSpan.end();
21120
21423
  }
21121
21424
  state.activeLlmSpansByParentToolUse.clear();
21425
+ state.activePartialMessageIdByParentKey.clear();
21426
+ state.finalOutputUsageMessageIds.clear();
21427
+ state.usageByMessageId.clear();
21122
21428
  for (const toolSpan of state.activeToolSpans.values()) {
21123
21429
  toolSpan.end();
21124
21430
  }
@@ -21243,6 +21549,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21243
21549
  const optionsWithHooks = injectTracingHooks(
21244
21550
  options,
21245
21551
  resolveToolUseParentSpan,
21552
+ taskIdToToolUseId,
21553
+ toolUseToParent,
21246
21554
  activeToolSpans,
21247
21555
  localToolHookNames,
21248
21556
  skipLocalToolHooks,
@@ -21253,8 +21561,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21253
21561
  params.options = optionsWithHooks;
21254
21562
  event.arguments[0] = params;
21255
21563
  spans.set(event, {
21256
- accumulatedOutputTokens: 0,
21257
21564
  activeLlmSpansByParentToolUse,
21565
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
21258
21566
  activeToolSpans,
21259
21567
  conversationHistoryByParentKey,
21260
21568
  capturedPromptMessages,
@@ -21262,6 +21570,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21262
21570
  currentMessageStartTime: startTime,
21263
21571
  currentMessages: [],
21264
21572
  endedSubAgentSpans,
21573
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
21265
21574
  finalResults: [],
21266
21575
  options: optionsWithHooks,
21267
21576
  originalPrompt,
@@ -21277,6 +21586,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21277
21586
  latestLlmParentBySubAgentToolUse,
21278
21587
  latestRootLlmParentRef,
21279
21588
  toolUseToParent,
21589
+ usageByMessageId: /* @__PURE__ */ new Map(),
21280
21590
  localToolContext
21281
21591
  });
21282
21592
  },
@@ -23751,9 +24061,9 @@ function extractEmbedPromptTokenCount(response) {
23751
24061
  let sawAny = false;
23752
24062
  for (const embedding of embeddings) {
23753
24063
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
23754
- const tokenCount = embeddingStats?.tokenCount;
23755
- if (typeof tokenCount === "number" && Number.isFinite(tokenCount)) {
23756
- total += tokenCount;
24064
+ const tokenCount2 = embeddingStats?.tokenCount;
24065
+ if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
24066
+ total += tokenCount2;
23757
24067
  sawAny = true;
23758
24068
  }
23759
24069
  }
@@ -30648,7 +30958,7 @@ function getStringProperty2(obj, key) {
30648
30958
  return typeof value === "string" ? value : void 0;
30649
30959
  }
30650
30960
  function extractMetricsFromUsage(usage) {
30651
- const metrics = {
30961
+ const rawMetrics = {
30652
30962
  prompt_tokens: usage.inputTokens,
30653
30963
  completion_tokens: usage.outputTokens,
30654
30964
  ...extractAnthropicCacheTokens(
@@ -30657,10 +30967,10 @@ function extractMetricsFromUsage(usage) {
30657
30967
  )
30658
30968
  };
30659
30969
  if (usage.reasoningTokens !== void 0) {
30660
- metrics.completion_reasoning_tokens = usage.reasoningTokens;
30661
- metrics.reasoning_tokens = usage.reasoningTokens;
30970
+ rawMetrics.completion_reasoning_tokens = usage.reasoningTokens;
30971
+ rawMetrics.reasoning_tokens = usage.reasoningTokens;
30662
30972
  }
30663
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
30973
+ const metrics = finalizeAnthropicTokens(rawMetrics);
30664
30974
  const metadata = {
30665
30975
  model: usage.model
30666
30976
  };
@@ -31599,17 +31909,20 @@ var FlueObserveBridge = class {
31599
31909
  return;
31600
31910
  }
31601
31911
  const metadata = {
31912
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
31602
31913
  ...extractEventMetadata(event),
31603
31914
  "flue.operation": event.operationKind,
31604
31915
  provider: "flue"
31605
31916
  };
31606
31917
  const parent = this.parentSpanForEvent(event);
31607
- const span = startFlueSpan(parent, {
31918
+ const args = {
31608
31919
  name: `flue.${event.operationKind}`,
31609
31920
  spanAttributes: { type: "task" /* TASK */ },
31610
31921
  startTime: eventTime(event.timestamp),
31611
31922
  event: { metadata }
31612
- });
31923
+ };
31924
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
31925
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
31613
31926
  this.operationsById.set(event.operationId, { metadata, span });
31614
31927
  }
31615
31928
  handleOperation(event) {
@@ -31624,6 +31937,11 @@ var FlueObserveBridge = class {
31624
31937
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
31625
31938
  ...event.usage ? { "flue.usage": event.usage } : {}
31626
31939
  };
31940
+ const input = flueOperationInput(event);
31941
+ if (!state.loggedInput && input !== void 0) {
31942
+ safeLog3(state.span, { input });
31943
+ state.loggedInput = true;
31944
+ }
31627
31945
  this.finishPendingChildrenForOperation(event, output);
31628
31946
  safeLog3(state.span, {
31629
31947
  ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
@@ -31640,6 +31958,8 @@ var FlueObserveBridge = class {
31640
31958
  return;
31641
31959
  }
31642
31960
  const input = flueTurnRequestInput(event);
31961
+ const operation = event.operationId ? this.operationsById.get(event.operationId) : void 0;
31962
+ const turnInput = prepareFlueTurnInput(event, input, operation);
31643
31963
  const model = flueTurnRequestModel(event);
31644
31964
  const provider = flueTurnRequestProvider(event);
31645
31965
  const api = flueTurnRequestApi(event);
@@ -31652,8 +31972,7 @@ var FlueObserveBridge = class {
31652
31972
  ...provider ? { "flue.provider": provider } : {},
31653
31973
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
31654
31974
  ...reasoning ? { reasoning } : {},
31655
- ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
31656
- ...input?.tools ? { tools: input.tools } : {}
31975
+ ...turnInput.metadata
31657
31976
  };
31658
31977
  const parent = this.parentSpanForTurn(event);
31659
31978
  const span = startFlueSpan(parent, {
@@ -31661,11 +31980,14 @@ var FlueObserveBridge = class {
31661
31980
  spanAttributes: { type: "llm" /* LLM */ },
31662
31981
  startTime: eventTime(event.timestamp),
31663
31982
  event: {
31664
- input: input?.messages,
31983
+ input: turnInput.messages,
31665
31984
  metadata
31666
31985
  }
31667
31986
  });
31668
- this.logOperationInput(event.operationId, input?.messages ?? input);
31987
+ this.logOperationInput(
31988
+ event.operationId,
31989
+ latestUserMessageInput(input?.messages)
31990
+ );
31669
31991
  this.turnsByKey.set(key, { metadata, span });
31670
31992
  }
31671
31993
  handleTurn(event) {
@@ -31912,16 +32234,20 @@ var FlueObserveBridge = class {
31912
32234
  }
31913
32235
  startSyntheticOperation(event) {
31914
32236
  const metadata = {
32237
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
31915
32238
  ...extractEventMetadata(event),
31916
32239
  "flue.operation": event.operationKind,
31917
32240
  provider: "flue"
31918
32241
  };
31919
- const span = startFlueSpan(this.parentSpanForEvent(event), {
32242
+ const args = {
31920
32243
  name: `flue.${event.operationKind}`,
31921
32244
  spanAttributes: { type: "task" /* TASK */ },
31922
32245
  startTime: eventTime(event.timestamp),
31923
32246
  event: { metadata }
31924
- });
32247
+ };
32248
+ const parent = this.parentSpanForEvent(event);
32249
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
32250
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
31925
32251
  return { metadata, span };
31926
32252
  }
31927
32253
  startSyntheticTurn(event) {
@@ -32100,6 +32426,71 @@ function flueRunInput(event) {
32100
32426
  function flueTurnRequestInput(event) {
32101
32427
  return event.request?.input ?? event.input;
32102
32428
  }
32429
+ function prepareFlueTurnInput(event, input, operation) {
32430
+ const messages = input?.messages;
32431
+ const tracksUserTurn = event.purpose === "agent" && operation?.metadata["flue.operation"] === "prompt" && Array.isArray(messages);
32432
+ if (!tracksUserTurn) {
32433
+ return {
32434
+ messages,
32435
+ metadata: {
32436
+ ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
32437
+ ...input?.tools ? { tools: input.tools } : {}
32438
+ }
32439
+ };
32440
+ }
32441
+ const previous = operation.turnInputState;
32442
+ const previousMessageCount = previous?.messageCount ?? 0;
32443
+ const boundaryFingerprint = messages.length > 0 ? fingerprintJsonValue(messages[messages.length - 1]) : void 0;
32444
+ const continuesPreviousInput = previous !== void 0 && messages.length >= previousMessageCount && (previousMessageCount === 0 || previous.boundaryFingerprint !== void 0 && previous.boundaryFingerprint === fingerprintJsonValue(messages[previousMessageCount - 1]));
32445
+ const inputMode = previous === void 0 ? "full" : continuesPreviousInput ? "delta" : "reset";
32446
+ const systemPromptFingerprint = fingerprintJsonValue(input?.systemPrompt);
32447
+ const toolsFingerprint = fingerprintJsonValue(input?.tools);
32448
+ operation.turnInputState = {
32449
+ ...boundaryFingerprint !== void 0 ? { boundaryFingerprint } : {},
32450
+ messageCount: messages.length,
32451
+ ...systemPromptFingerprint !== void 0 ? { systemPromptFingerprint } : {},
32452
+ ...toolsFingerprint !== void 0 ? { toolsFingerprint } : {}
32453
+ };
32454
+ return {
32455
+ messages: continuesPreviousInput ? messages.slice(previousMessageCount) : messages,
32456
+ metadata: {
32457
+ "flue.input_mode": inputMode,
32458
+ ...continuesPreviousInput ? { "flue.input_message_offset": previousMessageCount } : {},
32459
+ ...input?.systemPrompt && (!continuesPreviousInput || systemPromptFingerprint !== previous?.systemPromptFingerprint) ? { "flue.system_prompt": input.systemPrompt } : {},
32460
+ ...input?.tools && (!continuesPreviousInput || toolsFingerprint !== previous?.toolsFingerprint) ? { tools: input.tools } : {}
32461
+ }
32462
+ };
32463
+ }
32464
+ function fingerprintJsonValue(value) {
32465
+ try {
32466
+ const serialized = JSON.stringify(value);
32467
+ if (serialized === void 0) {
32468
+ return void 0;
32469
+ }
32470
+ let hash = 2166136261;
32471
+ for (let i = 0; i < serialized.length; i++) {
32472
+ hash = Math.imul(hash ^ serialized.charCodeAt(i), 16777619);
32473
+ }
32474
+ return `${serialized.length}:${hash >>> 0}`;
32475
+ } catch {
32476
+ return void 0;
32477
+ }
32478
+ }
32479
+ function latestUserMessageInput(messages) {
32480
+ if (!messages) {
32481
+ return void 0;
32482
+ }
32483
+ for (let i = messages.length - 1; i >= 0; i--) {
32484
+ const message = messages[i];
32485
+ if (isObjectLike(message) && Reflect.get(message, "role") === "user") {
32486
+ return [message];
32487
+ }
32488
+ }
32489
+ return void 0;
32490
+ }
32491
+ function flueOperationInput(event) {
32492
+ return typeof event.agentInput?.text === "string" ? [{ content: event.agentInput.text, role: "user" }] : void 0;
32493
+ }
32103
32494
  function flueTurnRequestModel(event) {
32104
32495
  return event.request?.requestedModel ?? event.request?.model ?? event.model;
32105
32496
  }
@@ -32257,6 +32648,21 @@ function startFlueSpan(parent, args) {
32257
32648
  withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE)
32258
32649
  );
32259
32650
  }
32651
+ function startFlueRootSpan(args) {
32652
+ const state = _internalGetGlobalState();
32653
+ const spanId = state.idGenerator.getSpanId();
32654
+ const rootSpanId = state.idGenerator.shareRootSpanId() ? spanId : state.idGenerator.getTraceId();
32655
+ return withCurrent(
32656
+ NOOP_SPAN,
32657
+ () => startSpan({
32658
+ ...withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE),
32659
+ parentSpanIds: { parentSpanIds: [], rootSpanId },
32660
+ spanId,
32661
+ state
32662
+ }),
32663
+ state
32664
+ );
32665
+ }
32260
32666
  function runWithCurrentSpanStore(span, next) {
32261
32667
  const state = _internalGetGlobalState();
32262
32668
  const contextManager = state?.contextManager;
@@ -34156,8 +34562,7 @@ function startAgentStream(event, activeChildParents) {
34156
34562
  ...extractAgentMetadata2(agent),
34157
34563
  ...extractModelMetadata3(model),
34158
34564
  "strands.operation": "Agent.stream",
34159
- provider: extractProvider(model),
34160
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34565
+ provider: extractProvider(model)
34161
34566
  };
34162
34567
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
34163
34568
  const attachmentCache = createStrandsAttachmentCache();
@@ -34207,8 +34612,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
34207
34612
  const metadata = {
34208
34613
  "strands.operation": operation,
34209
34614
  provider: "strands",
34210
- ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {},
34211
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34615
+ ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
34212
34616
  };
34213
34617
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
34214
34618
  const input = processStrandsInputAttachments(event.arguments[0]);
@@ -34994,6 +35398,320 @@ function logInstrumentationError5(context, error) {
34994
35398
  debugLogger.debug(`${context}:`, error);
34995
35399
  }
34996
35400
 
35401
+ // src/instrumentation/plugins/voyageai-channels.ts
35402
+ var voyageAIChannels = defineChannels(
35403
+ "voyageai",
35404
+ {
35405
+ embed: channel({
35406
+ channelName: "embed",
35407
+ kind: "async"
35408
+ }),
35409
+ multimodalEmbed: channel({
35410
+ channelName: "multimodalEmbed",
35411
+ kind: "async"
35412
+ }),
35413
+ rerank: channel({
35414
+ channelName: "rerank",
35415
+ kind: "async"
35416
+ }),
35417
+ contextualizedEmbed: channel({
35418
+ channelName: "contextualizedEmbed",
35419
+ kind: "async"
35420
+ })
35421
+ },
35422
+ { instrumentationName: INSTRUMENTATION_NAMES.VOYAGEAI }
35423
+ );
35424
+
35425
+ // src/instrumentation/plugins/voyageai-plugin.ts
35426
+ var RERANK_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
35427
+ "model",
35428
+ "returnDocuments",
35429
+ "topK",
35430
+ "truncation"
35431
+ ]);
35432
+ var VoyageAIPlugin = class extends BasePlugin {
35433
+ onEnable() {
35434
+ this.unsubscribers.push(
35435
+ interceptVoyageAICall(
35436
+ voyageAIChannels.embed,
35437
+ "voyageai.embed",
35438
+ extractTextEmbeddingInput,
35439
+ summarizeEmbeddingOutput,
35440
+ extractEmbeddingUsageMetrics
35441
+ ),
35442
+ interceptVoyageAICall(
35443
+ voyageAIChannels.multimodalEmbed,
35444
+ "voyageai.multimodalEmbed",
35445
+ extractMultimodalEmbeddingInput,
35446
+ summarizeEmbeddingOutput,
35447
+ extractEmbeddingUsageMetrics
35448
+ ),
35449
+ interceptVoyageAICall(
35450
+ voyageAIChannels.rerank,
35451
+ "voyageai.rerank",
35452
+ extractRerankInput,
35453
+ summarizeRerankOutput
35454
+ ),
35455
+ interceptVoyageAICall(
35456
+ voyageAIChannels.contextualizedEmbed,
35457
+ "voyageai.contextualizedEmbed",
35458
+ extractContextualizedEmbeddingInput,
35459
+ summarizeContextualizedEmbeddingOutput,
35460
+ extractEmbeddingUsageMetrics
35461
+ )
35462
+ );
35463
+ }
35464
+ onDisable() {
35465
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
35466
+ }
35467
+ };
35468
+ function interceptVoyageAICall(channel2, name, extractInput3, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
35469
+ return channel2.intercept((target, thisArg, args) => {
35470
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
35471
+ if (isAutoInstrumentationSuppressed()) {
35472
+ return invokeTarget();
35473
+ }
35474
+ let span;
35475
+ try {
35476
+ const { input, metadata } = extractInput3(args);
35477
+ span = startSpan(
35478
+ withSpanInstrumentationName(
35479
+ {
35480
+ event: { input, metadata },
35481
+ name,
35482
+ spanAttributes: { type: "llm" /* LLM */ }
35483
+ },
35484
+ INSTRUMENTATION_NAMES.VOYAGEAI
35485
+ )
35486
+ );
35487
+ } catch (error) {
35488
+ debugLogger.error(`Error starting span for ${name}:`, error);
35489
+ return invokeTarget();
35490
+ }
35491
+ let result;
35492
+ try {
35493
+ result = withCurrent(
35494
+ span,
35495
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
35496
+ );
35497
+ } catch (error) {
35498
+ finishVoyageAISpan(span, name, () => span.log({ error }));
35499
+ throw error;
35500
+ }
35501
+ void Promise.resolve(result).then(
35502
+ (value) => finishVoyageAISpan(span, name, () => {
35503
+ const metadata = extractResponseMetadata3(value);
35504
+ span.log({
35505
+ output: extractOutput2(value),
35506
+ ...metadata ? { metadata } : {},
35507
+ metrics: extractMetrics2(value)
35508
+ });
35509
+ }),
35510
+ (error) => finishVoyageAISpan(span, name, () => span.log({ error }))
35511
+ );
35512
+ return result;
35513
+ });
35514
+ }
35515
+ function finishVoyageAISpan(span, name, log3) {
35516
+ try {
35517
+ log3();
35518
+ } catch (error) {
35519
+ debugLogger.error(`Error logging span for ${name}:`, error);
35520
+ }
35521
+ try {
35522
+ span.end();
35523
+ } catch (error) {
35524
+ debugLogger.error(`Error ending span for ${name}:`, error);
35525
+ }
35526
+ }
35527
+ function getRequestArg2(args) {
35528
+ if (Array.isArray(args)) {
35529
+ return isObject(args[0]) ? args[0] : void 0;
35530
+ }
35531
+ if (!isObject(args)) {
35532
+ return void 0;
35533
+ }
35534
+ const firstArg = Reflect.get(args, "0");
35535
+ return isObject(firstArg) ? firstArg : void 0;
35536
+ }
35537
+ function pickMetadata(request, allowlist) {
35538
+ const metadata = {};
35539
+ if (request) {
35540
+ for (const key of allowlist) {
35541
+ if (!Object.hasOwn(request, key)) {
35542
+ continue;
35543
+ }
35544
+ const value = request[key];
35545
+ if (value !== void 0) {
35546
+ metadata[key] = value;
35547
+ }
35548
+ }
35549
+ }
35550
+ return {
35551
+ ...metadata,
35552
+ provider: "voyage"
35553
+ };
35554
+ }
35555
+ function buildEmbeddingInput(inputs, request) {
35556
+ const outputDimensions = request?.outputDimension;
35557
+ return {
35558
+ inputs,
35559
+ ...typeof outputDimensions === "number" && Number.isFinite(outputDimensions) ? { output_dimensions: outputDimensions } : {}
35560
+ };
35561
+ }
35562
+ function embeddingMetadata(request) {
35563
+ return {
35564
+ ...typeof request?.model === "string" ? { model: request.model } : {},
35565
+ provider: "voyage"
35566
+ };
35567
+ }
35568
+ function extractTextEmbeddingInput(args) {
35569
+ const request = getRequestArg2(args);
35570
+ const rawInput = request?.input;
35571
+ const values = Array.isArray(rawInput) ? rawInput : [rawInput];
35572
+ return {
35573
+ input: buildEmbeddingInput(
35574
+ values.flatMap(
35575
+ (value) => typeof value === "string" ? [{ content: value }] : []
35576
+ ),
35577
+ request
35578
+ ),
35579
+ metadata: embeddingMetadata(request)
35580
+ };
35581
+ }
35582
+ function extractContextualizedEmbeddingInput(args) {
35583
+ const request = getRequestArg2(args);
35584
+ const rawInputs = request?.inputs;
35585
+ const values = Array.isArray(rawInputs) ? rawInputs.flatMap((value) => Array.isArray(value) ? value : [value]) : [];
35586
+ return {
35587
+ input: buildEmbeddingInput(
35588
+ values.flatMap(
35589
+ (value) => typeof value === "string" ? [{ content: value }] : []
35590
+ ),
35591
+ request
35592
+ ),
35593
+ metadata: embeddingMetadata(request)
35594
+ };
35595
+ }
35596
+ function extractMultimodalEmbeddingInput(args) {
35597
+ const request = getRequestArg2(args);
35598
+ const rawInputs = request?.inputs;
35599
+ const inputs = Array.isArray(rawInputs) ? rawInputs.map((rawInput) => {
35600
+ const rawContent = isObject(rawInput) ? rawInput.content : void 0;
35601
+ return {
35602
+ content: Array.isArray(rawContent) ? rawContent.flatMap(normalizeMultimodalContentPart) : []
35603
+ };
35604
+ }) : [];
35605
+ const input = buildEmbeddingInput(inputs, request);
35606
+ const processedInput = processInputAttachments(input);
35607
+ return {
35608
+ input: hasInlineEmbeddingMedia(processedInput) ? input : processedInput,
35609
+ metadata: embeddingMetadata(request)
35610
+ };
35611
+ }
35612
+ function normalizeMultimodalContentPart(part) {
35613
+ if (!isObject(part) || typeof part.type !== "string") {
35614
+ return [];
35615
+ }
35616
+ if (part.type === "text") {
35617
+ return typeof part.text === "string" ? [{ type: "text", text: part.text }] : [];
35618
+ }
35619
+ const camelCaseField = {
35620
+ image_base64: "imageBase64",
35621
+ image_url: "imageUrl",
35622
+ video_base64: "videoBase64",
35623
+ video_url: "videoUrl"
35624
+ };
35625
+ const field = camelCaseField[part.type];
35626
+ if (!field) {
35627
+ return [];
35628
+ }
35629
+ const data = typeof part[field] === "string" ? part[field] : part[part.type];
35630
+ if (typeof data !== "string") {
35631
+ return [];
35632
+ }
35633
+ return part.type.startsWith("image_") ? [{ type: "image_url", image_url: { url: data } }] : [{ type: "file", file: { file_data: data } }];
35634
+ }
35635
+ function hasInlineEmbeddingMedia(input) {
35636
+ return input.inputs.some(
35637
+ ({ content }) => Array.isArray(content) ? content.some((part) => {
35638
+ const value = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
35639
+ return typeof value === "string" && value.startsWith("data:");
35640
+ }) : false
35641
+ );
35642
+ }
35643
+ function extractRerankInput(args) {
35644
+ const request = getRequestArg2(args);
35645
+ const documents = request?.documents;
35646
+ return {
35647
+ input: {
35648
+ documents,
35649
+ query: request?.query
35650
+ },
35651
+ metadata: {
35652
+ ...pickMetadata(request, RERANK_METADATA_ALLOWLIST),
35653
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
35654
+ }
35655
+ };
35656
+ }
35657
+ function extractResponseMetadata3(result) {
35658
+ if (!isObject(result)) {
35659
+ return void 0;
35660
+ }
35661
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35662
+ const model = typeof result.model === "string" ? result.model : typeof rawResponse?.model === "string" ? rawResponse.model : void 0;
35663
+ return model ? { model } : void 0;
35664
+ }
35665
+ function summarizeEmbeddingOutput(result) {
35666
+ return {
35667
+ count: isObject(result) && Array.isArray(result.data) ? result.data.length : 0
35668
+ };
35669
+ }
35670
+ function summarizeRerankOutput(result) {
35671
+ if (!isObject(result) || !Array.isArray(result.data)) {
35672
+ return void 0;
35673
+ }
35674
+ return result.data.slice(0, 100).map((item) => ({
35675
+ index: isObject(item) ? item.index : void 0,
35676
+ relevance_score: isObject(item) ? (typeof item.relevanceScore === "number" ? item.relevanceScore : item.relevance_score) ?? null : null
35677
+ }));
35678
+ }
35679
+ function summarizeContextualizedEmbeddingOutput(result) {
35680
+ if (!isObject(result)) {
35681
+ return { count: 0 };
35682
+ }
35683
+ if (Array.isArray(result.results)) {
35684
+ return {
35685
+ count: result.results.reduce(
35686
+ (count, item) => count + (isObject(item) && Array.isArray(item.embeddings) ? item.embeddings.length : 0),
35687
+ 0
35688
+ )
35689
+ };
35690
+ }
35691
+ if (!Array.isArray(result.data)) {
35692
+ return { count: 0 };
35693
+ }
35694
+ return {
35695
+ count: result.data.reduce(
35696
+ (count, item) => count + (isObject(item) && Array.isArray(item.data) ? item.data.length : 0),
35697
+ 0
35698
+ )
35699
+ };
35700
+ }
35701
+ function extractEmbeddingUsageMetrics(result) {
35702
+ const metrics = extractUsageMetrics3(result);
35703
+ return typeof metrics.tokens === "number" ? { prompt_tokens: metrics.tokens, tokens: metrics.tokens } : {};
35704
+ }
35705
+ function extractUsageMetrics3(result) {
35706
+ if (!isObject(result)) {
35707
+ return {};
35708
+ }
35709
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35710
+ const usage = isObject(result.usage) ? result.usage : isObject(rawResponse?.usage) ? rawResponse.usage : void 0;
35711
+ const tokens = typeof result.totalTokens === "number" ? result.totalTokens : usage?.totalTokens ?? usage?.total_tokens;
35712
+ return typeof tokens === "number" && Number.isFinite(tokens) && tokens >= 0 ? { tokens } : {};
35713
+ }
35714
+
34997
35715
  // src/instrumentation/plugins/cloudflare-ai-chat-channels.ts
34998
35716
  var cloudflareAIChatChannels = defineChannels(
34999
35717
  "@cloudflare/ai-chat",
@@ -35572,6 +36290,7 @@ var BraintrustPlugin = class extends BasePlugin {
35572
36290
  langSmithPlugin = null;
35573
36291
  piCodingAgentPlugin = null;
35574
36292
  strandsAgentSDKPlugin = null;
36293
+ voyageAIPlugin = null;
35575
36294
  cloudflareAIChatPlugin = null;
35576
36295
  cloudflareAgentsPlugin = null;
35577
36296
  constructor(config = {}) {
@@ -35646,6 +36365,10 @@ var BraintrustPlugin = class extends BasePlugin {
35646
36365
  this.coherePlugin = new CoherePlugin();
35647
36366
  this.coherePlugin.enable();
35648
36367
  }
36368
+ if (integrations.voyageai !== false) {
36369
+ this.voyageAIPlugin = new VoyageAIPlugin();
36370
+ this.voyageAIPlugin.enable();
36371
+ }
35649
36372
  if (integrations.groq !== false) {
35650
36373
  this.groqPlugin = new GroqPlugin();
35651
36374
  this.groqPlugin.enable();
@@ -35762,6 +36485,10 @@ var BraintrustPlugin = class extends BasePlugin {
35762
36485
  this.coherePlugin.disable();
35763
36486
  this.coherePlugin = null;
35764
36487
  }
36488
+ if (this.voyageAIPlugin) {
36489
+ this.voyageAIPlugin.disable();
36490
+ this.voyageAIPlugin = null;
36491
+ }
35765
36492
  if (this.groqPlugin) {
35766
36493
  this.groqPlugin.disable();
35767
36494
  this.groqPlugin = null;
@@ -35881,7 +36608,10 @@ var envIntegrationAliases = {
35881
36608
  "langchain-js": "langchain",
35882
36609
  "@langchain": "langchain",
35883
36610
  langgraph: "langgraph",
35884
- langsmith: "langsmith"
36611
+ langsmith: "langsmith",
36612
+ voyage: "voyageai",
36613
+ "voyage-ai": "voyageai",
36614
+ voyageai: "voyageai"
35885
36615
  };
35886
36616
  function getDefaultInstrumentationIntegrations() {
35887
36617
  return {
@@ -35916,6 +36646,7 @@ function getDefaultInstrumentationIntegrations() {
35916
36646
  langchain: true,
35917
36647
  langgraph: true,
35918
36648
  langsmith: true,
36649
+ voyageai: true,
35919
36650
  piCodingAgent: true,
35920
36651
  strandsAgentSDK: true,
35921
36652
  cloudflareAgents: true
@@ -36081,6 +36812,8 @@ __export(exports_exports, {
36081
36812
  BRAINTRUST_PARENT_KEY: () => BRAINTRUST_PARENT_KEY,
36082
36813
  BaseAttachment: () => BaseAttachment,
36083
36814
  BaseExperiment: () => BaseExperiment,
36815
+ BatchScorer: () => BatchScorer,
36816
+ BatchTask: () => BatchTask,
36084
36817
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
36085
36818
  BraintrustMiddleware: () => BraintrustMiddleware,
36086
36819
  BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
@@ -36094,6 +36827,8 @@ __export(exports_exports, {
36094
36827
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
36095
36828
  Dataset: () => Dataset2,
36096
36829
  DatasetPipeline: () => DatasetPipeline,
36830
+ DurableEvalMemoryStore: () => DurableEvalMemoryStore,
36831
+ DurableEvalRedisStore: () => DurableEvalRedisStore,
36097
36832
  ERR_PERMALINK: () => ERR_PERMALINK,
36098
36833
  Eval: () => Eval,
36099
36834
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -36151,6 +36886,7 @@ __export(exports_exports, {
36151
36886
  currentSpan: () => currentSpan,
36152
36887
  deepCopyEvent: () => deepCopyEvent,
36153
36888
  defaultErrorScoreHandler: () => defaultErrorScoreHandler,
36889
+ defineDurableEval: () => defineDurableEval,
36154
36890
  deserializePlainStringAsJSON: () => deserializePlainStringAsJSON,
36155
36891
  devNullWritableStream: () => devNullWritableStream,
36156
36892
  evaluatorDefinitionSchema: () => evaluatorDefinitionSchema,
@@ -36246,7 +36982,8 @@ __export(exports_exports, {
36246
36982
  wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
36247
36983
  wrapStrandsAgentSDK: () => wrapStrandsAgentSDK,
36248
36984
  wrapTraced: () => wrapTraced,
36249
- wrapVitest: () => wrapVitest
36985
+ wrapVitest: () => wrapVitest,
36986
+ wrapVoyageAI: () => wrapVoyageAI
36250
36987
  });
36251
36988
 
36252
36989
  // src/sandbox.ts
@@ -37507,7 +38244,7 @@ function normalizeUsageMetrics(usage, provider, providerMetadata) {
37507
38244
  cacheCreationTokens
37508
38245
  );
37509
38246
  Object.assign(metrics, cacheTokens);
37510
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
38247
+ return toNumericMetrics(finalizeAnthropicTokens(metrics));
37511
38248
  }
37512
38249
  }
37513
38250
  return metrics;
@@ -41840,6 +42577,84 @@ function wrapRerank3(rerank) {
41840
42577
  });
41841
42578
  }
41842
42579
 
42580
+ // src/wrappers/voyageai.ts
42581
+ function wrapVoyageAI(client) {
42582
+ if (!isSupportedVoyageAIClient(client)) {
42583
+ console.warn("Unsupported Voyage AI library. Not wrapping.");
42584
+ return client;
42585
+ }
42586
+ return voyageAIProxy(client);
42587
+ }
42588
+ var voyageAIProxyCache = /* @__PURE__ */ new WeakMap();
42589
+ function isObject3(value) {
42590
+ return typeof value === "object" && value !== null;
42591
+ }
42592
+ function hasFunction5(value, name) {
42593
+ return typeof Reflect.get(value, name) === "function";
42594
+ }
42595
+ function isSupportedVoyageAIClient(value) {
42596
+ if (!isObject3(value)) {
42597
+ return false;
42598
+ }
42599
+ return hasFunction5(value, "embed") || hasFunction5(value, "multimodalEmbed") || hasFunction5(value, "rerank") || hasFunction5(value, "contextualizedEmbed");
42600
+ }
42601
+ function voyageAIProxy(client) {
42602
+ const cached = voyageAIProxyCache.get(client);
42603
+ if (cached) {
42604
+ return cached;
42605
+ }
42606
+ const proxy = new Proxy(client, {
42607
+ get(target, prop, receiver) {
42608
+ switch (prop) {
42609
+ case "embed":
42610
+ if (typeof target.embed !== "function") {
42611
+ return target.embed;
42612
+ }
42613
+ return (request, options) => voyageAIChannels.embed.invoke(
42614
+ target.embed,
42615
+ target,
42616
+ [request, options],
42617
+ {}
42618
+ );
42619
+ case "multimodalEmbed":
42620
+ if (typeof target.multimodalEmbed !== "function") {
42621
+ return target.multimodalEmbed;
42622
+ }
42623
+ return (request, options) => voyageAIChannels.multimodalEmbed.invoke(
42624
+ target.multimodalEmbed,
42625
+ target,
42626
+ [request, options],
42627
+ {}
42628
+ );
42629
+ case "rerank":
42630
+ if (typeof target.rerank !== "function") {
42631
+ return target.rerank;
42632
+ }
42633
+ return (request, options) => voyageAIChannels.rerank.invoke(
42634
+ target.rerank,
42635
+ target,
42636
+ [request, options],
42637
+ {}
42638
+ );
42639
+ case "contextualizedEmbed":
42640
+ if (typeof target.contextualizedEmbed !== "function") {
42641
+ return target.contextualizedEmbed;
42642
+ }
42643
+ return (request, options) => voyageAIChannels.contextualizedEmbed.invoke(
42644
+ target.contextualizedEmbed,
42645
+ target,
42646
+ [request, options],
42647
+ {}
42648
+ );
42649
+ default:
42650
+ return Reflect.get(target, prop, receiver);
42651
+ }
42652
+ }
42653
+ });
42654
+ voyageAIProxyCache.set(client, proxy);
42655
+ return proxy;
42656
+ }
42657
+
41843
42658
  // src/wrappers/groq.ts
41844
42659
  function wrapGroq(groq) {
41845
42660
  if (isSupportedGroqClient(groq)) {
@@ -41851,14 +42666,14 @@ function wrapGroq(groq) {
41851
42666
  function isRecord6(value) {
41852
42667
  return typeof value === "object" && value !== null;
41853
42668
  }
41854
- function hasFunction5(value, methodName) {
42669
+ function hasFunction6(value, methodName) {
41855
42670
  return isRecord6(value) && methodName in value && typeof value[methodName] === "function";
41856
42671
  }
41857
42672
  function hasChat2(value) {
41858
- return isRecord6(value) && isRecord6(value.completions) && hasFunction5(value.completions, "create");
42673
+ return isRecord6(value) && isRecord6(value.completions) && hasFunction6(value.completions, "create");
41859
42674
  }
41860
42675
  function hasEmbeddings2(value) {
41861
- return hasFunction5(value, "create");
42676
+ return hasFunction6(value, "create");
41862
42677
  }
41863
42678
  function isSupportedGroqClient(value) {
41864
42679
  return isRecord6(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
@@ -42441,7 +43256,7 @@ async function flushExperimentWithSync(context, config) {
42441
43256
  // src/wrappers/shared/scorers.ts
42442
43257
  async function runScorers(args) {
42443
43258
  const { scorers, output, expected, input, metadata, span } = args;
42444
- const scorerArgs = {
43259
+ const scorerArgs2 = {
42445
43260
  output,
42446
43261
  expected,
42447
43262
  input,
@@ -42450,7 +43265,7 @@ async function runScorers(args) {
42450
43265
  await Promise.all(
42451
43266
  scorers.map(async (scorer) => {
42452
43267
  try {
42453
- const result = await scorer(scorerArgs);
43268
+ const result = await scorer(scorerArgs2);
42454
43269
  const scores = normalizeScores(result);
42455
43270
  if (scores.length > 0) {
42456
43271
  const accScores = {};
@@ -44809,6 +45624,26 @@ async function getExperimentParametersRef(parameters) {
44809
45624
  version: resolvedParameters.version
44810
45625
  };
44811
45626
  }
45627
+ async function _internalInitEvaluatorExperiment(projectName, evaluator, data, options = {}) {
45628
+ if (options.disabled) return null;
45629
+ const { baseExperiment } = callEvaluatorData(data);
45630
+ const parameters = await getExperimentParametersRef(evaluator.parameters);
45631
+ return initExperiment2(evaluator.state, {
45632
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: projectName },
45633
+ experiment: options.experimentName ?? evaluator.experimentName,
45634
+ description: evaluator.description,
45635
+ metadata: evaluator.metadata,
45636
+ tags: evaluator.tags,
45637
+ isPublic: evaluator.isPublic,
45638
+ update: options.update ?? evaluator.update,
45639
+ baseExperiment: evaluator.baseExperimentName ?? baseExperiment,
45640
+ baseExperimentId: evaluator.baseExperimentId,
45641
+ gitMetadataSettings: evaluator.gitMetadataSettings,
45642
+ repoInfo: evaluator.repoInfo,
45643
+ dataset: Dataset2.isDataset(data) ? data : void 0,
45644
+ parameters
45645
+ });
45646
+ }
44812
45647
  function callEvaluatorData(data) {
44813
45648
  const dataResult = typeof data === "function" ? data() : data;
44814
45649
  let baseExperiment = void 0;
@@ -44826,6 +45661,48 @@ function isAsyncIterable7(value) {
44826
45661
  function isIterable(value) {
44827
45662
  return typeof value === "object" && value !== null && Symbol.iterator in value && typeof value[Symbol.iterator] === "function";
44828
45663
  }
45664
+ async function _internalResolveEvaluatorData(evaluator, experiment) {
45665
+ if (typeof evaluator.data === "string") {
45666
+ throw new Error("Unimplemented: string data paths");
45667
+ }
45668
+ let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
45669
+ if ("_type" in dataResult) {
45670
+ if (dataResult._type !== "BaseExperiment") {
45671
+ throw new Error("Invalid _type");
45672
+ }
45673
+ if (!experiment) {
45674
+ throw new Error(
45675
+ "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
45676
+ );
45677
+ }
45678
+ let name = dataResult.name;
45679
+ if (isEmpty2(name)) {
45680
+ const baseExperiment = await experiment.fetchBaseExperiment();
45681
+ if (!baseExperiment) {
45682
+ throw new Error("BaseExperiment() failed to fetch base experiment");
45683
+ }
45684
+ name = baseExperiment.name;
45685
+ }
45686
+ dataResult = initExperiment2(evaluator.state, {
45687
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
45688
+ experiment: name,
45689
+ open: true
45690
+ }).asDataset();
45691
+ }
45692
+ const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
45693
+ if (isAsyncIterable7(resolvedDataResult)) {
45694
+ return resolvedDataResult;
45695
+ }
45696
+ if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
45697
+ const iterable = resolvedDataResult;
45698
+ return (async function* () {
45699
+ for (const datum of iterable) yield datum;
45700
+ })();
45701
+ }
45702
+ throw new Error(
45703
+ "Evaluator data must be an array, iterable, or async iterable"
45704
+ );
45705
+ }
44829
45706
  globalThis._evals = {
44830
45707
  functions: [],
44831
45708
  prompts: [],
@@ -44872,25 +45749,13 @@ async function Eval(name, evaluator, reporterOrOpts) {
44872
45749
  }
44873
45750
  const resolvedReporter = options.reporter || defaultReporter;
44874
45751
  try {
44875
- const { data, baseExperiment: defaultBaseExperiment } = callEvaluatorData(
44876
- evaluator.data
44877
- );
44878
- const parameters = await getExperimentParametersRef(evaluator.parameters);
44879
- const experiment = options.parent || options.noSendLogs ? null : initExperiment2(evaluator.state, {
44880
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: name },
44881
- experiment: evaluator.experimentName,
44882
- description: evaluator.description,
44883
- metadata: evaluator.metadata,
44884
- tags: evaluator.tags,
44885
- isPublic: evaluator.isPublic,
44886
- update: evaluator.update,
44887
- baseExperiment: evaluator.baseExperimentName ?? defaultBaseExperiment,
44888
- baseExperimentId: evaluator.baseExperimentId,
44889
- gitMetadataSettings: evaluator.gitMetadataSettings,
44890
- repoInfo: evaluator.repoInfo,
44891
- dataset: Dataset2.isDataset(data) ? data : void 0,
44892
- parameters
44893
- });
45752
+ const { data } = callEvaluatorData(evaluator.data);
45753
+ const experiment = await _internalInitEvaluatorExperiment(
45754
+ name,
45755
+ evaluator,
45756
+ data,
45757
+ { disabled: Boolean(options.parent || options.noSendLogs) }
45758
+ );
44894
45759
  if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
44895
45760
  await experiment._waitForId();
44896
45761
  }
@@ -44988,19 +45853,74 @@ function scorerName(scorer, scorer_idx) {
44988
45853
  function classifierName(classifier, classifier_idx) {
44989
45854
  return classifier.name || `classifier_${classifier_idx}`;
44990
45855
  }
45856
+ async function _internalRunEvaluatorTask(task, datum, trialIndex, parameters, span, reportProgress = () => void 0) {
45857
+ const metadata = {
45858
+ ..."metadata" in datum ? datum.metadata : {}
45859
+ };
45860
+ const hooks = {
45861
+ meta(value) {
45862
+ Object.assign(metadata, value);
45863
+ },
45864
+ metadata,
45865
+ expected: "expected" in datum ? datum.expected : void 0,
45866
+ span,
45867
+ parameters,
45868
+ reportProgress,
45869
+ trialIndex,
45870
+ tags: [...datum.tags ?? []]
45871
+ };
45872
+ const output = await task(datum.input, hooks);
45873
+ span.log({ output });
45874
+ return {
45875
+ output,
45876
+ metadata: hooks.metadata,
45877
+ tags: hooks.tags ?? []
45878
+ };
45879
+ }
44991
45880
  function buildSpanMetadata(results) {
44992
- return results.length === 1 ? results[0].metadata : results.reduce(
44993
- (prev, s) => mergeDicts(prev, { [s.name]: s.metadata }),
44994
- {}
45881
+ return results.length === 1 ? results[0].metadata : Object.fromEntries(
45882
+ results.map((result) => [result.name, result.metadata])
44995
45883
  );
44996
45884
  }
44997
45885
  function buildSpanScores(results) {
44998
- const scoresRecord = results.reduce(
44999
- (prev, s) => mergeDicts(prev, { [s.name]: s.score }),
45000
- {}
45886
+ const scoresRecord = Object.fromEntries(
45887
+ results.map((result) => [result.name, result.score])
45001
45888
  );
45002
45889
  return { resultMetadata: buildSpanMetadata(results), scoresRecord };
45003
45890
  }
45891
+ function _internalPrepareEvaluatorScore(scoreValue, name) {
45892
+ if (scoreValue === null) return { results: null };
45893
+ if (Array.isArray(scoreValue)) {
45894
+ for (const score of scoreValue) {
45895
+ if (!(typeof score === "object" && !isEmpty2(score))) {
45896
+ throw new Error(
45897
+ `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
45898
+ );
45899
+ }
45900
+ }
45901
+ }
45902
+ let results;
45903
+ if (Array.isArray(scoreValue)) {
45904
+ results = scoreValue;
45905
+ } else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
45906
+ results = [scoreValue];
45907
+ } else {
45908
+ results = [{ name, score: scoreValue }];
45909
+ }
45910
+ const { resultMetadata, scoresRecord } = buildSpanScores(results);
45911
+ const fields = (score) => {
45912
+ const { metadata: _metadata, name: _name, ...rest } = score;
45913
+ return rest;
45914
+ };
45915
+ return {
45916
+ results,
45917
+ output: results.length === 1 ? fields(results[0]) : Object.fromEntries(
45918
+ results.map((score) => [score.name ?? name, fields(score)])
45919
+ ),
45920
+ metadata: resultMetadata,
45921
+ scores: scoresRecord
45922
+ };
45923
+ }
45004
45924
  async function runInScorerSpan(rootSpan, spanName, spanType, propagatedEvent, eventInput, fn) {
45005
45925
  try {
45006
45926
  const value = await rootSpan.traced(fn, {
@@ -45045,6 +45965,27 @@ function toClassificationItem(c) {
45045
45965
  ...c.metadata !== void 0 ? { metadata: c.metadata } : {}
45046
45966
  };
45047
45967
  }
45968
+ function _internalPrepareEvaluatorClassification(value, name) {
45969
+ if (value === null) return { results: null };
45970
+ const results = (Array.isArray(value) ? value : [value]).map(
45971
+ (result) => validateClassificationResult(result, name)
45972
+ );
45973
+ const classifications = /* @__PURE__ */ Object.create(null);
45974
+ for (const result of results) {
45975
+ (classifications[result.name] ??= []).push(toClassificationItem(result));
45976
+ }
45977
+ return {
45978
+ results,
45979
+ output: results.length === 1 ? toClassificationItem(results[0]) : Object.fromEntries(
45980
+ results.map((result) => [
45981
+ result.name,
45982
+ toClassificationItem(result)
45983
+ ])
45984
+ ),
45985
+ metadata: buildSpanMetadata(results),
45986
+ classifications
45987
+ };
45988
+ }
45048
45989
  function logScoringFailures(kind, failures, metadata, rootSpan, state) {
45049
45990
  if (!failures.length) return [];
45050
45991
  const errorMap = Object.fromEntries(
@@ -45092,54 +46033,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45092
46033
  (evaluator.state ?? _internalGetGlobalState())?.spanCache?.start();
45093
46034
  }
45094
46035
  try {
45095
- if (typeof evaluator.data === "string") {
45096
- throw new Error("Unimplemented: string data paths");
45097
- }
45098
- let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
45099
46036
  parameters = await validateParameters(
45100
46037
  parameters ?? {},
45101
46038
  evaluator.parameters
45102
46039
  );
45103
- if ("_type" in dataResult) {
45104
- if (dataResult._type !== "BaseExperiment") {
45105
- throw new Error("Invalid _type");
45106
- }
45107
- if (!experiment) {
45108
- throw new Error(
45109
- "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
45110
- );
45111
- }
45112
- let name = dataResult.name;
45113
- if (isEmpty2(name)) {
45114
- const baseExperiment = await experiment.fetchBaseExperiment();
45115
- if (!baseExperiment) {
45116
- throw new Error("BaseExperiment() failed to fetch base experiment");
45117
- }
45118
- name = baseExperiment.name;
45119
- }
45120
- dataResult = initExperiment2(evaluator.state, {
45121
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
45122
- experiment: name,
45123
- open: true
45124
- }).asDataset();
45125
- }
45126
- const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
45127
- const dataIterable = (() => {
45128
- if (isAsyncIterable7(resolvedDataResult)) {
45129
- return resolvedDataResult;
45130
- }
45131
- if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
45132
- const iterable = resolvedDataResult;
45133
- return (async function* () {
45134
- for (const datum of iterable) {
45135
- yield datum;
45136
- }
45137
- })();
45138
- }
45139
- throw new Error(
45140
- "Evaluator data must be an array, iterable, or async iterable"
45141
- );
45142
- })();
46040
+ const dataIterable = await _internalResolveEvaluatorData(
46041
+ evaluator,
46042
+ experiment
46043
+ );
45143
46044
  progressReporter.start(evaluator.evalName, 0);
45144
46045
  const experimentIdPromise = experiment ? (async () => {
45145
46046
  try {
@@ -45208,57 +46109,45 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45208
46109
  ensureSpansFlushed,
45209
46110
  state
45210
46111
  }) : void 0;
45211
- let metadata = {
45212
- ..."metadata" in datum ? datum.metadata : {}
45213
- };
46112
+ let metadata = {};
45214
46113
  const expected = "expected" in datum ? datum.expected : void 0;
45215
46114
  let output = void 0;
45216
46115
  let error = void 0;
45217
- let tags = [...datum.tags ?? []];
45218
- const scores = {};
45219
- const classifications = {};
46116
+ let tags = [];
46117
+ const scores = /* @__PURE__ */ Object.create(null);
46118
+ const classifications = /* @__PURE__ */ Object.create(null);
45220
46119
  const scorerNames = (evaluator.scores ?? []).map(scorerName);
45221
46120
  const classifierNames = (evaluator.classifiers ?? []).map(
45222
46121
  classifierName
45223
46122
  );
45224
46123
  let unhandledScores = scorerNames;
45225
46124
  try {
45226
- const meta = (o) => metadata = { ...metadata, ...o };
45227
- await rootSpan.traced(
45228
- async (span) => {
45229
- const hooksForTask = {
45230
- meta,
45231
- metadata,
45232
- expected,
45233
- span,
45234
- parameters: parameters ?? {},
45235
- reportProgress: (event) => {
45236
- stream?.({
45237
- ...event,
45238
- id: rootSpan.id,
45239
- origin: baseEvent.event?.origin,
45240
- name: evaluator.evalName,
45241
- object_type: "task"
45242
- });
45243
- },
45244
- trialIndex,
45245
- tags
45246
- };
45247
- const outputResult = evaluator.task(datum.input, hooksForTask);
45248
- if (outputResult instanceof Promise) {
45249
- output = await outputResult;
45250
- } else {
45251
- output = outputResult;
46125
+ const taskResult = await rootSpan.traced(
46126
+ (span) => _internalRunEvaluatorTask(
46127
+ evaluator.task,
46128
+ datum,
46129
+ trialIndex,
46130
+ parameters ?? {},
46131
+ span,
46132
+ (event) => {
46133
+ stream?.({
46134
+ ...event,
46135
+ id: rootSpan.id,
46136
+ origin: baseEvent.event?.origin,
46137
+ name: evaluator.evalName,
46138
+ object_type: "task"
46139
+ });
45252
46140
  }
45253
- tags = hooksForTask.tags ?? [];
45254
- span.log({ output });
45255
- },
46141
+ ),
45256
46142
  {
45257
46143
  name: "task",
45258
46144
  spanAttributes: { type: "task" /* TASK */ },
45259
46145
  event: { input: datum.input }
45260
46146
  }
45261
46147
  );
46148
+ output = taskResult.output;
46149
+ metadata = taskResult.metadata;
46150
+ tags = taskResult.tags;
45262
46151
  if (tags.length) {
45263
46152
  rootSpan.log({ output, metadata, expected, tags });
45264
46153
  } else {
@@ -45268,20 +46157,18 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45268
46157
  await rootSpan.flush();
45269
46158
  }
45270
46159
  const scoringArgs = {
46160
+ id: datum.id,
45271
46161
  input: datum.input,
45272
46162
  expected: "expected" in datum ? datum.expected : void 0,
45273
46163
  metadata,
45274
46164
  output,
46165
+ tags,
45275
46166
  trace
45276
46167
  };
45277
46168
  const { trace: _trace, ...scoringArgsForLogging } = scoringArgs;
45278
46169
  const propagatedEvent = makeScorerPropagatedEvent(
45279
46170
  await rootSpan.export()
45280
46171
  );
45281
- const getOtherFields = (s) => {
45282
- const { metadata: _metadata, name: _name, ...rest } = s;
45283
- return rest;
45284
- };
45285
46172
  const [scoreResults, classificationResults] = await Promise.all([
45286
46173
  Promise.all(
45287
46174
  (evaluator.scores ?? []).map(
@@ -45295,35 +46182,17 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45295
46182
  const scoreValue = await Promise.resolve(
45296
46183
  score(scoringArgs)
45297
46184
  );
45298
- if (scoreValue === null) return null;
45299
- if (Array.isArray(scoreValue)) {
45300
- for (const s of scoreValue) {
45301
- if (!(typeof s === "object" && !isEmpty2(s))) {
45302
- throw new Error(
45303
- `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(s)}`
45304
- );
45305
- }
45306
- }
45307
- }
45308
- const results = Array.isArray(scoreValue) ? scoreValue : typeof scoreValue === "object" && !isEmpty2(scoreValue) ? [scoreValue] : [
45309
- {
45310
- name: scorerNames[score_idx],
45311
- score: scoreValue
45312
- }
45313
- ];
45314
- const { resultMetadata, scoresRecord } = buildSpanScores(results);
45315
- const resultOutput = results.length === 1 ? getOtherFields(results[0]) : results.reduce(
45316
- (prev, s) => mergeDicts(prev, {
45317
- [s.name]: getOtherFields(s)
45318
- }),
45319
- {}
46185
+ const prepared = _internalPrepareEvaluatorScore(
46186
+ scoreValue,
46187
+ scorerNames[score_idx]
45320
46188
  );
46189
+ if (prepared.results === null) return null;
45321
46190
  span.log({
45322
- output: resultOutput,
45323
- metadata: resultMetadata,
45324
- scores: scoresRecord
46191
+ output: prepared.output,
46192
+ metadata: prepared.metadata,
46193
+ scores: prepared.scores
45325
46194
  });
45326
- return results;
46195
+ return prepared.results;
45327
46196
  }
45328
46197
  )
45329
46198
  )
@@ -45340,24 +46209,16 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45340
46209
  const classifierValue = await Promise.resolve(
45341
46210
  classifier(scoringArgs)
45342
46211
  );
45343
- if (classifierValue === null) return null;
45344
- const rawResults = (Array.isArray(classifierValue) ? classifierValue : [classifierValue]).map(
45345
- (result) => validateClassificationResult(
45346
- result,
45347
- classifierNames[idx]
45348
- )
45349
- );
45350
- const resultOutput = rawResults.length === 1 ? toClassificationItem(rawResults[0]) : rawResults.reduce(
45351
- (prev, r) => mergeDicts(prev, {
45352
- [r.name]: toClassificationItem(r)
45353
- }),
45354
- {}
46212
+ const prepared = _internalPrepareEvaluatorClassification(
46213
+ classifierValue,
46214
+ classifierNames[idx]
45355
46215
  );
46216
+ if (prepared.results === null) return null;
45356
46217
  span.log({
45357
- output: resultOutput,
45358
- metadata: buildSpanMetadata(rawResults)
46218
+ output: prepared.output,
46219
+ metadata: prepared.metadata
45359
46220
  });
45360
- return rawResults;
46221
+ return prepared.results;
45361
46222
  }
45362
46223
  )
45363
46224
  )
@@ -45586,7 +46447,7 @@ function accumulateScores(accumulator, scores) {
45586
46447
  }
45587
46448
  }
45588
46449
  function ensureScoreAccumulator(results) {
45589
- const accumulator = {};
46450
+ const accumulator = /* @__PURE__ */ Object.create(null);
45590
46451
  for (const result of results) {
45591
46452
  accumulateScores(accumulator, result.scores);
45592
46453
  }
@@ -45729,6 +46590,1156 @@ var defaultReporter = {
45729
46590
  }
45730
46591
  };
45731
46592
 
46593
+ // src/durable-eval.ts
46594
+ var encoder = new TextEncoder();
46595
+ var decoder = new TextDecoder();
46596
+ var BATCH_TASK_KIND = "braintrust.durable.batch-task";
46597
+ var BATCH_SCORER_KIND = "braintrust.durable.batch-scorer";
46598
+ var DEFAULT_BATCH_SIZE = 1e3;
46599
+ var DurableEvalMemoryStore = class {
46600
+ values = /* @__PURE__ */ new Map();
46601
+ async read(key) {
46602
+ return this.values.get(key)?.slice();
46603
+ }
46604
+ async write(key, value) {
46605
+ this.values.set(key, value.slice());
46606
+ }
46607
+ async getOrSet(key, value) {
46608
+ const existing = this.values.get(key);
46609
+ if (existing) return { value: existing.slice(), created: false };
46610
+ this.values.set(key, value.slice());
46611
+ return { value: value.slice(), created: true };
46612
+ }
46613
+ };
46614
+ var DurableEvalRedisStore = class {
46615
+ client;
46616
+ keyPrefix;
46617
+ ttlMs;
46618
+ constructor(options) {
46619
+ this.client = options.client;
46620
+ this.keyPrefix = options.keyPrefix ?? "braintrust-eval:";
46621
+ this.ttlMs = options.ttlMs ?? 1e3 * 60 * 60 * 24 * 7;
46622
+ if (!Number.isInteger(this.ttlMs) || this.ttlMs < 1) {
46623
+ throw new Error("DurableEvalRedisStore ttlMs must be a positive integer");
46624
+ }
46625
+ }
46626
+ async read(key) {
46627
+ const value = await this.client.get(`${this.keyPrefix}${key}`);
46628
+ if (value == null) return void 0;
46629
+ if (typeof value !== "string") {
46630
+ throw new Error("DurableEvalRedisStore expected GET to return a string");
46631
+ }
46632
+ return base64ToUint8Array(value);
46633
+ }
46634
+ async write(key, value) {
46635
+ const client = this.client;
46636
+ const set = client.set;
46637
+ const redisKey = `${this.keyPrefix}${key}`;
46638
+ const encoded = uint8ArrayToBase64(value);
46639
+ if (typeof client.defineCommand === "function") {
46640
+ await set.call(client, redisKey, encoded, "PX", this.ttlMs);
46641
+ } else if (typeof client.sendCommand === "function") {
46642
+ await set.call(client, redisKey, encoded, { PX: this.ttlMs });
46643
+ } else if (typeof client.createScript === "function") {
46644
+ await set.call(client, redisKey, encoded, { px: this.ttlMs });
46645
+ } else {
46646
+ throw new Error(
46647
+ "DurableEvalRedisStore requires a node-redis, ioredis, or @upstash/redis client"
46648
+ );
46649
+ }
46650
+ }
46651
+ async getOrSet(key, value) {
46652
+ const redisKey = `${this.keyPrefix}${key}`;
46653
+ const encoded = uint8ArrayToBase64(value);
46654
+ const client = this.client;
46655
+ const set = client.set;
46656
+ let setOptions;
46657
+ if (typeof client.defineCommand === "function") {
46658
+ setOptions = ["PX", this.ttlMs, "NX", "GET"];
46659
+ } else if (typeof client.sendCommand === "function") {
46660
+ setOptions = [{ PX: this.ttlMs, NX: true, GET: true }];
46661
+ } else if (typeof client.createScript === "function") {
46662
+ setOptions = [{ px: this.ttlMs, nx: true, get: true }];
46663
+ } else {
46664
+ throw new Error(
46665
+ "DurableEvalRedisStore getOrSet requires a node-redis, ioredis, or @upstash/redis client"
46666
+ );
46667
+ }
46668
+ const existing = await set.call(client, redisKey, encoded, ...setOptions);
46669
+ if (existing === null) return { value: value.slice(), created: true };
46670
+ if (typeof existing !== "string") {
46671
+ throw new Error(
46672
+ "DurableEvalRedisStore expected atomic SET to return a string or null"
46673
+ );
46674
+ }
46675
+ return { value: base64ToUint8Array(existing), created: false };
46676
+ }
46677
+ };
46678
+ var BatchTask = class {
46679
+ constructor(processor) {
46680
+ this.processor = processor;
46681
+ }
46682
+ processor;
46683
+ kind = BATCH_TASK_KIND;
46684
+ };
46685
+ var BatchScorer = class {
46686
+ constructor(processor) {
46687
+ this.processor = processor;
46688
+ this.name = processor.name;
46689
+ }
46690
+ processor;
46691
+ kind = BATCH_SCORER_KIND;
46692
+ name;
46693
+ };
46694
+ function defineDurableEval(projectName, evaluator) {
46695
+ const definition = {
46696
+ projectName,
46697
+ evalName: evaluator.experimentName ?? projectName,
46698
+ evaluator
46699
+ };
46700
+ return {
46701
+ start: (options = {}) => startDurableEval(definition, options),
46702
+ status: (options) => getDurableEvalStatus(definition, options),
46703
+ poll: (options) => pollDurableEval(definition, options),
46704
+ processBatchResult: (result) => processDurableBatchResult(definition, result)
46705
+ };
46706
+ }
46707
+ async function startDurableEval(definition, options) {
46708
+ const store = definition.evaluator.store;
46709
+ const runId = newId();
46710
+ const key = runKey(definition.projectName, definition.evalName, runId);
46711
+ const { data } = callEvaluatorData(definition.evaluator.data);
46712
+ const parameters = await validateParameters(
46713
+ options.parameters ?? {},
46714
+ definition.evaluator.parameters
46715
+ );
46716
+ const experimentName = definition.evaluator.experimentName ?? `${definition.evalName}-${runId}`;
46717
+ const experiment = await _internalInitEvaluatorExperiment(
46718
+ definition.projectName,
46719
+ { ...definition.evaluator, data },
46720
+ data,
46721
+ {
46722
+ disabled: options.noSendLogs ?? false,
46723
+ experimentName,
46724
+ update: true
46725
+ }
46726
+ );
46727
+ if (!isBatchTask(definition.evaluator.task) && !(definition.evaluator.scores ?? []).some(isBatchScorer)) {
46728
+ const result = await runEvaluator(
46729
+ experiment,
46730
+ {
46731
+ ...definition.evaluator,
46732
+ projectName: definition.projectName,
46733
+ evalName: definition.evalName,
46734
+ data
46735
+ },
46736
+ {
46737
+ start: () => void 0,
46738
+ stop: () => void 0,
46739
+ increment: () => void 0
46740
+ },
46741
+ [],
46742
+ void 0,
46743
+ parameters,
46744
+ true,
46745
+ true
46746
+ );
46747
+ const state2 = {
46748
+ runId,
46749
+ experimentName,
46750
+ noSendLogs: options.noSendLogs ?? false,
46751
+ parameters: assertJsonValue(parameters, "eval parameters"),
46752
+ status: "completed",
46753
+ summary: result.summary,
46754
+ cases: [],
46755
+ batches: []
46756
+ };
46757
+ await experiment?.flush();
46758
+ await writeRunRecord(store, key, state2);
46759
+ return currentStatus(definition, state2);
46760
+ }
46761
+ const state = {
46762
+ runId,
46763
+ experimentName,
46764
+ noSendLogs: options.noSendLogs ?? false,
46765
+ parameters: assertJsonValue(parameters, "eval parameters"),
46766
+ status: "running",
46767
+ cases: await materializeCases(definition, data, experiment),
46768
+ batches: []
46769
+ };
46770
+ await writeCaseBaseRecords(store, key, state.cases);
46771
+ await writeRunRecord(store, key, state);
46772
+ return advanceDurableEval(definition, state, store, key, experiment);
46773
+ }
46774
+ async function getDurableEvalStatus(definition, options) {
46775
+ const store = definition.evaluator.store;
46776
+ const state = await readRunState(
46777
+ definition,
46778
+ store,
46779
+ runKey(definition.projectName, definition.evalName, options.runId)
46780
+ );
46781
+ if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
46782
+ return currentStatus(definition, state);
46783
+ }
46784
+ async function processDurableBatchResult(definition, result) {
46785
+ if (!result.batchId && !result.externalId) {
46786
+ throw new Error("Batch results require batchId or externalId");
46787
+ }
46788
+ const store = definition.evaluator.store;
46789
+ const key = runKey(definition.projectName, definition.evalName, result.runId);
46790
+ const state = await readRunState(definition, store, key);
46791
+ if (!state) throw new Error(`Durable eval run ${result.runId} is missing`);
46792
+ const byBatch = result.batchId ? state.batches.find((candidate) => candidate.id === result.batchId) : void 0;
46793
+ const byExternal = result.externalId ? state.batches.find(
46794
+ (candidate) => candidate.externalId === result.externalId
46795
+ ) : void 0;
46796
+ if (byBatch && byExternal && byBatch.id !== byExternal.id) {
46797
+ throw new Error("batchId and externalId identify different batches");
46798
+ }
46799
+ const batch = byBatch ?? byExternal;
46800
+ if (!batch) throw new Error("No submitted batch matches this result");
46801
+ if (batch.status !== "complete") {
46802
+ const records = await collectBatch(definition, state, batch);
46803
+ batch.status = "complete";
46804
+ await writeCaseRecords(store, key, records);
46805
+ await writeBatchRecords(store, key, [batch]);
46806
+ }
46807
+ return advanceDurableEval(
46808
+ definition,
46809
+ await readRunState(definition, store, key),
46810
+ store,
46811
+ key
46812
+ );
46813
+ }
46814
+ async function pollDurableEval(definition, options) {
46815
+ const store = definition.evaluator.store;
46816
+ const key = runKey(
46817
+ definition.projectName,
46818
+ definition.evalName,
46819
+ options.runId
46820
+ );
46821
+ const state = await readRunState(definition, store, key);
46822
+ if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
46823
+ const batches = state.batches.filter((batch) => {
46824
+ if (batch.status === "complete") return false;
46825
+ return processorForStage(definition, batch.kind, batch.scorerName).completion.mode === "poll";
46826
+ });
46827
+ const results = await Promise.all(
46828
+ batches.map(async (batch) => ({
46829
+ batch,
46830
+ result: await processorForStage(definition, batch.kind, batch.scorerName).completion.poll(batch.submissionData, {
46831
+ runId: state.runId,
46832
+ batchId: batch.id
46833
+ })
46834
+ }))
46835
+ );
46836
+ const changedCases = /* @__PURE__ */ new Map();
46837
+ const changedBatches = [];
46838
+ for (const { batch, result } of results) {
46839
+ if (result.status === "failed") throw asError(result.error);
46840
+ if (result.status !== "complete") continue;
46841
+ for (const record of await collectBatch(definition, state, batch)) {
46842
+ changedCases.set(record.id, record);
46843
+ }
46844
+ batch.status = "complete";
46845
+ changedBatches.push(batch);
46846
+ }
46847
+ if (changedBatches.length > 0) {
46848
+ await writeCaseRecords(store, key, [...changedCases.values()]);
46849
+ await writeBatchRecords(store, key, changedBatches);
46850
+ }
46851
+ const currentState = changedBatches.length > 0 ? await readRunState(definition, store, key) : state;
46852
+ return advanceDurableEval(definition, currentState, store, key);
46853
+ }
46854
+ async function openDurableExperiment(definition, state) {
46855
+ const data = [];
46856
+ return await _internalInitEvaluatorExperiment(
46857
+ definition.projectName,
46858
+ { ...definition.evaluator, data },
46859
+ data,
46860
+ {
46861
+ disabled: state.noSendLogs,
46862
+ experimentName: state.experimentName,
46863
+ update: true
46864
+ }
46865
+ );
46866
+ }
46867
+ async function advanceDurableEval(definition, state, store, key, existingExperiment) {
46868
+ if (state.status === "completed") return currentStatus(definition, state);
46869
+ const experiment = existingExperiment === void 0 ? await openDurableExperiment(definition, state) : existingExperiment;
46870
+ await runTaskStage(definition, state, store, key, experiment);
46871
+ await logCompletedTasks(definition, state, store, key, experiment);
46872
+ state = await readRunState(definition, store, key) ?? state;
46873
+ if (state.cases.some((record) => !record.taskComplete || !record.taskLogged)) {
46874
+ return currentStatus(definition, state);
46875
+ }
46876
+ await runScoreStages(definition, state, store, key, experiment);
46877
+ state = await readRunState(definition, store, key) ?? state;
46878
+ const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
46879
+ ({ name }) => name
46880
+ );
46881
+ const classifierNames = (definition.evaluator.classifiers ?? []).map(
46882
+ classifierName
46883
+ );
46884
+ if (state.cases.some(
46885
+ (record) => scorerNames.some(
46886
+ (name) => !Object.hasOwn(record.scores, name) || !Object.hasOwn(record.loggedScores, name)
46887
+ ) || classifierNames.some(
46888
+ (name) => !Object.hasOwn(record.loggedClassifications, name)
46889
+ )
46890
+ )) {
46891
+ return currentStatus(definition, state);
46892
+ }
46893
+ if (!await claimAction(store, key, "finish")) {
46894
+ const latest = await readRunState(definition, store, key);
46895
+ return currentStatus(definition, latest ?? state);
46896
+ }
46897
+ state.summary = await finishExperiment(definition, state, experiment);
46898
+ state.status = "completed";
46899
+ await writeRunRecord(store, key, state);
46900
+ return currentStatus(definition, state);
46901
+ }
46902
+ function currentStatus(definition, state) {
46903
+ if (state.status === "completed") {
46904
+ if (!state.summary) {
46905
+ throw new Error(`Durable eval run ${state.runId} has no saved summary`);
46906
+ }
46907
+ return {
46908
+ status: "completed",
46909
+ runId: state.runId,
46910
+ pending: { poll: 0, webhook: 0 },
46911
+ summary: state.summary
46912
+ };
46913
+ }
46914
+ const pending = { poll: 0, webhook: 0 };
46915
+ for (const batch of state.batches) {
46916
+ if (batch.status === "complete") continue;
46917
+ pending[processorForStage(definition, batch.kind, batch.scorerName).completion.mode]++;
46918
+ }
46919
+ return { status: "waiting", runId: state.runId, pending };
46920
+ }
46921
+ async function startCaseRoot(definition, state, record, experiment) {
46922
+ if (!experiment) return NOOP_SPAN;
46923
+ const datum = record.datum;
46924
+ return _internalStartSpanWithInitialMerge({
46925
+ ...definition.evaluator.state ? { state: definition.evaluator.state } : {},
46926
+ parent: await experiment.export(),
46927
+ name: "eval",
46928
+ spanId: deterministicId(`${state.runId}:${record.id}:span`),
46929
+ spanAttributes: { type: "eval" /* EVAL */ },
46930
+ event: {
46931
+ id: deterministicId(`${state.runId}:${record.id}:row`),
46932
+ input: datum.input,
46933
+ expected: "expected" in datum ? datum.expected : void 0,
46934
+ tags: datum.tags,
46935
+ origin: datum.origin
46936
+ }
46937
+ });
46938
+ }
46939
+ async function logTaskResult(definition, state, record, experiment, task) {
46940
+ const datum = record.datum;
46941
+ const root = await startCaseRoot(definition, state, record, experiment);
46942
+ try {
46943
+ if (task) {
46944
+ const result = await root.traced(
46945
+ (span) => _internalRunEvaluatorTask(
46946
+ task,
46947
+ datum,
46948
+ record.trialIndex,
46949
+ state.parameters,
46950
+ span
46951
+ ),
46952
+ {
46953
+ name: "task",
46954
+ spanId: deterministicId(`${state.runId}:${record.id}:task`),
46955
+ spanAttributes: { type: "task" /* TASK */ },
46956
+ event: { input: datum.input }
46957
+ }
46958
+ );
46959
+ record.output = assertJsonValue(
46960
+ result.output,
46961
+ `task output for ${record.caseId}`
46962
+ );
46963
+ record.metadata = assertJsonValue(result.metadata, "task metadata");
46964
+ record.tags = result.tags;
46965
+ record.taskComplete = true;
46966
+ } else {
46967
+ await root.traced((span) => span.log({ output: record.output }), {
46968
+ name: "task",
46969
+ spanId: deterministicId(`${state.runId}:${record.id}:task`),
46970
+ spanAttributes: { type: "task" /* TASK */ },
46971
+ event: { input: datum.input }
46972
+ });
46973
+ }
46974
+ root.log({
46975
+ output: record.output,
46976
+ expected: "expected" in datum ? datum.expected : void 0,
46977
+ metadata: {
46978
+ ...record.metadata,
46979
+ durable_eval: {
46980
+ run_id: state.runId,
46981
+ case_id: record.caseId,
46982
+ trial_index: record.trialIndex
46983
+ }
46984
+ },
46985
+ tags: record.tags
46986
+ });
46987
+ record.rootSpan = await root.export();
46988
+ record.taskLogged = true;
46989
+ } catch (error) {
46990
+ logError(root, error);
46991
+ throw error;
46992
+ } finally {
46993
+ root.end();
46994
+ }
46995
+ }
46996
+ async function logCompletedTasks(definition, state, store, key, experiment) {
46997
+ const changed = [];
46998
+ for (const record of state.cases) {
46999
+ if (!record.taskComplete || record.taskLogged) continue;
47000
+ if (!await claimAction(store, key, "task-log", record.id)) continue;
47001
+ await logTaskResult(definition, state, record, experiment);
47002
+ changed.push(record);
47003
+ }
47004
+ if (changed.length > 0) {
47005
+ await experiment?.flush();
47006
+ await writeCaseRecords(store, key, changed);
47007
+ }
47008
+ }
47009
+ async function runTaskStage(definition, state, store, key, experiment) {
47010
+ if (isBatchTask(definition.evaluator.task)) {
47011
+ await ensureBatches(definition, state, store, key, "task");
47012
+ return;
47013
+ }
47014
+ const task = definition.evaluator.task;
47015
+ const changed = [];
47016
+ for (const record of state.cases) {
47017
+ if (record.taskComplete) continue;
47018
+ if (!await claimAction(store, key, "task", record.id)) continue;
47019
+ await logTaskResult(definition, state, record, experiment, task);
47020
+ changed.push(record);
47021
+ }
47022
+ if (changed.length > 0) {
47023
+ await experiment?.flush();
47024
+ await writeCaseRecords(store, key, changed);
47025
+ }
47026
+ }
47027
+ async function runScoreStages(definition, state, store, key, experiment) {
47028
+ const scorers = resolveScorers(definition.evaluator.scores ?? []);
47029
+ const changed = /* @__PURE__ */ new Map();
47030
+ const persistChangedCases = async () => {
47031
+ if (changed.size === 0) return;
47032
+ await experiment?.flush();
47033
+ await writeCaseRecords(store, key, [...changed.values()]);
47034
+ changed.clear();
47035
+ };
47036
+ for (const { name, scorer } of scorers) {
47037
+ if (isBatchScorer(scorer)) {
47038
+ for (const record of state.cases) {
47039
+ if (Object.hasOwn(record.scores, name) && !Object.hasOwn(record.loggedScores, name)) {
47040
+ if (!await claimAction(store, key, "score-log", record.id, name)) {
47041
+ continue;
47042
+ }
47043
+ await evaluateAndLogScore(
47044
+ definition,
47045
+ state,
47046
+ record,
47047
+ name,
47048
+ experiment
47049
+ );
47050
+ changed.set(record.id, record);
47051
+ }
47052
+ }
47053
+ await persistChangedCases();
47054
+ await ensureBatches(definition, state, store, key, "score", name);
47055
+ continue;
47056
+ }
47057
+ for (const record of state.cases) {
47058
+ if (Object.hasOwn(record.loggedScores, name)) continue;
47059
+ if (!await claimAction(store, key, "score", record.id, name)) continue;
47060
+ await evaluateAndLogScore(
47061
+ definition,
47062
+ state,
47063
+ record,
47064
+ name,
47065
+ experiment,
47066
+ scorer
47067
+ );
47068
+ changed.set(record.id, record);
47069
+ }
47070
+ }
47071
+ for (const [index, classifier] of (definition.evaluator.classifiers ?? []).entries()) {
47072
+ const name = classifierName(classifier, index);
47073
+ for (const record of state.cases) {
47074
+ if (Object.hasOwn(record.loggedClassifications, name)) continue;
47075
+ if (!await claimAction(store, key, "classification", record.id, name)) {
47076
+ continue;
47077
+ }
47078
+ await evaluateAndLogClassification(
47079
+ definition,
47080
+ state,
47081
+ record,
47082
+ name,
47083
+ classifier,
47084
+ experiment
47085
+ );
47086
+ changed.set(record.id, record);
47087
+ }
47088
+ }
47089
+ await persistChangedCases();
47090
+ }
47091
+ function scorerArgs(record) {
47092
+ const datum = record.datum;
47093
+ return {
47094
+ ...datum,
47095
+ metadata: record.metadata,
47096
+ output: record.output
47097
+ };
47098
+ }
47099
+ function resumeCaseRoot(definition, record, experiment) {
47100
+ if (!experiment) return NOOP_SPAN;
47101
+ if (!record.rootSpan) {
47102
+ throw new Error(`Durable eval case ${record.caseId} has no root span`);
47103
+ }
47104
+ return _internalResumeSpan({
47105
+ exported: record.rootSpan,
47106
+ state: definition.evaluator.state
47107
+ });
47108
+ }
47109
+ async function evaluateAndLogScore(definition, state, record, name, experiment, scorer) {
47110
+ const root = resumeCaseRoot(definition, record, experiment);
47111
+ try {
47112
+ const rootExport = await root.export();
47113
+ const prepared = await root.traced(
47114
+ async (span) => {
47115
+ const value = scorer ? await scorer(scorerArgs(record)) : record.scores[name];
47116
+ if (scorer) {
47117
+ record.scores[name] = assertJsonValue(value, `scorer ${name} output`);
47118
+ }
47119
+ const result = _internalPrepareEvaluatorScore(value, name);
47120
+ if (result.results !== null) {
47121
+ span.log({
47122
+ output: result.output,
47123
+ metadata: result.metadata,
47124
+ scores: result.scores
47125
+ });
47126
+ }
47127
+ return result;
47128
+ },
47129
+ {
47130
+ name,
47131
+ spanId: deterministicId(`${state.runId}:${record.id}:score:${name}`),
47132
+ spanAttributes: {
47133
+ type: "score" /* SCORE */,
47134
+ purpose: "scorer"
47135
+ },
47136
+ propagatedEvent: makeScorerPropagatedEvent(rootExport || void 0),
47137
+ event: { input: scorerArgs(record) }
47138
+ }
47139
+ );
47140
+ if (prepared.scores) root.log({ scores: prepared.scores });
47141
+ record.loggedScores[name] = true;
47142
+ } catch (error) {
47143
+ logError(root, error);
47144
+ throw error;
47145
+ } finally {
47146
+ root.end();
47147
+ }
47148
+ }
47149
+ async function evaluateAndLogClassification(definition, state, record, name, classifier, experiment) {
47150
+ const root = resumeCaseRoot(definition, record, experiment);
47151
+ try {
47152
+ const rootExport = await root.export();
47153
+ const prepared = await root.traced(
47154
+ async (span) => {
47155
+ const value = await classifier(scorerArgs(record));
47156
+ record.classifications[name] = assertJsonValue(
47157
+ value,
47158
+ `classifier ${name} output`
47159
+ );
47160
+ const result = _internalPrepareEvaluatorClassification(value, name);
47161
+ if (result.results !== null) {
47162
+ span.log({ output: result.output, metadata: result.metadata });
47163
+ }
47164
+ return result;
47165
+ },
47166
+ {
47167
+ name,
47168
+ spanId: deterministicId(
47169
+ `${state.runId}:${record.id}:classification:${name}`
47170
+ ),
47171
+ spanAttributes: {
47172
+ type: "classifier" /* CLASSIFIER */,
47173
+ purpose: "scorer"
47174
+ },
47175
+ propagatedEvent: makeScorerPropagatedEvent(rootExport || void 0),
47176
+ event: { input: scorerArgs(record) }
47177
+ }
47178
+ );
47179
+ if (prepared.classifications) {
47180
+ root.log({ classifications: prepared.classifications });
47181
+ }
47182
+ record.loggedClassifications[name] = true;
47183
+ } catch (error) {
47184
+ logError(root, error);
47185
+ throw error;
47186
+ } finally {
47187
+ root.end();
47188
+ }
47189
+ }
47190
+ async function ensureBatches(definition, state, store, key, kind, scorerName2) {
47191
+ const processor = processorForStage(definition, kind, scorerName2);
47192
+ const plans = plannedBatches(
47193
+ definition,
47194
+ state.runId,
47195
+ state.cases.map(({ id }) => id)
47196
+ );
47197
+ const casesById = new Map(state.cases.map((record) => [record.id, record]));
47198
+ for (const plan of plans) {
47199
+ if (plan.kind !== kind || plan.scorerName !== scorerName2) continue;
47200
+ if (state.batches.some(({ id }) => id === plan.id)) continue;
47201
+ const records = plan.itemIds.map((id) => casesById.get(id));
47202
+ const ready = records.every(
47203
+ (record) => kind === "task" ? !record.taskComplete : !Object.hasOwn(record.scores, scorerName2)
47204
+ );
47205
+ if (!ready) continue;
47206
+ const batchId = plan.id;
47207
+ const claim = await store.getOrSet(
47208
+ claimRecordKey(key, "batch", batchId),
47209
+ encoder.encode(batchId)
47210
+ );
47211
+ if (!claim.created) continue;
47212
+ const context = { runId: state.runId, batchId };
47213
+ const items = records.map(
47214
+ (record) => kind === "task" ? taskBatchItem(record, state.parameters) : scorerBatchItem(record)
47215
+ );
47216
+ const submissionData = assertJsonValue(
47217
+ await processor.submit(items, context),
47218
+ `submission data for batch ${batchId}`
47219
+ );
47220
+ const externalId = processor.completion.mode === "webhook" ? processor.completion.getExternalId(submissionData, context) : void 0;
47221
+ if (externalId !== void 0 && !externalId.trim()) {
47222
+ throw new Error(`Batch ${batchId} produced an empty externalId`);
47223
+ }
47224
+ const batch = {
47225
+ id: batchId,
47226
+ kind,
47227
+ scorerName: scorerName2,
47228
+ itemIds: records.map((record) => record.id),
47229
+ submissionData,
47230
+ externalId,
47231
+ status: "submitted"
47232
+ };
47233
+ state.batches.push(batch);
47234
+ await writeBatchRecords(store, key, [batch]);
47235
+ }
47236
+ }
47237
+ async function collectBatch(definition, state, batch) {
47238
+ const processor = processorForStage(definition, batch.kind, batch.scorerName);
47239
+ const context = { runId: state.runId, batchId: batch.id };
47240
+ const results = await processor.collect(batch.submissionData, context);
47241
+ if (!Array.isArray(results)) {
47242
+ throw new Error(`collect for batch ${batch.id} must return an array`);
47243
+ }
47244
+ const expectedIds = new Set(batch.itemIds);
47245
+ const seen = /* @__PURE__ */ new Set();
47246
+ const records = [];
47247
+ for (const result of results) {
47248
+ const id = resultItemId(result);
47249
+ if (!expectedIds.has(id)) {
47250
+ throw new Error(`Batch ${batch.id} returned unknown item ${id}`);
47251
+ }
47252
+ if (seen.has(id)) {
47253
+ throw new Error(`Batch ${batch.id} returned item ${id} more than once`);
47254
+ }
47255
+ seen.add(id);
47256
+ const record = state.cases.find((candidate) => candidate.id === id);
47257
+ records.push(record);
47258
+ if (batch.kind === "task") {
47259
+ record.output = assertJsonValue(
47260
+ result.output,
47261
+ `task output for item ${id}`
47262
+ );
47263
+ if ("metadata" in result && result.metadata !== void 0) {
47264
+ record.metadata = assertJsonValue(
47265
+ {
47266
+ ...record.metadata,
47267
+ ...result.metadata
47268
+ },
47269
+ `metadata for ${id}`
47270
+ );
47271
+ }
47272
+ if ("tags" in result && result.tags !== void 0)
47273
+ record.tags = result.tags;
47274
+ record.taskComplete = true;
47275
+ } else {
47276
+ record.scores[batch.scorerName] = assertJsonValue(
47277
+ result.score,
47278
+ `score output for item ${id}`
47279
+ );
47280
+ }
47281
+ }
47282
+ const missing = batch.itemIds.filter((id) => !seen.has(id));
47283
+ if (missing.length > 0) {
47284
+ throw new Error(
47285
+ `Batch ${batch.id} did not return results for: ${missing.join(", ")}`
47286
+ );
47287
+ }
47288
+ return records;
47289
+ }
47290
+ function processorForStage(definition, kind, scorerName2) {
47291
+ if (kind === "task") {
47292
+ if (!isBatchTask(definition.evaluator.task)) {
47293
+ throw new Error("Definition no longer contains the batch task");
47294
+ }
47295
+ return definition.evaluator.task.processor;
47296
+ }
47297
+ const scorer = resolveScorers(definition.evaluator.scores ?? []).find(
47298
+ ({ name }) => name === scorerName2
47299
+ )?.scorer;
47300
+ if (!isBatchScorer(scorer)) {
47301
+ throw new Error(`Definition no longer contains scorer ${scorerName2}`);
47302
+ }
47303
+ return scorer.processor;
47304
+ }
47305
+ async function materializeCases(definition, data, experiment) {
47306
+ const evaluator = definition.evaluator;
47307
+ const iterable = await _internalResolveEvaluatorData(
47308
+ {
47309
+ data,
47310
+ projectName: definition.projectName,
47311
+ projectId: evaluator.projectId,
47312
+ state: evaluator.state
47313
+ },
47314
+ experiment
47315
+ );
47316
+ const records = [];
47317
+ const seen = /* @__PURE__ */ new Set();
47318
+ for await (const datum of iterable) {
47319
+ const caseId = datum.id ?? datum.upsert_id ?? (evaluator.caseId ? await evaluator.caseId(datum) : void 0);
47320
+ if (!caseId) {
47321
+ throw new Error(
47322
+ "Every durable eval case requires id, upsert_id, or caseId"
47323
+ );
47324
+ }
47325
+ if (seen.has(caseId))
47326
+ throw new Error(`Duplicate durable eval case id: ${caseId}`);
47327
+ seen.add(caseId);
47328
+ const trialCount = datum.trialCount ?? evaluator.trialCount ?? 1;
47329
+ if (!Number.isInteger(trialCount) || trialCount < 1) {
47330
+ throw new Error(`Invalid trialCount for durable eval case ${caseId}`);
47331
+ }
47332
+ for (let trialIndex = 0; trialIndex < trialCount; trialIndex++) {
47333
+ records.push({
47334
+ id: `${caseId}:trial:${trialIndex}`,
47335
+ caseId,
47336
+ trialIndex,
47337
+ datum: assertJsonValue(datum, `case ${caseId}`),
47338
+ metadata: assertJsonValue(
47339
+ "metadata" in datum ? datum.metadata : {},
47340
+ `metadata for ${caseId}`
47341
+ ),
47342
+ tags: datum.tags,
47343
+ taskComplete: false,
47344
+ taskLogged: false,
47345
+ scores: /* @__PURE__ */ Object.create(null),
47346
+ loggedScores: /* @__PURE__ */ Object.create(null),
47347
+ classifications: /* @__PURE__ */ Object.create(null),
47348
+ loggedClassifications: /* @__PURE__ */ Object.create(null)
47349
+ });
47350
+ }
47351
+ }
47352
+ return records;
47353
+ }
47354
+ function taskBatchItem(record, parameters) {
47355
+ const datum = record.datum;
47356
+ return {
47357
+ id: record.id,
47358
+ input: datum.input,
47359
+ expected: "expected" in datum ? datum.expected : void 0,
47360
+ metadata: record.metadata,
47361
+ tags: record.tags,
47362
+ parameters,
47363
+ trialIndex: record.trialIndex
47364
+ };
47365
+ }
47366
+ function scorerBatchItem(record) {
47367
+ const datum = record.datum;
47368
+ return {
47369
+ id: record.id,
47370
+ input: datum.input,
47371
+ output: record.output,
47372
+ expected: "expected" in datum ? datum.expected : void 0,
47373
+ metadata: record.metadata,
47374
+ tags: record.tags,
47375
+ trialIndex: record.trialIndex
47376
+ };
47377
+ }
47378
+ async function finishExperiment(definition, state, experiment) {
47379
+ const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
47380
+ ({ name }) => name
47381
+ );
47382
+ const results = state.cases.map((record) => {
47383
+ const datum = record.datum;
47384
+ const scores = Object.fromEntries(
47385
+ scorerNames.flatMap(
47386
+ (name) => Object.entries(
47387
+ _internalPrepareEvaluatorScore(
47388
+ record.scores[name],
47389
+ name
47390
+ ).scores ?? {}
47391
+ )
47392
+ )
47393
+ );
47394
+ const classifications = Object.fromEntries(
47395
+ Object.entries(record.classifications).flatMap(
47396
+ ([name, value]) => Object.entries(
47397
+ _internalPrepareEvaluatorClassification(value, name).classifications ?? {}
47398
+ )
47399
+ )
47400
+ );
47401
+ return {
47402
+ ...datum,
47403
+ output: record.output,
47404
+ metadata: record.metadata,
47405
+ tags: record.tags,
47406
+ scores,
47407
+ error: void 0,
47408
+ ...Object.keys(classifications).length > 0 ? { classifications } : {}
47409
+ };
47410
+ });
47411
+ if (!experiment) {
47412
+ return buildLocalSummary(
47413
+ {
47414
+ ...definition.evaluator,
47415
+ projectName: definition.projectName,
47416
+ evalName: state.experimentName
47417
+ },
47418
+ results
47419
+ );
47420
+ }
47421
+ await experiment.flush();
47422
+ let comparisonExperimentId = definition.evaluator.baseExperimentId;
47423
+ if (!comparisonExperimentId) {
47424
+ try {
47425
+ comparisonExperimentId = await experiment._getBaseExperimentId();
47426
+ } catch {
47427
+ comparisonExperimentId = void 0;
47428
+ }
47429
+ }
47430
+ return await experiment.summarize({
47431
+ summarizeScores: definition.evaluator.summarizeScores,
47432
+ ...comparisonExperimentId ? { comparisonExperimentId } : {}
47433
+ });
47434
+ }
47435
+ function resolveScorers(scorers) {
47436
+ return scorers.map((scorer, index) => ({
47437
+ name: isBatchScorer(scorer) ? scorer.name : scorer.name || `scorer_${index}`,
47438
+ scorer
47439
+ }));
47440
+ }
47441
+ function runKey(projectName, evalName, runId) {
47442
+ return `durable-eval/v1/runs/${contentVersion(encoder.encode(`${projectName}\0${evalName}\0${runId}`))}`;
47443
+ }
47444
+ function encodedKeyPart(value) {
47445
+ return uint8ArrayToBase64(encoder.encode(value)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
47446
+ }
47447
+ function caseRecordKey(key, caseId, kind, ...names) {
47448
+ const suffix = names.map(encodedKeyPart).join("/");
47449
+ return `${key}/cases/${encodedKeyPart(caseId)}/${kind}${suffix ? `/${suffix}` : ""}`;
47450
+ }
47451
+ function batchRecordKey(key, batchId) {
47452
+ return `${key}/batches/${encodedKeyPart(batchId)}`;
47453
+ }
47454
+ function claimRecordKey(key, kind, ...parts) {
47455
+ const identity = stableStringify([kind, parts]);
47456
+ return `${key}/claims/${contentVersion(encoder.encode(identity))}`;
47457
+ }
47458
+ async function claimAction(store, key, kind, ...parts) {
47459
+ return (await store.getOrSet(
47460
+ claimRecordKey(key, kind, ...parts),
47461
+ encoder.encode("claimed")
47462
+ )).created;
47463
+ }
47464
+ function plannedBatches(definition, runId, caseIds) {
47465
+ const stages = [];
47466
+ if (isBatchTask(definition.evaluator.task)) stages.push({ kind: "task" });
47467
+ for (const { name, scorer } of resolveScorers(
47468
+ definition.evaluator.scores ?? []
47469
+ )) {
47470
+ if (isBatchScorer(scorer)) {
47471
+ stages.push({ kind: "score", scorerName: name });
47472
+ }
47473
+ }
47474
+ const plans = [];
47475
+ for (const { kind, scorerName: scorerName2 } of stages) {
47476
+ const batchSize = processorForStage(definition, kind, scorerName2).batchSize ?? DEFAULT_BATCH_SIZE;
47477
+ if (!Number.isInteger(batchSize) || batchSize < 1) {
47478
+ throw new Error(
47479
+ `Invalid batchSize for ${scorerName2 ?? "task"}: ${batchSize}`
47480
+ );
47481
+ }
47482
+ for (let offset = 0; offset < caseIds.length; offset += batchSize) {
47483
+ const itemIds = caseIds.slice(offset, offset + batchSize);
47484
+ plans.push({
47485
+ id: deterministicId(
47486
+ stableStringify([runId, kind, scorerName2, itemIds])
47487
+ ),
47488
+ kind,
47489
+ scorerName: scorerName2,
47490
+ itemIds
47491
+ });
47492
+ }
47493
+ }
47494
+ return plans;
47495
+ }
47496
+ async function readCaseRecord(definition, store, key, id) {
47497
+ const scorers = resolveScorers(definition.evaluator.scores ?? []);
47498
+ const classifiers = (definition.evaluator.classifiers ?? []).map(
47499
+ classifierName
47500
+ );
47501
+ const [
47502
+ base,
47503
+ task,
47504
+ taskLog,
47505
+ scoreValues,
47506
+ scoreLogValues,
47507
+ classificationValues,
47508
+ classificationLogValues
47509
+ ] = await Promise.all([
47510
+ readJson(store, caseRecordKey(key, id, "base")),
47511
+ readJson(store, caseRecordKey(key, id, "task")),
47512
+ readJson(store, caseRecordKey(key, id, "task-log")),
47513
+ Promise.all(
47514
+ scorers.map(async ({ name }) => ({
47515
+ name,
47516
+ value: await readJson(
47517
+ store,
47518
+ caseRecordKey(key, id, "score", name)
47519
+ )
47520
+ }))
47521
+ ),
47522
+ Promise.all(
47523
+ scorers.map(async ({ name }) => ({
47524
+ name,
47525
+ value: await readJson(
47526
+ store,
47527
+ caseRecordKey(key, id, "score-log", name)
47528
+ )
47529
+ }))
47530
+ ),
47531
+ Promise.all(
47532
+ classifiers.map(async (name) => ({
47533
+ name,
47534
+ value: await readJson(
47535
+ store,
47536
+ caseRecordKey(key, id, "classification", name)
47537
+ )
47538
+ }))
47539
+ ),
47540
+ Promise.all(
47541
+ classifiers.map(async (name) => ({
47542
+ name,
47543
+ value: await readJson(
47544
+ store,
47545
+ caseRecordKey(key, id, "classification-log", name)
47546
+ )
47547
+ }))
47548
+ )
47549
+ ]);
47550
+ if (!base) throw new Error(`Durable eval case ${id} is missing`);
47551
+ const scores = /* @__PURE__ */ Object.create(null);
47552
+ for (const { name, value } of scoreValues) {
47553
+ if (value !== void 0) scores[name] = value;
47554
+ }
47555
+ const loggedScores = /* @__PURE__ */ Object.create(null);
47556
+ for (const { name, value } of scoreLogValues) {
47557
+ if (value) loggedScores[name] = true;
47558
+ }
47559
+ const classifications = /* @__PURE__ */ Object.create(null);
47560
+ for (const { name, value } of classificationValues) {
47561
+ if (value !== void 0) classifications[name] = value;
47562
+ }
47563
+ const loggedClassifications = /* @__PURE__ */ Object.create(null);
47564
+ for (const { name, value } of classificationLogValues) {
47565
+ if (value) loggedClassifications[name] = true;
47566
+ }
47567
+ return {
47568
+ ...base,
47569
+ metadata: task?.metadata ?? base.metadata,
47570
+ tags: task ? task.tags : base.tags,
47571
+ taskComplete: task !== void 0,
47572
+ taskLogged: taskLog !== void 0,
47573
+ output: task?.output,
47574
+ rootSpan: taskLog?.rootSpan,
47575
+ scores,
47576
+ loggedScores,
47577
+ classifications,
47578
+ loggedClassifications
47579
+ };
47580
+ }
47581
+ async function readRunState(definition, store, key) {
47582
+ const record = await readJson(store, key);
47583
+ if (!record) return void 0;
47584
+ const plans = plannedBatches(definition, record.runId, record.caseIds);
47585
+ const [cases, batchRecords] = await Promise.all([
47586
+ Promise.all(
47587
+ record.caseIds.map((id) => readCaseRecord(definition, store, key, id))
47588
+ ),
47589
+ Promise.all(
47590
+ plans.map(async ({ id }) => {
47591
+ return readJson(store, batchRecordKey(key, id));
47592
+ })
47593
+ )
47594
+ ]);
47595
+ const batches = batchRecords.filter(
47596
+ (value) => value !== void 0
47597
+ );
47598
+ const { caseIds: _caseIds, ...state } = record;
47599
+ return { ...state, cases, batches };
47600
+ }
47601
+ async function writeRunRecord(store, key, state) {
47602
+ const { cases, batches: _batches, ...record } = state;
47603
+ await writeJson(store, key, {
47604
+ ...record,
47605
+ caseIds: cases.map(({ id }) => id)
47606
+ });
47607
+ }
47608
+ async function writeCaseBaseRecords(store, key, records) {
47609
+ await Promise.all(
47610
+ records.map(
47611
+ ({ id, caseId, trialIndex, datum, metadata, tags }) => writeJson(store, caseRecordKey(key, id, "base"), {
47612
+ id,
47613
+ caseId,
47614
+ trialIndex,
47615
+ datum,
47616
+ metadata,
47617
+ tags
47618
+ })
47619
+ )
47620
+ );
47621
+ }
47622
+ async function writeCaseRecords(store, key, records) {
47623
+ const writes = [];
47624
+ for (const record of records) {
47625
+ if (record.taskComplete) {
47626
+ writes.push(
47627
+ writeJson(store, caseRecordKey(key, record.id, "task"), {
47628
+ output: record.output,
47629
+ metadata: record.metadata,
47630
+ tags: record.tags,
47631
+ taskComplete: true
47632
+ })
47633
+ );
47634
+ }
47635
+ if (record.taskLogged) {
47636
+ writes.push(
47637
+ writeJson(store, caseRecordKey(key, record.id, "task-log"), {
47638
+ rootSpan: record.rootSpan,
47639
+ taskLogged: true
47640
+ })
47641
+ );
47642
+ }
47643
+ for (const [name, value] of Object.entries(record.scores)) {
47644
+ writes.push(
47645
+ writeJson(store, caseRecordKey(key, record.id, "score", name), value)
47646
+ );
47647
+ }
47648
+ for (const name of Object.keys(record.loggedScores)) {
47649
+ writes.push(
47650
+ writeJson(
47651
+ store,
47652
+ caseRecordKey(key, record.id, "score-log", name),
47653
+ true
47654
+ )
47655
+ );
47656
+ }
47657
+ for (const [name, value] of Object.entries(record.classifications)) {
47658
+ writes.push(
47659
+ writeJson(
47660
+ store,
47661
+ caseRecordKey(key, record.id, "classification", name),
47662
+ value
47663
+ )
47664
+ );
47665
+ }
47666
+ for (const name of Object.keys(record.loggedClassifications)) {
47667
+ writes.push(
47668
+ writeJson(
47669
+ store,
47670
+ caseRecordKey(key, record.id, "classification-log", name),
47671
+ true
47672
+ )
47673
+ );
47674
+ }
47675
+ }
47676
+ await Promise.all(writes);
47677
+ }
47678
+ async function writeBatchRecords(store, key, records) {
47679
+ await Promise.all(
47680
+ records.map(
47681
+ (record) => writeJson(store, batchRecordKey(key, record.id), record)
47682
+ )
47683
+ );
47684
+ }
47685
+ function deterministicId(value) {
47686
+ const hex = contentVersion(encoder.encode(value)).padEnd(32, "0").slice(0, 32);
47687
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-5${hex.slice(13, 16)}-a${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
47688
+ }
47689
+ function contentVersion(value) {
47690
+ if (isomorph_default.hash) return isomorph_default.hash(decoder.decode(value));
47691
+ let hash = 2166136261;
47692
+ for (const byte of value) {
47693
+ hash ^= byte;
47694
+ hash = Math.imul(hash, 16777619);
47695
+ }
47696
+ return (hash >>> 0).toString(16).padStart(8, "0");
47697
+ }
47698
+ async function readJson(store, key) {
47699
+ const value = await store.read(key);
47700
+ return value ? JSON.parse(decoder.decode(value)) : void 0;
47701
+ }
47702
+ async function writeJson(store, key, value) {
47703
+ await store.write(key, encoder.encode(stableStringify(value)));
47704
+ }
47705
+ function stableStringify(value) {
47706
+ return JSON.stringify(value, (_key, nested) => {
47707
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
47708
+ return Object.fromEntries(
47709
+ Object.entries(nested).sort(
47710
+ ([left], [right]) => left.localeCompare(right)
47711
+ )
47712
+ );
47713
+ }
47714
+ return nested;
47715
+ });
47716
+ }
47717
+ function assertJsonValue(value, label) {
47718
+ try {
47719
+ const serialized = JSON.stringify(value);
47720
+ if (serialized === void 0)
47721
+ throw new Error("value serializes to undefined");
47722
+ return JSON.parse(serialized);
47723
+ } catch (error) {
47724
+ throw new Error(`${label} must be JSON serializable`, { cause: error });
47725
+ }
47726
+ }
47727
+ function resultItemId(value) {
47728
+ if (typeof value !== "object" || value === null || !("id" in value) || typeof value.id !== "string") {
47729
+ throw new Error("Batch results must contain a string id");
47730
+ }
47731
+ return value.id;
47732
+ }
47733
+ function isBatchTask(value) {
47734
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_TASK_KIND;
47735
+ }
47736
+ function isBatchScorer(value) {
47737
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_SCORER_KIND;
47738
+ }
47739
+ function asError(error) {
47740
+ return error instanceof Error ? error : new Error(String(error));
47741
+ }
47742
+
45732
47743
  // src/agent-assertions.ts
45733
47744
  function agentAssertionScorer(callback, options = {}) {
45734
47745
  return async (args) => {
@@ -46661,6 +48672,8 @@ export {
46661
48672
  BRAINTRUST_PARENT_KEY,
46662
48673
  BaseAttachment,
46663
48674
  BaseExperiment,
48675
+ BatchScorer,
48676
+ BatchTask,
46664
48677
  BraintrustLangChainCallbackHandler,
46665
48678
  BraintrustMiddleware,
46666
48679
  BraintrustObservabilityExporter,
@@ -46674,6 +48687,8 @@ export {
46674
48687
  DEFAULT_MAX_REQUEST_SIZE,
46675
48688
  Dataset2 as Dataset,
46676
48689
  DatasetPipeline,
48690
+ DurableEvalMemoryStore,
48691
+ DurableEvalRedisStore,
46677
48692
  ERR_PERMALINK,
46678
48693
  Eval,
46679
48694
  EvalResultWithSummary,
@@ -46732,6 +48747,7 @@ export {
46732
48747
  deepCopyEvent,
46733
48748
  exports_exports as default,
46734
48749
  defaultErrorScoreHandler,
48750
+ defineDurableEval,
46735
48751
  deserializePlainStringAsJSON,
46736
48752
  devNullWritableStream,
46737
48753
  evaluatorDefinitionSchema,
@@ -46827,5 +48843,6 @@ export {
46827
48843
  wrapPiCodingAgentSDK,
46828
48844
  wrapStrandsAgentSDK,
46829
48845
  wrapTraced,
46830
- wrapVitest
48846
+ wrapVitest,
48847
+ wrapVoyageAI
46831
48848
  };