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/workerd.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() {
@@ -13052,6 +13204,22 @@ function processInputAttachments(input) {
13052
13204
  };
13053
13205
  }
13054
13206
  }
13207
+ 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;
13208
+ const voyageBase64Value = voyageBase64Key ? node[voyageBase64Key] : void 0;
13209
+ if (voyageBase64Key && typeof voyageBase64Value === "string" && voyageBase64Value.startsWith("data:")) {
13210
+ const mediaType = inferMediaTypeFromDataUrl(
13211
+ voyageBase64Value,
13212
+ node.type === "video_base64" ? "video/mp4" : "image/png"
13213
+ );
13214
+ const filename = `${node.type === "video_base64" ? "video" : "image"}.${getExtensionFromMediaType(mediaType)}`;
13215
+ const attachment = toAttachment(voyageBase64Value, mediaType, filename);
13216
+ if (attachment) {
13217
+ return {
13218
+ ...node,
13219
+ [voyageBase64Key]: attachment
13220
+ };
13221
+ }
13222
+ }
13055
13223
  if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
13056
13224
  const mediaType = inferMediaTypeFromDataUrl(
13057
13225
  node.file.file_data,
@@ -14399,12 +14567,30 @@ function logInstrumentationError(context, error) {
14399
14567
 
14400
14568
  // src/wrappers/anthropic-tokens-util.ts
14401
14569
  function finalizeAnthropicTokens(metrics) {
14402
- const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + (metrics.prompt_cache_creation_tokens || 0);
14403
- return {
14570
+ const hasSplitCacheCreationTokens = metrics.prompt_cache_creation_5m_tokens !== void 0 || metrics.prompt_cache_creation_1h_tokens !== void 0;
14571
+ const splitCacheCreationTokens = (metrics.prompt_cache_creation_5m_tokens || 0) + (metrics.prompt_cache_creation_1h_tokens || 0);
14572
+ const aggregateCacheCreationTokens = metrics.prompt_cache_creation_tokens || 0;
14573
+ const effectiveCacheCreationTokens = Math.max(
14574
+ aggregateCacheCreationTokens,
14575
+ splitCacheCreationTokens
14576
+ );
14577
+ const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + effectiveCacheCreationTokens;
14578
+ const finalized = {
14404
14579
  ...metrics,
14405
14580
  prompt_tokens,
14406
14581
  tokens: prompt_tokens + (metrics.completion_tokens || 0)
14407
14582
  };
14583
+ if (hasSplitCacheCreationTokens && splitCacheCreationTokens >= aggregateCacheCreationTokens) {
14584
+ delete finalized.prompt_cache_creation_tokens;
14585
+ }
14586
+ return finalized;
14587
+ }
14588
+ function toNumericMetrics(metrics) {
14589
+ return Object.fromEntries(
14590
+ Object.entries(metrics).filter(
14591
+ (entry) => entry[1] !== void 0
14592
+ )
14593
+ );
14408
14594
  }
14409
14595
  function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens = 0) {
14410
14596
  const cacheTokens = {};
@@ -15010,6 +15196,18 @@ function parseMetricsFromUsage2(usage) {
15010
15196
  saveIfExistsTo("output_tokens", "completion_tokens");
15011
15197
  saveIfExistsTo("cache_read_input_tokens", "prompt_cached_tokens");
15012
15198
  saveIfExistsTo("cache_creation_input_tokens", "prompt_cache_creation_tokens");
15199
+ if (isObject(usage.cache_creation)) {
15200
+ const cacheCreation = usage.cache_creation;
15201
+ for (const [source, target] of [
15202
+ ["ephemeral_5m_input_tokens", "prompt_cache_creation_5m_tokens"],
15203
+ ["ephemeral_1h_input_tokens", "prompt_cache_creation_1h_tokens"]
15204
+ ]) {
15205
+ const value = cacheCreation[source];
15206
+ if (typeof value === "number") {
15207
+ metrics[target] = value;
15208
+ }
15209
+ }
15210
+ }
15013
15211
  if (isObject(usage.server_tool_use)) {
15014
15212
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
15015
15213
  if (typeof value === "number") {
@@ -20308,37 +20506,97 @@ function seedTaskToolUseIdMapping(taskIdToToolUseId, message) {
20308
20506
  taskIdToToolUseId.set(message.task_id, message.tool_use_id);
20309
20507
  }
20310
20508
  }
20311
- function extractUsageFromMessage(message) {
20312
- const metrics = {};
20313
- let usage;
20314
- if (message.type === "assistant") {
20315
- usage = message.message?.usage;
20316
- } else if (message.type === "result") {
20317
- usage = message.usage;
20318
- }
20509
+ function tokenCount(value) {
20510
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : void 0;
20511
+ }
20512
+ function copyUsage(usage) {
20319
20513
  if (!usage || typeof usage !== "object") {
20320
- return metrics;
20514
+ return void 0;
20515
+ }
20516
+ const copy = {};
20517
+ for (const key of [
20518
+ "input_tokens",
20519
+ "output_tokens",
20520
+ "cache_read_input_tokens",
20521
+ "cache_creation_input_tokens"
20522
+ ]) {
20523
+ const value = tokenCount(Reflect.get(usage, key));
20524
+ if (value !== void 0) {
20525
+ copy[key] = value;
20526
+ }
20527
+ }
20528
+ const cacheCreation = Reflect.get(usage, "cache_creation");
20529
+ if (cacheCreation && typeof cacheCreation === "object") {
20530
+ const cacheCreationCopy = {};
20531
+ for (const key of [
20532
+ "ephemeral_5m_input_tokens",
20533
+ "ephemeral_1h_input_tokens"
20534
+ ]) {
20535
+ const value = tokenCount(Reflect.get(cacheCreation, key));
20536
+ if (value !== void 0) {
20537
+ cacheCreationCopy[key] = value;
20538
+ }
20539
+ }
20540
+ if (Object.keys(cacheCreationCopy).length > 0) {
20541
+ copy.cache_creation = cacheCreationCopy;
20542
+ }
20543
+ }
20544
+ return Object.keys(copy).length > 0 ? copy : void 0;
20545
+ }
20546
+ function mergeUsage(base, override) {
20547
+ if (!base || !override) {
20548
+ return override ?? base;
20549
+ }
20550
+ const cacheCreation = base.cache_creation || override.cache_creation ? { ...base.cache_creation, ...override.cache_creation } : void 0;
20551
+ return {
20552
+ ...base,
20553
+ ...override,
20554
+ ...cacheCreation && { cache_creation: cacheCreation }
20555
+ };
20556
+ }
20557
+ function extractUsage(usage, includeOutput) {
20558
+ const metrics = {};
20559
+ if (!usage) {
20560
+ return {};
20321
20561
  }
20322
20562
  const inputTokens = getNumberProperty(usage, "input_tokens");
20323
20563
  if (inputTokens !== void 0) {
20324
20564
  metrics.prompt_tokens = inputTokens;
20325
20565
  }
20326
- const outputTokens = getNumberProperty(usage, "output_tokens");
20327
- if (outputTokens !== void 0) {
20328
- metrics.completion_tokens = outputTokens;
20566
+ if (includeOutput) {
20567
+ const outputTokens = getNumberProperty(usage, "output_tokens");
20568
+ if (outputTokens !== void 0) {
20569
+ metrics.completion_tokens = outputTokens;
20570
+ }
20329
20571
  }
20330
20572
  const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
20331
20573
  const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
20332
- if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
20333
- Object.assign(
20334
- metrics,
20335
- extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
20336
- );
20574
+ Object.assign(
20575
+ metrics,
20576
+ extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
20577
+ );
20578
+ const cacheCreation5mTokens = getNumberProperty(
20579
+ usage.cache_creation,
20580
+ "ephemeral_5m_input_tokens"
20581
+ );
20582
+ const cacheCreation1hTokens = getNumberProperty(
20583
+ usage.cache_creation,
20584
+ "ephemeral_1h_input_tokens"
20585
+ );
20586
+ if (cacheCreation5mTokens !== void 0) {
20587
+ metrics.prompt_cache_creation_5m_tokens = cacheCreation5mTokens;
20337
20588
  }
20338
- if (Object.keys(metrics).length > 0) {
20339
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
20589
+ if (cacheCreation1hTokens !== void 0) {
20590
+ metrics.prompt_cache_creation_1h_tokens = cacheCreation1hTokens;
20340
20591
  }
20341
- return metrics;
20592
+ if (Object.keys(metrics).length === 0) {
20593
+ return {};
20594
+ }
20595
+ const finalized = finalizeAnthropicTokens(metrics);
20596
+ if (metrics.completion_tokens === void 0) {
20597
+ delete finalized.tokens;
20598
+ }
20599
+ return toNumericMetrics(finalized);
20342
20600
  }
20343
20601
  function buildLLMInput(promptMessages, conversationHistory) {
20344
20602
  const inputParts = [...promptMessages, ...conversationHistory];
@@ -20372,16 +20630,16 @@ function buildRootPromptMessages(prompt, capturedPromptMessages) {
20372
20630
  function formatCapturedMessages(messages) {
20373
20631
  return messages.length > 0 ? messages : [];
20374
20632
  }
20375
- async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
20633
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, usage, hasFinalOutputUsage, existingSpan) {
20376
20634
  if (messages.length === 0) {
20377
20635
  return void 0;
20378
20636
  }
20379
20637
  const lastMessage = messages[messages.length - 1];
20380
- if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
20638
+ if (lastMessage.type !== "assistant") {
20381
20639
  return void 0;
20382
20640
  }
20383
- const model = lastMessage.message.model || options.model;
20384
- const usage = extractUsageFromMessage(lastMessage);
20641
+ const model = lastMessage.message?.model || options.model;
20642
+ const metrics = options.includePartialMessages ? extractUsage(usage, hasFinalOutputUsage) : {};
20385
20643
  const input = buildLLMInput(promptMessages, conversationHistory);
20386
20644
  const outputs = messages.map(
20387
20645
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
@@ -20403,8 +20661,8 @@ async function createLLMSpanForMessages(messages, promptMessages, conversationHi
20403
20661
  );
20404
20662
  span.log({
20405
20663
  input,
20406
- metadata: model ? { model } : void 0,
20407
- metrics: usage,
20664
+ metadata: { ...model && { model }, provider: "anthropic" },
20665
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
20408
20666
  output: outputs
20409
20667
  });
20410
20668
  const spanExport = await span.export();
@@ -20494,11 +20752,17 @@ function prepareLocalToolHandlersInMcpServers(mcpServers) {
20494
20752
  }
20495
20753
  return { hasLocalToolHandlers, localToolHookNames };
20496
20754
  }
20497
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20755
+ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20498
20756
  const preToolUse = async (input, toolUseID) => {
20499
20757
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
20500
20758
  return {};
20501
20759
  }
20760
+ if (!toolUseToParent.has(toolUseID) && input.agent_id) {
20761
+ const parentToolUseId = taskIdToToolUseId.get(input.agent_id);
20762
+ if (parentToolUseId) {
20763
+ toolUseToParent.set(toolUseID, parentToolUseId);
20764
+ }
20765
+ }
20502
20766
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
20503
20767
  return {};
20504
20768
  }
@@ -20694,9 +20958,6 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20694
20958
  }
20695
20959
  const metadata = {
20696
20960
  ...subAgentDetailsToMetadata(details),
20697
- ...input.agent_transcript_path && {
20698
- "claude_agent_sdk.agent_transcript_path": input.agent_transcript_path
20699
- },
20700
20961
  "claude_agent_sdk.stop_hook_active": input.stop_hook_active
20701
20962
  };
20702
20963
  try {
@@ -20718,7 +20979,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20718
20979
  subagentStop
20719
20980
  };
20720
20981
  }
20721
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20982
+ function injectTracingHooks(options, resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20722
20983
  const {
20723
20984
  preToolUse,
20724
20985
  postToolUse,
@@ -20727,6 +20988,8 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
20727
20988
  subagentStop
20728
20989
  } = createToolTracingHooks(
20729
20990
  resolveParentSpan,
20991
+ taskIdToToolUseId,
20992
+ toolUseToParent,
20730
20993
  activeToolSpans,
20731
20994
  options.mcpServers,
20732
20995
  localToolHookNames,
@@ -20808,6 +21071,13 @@ async function finalizeCurrentMessageGroup(state) {
20808
21071
  }
20809
21072
  }
20810
21073
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
21074
+ const lastMessage = state.currentMessages[state.currentMessages.length - 1];
21075
+ const messageId = lastMessage?.message?.id;
21076
+ const usage = state.options.includePartialMessages ? mergeUsage(
21077
+ copyUsage(lastMessage?.message?.usage),
21078
+ messageId ? state.usageByMessageId.get(messageId) : void 0
21079
+ ) : void 0;
21080
+ const hasFinalOutputUsage = messageId !== void 0 && state.finalOutputUsageMessageIds.has(messageId);
20811
21081
  const llmSpanResult = await createLLMSpanForMessages(
20812
21082
  state.currentMessages,
20813
21083
  promptMessages,
@@ -20815,6 +21085,8 @@ async function finalizeCurrentMessageGroup(state) {
20815
21085
  state.options,
20816
21086
  state.currentMessageStartTime,
20817
21087
  parentSpan,
21088
+ usage,
21089
+ hasFinalOutputUsage,
20818
21090
  existingLlmSpan
20819
21091
  );
20820
21092
  if (llmSpanResult) {
@@ -20832,9 +21104,17 @@ async function finalizeCurrentMessageGroup(state) {
20832
21104
  }
20833
21105
  }
20834
21106
  state.activeLlmSpansByParentToolUse.delete(parentKey);
20835
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20836
- if (lastMessage?.message?.usage) {
20837
- state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
21107
+ if (messageId) {
21108
+ state.usageByMessageId.delete(messageId);
21109
+ state.finalOutputUsageMessageIds.delete(messageId);
21110
+ for (const [
21111
+ parent,
21112
+ activeMessageId
21113
+ ] of state.activePartialMessageIdByParentKey) {
21114
+ if (activeMessageId === messageId) {
21115
+ state.activePartialMessageIdByParentKey.delete(parent);
21116
+ }
21117
+ }
20838
21118
  }
20839
21119
  state.currentMessages.length = 0;
20840
21120
  }
@@ -20925,6 +21205,10 @@ async function ensureActiveLlmSpanForParentToolUse(rootSpan, activeLlmSpansByPar
20925
21205
  );
20926
21206
  llmParentSpan = await subAgentSpan.export();
20927
21207
  }
21208
+ const racedLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
21209
+ if (racedLlmSpan) {
21210
+ return racedLlmSpan;
21211
+ }
20928
21212
  const llmSpan = startSpan(
20929
21213
  withSpanInstrumentationName(
20930
21214
  {
@@ -21044,7 +21328,49 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
21044
21328
  }
21045
21329
  return true;
21046
21330
  }
21331
+ function handlePartialUsageMessage(state, message) {
21332
+ if (message.type !== "stream_event") {
21333
+ return false;
21334
+ }
21335
+ const event = message.event;
21336
+ if (!event || typeof event !== "object") {
21337
+ return true;
21338
+ }
21339
+ const parentKey = llmParentKey(message.parent_tool_use_id ?? null);
21340
+ if (event.type === "message_start") {
21341
+ const messageId2 = event.message?.id;
21342
+ const usage = copyUsage(event.message?.usage);
21343
+ if (messageId2) {
21344
+ state.activePartialMessageIdByParentKey.set(parentKey, messageId2);
21345
+ if (usage) {
21346
+ state.usageByMessageId.set(messageId2, usage);
21347
+ }
21348
+ }
21349
+ return true;
21350
+ }
21351
+ const messageId = state.activePartialMessageIdByParentKey.get(parentKey);
21352
+ if (!messageId) {
21353
+ return true;
21354
+ }
21355
+ if (event.type === "message_delta") {
21356
+ const update = copyUsage(event.usage);
21357
+ if (update) {
21358
+ const usage = state.usageByMessageId.get(messageId) ?? {};
21359
+ Object.assign(usage, update);
21360
+ state.usageByMessageId.set(messageId, usage);
21361
+ if (update.output_tokens !== void 0) {
21362
+ state.finalOutputUsageMessageIds.add(messageId);
21363
+ }
21364
+ }
21365
+ } else if (event.type === "message_stop") {
21366
+ state.activePartialMessageIdByParentKey.delete(parentKey);
21367
+ }
21368
+ return true;
21369
+ }
21047
21370
  async function handleStreamMessage(state, message) {
21371
+ if (handlePartialUsageMessage(state, message)) {
21372
+ return;
21373
+ }
21048
21374
  maybeTrackToolUseContext(state, message);
21049
21375
  if (await maybeHandleTaskLifecycleMessage(state, message)) {
21050
21376
  return;
@@ -21091,36 +21417,9 @@ async function handleStreamMessage(state, message) {
21091
21417
  );
21092
21418
  state.currentMessages.push(message);
21093
21419
  }
21094
- if (message.type !== "result" || !message.usage) {
21420
+ if (message.type !== "result") {
21095
21421
  return;
21096
21422
  }
21097
- const finalUsageMetrics = extractUsageFromMessage(message);
21098
- if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
21099
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
21100
- if (lastMessage?.message?.usage) {
21101
- const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
21102
- if (adjustedTokens >= 0) {
21103
- lastMessage.message.usage.output_tokens = adjustedTokens;
21104
- }
21105
- const resultUsage = message.usage;
21106
- if (resultUsage && typeof resultUsage === "object") {
21107
- const cacheReadTokens = getNumberProperty(
21108
- resultUsage,
21109
- "cache_read_input_tokens"
21110
- );
21111
- if (cacheReadTokens !== void 0) {
21112
- lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
21113
- }
21114
- const cacheCreationTokens = getNumberProperty(
21115
- resultUsage,
21116
- "cache_creation_input_tokens"
21117
- );
21118
- if (cacheCreationTokens !== void 0) {
21119
- lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
21120
- }
21121
- }
21122
- }
21123
- }
21124
21423
  const metadata = {};
21125
21424
  if (message.num_turns !== void 0) {
21126
21425
  metadata.num_turns = message.num_turns;
@@ -21128,8 +21427,12 @@ async function handleStreamMessage(state, message) {
21128
21427
  if (message.session_id !== void 0) {
21129
21428
  metadata.session_id = message.session_id;
21130
21429
  }
21131
- if (Object.keys(metadata).length > 0) {
21132
- state.span.log({ metadata });
21430
+ const metrics = state.options.includePartialMessages ? {} : extractUsage(copyUsage(message.usage), true);
21431
+ if (Object.keys(metadata).length > 0 || Object.keys(metrics).length > 0) {
21432
+ state.span.log({
21433
+ ...Object.keys(metadata).length > 0 ? { metadata } : {},
21434
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
21435
+ });
21133
21436
  }
21134
21437
  }
21135
21438
  async function finalizeQuerySpan(state) {
@@ -21153,6 +21456,9 @@ async function finalizeQuerySpan(state) {
21153
21456
  llmSpan.end();
21154
21457
  }
21155
21458
  state.activeLlmSpansByParentToolUse.clear();
21459
+ state.activePartialMessageIdByParentKey.clear();
21460
+ state.finalOutputUsageMessageIds.clear();
21461
+ state.usageByMessageId.clear();
21156
21462
  for (const toolSpan of state.activeToolSpans.values()) {
21157
21463
  toolSpan.end();
21158
21464
  }
@@ -21277,6 +21583,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21277
21583
  const optionsWithHooks = injectTracingHooks(
21278
21584
  options,
21279
21585
  resolveToolUseParentSpan,
21586
+ taskIdToToolUseId,
21587
+ toolUseToParent,
21280
21588
  activeToolSpans,
21281
21589
  localToolHookNames,
21282
21590
  skipLocalToolHooks,
@@ -21287,8 +21595,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21287
21595
  params.options = optionsWithHooks;
21288
21596
  event.arguments[0] = params;
21289
21597
  spans.set(event, {
21290
- accumulatedOutputTokens: 0,
21291
21598
  activeLlmSpansByParentToolUse,
21599
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
21292
21600
  activeToolSpans,
21293
21601
  conversationHistoryByParentKey,
21294
21602
  capturedPromptMessages,
@@ -21296,6 +21604,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21296
21604
  currentMessageStartTime: startTime,
21297
21605
  currentMessages: [],
21298
21606
  endedSubAgentSpans,
21607
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
21299
21608
  finalResults: [],
21300
21609
  options: optionsWithHooks,
21301
21610
  originalPrompt,
@@ -21311,6 +21620,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21311
21620
  latestLlmParentBySubAgentToolUse,
21312
21621
  latestRootLlmParentRef,
21313
21622
  toolUseToParent,
21623
+ usageByMessageId: /* @__PURE__ */ new Map(),
21314
21624
  localToolContext
21315
21625
  });
21316
21626
  },
@@ -23785,9 +24095,9 @@ function extractEmbedPromptTokenCount(response) {
23785
24095
  let sawAny = false;
23786
24096
  for (const embedding of embeddings) {
23787
24097
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
23788
- const tokenCount = embeddingStats?.tokenCount;
23789
- if (typeof tokenCount === "number" && Number.isFinite(tokenCount)) {
23790
- total += tokenCount;
24098
+ const tokenCount2 = embeddingStats?.tokenCount;
24099
+ if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
24100
+ total += tokenCount2;
23791
24101
  sawAny = true;
23792
24102
  }
23793
24103
  }
@@ -30682,7 +30992,7 @@ function getStringProperty2(obj, key) {
30682
30992
  return typeof value === "string" ? value : void 0;
30683
30993
  }
30684
30994
  function extractMetricsFromUsage(usage) {
30685
- const metrics = {
30995
+ const rawMetrics = {
30686
30996
  prompt_tokens: usage.inputTokens,
30687
30997
  completion_tokens: usage.outputTokens,
30688
30998
  ...extractAnthropicCacheTokens(
@@ -30691,10 +31001,10 @@ function extractMetricsFromUsage(usage) {
30691
31001
  )
30692
31002
  };
30693
31003
  if (usage.reasoningTokens !== void 0) {
30694
- metrics.completion_reasoning_tokens = usage.reasoningTokens;
30695
- metrics.reasoning_tokens = usage.reasoningTokens;
31004
+ rawMetrics.completion_reasoning_tokens = usage.reasoningTokens;
31005
+ rawMetrics.reasoning_tokens = usage.reasoningTokens;
30696
31006
  }
30697
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
31007
+ const metrics = finalizeAnthropicTokens(rawMetrics);
30698
31008
  const metadata = {
30699
31009
  model: usage.model
30700
31010
  };
@@ -31633,17 +31943,20 @@ var FlueObserveBridge = class {
31633
31943
  return;
31634
31944
  }
31635
31945
  const metadata = {
31946
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
31636
31947
  ...extractEventMetadata(event),
31637
31948
  "flue.operation": event.operationKind,
31638
31949
  provider: "flue"
31639
31950
  };
31640
31951
  const parent = this.parentSpanForEvent(event);
31641
- const span = startFlueSpan(parent, {
31952
+ const args = {
31642
31953
  name: `flue.${event.operationKind}`,
31643
31954
  spanAttributes: { type: "task" /* TASK */ },
31644
31955
  startTime: eventTime(event.timestamp),
31645
31956
  event: { metadata }
31646
- });
31957
+ };
31958
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
31959
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
31647
31960
  this.operationsById.set(event.operationId, { metadata, span });
31648
31961
  }
31649
31962
  handleOperation(event) {
@@ -31658,6 +31971,11 @@ var FlueObserveBridge = class {
31658
31971
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
31659
31972
  ...event.usage ? { "flue.usage": event.usage } : {}
31660
31973
  };
31974
+ const input = flueOperationInput(event);
31975
+ if (!state.loggedInput && input !== void 0) {
31976
+ safeLog3(state.span, { input });
31977
+ state.loggedInput = true;
31978
+ }
31661
31979
  this.finishPendingChildrenForOperation(event, output);
31662
31980
  safeLog3(state.span, {
31663
31981
  ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
@@ -31674,6 +31992,8 @@ var FlueObserveBridge = class {
31674
31992
  return;
31675
31993
  }
31676
31994
  const input = flueTurnRequestInput(event);
31995
+ const operation = event.operationId ? this.operationsById.get(event.operationId) : void 0;
31996
+ const turnInput = prepareFlueTurnInput(event, input, operation);
31677
31997
  const model = flueTurnRequestModel(event);
31678
31998
  const provider = flueTurnRequestProvider(event);
31679
31999
  const api = flueTurnRequestApi(event);
@@ -31686,8 +32006,7 @@ var FlueObserveBridge = class {
31686
32006
  ...provider ? { "flue.provider": provider } : {},
31687
32007
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
31688
32008
  ...reasoning ? { reasoning } : {},
31689
- ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
31690
- ...input?.tools ? { tools: input.tools } : {}
32009
+ ...turnInput.metadata
31691
32010
  };
31692
32011
  const parent = this.parentSpanForTurn(event);
31693
32012
  const span = startFlueSpan(parent, {
@@ -31695,11 +32014,14 @@ var FlueObserveBridge = class {
31695
32014
  spanAttributes: { type: "llm" /* LLM */ },
31696
32015
  startTime: eventTime(event.timestamp),
31697
32016
  event: {
31698
- input: input?.messages,
32017
+ input: turnInput.messages,
31699
32018
  metadata
31700
32019
  }
31701
32020
  });
31702
- this.logOperationInput(event.operationId, input?.messages ?? input);
32021
+ this.logOperationInput(
32022
+ event.operationId,
32023
+ latestUserMessageInput(input?.messages)
32024
+ );
31703
32025
  this.turnsByKey.set(key, { metadata, span });
31704
32026
  }
31705
32027
  handleTurn(event) {
@@ -31946,16 +32268,20 @@ var FlueObserveBridge = class {
31946
32268
  }
31947
32269
  startSyntheticOperation(event) {
31948
32270
  const metadata = {
32271
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
31949
32272
  ...extractEventMetadata(event),
31950
32273
  "flue.operation": event.operationKind,
31951
32274
  provider: "flue"
31952
32275
  };
31953
- const span = startFlueSpan(this.parentSpanForEvent(event), {
32276
+ const args = {
31954
32277
  name: `flue.${event.operationKind}`,
31955
32278
  spanAttributes: { type: "task" /* TASK */ },
31956
32279
  startTime: eventTime(event.timestamp),
31957
32280
  event: { metadata }
31958
- });
32281
+ };
32282
+ const parent = this.parentSpanForEvent(event);
32283
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
32284
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
31959
32285
  return { metadata, span };
31960
32286
  }
31961
32287
  startSyntheticTurn(event) {
@@ -32134,6 +32460,71 @@ function flueRunInput(event) {
32134
32460
  function flueTurnRequestInput(event) {
32135
32461
  return event.request?.input ?? event.input;
32136
32462
  }
32463
+ function prepareFlueTurnInput(event, input, operation) {
32464
+ const messages = input?.messages;
32465
+ const tracksUserTurn = event.purpose === "agent" && operation?.metadata["flue.operation"] === "prompt" && Array.isArray(messages);
32466
+ if (!tracksUserTurn) {
32467
+ return {
32468
+ messages,
32469
+ metadata: {
32470
+ ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
32471
+ ...input?.tools ? { tools: input.tools } : {}
32472
+ }
32473
+ };
32474
+ }
32475
+ const previous = operation.turnInputState;
32476
+ const previousMessageCount = previous?.messageCount ?? 0;
32477
+ const boundaryFingerprint = messages.length > 0 ? fingerprintJsonValue(messages[messages.length - 1]) : void 0;
32478
+ const continuesPreviousInput = previous !== void 0 && messages.length >= previousMessageCount && (previousMessageCount === 0 || previous.boundaryFingerprint !== void 0 && previous.boundaryFingerprint === fingerprintJsonValue(messages[previousMessageCount - 1]));
32479
+ const inputMode = previous === void 0 ? "full" : continuesPreviousInput ? "delta" : "reset";
32480
+ const systemPromptFingerprint = fingerprintJsonValue(input?.systemPrompt);
32481
+ const toolsFingerprint = fingerprintJsonValue(input?.tools);
32482
+ operation.turnInputState = {
32483
+ ...boundaryFingerprint !== void 0 ? { boundaryFingerprint } : {},
32484
+ messageCount: messages.length,
32485
+ ...systemPromptFingerprint !== void 0 ? { systemPromptFingerprint } : {},
32486
+ ...toolsFingerprint !== void 0 ? { toolsFingerprint } : {}
32487
+ };
32488
+ return {
32489
+ messages: continuesPreviousInput ? messages.slice(previousMessageCount) : messages,
32490
+ metadata: {
32491
+ "flue.input_mode": inputMode,
32492
+ ...continuesPreviousInput ? { "flue.input_message_offset": previousMessageCount } : {},
32493
+ ...input?.systemPrompt && (!continuesPreviousInput || systemPromptFingerprint !== previous?.systemPromptFingerprint) ? { "flue.system_prompt": input.systemPrompt } : {},
32494
+ ...input?.tools && (!continuesPreviousInput || toolsFingerprint !== previous?.toolsFingerprint) ? { tools: input.tools } : {}
32495
+ }
32496
+ };
32497
+ }
32498
+ function fingerprintJsonValue(value) {
32499
+ try {
32500
+ const serialized = JSON.stringify(value);
32501
+ if (serialized === void 0) {
32502
+ return void 0;
32503
+ }
32504
+ let hash = 2166136261;
32505
+ for (let i = 0; i < serialized.length; i++) {
32506
+ hash = Math.imul(hash ^ serialized.charCodeAt(i), 16777619);
32507
+ }
32508
+ return `${serialized.length}:${hash >>> 0}`;
32509
+ } catch {
32510
+ return void 0;
32511
+ }
32512
+ }
32513
+ function latestUserMessageInput(messages) {
32514
+ if (!messages) {
32515
+ return void 0;
32516
+ }
32517
+ for (let i = messages.length - 1; i >= 0; i--) {
32518
+ const message = messages[i];
32519
+ if (isObjectLike(message) && Reflect.get(message, "role") === "user") {
32520
+ return [message];
32521
+ }
32522
+ }
32523
+ return void 0;
32524
+ }
32525
+ function flueOperationInput(event) {
32526
+ return typeof event.agentInput?.text === "string" ? [{ content: event.agentInput.text, role: "user" }] : void 0;
32527
+ }
32137
32528
  function flueTurnRequestModel(event) {
32138
32529
  return event.request?.requestedModel ?? event.request?.model ?? event.model;
32139
32530
  }
@@ -32291,6 +32682,21 @@ function startFlueSpan(parent, args) {
32291
32682
  withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE)
32292
32683
  );
32293
32684
  }
32685
+ function startFlueRootSpan(args) {
32686
+ const state = _internalGetGlobalState();
32687
+ const spanId = state.idGenerator.getSpanId();
32688
+ const rootSpanId = state.idGenerator.shareRootSpanId() ? spanId : state.idGenerator.getTraceId();
32689
+ return withCurrent(
32690
+ NOOP_SPAN,
32691
+ () => startSpan({
32692
+ ...withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE),
32693
+ parentSpanIds: { parentSpanIds: [], rootSpanId },
32694
+ spanId,
32695
+ state
32696
+ }),
32697
+ state
32698
+ );
32699
+ }
32294
32700
  function runWithCurrentSpanStore(span, next) {
32295
32701
  const state = _internalGetGlobalState();
32296
32702
  const contextManager = state?.contextManager;
@@ -34190,8 +34596,7 @@ function startAgentStream(event, activeChildParents) {
34190
34596
  ...extractAgentMetadata2(agent),
34191
34597
  ...extractModelMetadata3(model),
34192
34598
  "strands.operation": "Agent.stream",
34193
- provider: extractProvider(model),
34194
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34599
+ provider: extractProvider(model)
34195
34600
  };
34196
34601
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
34197
34602
  const attachmentCache = createStrandsAttachmentCache();
@@ -34241,8 +34646,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
34241
34646
  const metadata = {
34242
34647
  "strands.operation": operation,
34243
34648
  provider: "strands",
34244
- ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {},
34245
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
34649
+ ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
34246
34650
  };
34247
34651
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
34248
34652
  const input = processStrandsInputAttachments(event.arguments[0]);
@@ -35028,6 +35432,320 @@ function logInstrumentationError5(context, error) {
35028
35432
  debugLogger.debug(`${context}:`, error);
35029
35433
  }
35030
35434
 
35435
+ // src/instrumentation/plugins/voyageai-channels.ts
35436
+ var voyageAIChannels = defineChannels(
35437
+ "voyageai",
35438
+ {
35439
+ embed: channel({
35440
+ channelName: "embed",
35441
+ kind: "async"
35442
+ }),
35443
+ multimodalEmbed: channel({
35444
+ channelName: "multimodalEmbed",
35445
+ kind: "async"
35446
+ }),
35447
+ rerank: channel({
35448
+ channelName: "rerank",
35449
+ kind: "async"
35450
+ }),
35451
+ contextualizedEmbed: channel({
35452
+ channelName: "contextualizedEmbed",
35453
+ kind: "async"
35454
+ })
35455
+ },
35456
+ { instrumentationName: INSTRUMENTATION_NAMES.VOYAGEAI }
35457
+ );
35458
+
35459
+ // src/instrumentation/plugins/voyageai-plugin.ts
35460
+ var RERANK_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
35461
+ "model",
35462
+ "returnDocuments",
35463
+ "topK",
35464
+ "truncation"
35465
+ ]);
35466
+ var VoyageAIPlugin = class extends BasePlugin {
35467
+ onEnable() {
35468
+ this.unsubscribers.push(
35469
+ interceptVoyageAICall(
35470
+ voyageAIChannels.embed,
35471
+ "voyageai.embed",
35472
+ extractTextEmbeddingInput,
35473
+ summarizeEmbeddingOutput,
35474
+ extractEmbeddingUsageMetrics
35475
+ ),
35476
+ interceptVoyageAICall(
35477
+ voyageAIChannels.multimodalEmbed,
35478
+ "voyageai.multimodalEmbed",
35479
+ extractMultimodalEmbeddingInput,
35480
+ summarizeEmbeddingOutput,
35481
+ extractEmbeddingUsageMetrics
35482
+ ),
35483
+ interceptVoyageAICall(
35484
+ voyageAIChannels.rerank,
35485
+ "voyageai.rerank",
35486
+ extractRerankInput,
35487
+ summarizeRerankOutput
35488
+ ),
35489
+ interceptVoyageAICall(
35490
+ voyageAIChannels.contextualizedEmbed,
35491
+ "voyageai.contextualizedEmbed",
35492
+ extractContextualizedEmbeddingInput,
35493
+ summarizeContextualizedEmbeddingOutput,
35494
+ extractEmbeddingUsageMetrics
35495
+ )
35496
+ );
35497
+ }
35498
+ onDisable() {
35499
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
35500
+ }
35501
+ };
35502
+ function interceptVoyageAICall(channel2, name, extractInput3, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
35503
+ return channel2.intercept((target, thisArg, args) => {
35504
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
35505
+ if (isAutoInstrumentationSuppressed()) {
35506
+ return invokeTarget();
35507
+ }
35508
+ let span;
35509
+ try {
35510
+ const { input, metadata } = extractInput3(args);
35511
+ span = startSpan(
35512
+ withSpanInstrumentationName(
35513
+ {
35514
+ event: { input, metadata },
35515
+ name,
35516
+ spanAttributes: { type: "llm" /* LLM */ }
35517
+ },
35518
+ INSTRUMENTATION_NAMES.VOYAGEAI
35519
+ )
35520
+ );
35521
+ } catch (error) {
35522
+ debugLogger.error(`Error starting span for ${name}:`, error);
35523
+ return invokeTarget();
35524
+ }
35525
+ let result;
35526
+ try {
35527
+ result = withCurrent(
35528
+ span,
35529
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
35530
+ );
35531
+ } catch (error) {
35532
+ finishVoyageAISpan(span, name, () => span.log({ error }));
35533
+ throw error;
35534
+ }
35535
+ void Promise.resolve(result).then(
35536
+ (value) => finishVoyageAISpan(span, name, () => {
35537
+ const metadata = extractResponseMetadata3(value);
35538
+ span.log({
35539
+ output: extractOutput2(value),
35540
+ ...metadata ? { metadata } : {},
35541
+ metrics: extractMetrics2(value)
35542
+ });
35543
+ }),
35544
+ (error) => finishVoyageAISpan(span, name, () => span.log({ error }))
35545
+ );
35546
+ return result;
35547
+ });
35548
+ }
35549
+ function finishVoyageAISpan(span, name, log3) {
35550
+ try {
35551
+ log3();
35552
+ } catch (error) {
35553
+ debugLogger.error(`Error logging span for ${name}:`, error);
35554
+ }
35555
+ try {
35556
+ span.end();
35557
+ } catch (error) {
35558
+ debugLogger.error(`Error ending span for ${name}:`, error);
35559
+ }
35560
+ }
35561
+ function getRequestArg2(args) {
35562
+ if (Array.isArray(args)) {
35563
+ return isObject(args[0]) ? args[0] : void 0;
35564
+ }
35565
+ if (!isObject(args)) {
35566
+ return void 0;
35567
+ }
35568
+ const firstArg = Reflect.get(args, "0");
35569
+ return isObject(firstArg) ? firstArg : void 0;
35570
+ }
35571
+ function pickMetadata(request, allowlist) {
35572
+ const metadata = {};
35573
+ if (request) {
35574
+ for (const key of allowlist) {
35575
+ if (!Object.hasOwn(request, key)) {
35576
+ continue;
35577
+ }
35578
+ const value = request[key];
35579
+ if (value !== void 0) {
35580
+ metadata[key] = value;
35581
+ }
35582
+ }
35583
+ }
35584
+ return {
35585
+ ...metadata,
35586
+ provider: "voyage"
35587
+ };
35588
+ }
35589
+ function buildEmbeddingInput(inputs, request) {
35590
+ const outputDimensions = request?.outputDimension;
35591
+ return {
35592
+ inputs,
35593
+ ...typeof outputDimensions === "number" && Number.isFinite(outputDimensions) ? { output_dimensions: outputDimensions } : {}
35594
+ };
35595
+ }
35596
+ function embeddingMetadata(request) {
35597
+ return {
35598
+ ...typeof request?.model === "string" ? { model: request.model } : {},
35599
+ provider: "voyage"
35600
+ };
35601
+ }
35602
+ function extractTextEmbeddingInput(args) {
35603
+ const request = getRequestArg2(args);
35604
+ const rawInput = request?.input;
35605
+ const values = Array.isArray(rawInput) ? rawInput : [rawInput];
35606
+ return {
35607
+ input: buildEmbeddingInput(
35608
+ values.flatMap(
35609
+ (value) => typeof value === "string" ? [{ content: value }] : []
35610
+ ),
35611
+ request
35612
+ ),
35613
+ metadata: embeddingMetadata(request)
35614
+ };
35615
+ }
35616
+ function extractContextualizedEmbeddingInput(args) {
35617
+ const request = getRequestArg2(args);
35618
+ const rawInputs = request?.inputs;
35619
+ const values = Array.isArray(rawInputs) ? rawInputs.flatMap((value) => Array.isArray(value) ? value : [value]) : [];
35620
+ return {
35621
+ input: buildEmbeddingInput(
35622
+ values.flatMap(
35623
+ (value) => typeof value === "string" ? [{ content: value }] : []
35624
+ ),
35625
+ request
35626
+ ),
35627
+ metadata: embeddingMetadata(request)
35628
+ };
35629
+ }
35630
+ function extractMultimodalEmbeddingInput(args) {
35631
+ const request = getRequestArg2(args);
35632
+ const rawInputs = request?.inputs;
35633
+ const inputs = Array.isArray(rawInputs) ? rawInputs.map((rawInput) => {
35634
+ const rawContent = isObject(rawInput) ? rawInput.content : void 0;
35635
+ return {
35636
+ content: Array.isArray(rawContent) ? rawContent.flatMap(normalizeMultimodalContentPart) : []
35637
+ };
35638
+ }) : [];
35639
+ const input = buildEmbeddingInput(inputs, request);
35640
+ const processedInput = processInputAttachments(input);
35641
+ return {
35642
+ input: hasInlineEmbeddingMedia(processedInput) ? input : processedInput,
35643
+ metadata: embeddingMetadata(request)
35644
+ };
35645
+ }
35646
+ function normalizeMultimodalContentPart(part) {
35647
+ if (!isObject(part) || typeof part.type !== "string") {
35648
+ return [];
35649
+ }
35650
+ if (part.type === "text") {
35651
+ return typeof part.text === "string" ? [{ type: "text", text: part.text }] : [];
35652
+ }
35653
+ const camelCaseField = {
35654
+ image_base64: "imageBase64",
35655
+ image_url: "imageUrl",
35656
+ video_base64: "videoBase64",
35657
+ video_url: "videoUrl"
35658
+ };
35659
+ const field = camelCaseField[part.type];
35660
+ if (!field) {
35661
+ return [];
35662
+ }
35663
+ const data = typeof part[field] === "string" ? part[field] : part[part.type];
35664
+ if (typeof data !== "string") {
35665
+ return [];
35666
+ }
35667
+ return part.type.startsWith("image_") ? [{ type: "image_url", image_url: { url: data } }] : [{ type: "file", file: { file_data: data } }];
35668
+ }
35669
+ function hasInlineEmbeddingMedia(input) {
35670
+ return input.inputs.some(
35671
+ ({ content }) => Array.isArray(content) ? content.some((part) => {
35672
+ const value = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
35673
+ return typeof value === "string" && value.startsWith("data:");
35674
+ }) : false
35675
+ );
35676
+ }
35677
+ function extractRerankInput(args) {
35678
+ const request = getRequestArg2(args);
35679
+ const documents = request?.documents;
35680
+ return {
35681
+ input: {
35682
+ documents,
35683
+ query: request?.query
35684
+ },
35685
+ metadata: {
35686
+ ...pickMetadata(request, RERANK_METADATA_ALLOWLIST),
35687
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
35688
+ }
35689
+ };
35690
+ }
35691
+ function extractResponseMetadata3(result) {
35692
+ if (!isObject(result)) {
35693
+ return void 0;
35694
+ }
35695
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35696
+ const model = typeof result.model === "string" ? result.model : typeof rawResponse?.model === "string" ? rawResponse.model : void 0;
35697
+ return model ? { model } : void 0;
35698
+ }
35699
+ function summarizeEmbeddingOutput(result) {
35700
+ return {
35701
+ count: isObject(result) && Array.isArray(result.data) ? result.data.length : 0
35702
+ };
35703
+ }
35704
+ function summarizeRerankOutput(result) {
35705
+ if (!isObject(result) || !Array.isArray(result.data)) {
35706
+ return void 0;
35707
+ }
35708
+ return result.data.slice(0, 100).map((item) => ({
35709
+ index: isObject(item) ? item.index : void 0,
35710
+ relevance_score: isObject(item) ? (typeof item.relevanceScore === "number" ? item.relevanceScore : item.relevance_score) ?? null : null
35711
+ }));
35712
+ }
35713
+ function summarizeContextualizedEmbeddingOutput(result) {
35714
+ if (!isObject(result)) {
35715
+ return { count: 0 };
35716
+ }
35717
+ if (Array.isArray(result.results)) {
35718
+ return {
35719
+ count: result.results.reduce(
35720
+ (count, item) => count + (isObject(item) && Array.isArray(item.embeddings) ? item.embeddings.length : 0),
35721
+ 0
35722
+ )
35723
+ };
35724
+ }
35725
+ if (!Array.isArray(result.data)) {
35726
+ return { count: 0 };
35727
+ }
35728
+ return {
35729
+ count: result.data.reduce(
35730
+ (count, item) => count + (isObject(item) && Array.isArray(item.data) ? item.data.length : 0),
35731
+ 0
35732
+ )
35733
+ };
35734
+ }
35735
+ function extractEmbeddingUsageMetrics(result) {
35736
+ const metrics = extractUsageMetrics3(result);
35737
+ return typeof metrics.tokens === "number" ? { prompt_tokens: metrics.tokens, tokens: metrics.tokens } : {};
35738
+ }
35739
+ function extractUsageMetrics3(result) {
35740
+ if (!isObject(result)) {
35741
+ return {};
35742
+ }
35743
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
35744
+ const usage = isObject(result.usage) ? result.usage : isObject(rawResponse?.usage) ? rawResponse.usage : void 0;
35745
+ const tokens = typeof result.totalTokens === "number" ? result.totalTokens : usage?.totalTokens ?? usage?.total_tokens;
35746
+ return typeof tokens === "number" && Number.isFinite(tokens) && tokens >= 0 ? { tokens } : {};
35747
+ }
35748
+
35031
35749
  // src/instrumentation/plugins/cloudflare-ai-chat-channels.ts
35032
35750
  var cloudflareAIChatChannels = defineChannels(
35033
35751
  "@cloudflare/ai-chat",
@@ -35606,6 +36324,7 @@ var BraintrustPlugin = class extends BasePlugin {
35606
36324
  langSmithPlugin = null;
35607
36325
  piCodingAgentPlugin = null;
35608
36326
  strandsAgentSDKPlugin = null;
36327
+ voyageAIPlugin = null;
35609
36328
  cloudflareAIChatPlugin = null;
35610
36329
  cloudflareAgentsPlugin = null;
35611
36330
  constructor(config = {}) {
@@ -35680,6 +36399,10 @@ var BraintrustPlugin = class extends BasePlugin {
35680
36399
  this.coherePlugin = new CoherePlugin();
35681
36400
  this.coherePlugin.enable();
35682
36401
  }
36402
+ if (integrations.voyageai !== false) {
36403
+ this.voyageAIPlugin = new VoyageAIPlugin();
36404
+ this.voyageAIPlugin.enable();
36405
+ }
35683
36406
  if (integrations.groq !== false) {
35684
36407
  this.groqPlugin = new GroqPlugin();
35685
36408
  this.groqPlugin.enable();
@@ -35796,6 +36519,10 @@ var BraintrustPlugin = class extends BasePlugin {
35796
36519
  this.coherePlugin.disable();
35797
36520
  this.coherePlugin = null;
35798
36521
  }
36522
+ if (this.voyageAIPlugin) {
36523
+ this.voyageAIPlugin.disable();
36524
+ this.voyageAIPlugin = null;
36525
+ }
35799
36526
  if (this.groqPlugin) {
35800
36527
  this.groqPlugin.disable();
35801
36528
  this.groqPlugin = null;
@@ -35915,7 +36642,10 @@ var envIntegrationAliases = {
35915
36642
  "langchain-js": "langchain",
35916
36643
  "@langchain": "langchain",
35917
36644
  langgraph: "langgraph",
35918
- langsmith: "langsmith"
36645
+ langsmith: "langsmith",
36646
+ voyage: "voyageai",
36647
+ "voyage-ai": "voyageai",
36648
+ voyageai: "voyageai"
35919
36649
  };
35920
36650
  function getDefaultInstrumentationIntegrations() {
35921
36651
  return {
@@ -35950,6 +36680,7 @@ function getDefaultInstrumentationIntegrations() {
35950
36680
  langchain: true,
35951
36681
  langgraph: true,
35952
36682
  langsmith: true,
36683
+ voyageai: true,
35953
36684
  piCodingAgent: true,
35954
36685
  strandsAgentSDK: true,
35955
36686
  cloudflareAgents: true
@@ -36113,6 +36844,8 @@ __export(exports_exports, {
36113
36844
  BRAINTRUST_PARENT_KEY: () => BRAINTRUST_PARENT_KEY,
36114
36845
  BaseAttachment: () => BaseAttachment,
36115
36846
  BaseExperiment: () => BaseExperiment,
36847
+ BatchScorer: () => BatchScorer,
36848
+ BatchTask: () => BatchTask,
36116
36849
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
36117
36850
  BraintrustMiddleware: () => BraintrustMiddleware,
36118
36851
  BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
@@ -36126,6 +36859,8 @@ __export(exports_exports, {
36126
36859
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
36127
36860
  Dataset: () => Dataset2,
36128
36861
  DatasetPipeline: () => DatasetPipeline,
36862
+ DurableEvalMemoryStore: () => DurableEvalMemoryStore,
36863
+ DurableEvalRedisStore: () => DurableEvalRedisStore,
36129
36864
  ERR_PERMALINK: () => ERR_PERMALINK,
36130
36865
  Eval: () => Eval,
36131
36866
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -36183,6 +36918,7 @@ __export(exports_exports, {
36183
36918
  currentSpan: () => currentSpan,
36184
36919
  deepCopyEvent: () => deepCopyEvent,
36185
36920
  defaultErrorScoreHandler: () => defaultErrorScoreHandler,
36921
+ defineDurableEval: () => defineDurableEval,
36186
36922
  deserializePlainStringAsJSON: () => deserializePlainStringAsJSON,
36187
36923
  devNullWritableStream: () => devNullWritableStream,
36188
36924
  evaluatorDefinitionSchema: () => evaluatorDefinitionSchema,
@@ -36278,7 +37014,8 @@ __export(exports_exports, {
36278
37014
  wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
36279
37015
  wrapStrandsAgentSDK: () => wrapStrandsAgentSDK,
36280
37016
  wrapTraced: () => wrapTraced,
36281
- wrapVitest: () => wrapVitest
37017
+ wrapVitest: () => wrapVitest,
37018
+ wrapVoyageAI: () => wrapVoyageAI
36282
37019
  });
36283
37020
 
36284
37021
  // src/sandbox.ts
@@ -37539,7 +38276,7 @@ function normalizeUsageMetrics(usage, provider, providerMetadata) {
37539
38276
  cacheCreationTokens
37540
38277
  );
37541
38278
  Object.assign(metrics, cacheTokens);
37542
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
38279
+ return toNumericMetrics(finalizeAnthropicTokens(metrics));
37543
38280
  }
37544
38281
  }
37545
38282
  return metrics;
@@ -41872,6 +42609,84 @@ function wrapRerank3(rerank) {
41872
42609
  });
41873
42610
  }
41874
42611
 
42612
+ // src/wrappers/voyageai.ts
42613
+ function wrapVoyageAI(client) {
42614
+ if (!isSupportedVoyageAIClient(client)) {
42615
+ console.warn("Unsupported Voyage AI library. Not wrapping.");
42616
+ return client;
42617
+ }
42618
+ return voyageAIProxy(client);
42619
+ }
42620
+ var voyageAIProxyCache = /* @__PURE__ */ new WeakMap();
42621
+ function isObject3(value) {
42622
+ return typeof value === "object" && value !== null;
42623
+ }
42624
+ function hasFunction5(value, name) {
42625
+ return typeof Reflect.get(value, name) === "function";
42626
+ }
42627
+ function isSupportedVoyageAIClient(value) {
42628
+ if (!isObject3(value)) {
42629
+ return false;
42630
+ }
42631
+ return hasFunction5(value, "embed") || hasFunction5(value, "multimodalEmbed") || hasFunction5(value, "rerank") || hasFunction5(value, "contextualizedEmbed");
42632
+ }
42633
+ function voyageAIProxy(client) {
42634
+ const cached = voyageAIProxyCache.get(client);
42635
+ if (cached) {
42636
+ return cached;
42637
+ }
42638
+ const proxy = new Proxy(client, {
42639
+ get(target, prop, receiver) {
42640
+ switch (prop) {
42641
+ case "embed":
42642
+ if (typeof target.embed !== "function") {
42643
+ return target.embed;
42644
+ }
42645
+ return (request, options) => voyageAIChannels.embed.invoke(
42646
+ target.embed,
42647
+ target,
42648
+ [request, options],
42649
+ {}
42650
+ );
42651
+ case "multimodalEmbed":
42652
+ if (typeof target.multimodalEmbed !== "function") {
42653
+ return target.multimodalEmbed;
42654
+ }
42655
+ return (request, options) => voyageAIChannels.multimodalEmbed.invoke(
42656
+ target.multimodalEmbed,
42657
+ target,
42658
+ [request, options],
42659
+ {}
42660
+ );
42661
+ case "rerank":
42662
+ if (typeof target.rerank !== "function") {
42663
+ return target.rerank;
42664
+ }
42665
+ return (request, options) => voyageAIChannels.rerank.invoke(
42666
+ target.rerank,
42667
+ target,
42668
+ [request, options],
42669
+ {}
42670
+ );
42671
+ case "contextualizedEmbed":
42672
+ if (typeof target.contextualizedEmbed !== "function") {
42673
+ return target.contextualizedEmbed;
42674
+ }
42675
+ return (request, options) => voyageAIChannels.contextualizedEmbed.invoke(
42676
+ target.contextualizedEmbed,
42677
+ target,
42678
+ [request, options],
42679
+ {}
42680
+ );
42681
+ default:
42682
+ return Reflect.get(target, prop, receiver);
42683
+ }
42684
+ }
42685
+ });
42686
+ voyageAIProxyCache.set(client, proxy);
42687
+ return proxy;
42688
+ }
42689
+
41875
42690
  // src/wrappers/groq.ts
41876
42691
  function wrapGroq(groq) {
41877
42692
  if (isSupportedGroqClient(groq)) {
@@ -41883,14 +42698,14 @@ function wrapGroq(groq) {
41883
42698
  function isRecord6(value) {
41884
42699
  return typeof value === "object" && value !== null;
41885
42700
  }
41886
- function hasFunction5(value, methodName) {
42701
+ function hasFunction6(value, methodName) {
41887
42702
  return isRecord6(value) && methodName in value && typeof value[methodName] === "function";
41888
42703
  }
41889
42704
  function hasChat2(value) {
41890
- return isRecord6(value) && isRecord6(value.completions) && hasFunction5(value.completions, "create");
42705
+ return isRecord6(value) && isRecord6(value.completions) && hasFunction6(value.completions, "create");
41891
42706
  }
41892
42707
  function hasEmbeddings2(value) {
41893
- return hasFunction5(value, "create");
42708
+ return hasFunction6(value, "create");
41894
42709
  }
41895
42710
  function isSupportedGroqClient(value) {
41896
42711
  return isRecord6(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
@@ -42473,7 +43288,7 @@ async function flushExperimentWithSync(context, config) {
42473
43288
  // src/wrappers/shared/scorers.ts
42474
43289
  async function runScorers(args) {
42475
43290
  const { scorers, output, expected, input, metadata, span } = args;
42476
- const scorerArgs = {
43291
+ const scorerArgs2 = {
42477
43292
  output,
42478
43293
  expected,
42479
43294
  input,
@@ -42482,7 +43297,7 @@ async function runScorers(args) {
42482
43297
  await Promise.all(
42483
43298
  scorers.map(async (scorer) => {
42484
43299
  try {
42485
- const result = await scorer(scorerArgs);
43300
+ const result = await scorer(scorerArgs2);
42486
43301
  const scores = normalizeScores(result);
42487
43302
  if (scores.length > 0) {
42488
43303
  const accScores = {};
@@ -44841,6 +45656,26 @@ async function getExperimentParametersRef(parameters) {
44841
45656
  version: resolvedParameters.version
44842
45657
  };
44843
45658
  }
45659
+ async function _internalInitEvaluatorExperiment(projectName, evaluator, data, options = {}) {
45660
+ if (options.disabled) return null;
45661
+ const { baseExperiment } = callEvaluatorData(data);
45662
+ const parameters = await getExperimentParametersRef(evaluator.parameters);
45663
+ return initExperiment2(evaluator.state, {
45664
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: projectName },
45665
+ experiment: options.experimentName ?? evaluator.experimentName,
45666
+ description: evaluator.description,
45667
+ metadata: evaluator.metadata,
45668
+ tags: evaluator.tags,
45669
+ isPublic: evaluator.isPublic,
45670
+ update: options.update ?? evaluator.update,
45671
+ baseExperiment: evaluator.baseExperimentName ?? baseExperiment,
45672
+ baseExperimentId: evaluator.baseExperimentId,
45673
+ gitMetadataSettings: evaluator.gitMetadataSettings,
45674
+ repoInfo: evaluator.repoInfo,
45675
+ dataset: Dataset2.isDataset(data) ? data : void 0,
45676
+ parameters
45677
+ });
45678
+ }
44844
45679
  function callEvaluatorData(data) {
44845
45680
  const dataResult = typeof data === "function" ? data() : data;
44846
45681
  let baseExperiment = void 0;
@@ -44858,6 +45693,48 @@ function isAsyncIterable7(value) {
44858
45693
  function isIterable(value) {
44859
45694
  return typeof value === "object" && value !== null && Symbol.iterator in value && typeof value[Symbol.iterator] === "function";
44860
45695
  }
45696
+ async function _internalResolveEvaluatorData(evaluator, experiment) {
45697
+ if (typeof evaluator.data === "string") {
45698
+ throw new Error("Unimplemented: string data paths");
45699
+ }
45700
+ let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
45701
+ if ("_type" in dataResult) {
45702
+ if (dataResult._type !== "BaseExperiment") {
45703
+ throw new Error("Invalid _type");
45704
+ }
45705
+ if (!experiment) {
45706
+ throw new Error(
45707
+ "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
45708
+ );
45709
+ }
45710
+ let name = dataResult.name;
45711
+ if (isEmpty2(name)) {
45712
+ const baseExperiment = await experiment.fetchBaseExperiment();
45713
+ if (!baseExperiment) {
45714
+ throw new Error("BaseExperiment() failed to fetch base experiment");
45715
+ }
45716
+ name = baseExperiment.name;
45717
+ }
45718
+ dataResult = initExperiment2(evaluator.state, {
45719
+ ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
45720
+ experiment: name,
45721
+ open: true
45722
+ }).asDataset();
45723
+ }
45724
+ const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
45725
+ if (isAsyncIterable7(resolvedDataResult)) {
45726
+ return resolvedDataResult;
45727
+ }
45728
+ if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
45729
+ const iterable = resolvedDataResult;
45730
+ return (async function* () {
45731
+ for (const datum of iterable) yield datum;
45732
+ })();
45733
+ }
45734
+ throw new Error(
45735
+ "Evaluator data must be an array, iterable, or async iterable"
45736
+ );
45737
+ }
44861
45738
  globalThis._evals = {
44862
45739
  functions: [],
44863
45740
  prompts: [],
@@ -44904,25 +45781,13 @@ async function Eval(name, evaluator, reporterOrOpts) {
44904
45781
  }
44905
45782
  const resolvedReporter = options.reporter || defaultReporter;
44906
45783
  try {
44907
- const { data, baseExperiment: defaultBaseExperiment } = callEvaluatorData(
44908
- evaluator.data
44909
- );
44910
- const parameters = await getExperimentParametersRef(evaluator.parameters);
44911
- const experiment = options.parent || options.noSendLogs ? null : initExperiment2(evaluator.state, {
44912
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: name },
44913
- experiment: evaluator.experimentName,
44914
- description: evaluator.description,
44915
- metadata: evaluator.metadata,
44916
- tags: evaluator.tags,
44917
- isPublic: evaluator.isPublic,
44918
- update: evaluator.update,
44919
- baseExperiment: evaluator.baseExperimentName ?? defaultBaseExperiment,
44920
- baseExperimentId: evaluator.baseExperimentId,
44921
- gitMetadataSettings: evaluator.gitMetadataSettings,
44922
- repoInfo: evaluator.repoInfo,
44923
- dataset: Dataset2.isDataset(data) ? data : void 0,
44924
- parameters
44925
- });
45784
+ const { data } = callEvaluatorData(evaluator.data);
45785
+ const experiment = await _internalInitEvaluatorExperiment(
45786
+ name,
45787
+ evaluator,
45788
+ data,
45789
+ { disabled: Boolean(options.parent || options.noSendLogs) }
45790
+ );
44926
45791
  if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
44927
45792
  await experiment._waitForId();
44928
45793
  }
@@ -45020,19 +45885,74 @@ function scorerName(scorer, scorer_idx) {
45020
45885
  function classifierName(classifier, classifier_idx) {
45021
45886
  return classifier.name || `classifier_${classifier_idx}`;
45022
45887
  }
45888
+ async function _internalRunEvaluatorTask(task, datum, trialIndex, parameters, span, reportProgress = () => void 0) {
45889
+ const metadata = {
45890
+ ..."metadata" in datum ? datum.metadata : {}
45891
+ };
45892
+ const hooks = {
45893
+ meta(value) {
45894
+ Object.assign(metadata, value);
45895
+ },
45896
+ metadata,
45897
+ expected: "expected" in datum ? datum.expected : void 0,
45898
+ span,
45899
+ parameters,
45900
+ reportProgress,
45901
+ trialIndex,
45902
+ tags: [...datum.tags ?? []]
45903
+ };
45904
+ const output = await task(datum.input, hooks);
45905
+ span.log({ output });
45906
+ return {
45907
+ output,
45908
+ metadata: hooks.metadata,
45909
+ tags: hooks.tags ?? []
45910
+ };
45911
+ }
45023
45912
  function buildSpanMetadata(results) {
45024
- return results.length === 1 ? results[0].metadata : results.reduce(
45025
- (prev, s) => mergeDicts(prev, { [s.name]: s.metadata }),
45026
- {}
45913
+ return results.length === 1 ? results[0].metadata : Object.fromEntries(
45914
+ results.map((result) => [result.name, result.metadata])
45027
45915
  );
45028
45916
  }
45029
45917
  function buildSpanScores(results) {
45030
- const scoresRecord = results.reduce(
45031
- (prev, s) => mergeDicts(prev, { [s.name]: s.score }),
45032
- {}
45918
+ const scoresRecord = Object.fromEntries(
45919
+ results.map((result) => [result.name, result.score])
45033
45920
  );
45034
45921
  return { resultMetadata: buildSpanMetadata(results), scoresRecord };
45035
45922
  }
45923
+ function _internalPrepareEvaluatorScore(scoreValue, name) {
45924
+ if (scoreValue === null) return { results: null };
45925
+ if (Array.isArray(scoreValue)) {
45926
+ for (const score of scoreValue) {
45927
+ if (!(typeof score === "object" && !isEmpty2(score))) {
45928
+ throw new Error(
45929
+ `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
45930
+ );
45931
+ }
45932
+ }
45933
+ }
45934
+ let results;
45935
+ if (Array.isArray(scoreValue)) {
45936
+ results = scoreValue;
45937
+ } else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
45938
+ results = [scoreValue];
45939
+ } else {
45940
+ results = [{ name, score: scoreValue }];
45941
+ }
45942
+ const { resultMetadata, scoresRecord } = buildSpanScores(results);
45943
+ const fields = (score) => {
45944
+ const { metadata: _metadata, name: _name, ...rest } = score;
45945
+ return rest;
45946
+ };
45947
+ return {
45948
+ results,
45949
+ output: results.length === 1 ? fields(results[0]) : Object.fromEntries(
45950
+ results.map((score) => [score.name ?? name, fields(score)])
45951
+ ),
45952
+ metadata: resultMetadata,
45953
+ scores: scoresRecord
45954
+ };
45955
+ }
45036
45956
  async function runInScorerSpan(rootSpan, spanName, spanType, propagatedEvent, eventInput, fn) {
45037
45957
  try {
45038
45958
  const value = await rootSpan.traced(fn, {
@@ -45077,6 +45997,27 @@ function toClassificationItem(c) {
45077
45997
  ...c.metadata !== void 0 ? { metadata: c.metadata } : {}
45078
45998
  };
45079
45999
  }
46000
+ function _internalPrepareEvaluatorClassification(value, name) {
46001
+ if (value === null) return { results: null };
46002
+ const results = (Array.isArray(value) ? value : [value]).map(
46003
+ (result) => validateClassificationResult(result, name)
46004
+ );
46005
+ const classifications = /* @__PURE__ */ Object.create(null);
46006
+ for (const result of results) {
46007
+ (classifications[result.name] ??= []).push(toClassificationItem(result));
46008
+ }
46009
+ return {
46010
+ results,
46011
+ output: results.length === 1 ? toClassificationItem(results[0]) : Object.fromEntries(
46012
+ results.map((result) => [
46013
+ result.name,
46014
+ toClassificationItem(result)
46015
+ ])
46016
+ ),
46017
+ metadata: buildSpanMetadata(results),
46018
+ classifications
46019
+ };
46020
+ }
45080
46021
  function logScoringFailures(kind, failures, metadata, rootSpan, state) {
45081
46022
  if (!failures.length) return [];
45082
46023
  const errorMap = Object.fromEntries(
@@ -45124,54 +46065,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45124
46065
  (evaluator.state ?? _internalGetGlobalState())?.spanCache?.start();
45125
46066
  }
45126
46067
  try {
45127
- if (typeof evaluator.data === "string") {
45128
- throw new Error("Unimplemented: string data paths");
45129
- }
45130
- let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
45131
46068
  parameters = await validateParameters(
45132
46069
  parameters ?? {},
45133
46070
  evaluator.parameters
45134
46071
  );
45135
- if ("_type" in dataResult) {
45136
- if (dataResult._type !== "BaseExperiment") {
45137
- throw new Error("Invalid _type");
45138
- }
45139
- if (!experiment) {
45140
- throw new Error(
45141
- "Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
45142
- );
45143
- }
45144
- let name = dataResult.name;
45145
- if (isEmpty2(name)) {
45146
- const baseExperiment = await experiment.fetchBaseExperiment();
45147
- if (!baseExperiment) {
45148
- throw new Error("BaseExperiment() failed to fetch base experiment");
45149
- }
45150
- name = baseExperiment.name;
45151
- }
45152
- dataResult = initExperiment2(evaluator.state, {
45153
- ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
45154
- experiment: name,
45155
- open: true
45156
- }).asDataset();
45157
- }
45158
- const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
45159
- const dataIterable = (() => {
45160
- if (isAsyncIterable7(resolvedDataResult)) {
45161
- return resolvedDataResult;
45162
- }
45163
- if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
45164
- const iterable = resolvedDataResult;
45165
- return (async function* () {
45166
- for (const datum of iterable) {
45167
- yield datum;
45168
- }
45169
- })();
45170
- }
45171
- throw new Error(
45172
- "Evaluator data must be an array, iterable, or async iterable"
45173
- );
45174
- })();
46072
+ const dataIterable = await _internalResolveEvaluatorData(
46073
+ evaluator,
46074
+ experiment
46075
+ );
45175
46076
  progressReporter.start(evaluator.evalName, 0);
45176
46077
  const experimentIdPromise = experiment ? (async () => {
45177
46078
  try {
@@ -45240,57 +46141,45 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45240
46141
  ensureSpansFlushed,
45241
46142
  state
45242
46143
  }) : void 0;
45243
- let metadata = {
45244
- ..."metadata" in datum ? datum.metadata : {}
45245
- };
46144
+ let metadata = {};
45246
46145
  const expected = "expected" in datum ? datum.expected : void 0;
45247
46146
  let output = void 0;
45248
46147
  let error = void 0;
45249
- let tags = [...datum.tags ?? []];
45250
- const scores = {};
45251
- const classifications = {};
46148
+ let tags = [];
46149
+ const scores = /* @__PURE__ */ Object.create(null);
46150
+ const classifications = /* @__PURE__ */ Object.create(null);
45252
46151
  const scorerNames = (evaluator.scores ?? []).map(scorerName);
45253
46152
  const classifierNames = (evaluator.classifiers ?? []).map(
45254
46153
  classifierName
45255
46154
  );
45256
46155
  let unhandledScores = scorerNames;
45257
46156
  try {
45258
- const meta = (o) => metadata = { ...metadata, ...o };
45259
- await rootSpan.traced(
45260
- async (span) => {
45261
- const hooksForTask = {
45262
- meta,
45263
- metadata,
45264
- expected,
45265
- span,
45266
- parameters: parameters ?? {},
45267
- reportProgress: (event) => {
45268
- stream?.({
45269
- ...event,
45270
- id: rootSpan.id,
45271
- origin: baseEvent.event?.origin,
45272
- name: evaluator.evalName,
45273
- object_type: "task"
45274
- });
45275
- },
45276
- trialIndex,
45277
- tags
45278
- };
45279
- const outputResult = evaluator.task(datum.input, hooksForTask);
45280
- if (outputResult instanceof Promise) {
45281
- output = await outputResult;
45282
- } else {
45283
- output = outputResult;
46157
+ const taskResult = await rootSpan.traced(
46158
+ (span) => _internalRunEvaluatorTask(
46159
+ evaluator.task,
46160
+ datum,
46161
+ trialIndex,
46162
+ parameters ?? {},
46163
+ span,
46164
+ (event) => {
46165
+ stream?.({
46166
+ ...event,
46167
+ id: rootSpan.id,
46168
+ origin: baseEvent.event?.origin,
46169
+ name: evaluator.evalName,
46170
+ object_type: "task"
46171
+ });
45284
46172
  }
45285
- tags = hooksForTask.tags ?? [];
45286
- span.log({ output });
45287
- },
46173
+ ),
45288
46174
  {
45289
46175
  name: "task",
45290
46176
  spanAttributes: { type: "task" /* TASK */ },
45291
46177
  event: { input: datum.input }
45292
46178
  }
45293
46179
  );
46180
+ output = taskResult.output;
46181
+ metadata = taskResult.metadata;
46182
+ tags = taskResult.tags;
45294
46183
  if (tags.length) {
45295
46184
  rootSpan.log({ output, metadata, expected, tags });
45296
46185
  } else {
@@ -45300,20 +46189,18 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45300
46189
  await rootSpan.flush();
45301
46190
  }
45302
46191
  const scoringArgs = {
46192
+ id: datum.id,
45303
46193
  input: datum.input,
45304
46194
  expected: "expected" in datum ? datum.expected : void 0,
45305
46195
  metadata,
45306
46196
  output,
46197
+ tags,
45307
46198
  trace
45308
46199
  };
45309
46200
  const { trace: _trace, ...scoringArgsForLogging } = scoringArgs;
45310
46201
  const propagatedEvent = makeScorerPropagatedEvent(
45311
46202
  await rootSpan.export()
45312
46203
  );
45313
- const getOtherFields = (s) => {
45314
- const { metadata: _metadata, name: _name, ...rest } = s;
45315
- return rest;
45316
- };
45317
46204
  const [scoreResults, classificationResults] = await Promise.all([
45318
46205
  Promise.all(
45319
46206
  (evaluator.scores ?? []).map(
@@ -45327,35 +46214,17 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45327
46214
  const scoreValue = await Promise.resolve(
45328
46215
  score(scoringArgs)
45329
46216
  );
45330
- if (scoreValue === null) return null;
45331
- if (Array.isArray(scoreValue)) {
45332
- for (const s of scoreValue) {
45333
- if (!(typeof s === "object" && !isEmpty2(s))) {
45334
- throw new Error(
45335
- `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(s)}`
45336
- );
45337
- }
45338
- }
45339
- }
45340
- const results = Array.isArray(scoreValue) ? scoreValue : typeof scoreValue === "object" && !isEmpty2(scoreValue) ? [scoreValue] : [
45341
- {
45342
- name: scorerNames[score_idx],
45343
- score: scoreValue
45344
- }
45345
- ];
45346
- const { resultMetadata, scoresRecord } = buildSpanScores(results);
45347
- const resultOutput = results.length === 1 ? getOtherFields(results[0]) : results.reduce(
45348
- (prev, s) => mergeDicts(prev, {
45349
- [s.name]: getOtherFields(s)
45350
- }),
45351
- {}
46217
+ const prepared = _internalPrepareEvaluatorScore(
46218
+ scoreValue,
46219
+ scorerNames[score_idx]
45352
46220
  );
46221
+ if (prepared.results === null) return null;
45353
46222
  span.log({
45354
- output: resultOutput,
45355
- metadata: resultMetadata,
45356
- scores: scoresRecord
46223
+ output: prepared.output,
46224
+ metadata: prepared.metadata,
46225
+ scores: prepared.scores
45357
46226
  });
45358
- return results;
46227
+ return prepared.results;
45359
46228
  }
45360
46229
  )
45361
46230
  )
@@ -45372,24 +46241,16 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
45372
46241
  const classifierValue = await Promise.resolve(
45373
46242
  classifier(scoringArgs)
45374
46243
  );
45375
- if (classifierValue === null) return null;
45376
- const rawResults = (Array.isArray(classifierValue) ? classifierValue : [classifierValue]).map(
45377
- (result) => validateClassificationResult(
45378
- result,
45379
- classifierNames[idx]
45380
- )
45381
- );
45382
- const resultOutput = rawResults.length === 1 ? toClassificationItem(rawResults[0]) : rawResults.reduce(
45383
- (prev, r) => mergeDicts(prev, {
45384
- [r.name]: toClassificationItem(r)
45385
- }),
45386
- {}
46244
+ const prepared = _internalPrepareEvaluatorClassification(
46245
+ classifierValue,
46246
+ classifierNames[idx]
45387
46247
  );
46248
+ if (prepared.results === null) return null;
45388
46249
  span.log({
45389
- output: resultOutput,
45390
- metadata: buildSpanMetadata(rawResults)
46250
+ output: prepared.output,
46251
+ metadata: prepared.metadata
45391
46252
  });
45392
- return rawResults;
46253
+ return prepared.results;
45393
46254
  }
45394
46255
  )
45395
46256
  )
@@ -45618,7 +46479,7 @@ function accumulateScores(accumulator, scores) {
45618
46479
  }
45619
46480
  }
45620
46481
  function ensureScoreAccumulator(results) {
45621
- const accumulator = {};
46482
+ const accumulator = /* @__PURE__ */ Object.create(null);
45622
46483
  for (const result of results) {
45623
46484
  accumulateScores(accumulator, result.scores);
45624
46485
  }
@@ -45761,6 +46622,1156 @@ var defaultReporter = {
45761
46622
  }
45762
46623
  };
45763
46624
 
46625
+ // src/durable-eval.ts
46626
+ var encoder = new TextEncoder();
46627
+ var decoder = new TextDecoder();
46628
+ var BATCH_TASK_KIND = "braintrust.durable.batch-task";
46629
+ var BATCH_SCORER_KIND = "braintrust.durable.batch-scorer";
46630
+ var DEFAULT_BATCH_SIZE = 1e3;
46631
+ var DurableEvalMemoryStore = class {
46632
+ values = /* @__PURE__ */ new Map();
46633
+ async read(key) {
46634
+ return this.values.get(key)?.slice();
46635
+ }
46636
+ async write(key, value) {
46637
+ this.values.set(key, value.slice());
46638
+ }
46639
+ async getOrSet(key, value) {
46640
+ const existing = this.values.get(key);
46641
+ if (existing) return { value: existing.slice(), created: false };
46642
+ this.values.set(key, value.slice());
46643
+ return { value: value.slice(), created: true };
46644
+ }
46645
+ };
46646
+ var DurableEvalRedisStore = class {
46647
+ client;
46648
+ keyPrefix;
46649
+ ttlMs;
46650
+ constructor(options) {
46651
+ this.client = options.client;
46652
+ this.keyPrefix = options.keyPrefix ?? "braintrust-eval:";
46653
+ this.ttlMs = options.ttlMs ?? 1e3 * 60 * 60 * 24 * 7;
46654
+ if (!Number.isInteger(this.ttlMs) || this.ttlMs < 1) {
46655
+ throw new Error("DurableEvalRedisStore ttlMs must be a positive integer");
46656
+ }
46657
+ }
46658
+ async read(key) {
46659
+ const value = await this.client.get(`${this.keyPrefix}${key}`);
46660
+ if (value == null) return void 0;
46661
+ if (typeof value !== "string") {
46662
+ throw new Error("DurableEvalRedisStore expected GET to return a string");
46663
+ }
46664
+ return base64ToUint8Array(value);
46665
+ }
46666
+ async write(key, value) {
46667
+ const client = this.client;
46668
+ const set = client.set;
46669
+ const redisKey = `${this.keyPrefix}${key}`;
46670
+ const encoded = uint8ArrayToBase64(value);
46671
+ if (typeof client.defineCommand === "function") {
46672
+ await set.call(client, redisKey, encoded, "PX", this.ttlMs);
46673
+ } else if (typeof client.sendCommand === "function") {
46674
+ await set.call(client, redisKey, encoded, { PX: this.ttlMs });
46675
+ } else if (typeof client.createScript === "function") {
46676
+ await set.call(client, redisKey, encoded, { px: this.ttlMs });
46677
+ } else {
46678
+ throw new Error(
46679
+ "DurableEvalRedisStore requires a node-redis, ioredis, or @upstash/redis client"
46680
+ );
46681
+ }
46682
+ }
46683
+ async getOrSet(key, value) {
46684
+ const redisKey = `${this.keyPrefix}${key}`;
46685
+ const encoded = uint8ArrayToBase64(value);
46686
+ const client = this.client;
46687
+ const set = client.set;
46688
+ let setOptions;
46689
+ if (typeof client.defineCommand === "function") {
46690
+ setOptions = ["PX", this.ttlMs, "NX", "GET"];
46691
+ } else if (typeof client.sendCommand === "function") {
46692
+ setOptions = [{ PX: this.ttlMs, NX: true, GET: true }];
46693
+ } else if (typeof client.createScript === "function") {
46694
+ setOptions = [{ px: this.ttlMs, nx: true, get: true }];
46695
+ } else {
46696
+ throw new Error(
46697
+ "DurableEvalRedisStore getOrSet requires a node-redis, ioredis, or @upstash/redis client"
46698
+ );
46699
+ }
46700
+ const existing = await set.call(client, redisKey, encoded, ...setOptions);
46701
+ if (existing === null) return { value: value.slice(), created: true };
46702
+ if (typeof existing !== "string") {
46703
+ throw new Error(
46704
+ "DurableEvalRedisStore expected atomic SET to return a string or null"
46705
+ );
46706
+ }
46707
+ return { value: base64ToUint8Array(existing), created: false };
46708
+ }
46709
+ };
46710
+ var BatchTask = class {
46711
+ constructor(processor) {
46712
+ this.processor = processor;
46713
+ }
46714
+ processor;
46715
+ kind = BATCH_TASK_KIND;
46716
+ };
46717
+ var BatchScorer = class {
46718
+ constructor(processor) {
46719
+ this.processor = processor;
46720
+ this.name = processor.name;
46721
+ }
46722
+ processor;
46723
+ kind = BATCH_SCORER_KIND;
46724
+ name;
46725
+ };
46726
+ function defineDurableEval(projectName, evaluator) {
46727
+ const definition = {
46728
+ projectName,
46729
+ evalName: evaluator.experimentName ?? projectName,
46730
+ evaluator
46731
+ };
46732
+ return {
46733
+ start: (options = {}) => startDurableEval(definition, options),
46734
+ status: (options) => getDurableEvalStatus(definition, options),
46735
+ poll: (options) => pollDurableEval(definition, options),
46736
+ processBatchResult: (result) => processDurableBatchResult(definition, result)
46737
+ };
46738
+ }
46739
+ async function startDurableEval(definition, options) {
46740
+ const store = definition.evaluator.store;
46741
+ const runId = newId();
46742
+ const key = runKey(definition.projectName, definition.evalName, runId);
46743
+ const { data } = callEvaluatorData(definition.evaluator.data);
46744
+ const parameters = await validateParameters(
46745
+ options.parameters ?? {},
46746
+ definition.evaluator.parameters
46747
+ );
46748
+ const experimentName = definition.evaluator.experimentName ?? `${definition.evalName}-${runId}`;
46749
+ const experiment = await _internalInitEvaluatorExperiment(
46750
+ definition.projectName,
46751
+ { ...definition.evaluator, data },
46752
+ data,
46753
+ {
46754
+ disabled: options.noSendLogs ?? false,
46755
+ experimentName,
46756
+ update: true
46757
+ }
46758
+ );
46759
+ if (!isBatchTask(definition.evaluator.task) && !(definition.evaluator.scores ?? []).some(isBatchScorer)) {
46760
+ const result = await runEvaluator(
46761
+ experiment,
46762
+ {
46763
+ ...definition.evaluator,
46764
+ projectName: definition.projectName,
46765
+ evalName: definition.evalName,
46766
+ data
46767
+ },
46768
+ {
46769
+ start: () => void 0,
46770
+ stop: () => void 0,
46771
+ increment: () => void 0
46772
+ },
46773
+ [],
46774
+ void 0,
46775
+ parameters,
46776
+ true,
46777
+ true
46778
+ );
46779
+ const state2 = {
46780
+ runId,
46781
+ experimentName,
46782
+ noSendLogs: options.noSendLogs ?? false,
46783
+ parameters: assertJsonValue(parameters, "eval parameters"),
46784
+ status: "completed",
46785
+ summary: result.summary,
46786
+ cases: [],
46787
+ batches: []
46788
+ };
46789
+ await experiment?.flush();
46790
+ await writeRunRecord(store, key, state2);
46791
+ return currentStatus(definition, state2);
46792
+ }
46793
+ const state = {
46794
+ runId,
46795
+ experimentName,
46796
+ noSendLogs: options.noSendLogs ?? false,
46797
+ parameters: assertJsonValue(parameters, "eval parameters"),
46798
+ status: "running",
46799
+ cases: await materializeCases(definition, data, experiment),
46800
+ batches: []
46801
+ };
46802
+ await writeCaseBaseRecords(store, key, state.cases);
46803
+ await writeRunRecord(store, key, state);
46804
+ return advanceDurableEval(definition, state, store, key, experiment);
46805
+ }
46806
+ async function getDurableEvalStatus(definition, options) {
46807
+ const store = definition.evaluator.store;
46808
+ const state = await readRunState(
46809
+ definition,
46810
+ store,
46811
+ runKey(definition.projectName, definition.evalName, options.runId)
46812
+ );
46813
+ if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
46814
+ return currentStatus(definition, state);
46815
+ }
46816
+ async function processDurableBatchResult(definition, result) {
46817
+ if (!result.batchId && !result.externalId) {
46818
+ throw new Error("Batch results require batchId or externalId");
46819
+ }
46820
+ const store = definition.evaluator.store;
46821
+ const key = runKey(definition.projectName, definition.evalName, result.runId);
46822
+ const state = await readRunState(definition, store, key);
46823
+ if (!state) throw new Error(`Durable eval run ${result.runId} is missing`);
46824
+ const byBatch = result.batchId ? state.batches.find((candidate) => candidate.id === result.batchId) : void 0;
46825
+ const byExternal = result.externalId ? state.batches.find(
46826
+ (candidate) => candidate.externalId === result.externalId
46827
+ ) : void 0;
46828
+ if (byBatch && byExternal && byBatch.id !== byExternal.id) {
46829
+ throw new Error("batchId and externalId identify different batches");
46830
+ }
46831
+ const batch = byBatch ?? byExternal;
46832
+ if (!batch) throw new Error("No submitted batch matches this result");
46833
+ if (batch.status !== "complete") {
46834
+ const records = await collectBatch(definition, state, batch);
46835
+ batch.status = "complete";
46836
+ await writeCaseRecords(store, key, records);
46837
+ await writeBatchRecords(store, key, [batch]);
46838
+ }
46839
+ return advanceDurableEval(
46840
+ definition,
46841
+ await readRunState(definition, store, key),
46842
+ store,
46843
+ key
46844
+ );
46845
+ }
46846
+ async function pollDurableEval(definition, options) {
46847
+ const store = definition.evaluator.store;
46848
+ const key = runKey(
46849
+ definition.projectName,
46850
+ definition.evalName,
46851
+ options.runId
46852
+ );
46853
+ const state = await readRunState(definition, store, key);
46854
+ if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
46855
+ const batches = state.batches.filter((batch) => {
46856
+ if (batch.status === "complete") return false;
46857
+ return processorForStage(definition, batch.kind, batch.scorerName).completion.mode === "poll";
46858
+ });
46859
+ const results = await Promise.all(
46860
+ batches.map(async (batch) => ({
46861
+ batch,
46862
+ result: await processorForStage(definition, batch.kind, batch.scorerName).completion.poll(batch.submissionData, {
46863
+ runId: state.runId,
46864
+ batchId: batch.id
46865
+ })
46866
+ }))
46867
+ );
46868
+ const changedCases = /* @__PURE__ */ new Map();
46869
+ const changedBatches = [];
46870
+ for (const { batch, result } of results) {
46871
+ if (result.status === "failed") throw asError(result.error);
46872
+ if (result.status !== "complete") continue;
46873
+ for (const record of await collectBatch(definition, state, batch)) {
46874
+ changedCases.set(record.id, record);
46875
+ }
46876
+ batch.status = "complete";
46877
+ changedBatches.push(batch);
46878
+ }
46879
+ if (changedBatches.length > 0) {
46880
+ await writeCaseRecords(store, key, [...changedCases.values()]);
46881
+ await writeBatchRecords(store, key, changedBatches);
46882
+ }
46883
+ const currentState = changedBatches.length > 0 ? await readRunState(definition, store, key) : state;
46884
+ return advanceDurableEval(definition, currentState, store, key);
46885
+ }
46886
+ async function openDurableExperiment(definition, state) {
46887
+ const data = [];
46888
+ return await _internalInitEvaluatorExperiment(
46889
+ definition.projectName,
46890
+ { ...definition.evaluator, data },
46891
+ data,
46892
+ {
46893
+ disabled: state.noSendLogs,
46894
+ experimentName: state.experimentName,
46895
+ update: true
46896
+ }
46897
+ );
46898
+ }
46899
+ async function advanceDurableEval(definition, state, store, key, existingExperiment) {
46900
+ if (state.status === "completed") return currentStatus(definition, state);
46901
+ const experiment = existingExperiment === void 0 ? await openDurableExperiment(definition, state) : existingExperiment;
46902
+ await runTaskStage(definition, state, store, key, experiment);
46903
+ await logCompletedTasks(definition, state, store, key, experiment);
46904
+ state = await readRunState(definition, store, key) ?? state;
46905
+ if (state.cases.some((record) => !record.taskComplete || !record.taskLogged)) {
46906
+ return currentStatus(definition, state);
46907
+ }
46908
+ await runScoreStages(definition, state, store, key, experiment);
46909
+ state = await readRunState(definition, store, key) ?? state;
46910
+ const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
46911
+ ({ name }) => name
46912
+ );
46913
+ const classifierNames = (definition.evaluator.classifiers ?? []).map(
46914
+ classifierName
46915
+ );
46916
+ if (state.cases.some(
46917
+ (record) => scorerNames.some(
46918
+ (name) => !Object.hasOwn(record.scores, name) || !Object.hasOwn(record.loggedScores, name)
46919
+ ) || classifierNames.some(
46920
+ (name) => !Object.hasOwn(record.loggedClassifications, name)
46921
+ )
46922
+ )) {
46923
+ return currentStatus(definition, state);
46924
+ }
46925
+ if (!await claimAction(store, key, "finish")) {
46926
+ const latest = await readRunState(definition, store, key);
46927
+ return currentStatus(definition, latest ?? state);
46928
+ }
46929
+ state.summary = await finishExperiment(definition, state, experiment);
46930
+ state.status = "completed";
46931
+ await writeRunRecord(store, key, state);
46932
+ return currentStatus(definition, state);
46933
+ }
46934
+ function currentStatus(definition, state) {
46935
+ if (state.status === "completed") {
46936
+ if (!state.summary) {
46937
+ throw new Error(`Durable eval run ${state.runId} has no saved summary`);
46938
+ }
46939
+ return {
46940
+ status: "completed",
46941
+ runId: state.runId,
46942
+ pending: { poll: 0, webhook: 0 },
46943
+ summary: state.summary
46944
+ };
46945
+ }
46946
+ const pending = { poll: 0, webhook: 0 };
46947
+ for (const batch of state.batches) {
46948
+ if (batch.status === "complete") continue;
46949
+ pending[processorForStage(definition, batch.kind, batch.scorerName).completion.mode]++;
46950
+ }
46951
+ return { status: "waiting", runId: state.runId, pending };
46952
+ }
46953
+ async function startCaseRoot(definition, state, record, experiment) {
46954
+ if (!experiment) return NOOP_SPAN;
46955
+ const datum = record.datum;
46956
+ return _internalStartSpanWithInitialMerge({
46957
+ ...definition.evaluator.state ? { state: definition.evaluator.state } : {},
46958
+ parent: await experiment.export(),
46959
+ name: "eval",
46960
+ spanId: deterministicId(`${state.runId}:${record.id}:span`),
46961
+ spanAttributes: { type: "eval" /* EVAL */ },
46962
+ event: {
46963
+ id: deterministicId(`${state.runId}:${record.id}:row`),
46964
+ input: datum.input,
46965
+ expected: "expected" in datum ? datum.expected : void 0,
46966
+ tags: datum.tags,
46967
+ origin: datum.origin
46968
+ }
46969
+ });
46970
+ }
46971
+ async function logTaskResult(definition, state, record, experiment, task) {
46972
+ const datum = record.datum;
46973
+ const root = await startCaseRoot(definition, state, record, experiment);
46974
+ try {
46975
+ if (task) {
46976
+ const result = await root.traced(
46977
+ (span) => _internalRunEvaluatorTask(
46978
+ task,
46979
+ datum,
46980
+ record.trialIndex,
46981
+ state.parameters,
46982
+ span
46983
+ ),
46984
+ {
46985
+ name: "task",
46986
+ spanId: deterministicId(`${state.runId}:${record.id}:task`),
46987
+ spanAttributes: { type: "task" /* TASK */ },
46988
+ event: { input: datum.input }
46989
+ }
46990
+ );
46991
+ record.output = assertJsonValue(
46992
+ result.output,
46993
+ `task output for ${record.caseId}`
46994
+ );
46995
+ record.metadata = assertJsonValue(result.metadata, "task metadata");
46996
+ record.tags = result.tags;
46997
+ record.taskComplete = true;
46998
+ } else {
46999
+ await root.traced((span) => span.log({ output: record.output }), {
47000
+ name: "task",
47001
+ spanId: deterministicId(`${state.runId}:${record.id}:task`),
47002
+ spanAttributes: { type: "task" /* TASK */ },
47003
+ event: { input: datum.input }
47004
+ });
47005
+ }
47006
+ root.log({
47007
+ output: record.output,
47008
+ expected: "expected" in datum ? datum.expected : void 0,
47009
+ metadata: {
47010
+ ...record.metadata,
47011
+ durable_eval: {
47012
+ run_id: state.runId,
47013
+ case_id: record.caseId,
47014
+ trial_index: record.trialIndex
47015
+ }
47016
+ },
47017
+ tags: record.tags
47018
+ });
47019
+ record.rootSpan = await root.export();
47020
+ record.taskLogged = true;
47021
+ } catch (error) {
47022
+ logError(root, error);
47023
+ throw error;
47024
+ } finally {
47025
+ root.end();
47026
+ }
47027
+ }
47028
+ async function logCompletedTasks(definition, state, store, key, experiment) {
47029
+ const changed = [];
47030
+ for (const record of state.cases) {
47031
+ if (!record.taskComplete || record.taskLogged) continue;
47032
+ if (!await claimAction(store, key, "task-log", record.id)) continue;
47033
+ await logTaskResult(definition, state, record, experiment);
47034
+ changed.push(record);
47035
+ }
47036
+ if (changed.length > 0) {
47037
+ await experiment?.flush();
47038
+ await writeCaseRecords(store, key, changed);
47039
+ }
47040
+ }
47041
+ async function runTaskStage(definition, state, store, key, experiment) {
47042
+ if (isBatchTask(definition.evaluator.task)) {
47043
+ await ensureBatches(definition, state, store, key, "task");
47044
+ return;
47045
+ }
47046
+ const task = definition.evaluator.task;
47047
+ const changed = [];
47048
+ for (const record of state.cases) {
47049
+ if (record.taskComplete) continue;
47050
+ if (!await claimAction(store, key, "task", record.id)) continue;
47051
+ await logTaskResult(definition, state, record, experiment, task);
47052
+ changed.push(record);
47053
+ }
47054
+ if (changed.length > 0) {
47055
+ await experiment?.flush();
47056
+ await writeCaseRecords(store, key, changed);
47057
+ }
47058
+ }
47059
+ async function runScoreStages(definition, state, store, key, experiment) {
47060
+ const scorers = resolveScorers(definition.evaluator.scores ?? []);
47061
+ const changed = /* @__PURE__ */ new Map();
47062
+ const persistChangedCases = async () => {
47063
+ if (changed.size === 0) return;
47064
+ await experiment?.flush();
47065
+ await writeCaseRecords(store, key, [...changed.values()]);
47066
+ changed.clear();
47067
+ };
47068
+ for (const { name, scorer } of scorers) {
47069
+ if (isBatchScorer(scorer)) {
47070
+ for (const record of state.cases) {
47071
+ if (Object.hasOwn(record.scores, name) && !Object.hasOwn(record.loggedScores, name)) {
47072
+ if (!await claimAction(store, key, "score-log", record.id, name)) {
47073
+ continue;
47074
+ }
47075
+ await evaluateAndLogScore(
47076
+ definition,
47077
+ state,
47078
+ record,
47079
+ name,
47080
+ experiment
47081
+ );
47082
+ changed.set(record.id, record);
47083
+ }
47084
+ }
47085
+ await persistChangedCases();
47086
+ await ensureBatches(definition, state, store, key, "score", name);
47087
+ continue;
47088
+ }
47089
+ for (const record of state.cases) {
47090
+ if (Object.hasOwn(record.loggedScores, name)) continue;
47091
+ if (!await claimAction(store, key, "score", record.id, name)) continue;
47092
+ await evaluateAndLogScore(
47093
+ definition,
47094
+ state,
47095
+ record,
47096
+ name,
47097
+ experiment,
47098
+ scorer
47099
+ );
47100
+ changed.set(record.id, record);
47101
+ }
47102
+ }
47103
+ for (const [index, classifier] of (definition.evaluator.classifiers ?? []).entries()) {
47104
+ const name = classifierName(classifier, index);
47105
+ for (const record of state.cases) {
47106
+ if (Object.hasOwn(record.loggedClassifications, name)) continue;
47107
+ if (!await claimAction(store, key, "classification", record.id, name)) {
47108
+ continue;
47109
+ }
47110
+ await evaluateAndLogClassification(
47111
+ definition,
47112
+ state,
47113
+ record,
47114
+ name,
47115
+ classifier,
47116
+ experiment
47117
+ );
47118
+ changed.set(record.id, record);
47119
+ }
47120
+ }
47121
+ await persistChangedCases();
47122
+ }
47123
+ function scorerArgs(record) {
47124
+ const datum = record.datum;
47125
+ return {
47126
+ ...datum,
47127
+ metadata: record.metadata,
47128
+ output: record.output
47129
+ };
47130
+ }
47131
+ function resumeCaseRoot(definition, record, experiment) {
47132
+ if (!experiment) return NOOP_SPAN;
47133
+ if (!record.rootSpan) {
47134
+ throw new Error(`Durable eval case ${record.caseId} has no root span`);
47135
+ }
47136
+ return _internalResumeSpan({
47137
+ exported: record.rootSpan,
47138
+ state: definition.evaluator.state
47139
+ });
47140
+ }
47141
+ async function evaluateAndLogScore(definition, state, record, name, experiment, scorer) {
47142
+ const root = resumeCaseRoot(definition, record, experiment);
47143
+ try {
47144
+ const rootExport = await root.export();
47145
+ const prepared = await root.traced(
47146
+ async (span) => {
47147
+ const value = scorer ? await scorer(scorerArgs(record)) : record.scores[name];
47148
+ if (scorer) {
47149
+ record.scores[name] = assertJsonValue(value, `scorer ${name} output`);
47150
+ }
47151
+ const result = _internalPrepareEvaluatorScore(value, name);
47152
+ if (result.results !== null) {
47153
+ span.log({
47154
+ output: result.output,
47155
+ metadata: result.metadata,
47156
+ scores: result.scores
47157
+ });
47158
+ }
47159
+ return result;
47160
+ },
47161
+ {
47162
+ name,
47163
+ spanId: deterministicId(`${state.runId}:${record.id}:score:${name}`),
47164
+ spanAttributes: {
47165
+ type: "score" /* SCORE */,
47166
+ purpose: "scorer"
47167
+ },
47168
+ propagatedEvent: makeScorerPropagatedEvent(rootExport || void 0),
47169
+ event: { input: scorerArgs(record) }
47170
+ }
47171
+ );
47172
+ if (prepared.scores) root.log({ scores: prepared.scores });
47173
+ record.loggedScores[name] = true;
47174
+ } catch (error) {
47175
+ logError(root, error);
47176
+ throw error;
47177
+ } finally {
47178
+ root.end();
47179
+ }
47180
+ }
47181
+ async function evaluateAndLogClassification(definition, state, record, name, classifier, experiment) {
47182
+ const root = resumeCaseRoot(definition, record, experiment);
47183
+ try {
47184
+ const rootExport = await root.export();
47185
+ const prepared = await root.traced(
47186
+ async (span) => {
47187
+ const value = await classifier(scorerArgs(record));
47188
+ record.classifications[name] = assertJsonValue(
47189
+ value,
47190
+ `classifier ${name} output`
47191
+ );
47192
+ const result = _internalPrepareEvaluatorClassification(value, name);
47193
+ if (result.results !== null) {
47194
+ span.log({ output: result.output, metadata: result.metadata });
47195
+ }
47196
+ return result;
47197
+ },
47198
+ {
47199
+ name,
47200
+ spanId: deterministicId(
47201
+ `${state.runId}:${record.id}:classification:${name}`
47202
+ ),
47203
+ spanAttributes: {
47204
+ type: "classifier" /* CLASSIFIER */,
47205
+ purpose: "scorer"
47206
+ },
47207
+ propagatedEvent: makeScorerPropagatedEvent(rootExport || void 0),
47208
+ event: { input: scorerArgs(record) }
47209
+ }
47210
+ );
47211
+ if (prepared.classifications) {
47212
+ root.log({ classifications: prepared.classifications });
47213
+ }
47214
+ record.loggedClassifications[name] = true;
47215
+ } catch (error) {
47216
+ logError(root, error);
47217
+ throw error;
47218
+ } finally {
47219
+ root.end();
47220
+ }
47221
+ }
47222
+ async function ensureBatches(definition, state, store, key, kind, scorerName2) {
47223
+ const processor = processorForStage(definition, kind, scorerName2);
47224
+ const plans = plannedBatches(
47225
+ definition,
47226
+ state.runId,
47227
+ state.cases.map(({ id }) => id)
47228
+ );
47229
+ const casesById = new Map(state.cases.map((record) => [record.id, record]));
47230
+ for (const plan of plans) {
47231
+ if (plan.kind !== kind || plan.scorerName !== scorerName2) continue;
47232
+ if (state.batches.some(({ id }) => id === plan.id)) continue;
47233
+ const records = plan.itemIds.map((id) => casesById.get(id));
47234
+ const ready = records.every(
47235
+ (record) => kind === "task" ? !record.taskComplete : !Object.hasOwn(record.scores, scorerName2)
47236
+ );
47237
+ if (!ready) continue;
47238
+ const batchId = plan.id;
47239
+ const claim = await store.getOrSet(
47240
+ claimRecordKey(key, "batch", batchId),
47241
+ encoder.encode(batchId)
47242
+ );
47243
+ if (!claim.created) continue;
47244
+ const context = { runId: state.runId, batchId };
47245
+ const items = records.map(
47246
+ (record) => kind === "task" ? taskBatchItem(record, state.parameters) : scorerBatchItem(record)
47247
+ );
47248
+ const submissionData = assertJsonValue(
47249
+ await processor.submit(items, context),
47250
+ `submission data for batch ${batchId}`
47251
+ );
47252
+ const externalId = processor.completion.mode === "webhook" ? processor.completion.getExternalId(submissionData, context) : void 0;
47253
+ if (externalId !== void 0 && !externalId.trim()) {
47254
+ throw new Error(`Batch ${batchId} produced an empty externalId`);
47255
+ }
47256
+ const batch = {
47257
+ id: batchId,
47258
+ kind,
47259
+ scorerName: scorerName2,
47260
+ itemIds: records.map((record) => record.id),
47261
+ submissionData,
47262
+ externalId,
47263
+ status: "submitted"
47264
+ };
47265
+ state.batches.push(batch);
47266
+ await writeBatchRecords(store, key, [batch]);
47267
+ }
47268
+ }
47269
+ async function collectBatch(definition, state, batch) {
47270
+ const processor = processorForStage(definition, batch.kind, batch.scorerName);
47271
+ const context = { runId: state.runId, batchId: batch.id };
47272
+ const results = await processor.collect(batch.submissionData, context);
47273
+ if (!Array.isArray(results)) {
47274
+ throw new Error(`collect for batch ${batch.id} must return an array`);
47275
+ }
47276
+ const expectedIds = new Set(batch.itemIds);
47277
+ const seen = /* @__PURE__ */ new Set();
47278
+ const records = [];
47279
+ for (const result of results) {
47280
+ const id = resultItemId(result);
47281
+ if (!expectedIds.has(id)) {
47282
+ throw new Error(`Batch ${batch.id} returned unknown item ${id}`);
47283
+ }
47284
+ if (seen.has(id)) {
47285
+ throw new Error(`Batch ${batch.id} returned item ${id} more than once`);
47286
+ }
47287
+ seen.add(id);
47288
+ const record = state.cases.find((candidate) => candidate.id === id);
47289
+ records.push(record);
47290
+ if (batch.kind === "task") {
47291
+ record.output = assertJsonValue(
47292
+ result.output,
47293
+ `task output for item ${id}`
47294
+ );
47295
+ if ("metadata" in result && result.metadata !== void 0) {
47296
+ record.metadata = assertJsonValue(
47297
+ {
47298
+ ...record.metadata,
47299
+ ...result.metadata
47300
+ },
47301
+ `metadata for ${id}`
47302
+ );
47303
+ }
47304
+ if ("tags" in result && result.tags !== void 0)
47305
+ record.tags = result.tags;
47306
+ record.taskComplete = true;
47307
+ } else {
47308
+ record.scores[batch.scorerName] = assertJsonValue(
47309
+ result.score,
47310
+ `score output for item ${id}`
47311
+ );
47312
+ }
47313
+ }
47314
+ const missing = batch.itemIds.filter((id) => !seen.has(id));
47315
+ if (missing.length > 0) {
47316
+ throw new Error(
47317
+ `Batch ${batch.id} did not return results for: ${missing.join(", ")}`
47318
+ );
47319
+ }
47320
+ return records;
47321
+ }
47322
+ function processorForStage(definition, kind, scorerName2) {
47323
+ if (kind === "task") {
47324
+ if (!isBatchTask(definition.evaluator.task)) {
47325
+ throw new Error("Definition no longer contains the batch task");
47326
+ }
47327
+ return definition.evaluator.task.processor;
47328
+ }
47329
+ const scorer = resolveScorers(definition.evaluator.scores ?? []).find(
47330
+ ({ name }) => name === scorerName2
47331
+ )?.scorer;
47332
+ if (!isBatchScorer(scorer)) {
47333
+ throw new Error(`Definition no longer contains scorer ${scorerName2}`);
47334
+ }
47335
+ return scorer.processor;
47336
+ }
47337
+ async function materializeCases(definition, data, experiment) {
47338
+ const evaluator = definition.evaluator;
47339
+ const iterable = await _internalResolveEvaluatorData(
47340
+ {
47341
+ data,
47342
+ projectName: definition.projectName,
47343
+ projectId: evaluator.projectId,
47344
+ state: evaluator.state
47345
+ },
47346
+ experiment
47347
+ );
47348
+ const records = [];
47349
+ const seen = /* @__PURE__ */ new Set();
47350
+ for await (const datum of iterable) {
47351
+ const caseId = datum.id ?? datum.upsert_id ?? (evaluator.caseId ? await evaluator.caseId(datum) : void 0);
47352
+ if (!caseId) {
47353
+ throw new Error(
47354
+ "Every durable eval case requires id, upsert_id, or caseId"
47355
+ );
47356
+ }
47357
+ if (seen.has(caseId))
47358
+ throw new Error(`Duplicate durable eval case id: ${caseId}`);
47359
+ seen.add(caseId);
47360
+ const trialCount = datum.trialCount ?? evaluator.trialCount ?? 1;
47361
+ if (!Number.isInteger(trialCount) || trialCount < 1) {
47362
+ throw new Error(`Invalid trialCount for durable eval case ${caseId}`);
47363
+ }
47364
+ for (let trialIndex = 0; trialIndex < trialCount; trialIndex++) {
47365
+ records.push({
47366
+ id: `${caseId}:trial:${trialIndex}`,
47367
+ caseId,
47368
+ trialIndex,
47369
+ datum: assertJsonValue(datum, `case ${caseId}`),
47370
+ metadata: assertJsonValue(
47371
+ "metadata" in datum ? datum.metadata : {},
47372
+ `metadata for ${caseId}`
47373
+ ),
47374
+ tags: datum.tags,
47375
+ taskComplete: false,
47376
+ taskLogged: false,
47377
+ scores: /* @__PURE__ */ Object.create(null),
47378
+ loggedScores: /* @__PURE__ */ Object.create(null),
47379
+ classifications: /* @__PURE__ */ Object.create(null),
47380
+ loggedClassifications: /* @__PURE__ */ Object.create(null)
47381
+ });
47382
+ }
47383
+ }
47384
+ return records;
47385
+ }
47386
+ function taskBatchItem(record, parameters) {
47387
+ const datum = record.datum;
47388
+ return {
47389
+ id: record.id,
47390
+ input: datum.input,
47391
+ expected: "expected" in datum ? datum.expected : void 0,
47392
+ metadata: record.metadata,
47393
+ tags: record.tags,
47394
+ parameters,
47395
+ trialIndex: record.trialIndex
47396
+ };
47397
+ }
47398
+ function scorerBatchItem(record) {
47399
+ const datum = record.datum;
47400
+ return {
47401
+ id: record.id,
47402
+ input: datum.input,
47403
+ output: record.output,
47404
+ expected: "expected" in datum ? datum.expected : void 0,
47405
+ metadata: record.metadata,
47406
+ tags: record.tags,
47407
+ trialIndex: record.trialIndex
47408
+ };
47409
+ }
47410
+ async function finishExperiment(definition, state, experiment) {
47411
+ const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
47412
+ ({ name }) => name
47413
+ );
47414
+ const results = state.cases.map((record) => {
47415
+ const datum = record.datum;
47416
+ const scores = Object.fromEntries(
47417
+ scorerNames.flatMap(
47418
+ (name) => Object.entries(
47419
+ _internalPrepareEvaluatorScore(
47420
+ record.scores[name],
47421
+ name
47422
+ ).scores ?? {}
47423
+ )
47424
+ )
47425
+ );
47426
+ const classifications = Object.fromEntries(
47427
+ Object.entries(record.classifications).flatMap(
47428
+ ([name, value]) => Object.entries(
47429
+ _internalPrepareEvaluatorClassification(value, name).classifications ?? {}
47430
+ )
47431
+ )
47432
+ );
47433
+ return {
47434
+ ...datum,
47435
+ output: record.output,
47436
+ metadata: record.metadata,
47437
+ tags: record.tags,
47438
+ scores,
47439
+ error: void 0,
47440
+ ...Object.keys(classifications).length > 0 ? { classifications } : {}
47441
+ };
47442
+ });
47443
+ if (!experiment) {
47444
+ return buildLocalSummary(
47445
+ {
47446
+ ...definition.evaluator,
47447
+ projectName: definition.projectName,
47448
+ evalName: state.experimentName
47449
+ },
47450
+ results
47451
+ );
47452
+ }
47453
+ await experiment.flush();
47454
+ let comparisonExperimentId = definition.evaluator.baseExperimentId;
47455
+ if (!comparisonExperimentId) {
47456
+ try {
47457
+ comparisonExperimentId = await experiment._getBaseExperimentId();
47458
+ } catch {
47459
+ comparisonExperimentId = void 0;
47460
+ }
47461
+ }
47462
+ return await experiment.summarize({
47463
+ summarizeScores: definition.evaluator.summarizeScores,
47464
+ ...comparisonExperimentId ? { comparisonExperimentId } : {}
47465
+ });
47466
+ }
47467
+ function resolveScorers(scorers) {
47468
+ return scorers.map((scorer, index) => ({
47469
+ name: isBatchScorer(scorer) ? scorer.name : scorer.name || `scorer_${index}`,
47470
+ scorer
47471
+ }));
47472
+ }
47473
+ function runKey(projectName, evalName, runId) {
47474
+ return `durable-eval/v1/runs/${contentVersion(encoder.encode(`${projectName}\0${evalName}\0${runId}`))}`;
47475
+ }
47476
+ function encodedKeyPart(value) {
47477
+ return uint8ArrayToBase64(encoder.encode(value)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
47478
+ }
47479
+ function caseRecordKey(key, caseId, kind, ...names) {
47480
+ const suffix = names.map(encodedKeyPart).join("/");
47481
+ return `${key}/cases/${encodedKeyPart(caseId)}/${kind}${suffix ? `/${suffix}` : ""}`;
47482
+ }
47483
+ function batchRecordKey(key, batchId) {
47484
+ return `${key}/batches/${encodedKeyPart(batchId)}`;
47485
+ }
47486
+ function claimRecordKey(key, kind, ...parts) {
47487
+ const identity = stableStringify([kind, parts]);
47488
+ return `${key}/claims/${contentVersion(encoder.encode(identity))}`;
47489
+ }
47490
+ async function claimAction(store, key, kind, ...parts) {
47491
+ return (await store.getOrSet(
47492
+ claimRecordKey(key, kind, ...parts),
47493
+ encoder.encode("claimed")
47494
+ )).created;
47495
+ }
47496
+ function plannedBatches(definition, runId, caseIds) {
47497
+ const stages = [];
47498
+ if (isBatchTask(definition.evaluator.task)) stages.push({ kind: "task" });
47499
+ for (const { name, scorer } of resolveScorers(
47500
+ definition.evaluator.scores ?? []
47501
+ )) {
47502
+ if (isBatchScorer(scorer)) {
47503
+ stages.push({ kind: "score", scorerName: name });
47504
+ }
47505
+ }
47506
+ const plans = [];
47507
+ for (const { kind, scorerName: scorerName2 } of stages) {
47508
+ const batchSize = processorForStage(definition, kind, scorerName2).batchSize ?? DEFAULT_BATCH_SIZE;
47509
+ if (!Number.isInteger(batchSize) || batchSize < 1) {
47510
+ throw new Error(
47511
+ `Invalid batchSize for ${scorerName2 ?? "task"}: ${batchSize}`
47512
+ );
47513
+ }
47514
+ for (let offset = 0; offset < caseIds.length; offset += batchSize) {
47515
+ const itemIds = caseIds.slice(offset, offset + batchSize);
47516
+ plans.push({
47517
+ id: deterministicId(
47518
+ stableStringify([runId, kind, scorerName2, itemIds])
47519
+ ),
47520
+ kind,
47521
+ scorerName: scorerName2,
47522
+ itemIds
47523
+ });
47524
+ }
47525
+ }
47526
+ return plans;
47527
+ }
47528
+ async function readCaseRecord(definition, store, key, id) {
47529
+ const scorers = resolveScorers(definition.evaluator.scores ?? []);
47530
+ const classifiers = (definition.evaluator.classifiers ?? []).map(
47531
+ classifierName
47532
+ );
47533
+ const [
47534
+ base,
47535
+ task,
47536
+ taskLog,
47537
+ scoreValues,
47538
+ scoreLogValues,
47539
+ classificationValues,
47540
+ classificationLogValues
47541
+ ] = await Promise.all([
47542
+ readJson(store, caseRecordKey(key, id, "base")),
47543
+ readJson(store, caseRecordKey(key, id, "task")),
47544
+ readJson(store, caseRecordKey(key, id, "task-log")),
47545
+ Promise.all(
47546
+ scorers.map(async ({ name }) => ({
47547
+ name,
47548
+ value: await readJson(
47549
+ store,
47550
+ caseRecordKey(key, id, "score", name)
47551
+ )
47552
+ }))
47553
+ ),
47554
+ Promise.all(
47555
+ scorers.map(async ({ name }) => ({
47556
+ name,
47557
+ value: await readJson(
47558
+ store,
47559
+ caseRecordKey(key, id, "score-log", name)
47560
+ )
47561
+ }))
47562
+ ),
47563
+ Promise.all(
47564
+ classifiers.map(async (name) => ({
47565
+ name,
47566
+ value: await readJson(
47567
+ store,
47568
+ caseRecordKey(key, id, "classification", name)
47569
+ )
47570
+ }))
47571
+ ),
47572
+ Promise.all(
47573
+ classifiers.map(async (name) => ({
47574
+ name,
47575
+ value: await readJson(
47576
+ store,
47577
+ caseRecordKey(key, id, "classification-log", name)
47578
+ )
47579
+ }))
47580
+ )
47581
+ ]);
47582
+ if (!base) throw new Error(`Durable eval case ${id} is missing`);
47583
+ const scores = /* @__PURE__ */ Object.create(null);
47584
+ for (const { name, value } of scoreValues) {
47585
+ if (value !== void 0) scores[name] = value;
47586
+ }
47587
+ const loggedScores = /* @__PURE__ */ Object.create(null);
47588
+ for (const { name, value } of scoreLogValues) {
47589
+ if (value) loggedScores[name] = true;
47590
+ }
47591
+ const classifications = /* @__PURE__ */ Object.create(null);
47592
+ for (const { name, value } of classificationValues) {
47593
+ if (value !== void 0) classifications[name] = value;
47594
+ }
47595
+ const loggedClassifications = /* @__PURE__ */ Object.create(null);
47596
+ for (const { name, value } of classificationLogValues) {
47597
+ if (value) loggedClassifications[name] = true;
47598
+ }
47599
+ return {
47600
+ ...base,
47601
+ metadata: task?.metadata ?? base.metadata,
47602
+ tags: task ? task.tags : base.tags,
47603
+ taskComplete: task !== void 0,
47604
+ taskLogged: taskLog !== void 0,
47605
+ output: task?.output,
47606
+ rootSpan: taskLog?.rootSpan,
47607
+ scores,
47608
+ loggedScores,
47609
+ classifications,
47610
+ loggedClassifications
47611
+ };
47612
+ }
47613
+ async function readRunState(definition, store, key) {
47614
+ const record = await readJson(store, key);
47615
+ if (!record) return void 0;
47616
+ const plans = plannedBatches(definition, record.runId, record.caseIds);
47617
+ const [cases, batchRecords] = await Promise.all([
47618
+ Promise.all(
47619
+ record.caseIds.map((id) => readCaseRecord(definition, store, key, id))
47620
+ ),
47621
+ Promise.all(
47622
+ plans.map(async ({ id }) => {
47623
+ return readJson(store, batchRecordKey(key, id));
47624
+ })
47625
+ )
47626
+ ]);
47627
+ const batches = batchRecords.filter(
47628
+ (value) => value !== void 0
47629
+ );
47630
+ const { caseIds: _caseIds, ...state } = record;
47631
+ return { ...state, cases, batches };
47632
+ }
47633
+ async function writeRunRecord(store, key, state) {
47634
+ const { cases, batches: _batches, ...record } = state;
47635
+ await writeJson(store, key, {
47636
+ ...record,
47637
+ caseIds: cases.map(({ id }) => id)
47638
+ });
47639
+ }
47640
+ async function writeCaseBaseRecords(store, key, records) {
47641
+ await Promise.all(
47642
+ records.map(
47643
+ ({ id, caseId, trialIndex, datum, metadata, tags }) => writeJson(store, caseRecordKey(key, id, "base"), {
47644
+ id,
47645
+ caseId,
47646
+ trialIndex,
47647
+ datum,
47648
+ metadata,
47649
+ tags
47650
+ })
47651
+ )
47652
+ );
47653
+ }
47654
+ async function writeCaseRecords(store, key, records) {
47655
+ const writes = [];
47656
+ for (const record of records) {
47657
+ if (record.taskComplete) {
47658
+ writes.push(
47659
+ writeJson(store, caseRecordKey(key, record.id, "task"), {
47660
+ output: record.output,
47661
+ metadata: record.metadata,
47662
+ tags: record.tags,
47663
+ taskComplete: true
47664
+ })
47665
+ );
47666
+ }
47667
+ if (record.taskLogged) {
47668
+ writes.push(
47669
+ writeJson(store, caseRecordKey(key, record.id, "task-log"), {
47670
+ rootSpan: record.rootSpan,
47671
+ taskLogged: true
47672
+ })
47673
+ );
47674
+ }
47675
+ for (const [name, value] of Object.entries(record.scores)) {
47676
+ writes.push(
47677
+ writeJson(store, caseRecordKey(key, record.id, "score", name), value)
47678
+ );
47679
+ }
47680
+ for (const name of Object.keys(record.loggedScores)) {
47681
+ writes.push(
47682
+ writeJson(
47683
+ store,
47684
+ caseRecordKey(key, record.id, "score-log", name),
47685
+ true
47686
+ )
47687
+ );
47688
+ }
47689
+ for (const [name, value] of Object.entries(record.classifications)) {
47690
+ writes.push(
47691
+ writeJson(
47692
+ store,
47693
+ caseRecordKey(key, record.id, "classification", name),
47694
+ value
47695
+ )
47696
+ );
47697
+ }
47698
+ for (const name of Object.keys(record.loggedClassifications)) {
47699
+ writes.push(
47700
+ writeJson(
47701
+ store,
47702
+ caseRecordKey(key, record.id, "classification-log", name),
47703
+ true
47704
+ )
47705
+ );
47706
+ }
47707
+ }
47708
+ await Promise.all(writes);
47709
+ }
47710
+ async function writeBatchRecords(store, key, records) {
47711
+ await Promise.all(
47712
+ records.map(
47713
+ (record) => writeJson(store, batchRecordKey(key, record.id), record)
47714
+ )
47715
+ );
47716
+ }
47717
+ function deterministicId(value) {
47718
+ const hex = contentVersion(encoder.encode(value)).padEnd(32, "0").slice(0, 32);
47719
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-5${hex.slice(13, 16)}-a${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
47720
+ }
47721
+ function contentVersion(value) {
47722
+ if (isomorph_default.hash) return isomorph_default.hash(decoder.decode(value));
47723
+ let hash = 2166136261;
47724
+ for (const byte of value) {
47725
+ hash ^= byte;
47726
+ hash = Math.imul(hash, 16777619);
47727
+ }
47728
+ return (hash >>> 0).toString(16).padStart(8, "0");
47729
+ }
47730
+ async function readJson(store, key) {
47731
+ const value = await store.read(key);
47732
+ return value ? JSON.parse(decoder.decode(value)) : void 0;
47733
+ }
47734
+ async function writeJson(store, key, value) {
47735
+ await store.write(key, encoder.encode(stableStringify(value)));
47736
+ }
47737
+ function stableStringify(value) {
47738
+ return JSON.stringify(value, (_key, nested) => {
47739
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
47740
+ return Object.fromEntries(
47741
+ Object.entries(nested).sort(
47742
+ ([left], [right]) => left.localeCompare(right)
47743
+ )
47744
+ );
47745
+ }
47746
+ return nested;
47747
+ });
47748
+ }
47749
+ function assertJsonValue(value, label) {
47750
+ try {
47751
+ const serialized = JSON.stringify(value);
47752
+ if (serialized === void 0)
47753
+ throw new Error("value serializes to undefined");
47754
+ return JSON.parse(serialized);
47755
+ } catch (error) {
47756
+ throw new Error(`${label} must be JSON serializable`, { cause: error });
47757
+ }
47758
+ }
47759
+ function resultItemId(value) {
47760
+ if (typeof value !== "object" || value === null || !("id" in value) || typeof value.id !== "string") {
47761
+ throw new Error("Batch results must contain a string id");
47762
+ }
47763
+ return value.id;
47764
+ }
47765
+ function isBatchTask(value) {
47766
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_TASK_KIND;
47767
+ }
47768
+ function isBatchScorer(value) {
47769
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_SCORER_KIND;
47770
+ }
47771
+ function asError(error) {
47772
+ return error instanceof Error ? error : new Error(String(error));
47773
+ }
47774
+
45764
47775
  // src/agent-assertions.ts
45765
47776
  function agentAssertionScorer(callback, options = {}) {
45766
47777
  return async (args) => {
@@ -46693,6 +48704,8 @@ export {
46693
48704
  BRAINTRUST_PARENT_KEY,
46694
48705
  BaseAttachment,
46695
48706
  BaseExperiment,
48707
+ BatchScorer,
48708
+ BatchTask,
46696
48709
  BraintrustLangChainCallbackHandler,
46697
48710
  BraintrustMiddleware,
46698
48711
  BraintrustObservabilityExporter,
@@ -46706,6 +48719,8 @@ export {
46706
48719
  DEFAULT_MAX_REQUEST_SIZE,
46707
48720
  Dataset2 as Dataset,
46708
48721
  DatasetPipeline,
48722
+ DurableEvalMemoryStore,
48723
+ DurableEvalRedisStore,
46709
48724
  ERR_PERMALINK,
46710
48725
  Eval,
46711
48726
  EvalResultWithSummary,
@@ -46764,6 +48779,7 @@ export {
46764
48779
  deepCopyEvent,
46765
48780
  exports_exports as default,
46766
48781
  defaultErrorScoreHandler,
48782
+ defineDurableEval,
46767
48783
  deserializePlainStringAsJSON,
46768
48784
  devNullWritableStream,
46769
48785
  evaluatorDefinitionSchema,
@@ -46859,5 +48875,6 @@ export {
46859
48875
  wrapPiCodingAgentSDK,
46860
48876
  wrapStrandsAgentSDK,
46861
48877
  wrapTraced,
46862
- wrapVitest
48878
+ wrapVitest,
48879
+ wrapVoyageAI
46863
48880
  };